Torna alla documentazione
Guida 10

Sviluppo

Guida per contribuire al codebase: setup, struttura monorepo, script, convenzioni, i18n.

4 min di lettura

Guida per contribuire al codebase: setup, struttura monorepo, script, convenzioni, i18n.

Prerequisiti: Node.js >=24.0.0 (enforced da engines.node nel root package.json), pnpm 12.8.1 (pinnato via packageManager), PostgreSQL 16 (DEVELOPMENT.md row-time).

Setup

bash
git clone <repo> && cd simmetric-chat
pnpm install            # installa dipendenze tutti i package
cp .env.example .env    # .env radice = unica config runtime; poi edita JWT_SECRET, COLLECTOR_SECRET
pnpm db:generate        # client Prisma (+ fix symlink Prisma 7/pnpm)
pnpm db:migrate         # applica le migrazioni (prisma migrate dev)
pnpm db:seed            # ruoli, permessi, config, admin bootstrap
pnpm dev                # avvia server/collector/widget/frontend via turborepo

PostgreSQL 16 in locale (es. docker compose -f docker/docker-compose.infra.yml up -d postgres). pnpm db:migrate applica le migrazioni Prisma (packages/server/prisma/migrations); pnpm db:seed semina ruoli/permessi e l'admin bootstrap (admin / admin123, mustChangePassword=true). Le migrazioni sono additive-only: le destructive richiedono consenso esplicito (PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION) e pnpm audit:migrations rigenera docs/MIGRATION_AUDIT.md da committare nella stessa PR.

Struttura monorepo

pnpm workspaces + Turborepo. 5 package + Tauri:

PackagePortaStackRuolo
shared-TS + ZodTipi, schema, costanti (leaf, dip solo zod)
server3000Express + PrismaAPI, RBAC, agent, RAG FTS/RRF, backup
collector3210ExpressIngestione, parsing, embedding, vector store
widget3211Express + Preact IIFEWidget embeddabile
frontend5173Vite + React 19 + TailwindSPA admin/chat
src-tauri-Rust + TauriDesktop app

Grafo dipendenze: shared ← {server, collector, frontend, widget}. Modularità strict: server↔collector = HTTP only (COLLECTOR_SECRET); widget↔server = API key (X-Api-Key). Nessun import diretto tra server/collector/widget.

Script comuni

ScriptScopeDescrizione
pnpm devrootTurborepo: avvia tutti i servizi in parallelo
pnpm buildrootBuild produzione tutti i package (dipende da ^build)
pnpm lintrootESLint 10 flat config, tutti i package
pnpm typecheckrootTypeScript strict mode
pnpm testrootJest (5 progetti, Postgres-free) via Turborepo
pnpm test:allrootStesse 5 suite via jest.config.cjs (Jest puro)
pnpm test:e2erootPlaywright
pnpm db:generaterootRigenera il client Prisma
pnpm db:migrateserverprisma migrate dev
pnpm db:seedserverSeed ruoli/permessi/config
pnpm audit:migrationsserverAudit migrazioni destructive → docs/MIGRATION_AUDIT.md
pnpm i18n:checkrootVerifica parità traduzioni 8 locale
pnpm kniprootDead-code gate (file/dipendenze/export inutilizzati)
pnpm license:checkserverVerifica licenza configurata senza boot del server

Script per-package in packages/<pkg>/package.json. Turborepo cachea output e dipendenze tra task. pnpm db:generate deve girare prima di build/lint/typecheck/test (task turbo build dipende da esso).

Convenzioni di codice

  • TypeScript strict ovunque; niente any non giustificato (target ES2022).
  • Zod per validazione input (shared definisce gli schema riutilizzabili; valida con safeParse nei route handler → 400 invece di 500).
  • Prisma come ORM (Prisma 7, driver adapter); schema in packages/server/prisma/schema.prisma. Mai new PrismaClient(): singleton da src/utils/prisma (pool driver-adapter + withSoftDelete()).
  • RBAC via middleware: requirePermission, requireAdmin, requireWorkspaceAccess (44 permessi in shared/src/constants/permissions.ts).
  • Error handling: risposte { error } (400/401/403/404/409/402/429/500); validazione Zod → 400 con details; license gating → 402 { error, feature, tier }.
  • SSE per streaming chat (@microsoft/fetch-event-source lato frontend).
  • Logging: LOG_LEVEL env; usa il logger configurato, non console.log diretto in prod.
  • Commit: formato Conventional Commits (feat:, fix:, docs:, refactor:...); una modifica logica per commit; un bullet [Unreleased] in CHANGELOG.md per ogni modifica a packages/*/src/** (pnpm changelog:check).

Frontend (React 19)

  • State 3-tier (server-persisted / session / local) - TanStack Query per REST/CRUD, React Context per UI state, fetchEventSource per SSE.
  • shadcn/ui + Tailwind per l'admin; widget usa Preact + Tailwind, NO shadcn (IIFE bundle).
  • i18n via hook; file in packages/frontend/src/i18n/<locale>/translation.json.
  • Shortcut chat: /model (palette Cmd+K), confronto Cmd+Shift+M.
  • ESLint: React Compiler + rules-of-hooks error in sorgente; module format ESM (root + frontend) vs CommonJS (server/collector/shared/widget) - rispetta il tsconfig per package.
  • Il Vite proxy retry hook NON si rimuove: il server (tsx watch) parte più lento di Vite (~1s); packages/frontend/vite.config.ts installa un handler onError che riprova ECONNREFUSED fino a 8 volte su ~4s (solo GET/HEAD - i body POST/SSE non vengono mai replayati) e poi restituisce un 502 conciso. L'handler di default sversa uno stack AggregateError su ogni cold start.

Server (Express)

  • Route in src/routes/, servizi in src/services/, middleware in src/middleware/.
  • Agent in src/agent/ (orchestrator.ts, builtinSkills.ts, mcpClient.ts).
  • Config env in src/config/env.ts (Zod, process.exit(1) se invalide).
  • OpenAPI via annotazioni @openapi JSDoc → Swagger su /api-docs.
  • Job queue pg-boss (Postgres-backed): 12 cron-style schedulers (MCP health-check, MCP reaper, synthesis reaper, weekly fidelity sampling, vector cleanup, upload-draft reaping, chat-message retention, hourly token-quota reset, DLP document scan/backfill, MCP OAuth token refresh, daily connector health sweep) + un guard self-heal delle code; initWikiConsistencyScheduler gira come intervallo in-process. Le pipeline OCR + synthesis restano su setInterval 10s poller (dev e prod). Multi-instance-ready senza infrastruttura extra (vedi 02 - Architecture).

i18n

8 locale con file concreti: en, it, ru, de, fr, es, zh, pt (EN è la baseline; parità strict - nessuna lingua può restare indietro). Aggiungi le chiavi in tutti e otto i file. pnpm i18n:check (frontend + widget) esce 1 su chiavi mancanti o extra in qualunque locale rispetto a en; il widget check fallisce anche su valori stringa vuoti. Il set locale del widget è pinnato contro ALL_LANGUAGES del frontend da widgetLocalesParity.test.ts - aggiungi/rimuovi lingue in entrambi i posti insieme.

Aggiungere una feature (workflow)

  1. Schema shared - tipi/Zod in packages/shared/src/.
  2. Prisma - modello + migrazione (pnpm db:migrate; audit se destructive).
  3. Server - servizio + route + middleware RBAC/license.
  4. Frontend - UI + hook + i18n (tutte le 8 lingue).
  5. Test - unit (Prisma mock) + integration (worker DB) + E2E se user-facing.
  6. Docs - aggiorna docs/ e OpenAPI @openapi; changelog [Unreleased] se tocca src/.

Estensioni comuni

  • Nuova skill agente: registerSkill in server/src/agent/builtinSkills.ts.
  • Nuovo endpoint: route in server/src/routes/ + mount in src/index.ts.
  • Nuovo permesso: PERMISSION_NAMES in shared/src/constants/permissions.ts + ruoli.
  • Nuovo provider LLM: preset in shared/src/constants/providerPresets.ts (seedato in provider_presets) + handler in server/src/agent/llmStreaming.ts + providerService.
  • Nuova destinazione backup: implementa IBackupDestinationProvider nei provider backup del plugin Enterprise (services/backup/providers/).

Provenienza v0.28.1

AffermazioneFonte
44 permessi (PERMISSION_NAMES)packages/shared/src/constants/permissions.ts (conteggio row-time, probe 35-02) - F-RBAC-1
Node.js >=24.0.0 (engines.node), pnpm 12.8.1 (packageManager), PostgreSQL 16docs/DEVELOPMENT.md (§ Prerequisites, row-time)
Il Vite proxy retry hook (8 riprova GET/HEAD, POST/SSE mai replayati)docs/DEVELOPMENT.md (§ Proxy, row-time)
pg-boss: 12 cron-style schedulers + self-heal guard; wiki-consistency in-process; OCR/URL + synthesis poller 10sdocs/ARCHITECTURE.md:175-176 (row-time)

Riferimento operativo - Simmetric Chat v0.28.1 (docs aggiornate 2026-10-02, census SHA `aca5b8ff`).