Ir para o conteúdo
Q
QuoteNode

Instalação

Instalar num Portátil Local

Corre o QuoteNode localmente para avaliação sem o expor a clientes.

Instalar num Portátil Local

Usa este caminho quando queres experimentar o QuoteNode num computador. É a forma mais rápida de avaliar a aplicação, mas não é um deployment orientado a clientes.

Quando usar

  • Queres uma instância de demo ou avaliação.
  • Estás a testar criação de propostas, PDFs, templates, produtos e definições.
  • Não precisas que os clientes abram links públicos de propostas a partir de outro dispositivo.

O que não vai funcionar

  • Links públicos de propostas gerados como http://localhost/... funcionam apenas no mesmo portátil.
  • Links de email normalmente não são úteis porque os destinatários não conseguem abrir localhost a partir das suas máquinas.
  • HTTPS normalmente não está configurado para esta topologia.
  • O portátil deve estar acordado e o Docker deve estar a correr.

Pré-requisitos

  • Docker Desktop ou Docker Engine com Docker Compose v2.
  • Pelo menos 2,5 GB de RAM disponíveis para a stack.
  • Pelo menos 10 GB de espaço livre em disco.

Verifica a tua configuração:

docker --version        # Should show 24.0+
docker compose version  # Should show v2.x

Passo 1 — Criar uma diretoria de projeto

mkdir quotenode && cd quotenode

Passo 2 — Criar o ficheiro de configuração

Cria um ficheiro chamado .env com as definições mínimas necessárias. Gera os teus próprios segredos — não uses os valores de substituição em produção:

# Database
DB_URL=jdbc:postgresql://postgres:5432/quotenode
DB_USERNAME=quotenode
DB_PASSWORD=change-me-to-something-random-32-chars
DB_NAME=quotenode

# ============================================================
# SECURITY SECRETS — READ THIS BEFORE CONTINUING
# These values are UNIQUE to your installation.
# If you lose this file, you CANNOT regenerate the same secrets.
# SAVE THIS FILE and keep a secure backup.
# ============================================================
DB_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
TIMING_TOKEN_SECRET=change-me-timing-secret-min-32-chars
PUBLIC_LINK_PASSWORD_SESSION_SECRET=change-me-session-secret-min-32

# Domain (for CORS and Caddy)
CORS_ALLOWED_ORIGINS=http://localhost
DOMAIN=localhost

# O IP do cliente é detetado automaticamente atrás de proxies internos e CDNs (incluindo Cloudflare) — deixe vazio.
# Defina apenas para um proxy invulgar cujo par de transporte seja um endereço PÚBLICO a confiar (IP/CIDR ou nome de host).
SECURITY_TRUSTED_PROXIES=

# Application
LOG_LEVEL=INFO
SPRING_PROFILES_ACTIVE=prod

Guarda o teu ficheiro .env imediatamente. O DB_ENCRYPTION_KEY cifra dados sensíveis em repouso. Se o perderes, os campos cifrados (códigos MFA, password SMTP, chaves API) tornam-se permanentemente ilegíveis. Copia este ficheiro para um local seguro.

Passo 3 — Criar o ficheiro Docker Compose

Cria um ficheiro chamado docker-compose.yml:

services:
  postgres:
    image: postgres:18-alpine
    cpus: 2.0
    mem_limit: 384m
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      PGDATA: /var/lib/postgresql/data   # required for the postgres:18 image
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME}"]
      interval: 10s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  gotenberg:
    image: gotenberg/gotenberg:8
    cpus: 2.0
    mem_limit: 384m
    environment:
      LOG_LEVEL: info
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  backend:
    image: ghcr.io/lesisty7/quotenode/quotenode-api:latest
    cpus: 2.0
    mem_limit: 1280m
    depends_on:
      postgres: { condition: service_healthy }
      gotenberg: { condition: service_healthy }
    env_file: .env
    environment:
      SPRING_PROFILES_ACTIVE: prod
      # Single-container eval (WEB_MAINTENANCE backup profile): the backend runs
      # scheduled backups in-process, so no separate backup-worker container is needed.
      # For production, split into a web backend + a dedicated backup-only worker.
      JOBS_MODE: all
      BACKUP_RUNTIME_PROFILE: WEB_MAINTENANCE
      PDF_ENABLED: "true"
      PDF_GOTENBERG_URL: http://gotenberg:3000
    volumes:
      - backend_uploads:/app/data/uploads
      - backend_pdfs:/app/data/pdfs
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
      interval: 15s
      timeout: 10s
      retries: 5
      start_period: 45s
    restart: unless-stopped

  frontend:
    image: ghcr.io/lesisty7/quotenode/quotenode-frontend:latest
    cpus: 1.0
    mem_limit: 128m
    depends_on:
      backend: { condition: service_healthy }
    ports:
      - "80:80"
      - "443:443"
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:80/"]
      interval: 15s
      timeout: 5s
      retries: 3
    restart: unless-stopped

volumes:
  postgres_data:
  backend_uploads:
  backend_pdfs:

Passo 4 — Iniciar o QuoteNode

docker compose up -d

O Docker vai descarregar as imagens dos containers (isto demora alguns minutos na primeira execução). Acompanha o progresso do arranque:

docker compose logs -f backend

Aguarda até ver Started QuoteNodeApplication — isso significa que o backend está pronto.

Passo 5 — Abrir o QuoteNode

Navega para http://localhost no teu browser.

Credenciais de acesso predefinidas:

CampoValor
Email[email protected]
PasswordAdmin123!

Altera a password predefinida imediatamente após iniciar sessão (Definições > O meu perfil > Alterar password).

O que está a correr?

Após docker compose up, tens 4 containers:

ContainerO que fazUso de RAM
postgresArmazena todos os teus dados~256 MB
backendServidor API Java, lógica de negócio~512 MB – 1,5 GB
gotenbergConverte HTML para PDF (baseado em Chromium)~200 MB
frontendServe a interface web + reverse proxy~20 MB

Total: aproximadamente 1,5 – 2,5 GB de RAM.

Comandos habituais

# Check if all services are running
docker compose ps

# View logs (all services)
docker compose logs -f

# View logs (backend only)
docker compose logs -f backend

# Stop QuoteNode
docker compose down

# Update to the latest version
docker compose pull && docker compose up -d

Manter os teus segredos seguros

O teu ficheiro .env contém segredos criptográficos únicos para a tua instalação:

SegredoO que protegeSe perdido
DB_PASSWORDAcesso à base de dadosRecuperável — reiniciar via ferramentas de administração PostgreSQL
DB_ENCRYPTION_KEYCódigos MFA, password SMTP, chave API FX e todos os campos PII se ENCRYPT_PII=truePermanentemente ilegível — não pode ser desencriptado sem a chave original
TIMING_TOKEN_SECRETTokens anti-timing-attackRegenerar — tokens existentes invalidados, utilizadores re-autenticam-se
PUBLIC_LINK_PASSWORD_SESSION_SECRETSessões de links públicosRegenerar — sessões ativas expiram, os links continuam a funcionar

O segredo crítico é o DB_ENCRYPTION_KEY. Todos os outros segredos podem ser regenerados com um pequeno incómodo. Mas o DB_ENCRYPTION_KEY cifra dados em repouso — perdê-lo significa que esses campos ficam perdidos para sempre.

Recuperação se .env for perdido

Se perderes o teu ficheiro .env mas tiveres uma cópia de segurança da base de dados não cifrada (o modo de cópia padrão):

  1. Cria um novo .env com novos segredos.
  2. Restaura a base de dados a partir da tua cópia de segurança.
  3. Todos os dados de negócio (clientes, propostas, produtos, utilizadores) serão totalmente acessíveis.
  4. Apenas alguns campos são perdidos: códigos MFA (utilizadores re-inscrevem-se), password SMTP (reinserir nas definições), chave API FX (reinserir nas definições). Se ENCRYPT_PII=true estava ativo, os dados de clientes cifrados também são perdidos.

Cópias de segurança

Esta configuração de contentor único executa as cópias de segurança agendadas dentro do processo do backend (JOBS_MODE: all), por isso não precisas de um contentor backup-worker separado. A própria cópia é executada como um pipeline de shell (pg_dump → compressão → cifragem) fora da JVM, pelo que o seu custo de memória é pequeno — é por isso que o backend no portátil está dimensionado em 1280m em vez de 1g.

Isto é aceitável para um portátil ou uma instância de avaliação. Para uma implementação em produção, executa um contentor worker dedicado backup-only (JOBS_MODE: backup-only) ao lado de um backend web (JOBS_MODE: web) para que as cópias de segurança nunca compitam por memória com o tráfego web. Consulta Cópia de segurança e recuperação.

Mudar do portátil para servidor

Não publiques links de portátil para clientes. Quando estiveres pronto para um deployment partilhado ou público, escolhe um destes caminhos:

Last reviewed: Recently