Simmetric Chat è air-gap capable e local-first. Tre modalità principali: Docker Compose (raccomandata), sviluppo locale (pnpm), desktop Tauri.
Prerequisiti
- Node.js ≥ 20, pnpm ≥ 9, PostgreSQL 16.
- Per embedding locale: ~2 GB RAM per
all-MiniLM-L6-v2(Xenova, CPU). - Per LLM locale: Ollama con modello(s) pre-pullati (
gemma4:latestdefault). - Per OCR vision: Ollama con modello vision (
glm-ocr:latestdefault).
Docker Compose (produzione)
Il repo include docker-compose.yml con servizi: server (:3000), collector (:3210),
widget (:3211), frontend (:5173 o build statica), postgres (16), ollama.
cp .env.example .env
# Modifica .env: JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, DATABASE_URL, LICENSE_KEY (se Enterprise)
docker compose up -d --build
Env critici di produzione (vedi 03 — Configuration):
JWT_SECRET— obbligatorio, materiale critografico (derivaENCRYPTION_KEYse unset).COLLECTOR_SECRET— obbligatorio, deve matchare tra server e collector.WIDGET_API_KEY— obbligatorio per widget, deve matchare tra widget e server.DATABASE_URL— PostgreSQL 16.LICENSE_KEY+LICENSE_SECRET— solo Enterprise.ENCRYPTION_KEY(base64 32 byte) — consigliato per data-at-rest persistente oltre rotazioni diJWT_SECRET.
Rotazione chiavi: imposta
LEGACY_PREVIOUS_ENCRYPTION_KEYS(CSV base64 32-byte) per mantenere decryptabilità dei backup/dati vecchi durante la rotazione. Non esiste job automatico di re-encryption: procedura manuale decrypt-old → re-encrypt-new.
Profili Compose
.env.example documenta --profile enterprise ma il compose non lo definisce
esplicitamente come profilo separato — Enterprise si attiva via LICENSE_KEY, non via
profilo. Verificare la versione corrente di docker-compose.yml prima di affidarsi a
profili.
Volumi & persistenza
- PostgreSQL: volume dedicato (
postgres-data). - LanceDB:
${STORAGE_PATH}/vectors/lancedb(collector). - File storage:
${STORAGE_PATH}(collector, documenti/avatar/uploads). - Backup: destinazioni configurate per-job (disk/S3/Dropbox/...).
Health check post-deploy
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 # widget
Sviluppo locale
pnpm install
pnpm db:setup # crea DB, migra, seed admin
pnpm dev # turborepo: server + collector + widget + frontend paralleli
Dettagli in 10 — Development.
Desktop (Tauri)
packages/src-tauri — app desktop che wrappa il frontend. Build con pnpm tauri:build.
Configura src-tauri/tauri.conf.json per URL server remoto o bundle locale.
Reverse proxy (Nginx)
Punti chiave:
- SSE: disabilitare buffering (
proxy_buffering off;,X-Accel-Buffering: nogià inviato dal server/widget). - Timeout: LLM locali lenti →
proxy_read_timeoutalto (≥ 600s, l'agent watchdog default è 10 min). - Upload:
client_max_body_size≥ 100 MB (limite multer documenti). - CORS: l'allowlist è gestita lato app (
ALLOWED_ORIGINS); il widget ha CORS dinamico per-origin (allowedOrigins).
Backup in produzione
- Crea destinazione (
POST /api/backup-destinations). - Crea job (
POST /api/backup-jobs) con cronfrequency/time+retentionDays. - Verifica con
POST /backup-destinations/:id/teste un run manualePOST /backup-jobs/:id/run. - Restore:
POST /api/backups/restore/:logId(dry-run consigliato prima:/restore/:logId/dry-run). Atomicità via psql--single-transaction.
Vedi 05 — Feature Guide § Backup.
Sicurezza di produzione
- Cambia password admin bootstrap; imposta
ALLOW_REGISTRATION=falsein prod. DLP_ENABLEDdefault false — abilita se gestisci PII (redaction input/output chat).- Abilita
audit_log_immutable(Enterprise) per audit append-only. - HTTPS terminato al reverse proxy; header
helmetattivi sul server (rilassati sul widget per embedding). - Rate limit già configurati (vedi 04 — API Reference § Rate limit);
valuta di alzarli per Enterprise (
chat LLM100/min).
Cross-link
- Env completi: 03 — Configuration
- Sviluppo: 10 — Development
- Troubleshooting deploy: 12 — Troubleshooting