Deploy
Simmetric Chat é air-gap capable e local-first. Cinco targets de deploy: Docker Compose multi-container (recomendado para produção), container único all-in-one (ambientes air-gapped), stack gerido Coolify, override dev (hot-reload sobre Docker) e desktop…
Simmetric Chat é air-gap capable e local-first. Cinco targets de deploy: Docker Compose multi-container (recomendado para produção), container único all-in-one (ambientes air-gapped), stack gerido Coolify, override dev (hot-reload sobre Docker) e desktop Tauri. Todos os artefatos vivem em docker/; o shell desktop em src-tauri/. As imagens publicadas no GHCR são apenas amd64 (linux/amd64 - os builds arm64 emulados via QEMU bloqueavam; em arm64 faz-se self-build local a partir do host nativo). Todos os containers usam healthcheck wget (--spider): server GET /api/health, collector GET /api/health em 3210, widget GET /health em 3211, Postgres pg_isready, Redis redis-cli ping.
Pré-requisitos
- Node.js ≥ 24, pnpm 11.24.0, PostgreSQL 16.
- Para embedding local: ~2 GB RAM por
all-MiniLM-L6-v2(Xenova, CPU). - Para LLM local: Ollama com modelo(s) pré-puxados (
gemma4:latestpor defeito). - Para OCR vision: Ollama com modelo vision (
glm-ocr:latestpor defeito).
Docker Compose (produção)
O compose de produção (docker/docker-compose.yml) define 6 serviços ativos: frontend (nginx, :80/:443), server (:3000), collector (:3210), widget (:3211), postgres (16, imagem pgvector/pgvector:pg16), redis (7-alpine, cache de scaling opcional). ollama e qdrant estão desativados por defeito (blocos comentados: descomenta + define OLLAMA_BASE_URL / VECTOR_DB_PROVIDER=qdrant para os usar).
cp .env.example .env
# Edita .env: JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, DATABASE_URL, LICENSE_KEY (se Enterprise)
docker compose -f docker/docker-compose.yml up -dEnv críticos de produção (ver 03 - Configuration):
JWT_SECRET- obrigatório, material criptográfico (derivaENCRYPTION_KEYse unset).COLLECTOR_SECRET- obrigatório, deve casar entre server e collector.WIDGET_API_KEY- obrigatório para widget, deve casar entre widget e server.DATABASE_URL- PostgreSQL 16.LICENSE_KEY+LICENSE_SECRET- apenas Enterprise.ENCRYPTION_KEY(base64 32 byte) - recomendado para persistência data-at-rest além de rotações deJWT_SECRET.
Rotação de chaves: define LEGACY_PREVIOUS_ENCRYPTION_KEYS (CSV base64 32-byte) para manter a decryptabilidade de backups/dados antigos durante a rotação. Não existe job automático de re-encryption: procedimento manual decrypt-old → re-encrypt-new.Auto-provisioning de chaves (entrypoint server)
O entrypoint de produção (docker/entrypoint-server.sh) executa a cada boot: provisioning de ENCRYPTION_KEY e API_KEY_HMAC_SECRET com precedência valor operator-supplied > valor persisitido no volume server-storage > gerado uma vez e persistido (nunca regenerado sobre material existente); depois prisma migrate deploy + seed e o arranque do servidor. As configurações dev (docker-compose.dev.yml) saltam o provisioning e mantêm o fallback scrypt.
Volumes & persistência
- PostgreSQL: volume dedicado (
pgdata). - LanceDB:
${STORAGE_PATH}/vectors/lancedb(collector). - File storage:
${STORAGE_PATH}(collector, documentos/avatar/uploads). - Backup: destinos configurados por-job (disk/S3/Dropbox/...).
Health check pós-deploy
Os containers auto-verificam-se via wget (ver intro). Checks manuais equivalentes:
curl http://localhost:3000/api/health
# { "status": "ok", "checks": { "database": "ok", "collector": "ok", "disk": "ok" } }
curl http://localhost:3210/api/health # collector
curl http://localhost:3211/health # widgetContainer único all-in-one
docker/Dockerfile constrói uma única imagem supervisionada por supervisord que executa PostgreSQL 16 (pgvector compilado offline para air-gap), server, collector e widget. Expõe 3000/3210/3211, usa DATABASE_URL em localhost, healthcheck em /api/health. Pensada para ambientes air-gapped/offline/demo: os env por defeito são placeholder - sobrescreve-os via .env ou -e.
Coolify
docker/docker-compose.coolify.yml + docker/nginx.coolify.conf automatizam build das imagens, networking interno, volumes, healthchecks e o mount do plugin enterprise (path host absoluto ${ENTERPRISE_PLUGIN_PATH:-/opt/simmetric-enterprise}). Os segredos requeridos usam a sintaxe :? (o Coolify recusa o deploy se faltarem): JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, POSTGRES_PASSWORD, APP_URL, ALLOWED_ORIGINS. Diferenças do compose base: sem container_name, sem porta host nas apps (ingress confiado ao Traefik, HTTP-only - TLS terminado pelo Traefik), ENCRYPTION_KEY/API_KEY_HMAC_SECRET não interpoladas (auto-provisionadas no volume).
Desenvolvimento local
pnpm install
pnpm db:generate # Prisma client (+ fix symlink Prisma/pnpm)
pnpm --filter server db:migrate # aplica as migrações
pnpm dev # turborepo: server + collector + widget + frontend em paraleloDetalhes em 10 - Development.
Override dev (Docker)
docker/docker-compose.dev.yml monta as fontes sobre o compose de produção para hot-reload (NODE_ENV=development). docker-compose.infra.yml arranca apenas Postgres/Qdrant com a app em execução no host.
Desktop (Tauri)
src-tauri/ - app desktop que wrappea o frontend. Build com pnpm tauri build. Configura src-tauri/tauri.conf.json para URL server remota ou bundle local.
Reverse proxy (Nginx)
Pontos-chave:
- SSE: desativar buffering (
proxy_buffering off;,X-Accel-Buffering: nojá enviado pelo server/widget). - Timeout: LLM locais lentos →
proxy_read_timeoutalto (≥ 600s, o agent watchdog default é 10 min). - Upload:
client_max_body_size≥ 100 MB (limite multer documentos). - CORS: a allowlist é gerida do lado app (
ALLOWED_ORIGINS); o widget tem CORS dinâmico per-origem (allowedOrigins).
Backup em produção
- Cria destino (
POST /api/backup-destinations). - Cria job (
POST /api/backup-jobs) com cronfrequency/time+retentionDays. - Verifica com
POST /backup-destinations/:id/teste um run manualPOST /backup-jobs/:id/run. - Restore:
POST /api/backups/restore/:logId(dry-run recomendado antes:/restore/:logId/dry-run). Atomicidade via psql--single-transaction.
Ver 05 - Feature Guide § Backup.
Segurança de produção
- Muda a password admin bootstrap; define
ALLOW_REGISTRATION=falseem prod (self-registration fechada). DLP_ENABLEDdefault"true"em v0.22 - redaction input/output chat sobre 10 padrões built-in (ver 05 - Feature Guide); usaDLP_BYPASS_ROLESpara isentar roles selecionados.- Ativa
audit_log_immutable(Enterprise) para audit append-only. - HTTPS terminado no reverse proxy; headers
helmetativos no server (relaxados no widget para embedding). - Rate limit já configurados (ver 04 - API Reference § Rate limit): o limite chat é agora gerido pelo budget tracker do agente (concorrência per-utilizador, wallclock, token) mais a rede de proteção global 200 req/min.
Cross-link
- Env completos: 03 - Configuration
- Desenvolvimento: 10 - Development
- Troubleshooting deploy: 12 - Troubleshooting