Development
Guide to contributing to the codebase: setup, monorepo structure, scripts, conventions, i18n.
Guide to contributing to the codebase: setup, monorepo structure, scripts, conventions, i18n.
Prerequisites: Node.js >=24.0.0 (enforced by engines.node in the root package.json), pnpm 12.8.1 (pinned via packageManager), PostgreSQL 16 (DEVELOPMENT.md row-time).
Setup
git clone <repo> && cd simmetric-chat
pnpm install # installs dependencies for every package
cp .env.example .env # root .env = single runtime config; then edit JWT_SECRET, COLLECTOR_SECRET
pnpm db:generate # Prisma client (+ Prisma 7/pnpm symlink fix)
pnpm db:migrate # applies the migrations (prisma migrate dev)
pnpm db:seed # roles, permissions, config, admin bootstrap
pnpm dev # starts server/collector/widget/frontend via turborepoPostgreSQL 16 locally (e.g. docker compose -f docker/docker-compose.infra.yml up -d postgres). pnpm db:migrate applies the Prisma migrations (packages/server/prisma/migrations); pnpm db:seed seeds roles/permissions and the admin bootstrap (admin / admin123, mustChangePassword=true). Migrations are additive-only: destructive ones require explicit consent (PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION) and pnpm audit:migrations regenerates docs/MIGRATION_AUDIT.md, to be committed in the same PR.
Monorepo structure
pnpm workspaces + Turborepo. 5 packages + Tauri:
| Package | Port | Stack | Role |
|---|---|---|---|
shared | - | TS + Zod | Types, schemas, constants (leaf, depends only on zod) |
server | 3000 | Express + Prisma | API, RBAC, agent, RAG FTS/RRF, backup |
collector | 3210 | Express | Ingestion, parsing, embedding, vector store |
widget | 3211 | Express + Preact IIFE | Embeddable widget |
frontend | 5173 | Vite + React 19 + Tailwind | Admin/chat SPA |
src-tauri | - | Rust + Tauri | Desktop app |
Dependency graph: shared ← {server, collector, frontend, widget}. Strict modularity: server↔collector = HTTP only (COLLECTOR_SECRET); widget↔server = API key (X-Api-Key). No direct imports among server/collector/widget.
Common scripts
| Script | Scope | Description |
|---|---|---|
pnpm dev | root | Turborepo: starts all services in parallel |
pnpm build | root | Production build for all packages (depends on ^build) |
pnpm lint | root | ESLint 10 flat config, all packages |
pnpm typecheck | root | TypeScript strict mode |
pnpm test | root | Jest (5 projects, Postgres-free) via Turborepo |
pnpm test:all | root | Same 5 suites via jest.config.cjs (plain Jest) |
pnpm test:e2e | root | Playwright |
pnpm db:generate | root | Regenerates the Prisma client |
pnpm db:migrate | server | prisma migrate dev |
pnpm db:seed | server | Seeds roles/permissions/config |
pnpm audit:migrations | server | Audits destructive migrations → docs/MIGRATION_AUDIT.md |
pnpm i18n:check | root | Validates 8-locale translation parity |
pnpm knip | root | Dead-code gate (unused files/deps/exports) |
pnpm license:check | server | Verifies the configured license without booting the server |
Per-package scripts in packages/<pkg>/package.json. Turborepo caches outputs and dependencies across tasks. pnpm db:generate must run before build/lint/typecheck/test (the turbo build task depends on it).
Code conventions
- TypeScript strict everywhere; no unjustified
any(targetES2022). - Zod for input validation (
shareddefines the reusable schemas; validate withsafeParsein route handlers → 400 instead of 500). - Prisma as ORM (Prisma 7, driver adapter); schema in
packages/server/prisma/schema.prisma. Nevernew PrismaClient(): singleton fromsrc/utils/prisma(driver-adapter pool +withSoftDelete()). - RBAC via middleware:
requirePermission,requireAdmin,requireWorkspaceAccess(44 permissions inshared/src/constants/permissions.ts). - Error handling:
{ error }responses (400/401/403/404/409/402/429/500); Zod validation → 400 withdetails; license gating →402 { error, feature, tier }. - SSE for chat streaming (
@microsoft/fetch-event-sourceon the frontend). - Logging:
LOG_LEVELenv; use the configured logger, not bareconsole.login prod. - Commits: Conventional Commits format (
feat:,fix:,docs:,refactor:...); one logical change per commit; a[Unreleased]bullet inCHANGELOG.mdfor every change topackages/*/src/**(pnpm changelog:check).
Frontend (React 19)
- 3-tier state (server-persisted / session / local) - TanStack Query for REST/CRUD, React Context for UI state, fetchEventSource for SSE.
- shadcn/ui + Tailwind for the admin; the widget uses Preact + Tailwind, NO shadcn (IIFE bundle).
- i18n via hooks; files in
packages/frontend/src/i18n/<locale>/translation.json. - Chat shortcuts:
/model(Cmd+Kpalette), comparisonCmd+Shift+M. - ESLint: React Compiler + rules-of-hooks
errorin source; module format ESM (root + frontend) vs CommonJS (server/collector/shared/widget) - respect each package's tsconfig. - The Vite proxy retry hook must NOT be removed: the server (
tsx watch) boots slower than Vite (~1s);packages/frontend/vite.config.tsinstalls anonErrorhandler that retriesECONNREFUSEDup to 8 times over ~4s (GET/HEAD only - POST/SSE bodies are never replayed), then falls back to a single concise 502. The default handler dumps anAggregateErrorstack on every cold start.
Server (Express)
- Routes in
src/routes/, services insrc/services/, middleware insrc/middleware/. - Agent in
src/agent/(orchestrator.ts,builtinSkills.ts,mcpClient.ts). - Env config in
src/config/env.ts(Zod,process.exit(1)when invalid). - OpenAPI via
@openapiJSDoc annotations → Swagger at/api-docs. - pg-boss job queue (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) + a self-heal queue guard;
initWikiConsistencySchedulerruns as an in-process interval. The OCR + synthesis pipelines stay on setInterval 10s pollers (dev and prod). Multi-instance-ready with no extra infrastructure (see 02 - Architecture).
i18n
8 locales with concrete files: en, it, ru, de, fr, es, zh, pt (EN is the baseline; strict parity - no locale may lag). Add keys to all eight files. pnpm i18n:check (frontend + widget) exits 1 on missing or extra keys in any locale relative to en; the widget check also fails on empty-string values. The widget locale set is pinned against the frontend ALL_LANGUAGES by widgetLocalesParity.test.ts - add/remove locales in both places together.
Adding a feature (workflow)
- Shared schema - types/Zod in
packages/shared/src/. - Prisma - model + migration (
pnpm db:migrate; audit if destructive). - Server - service + route + RBAC/license middleware.
- Frontend - UI + hooks + i18n (all 8 locales).
- Tests - unit (Prisma mock) + integration (worker DB) + E2E if user-facing.
- Docs - update
docs/and the OpenAPI@openapi;[Unreleased]changelog when touchingsrc/.
Common extensions
- New agent skill:
registerSkillinserver/src/agent/builtinSkills.ts. - New endpoint: route in
server/src/routes/+ mount insrc/index.ts. - New permission:
PERMISSION_NAMESinshared/src/constants/permissions.ts+ roles. - New LLM provider: preset in
shared/src/constants/providerPresets.ts(seeded intoprovider_presets) + handler inserver/src/agent/llmStreaming.ts+providerService. - New backup destination: implement
IBackupDestinationProviderin the Enterprise plugin's backup providers (services/backup/providers/).
v0.28.1 Provenance
| Statement | Source |
|---|---|
44 permissions (PERMISSION_NAMES) | packages/shared/src/constants/permissions.ts (row-time count, 35-02 probe) - F-RBAC-1 |
Node.js >=24.0.0 (engines.node), pnpm 12.8.1 (packageManager), PostgreSQL 16 | docs/DEVELOPMENT.md (Prerequisites, row-time) |
| The Vite proxy retry hook (8 GET/HEAD retries, POST/SSE never replayed) | docs/DEVELOPMENT.md (Proxy, row-time) |
| pg-boss: 12 cron-style schedulers + self-heal guard; wiki-consistency in-process; OCR/URL + synthesis 10s pollers | docs/ARCHITECTURE.md:175-176 (row-time) |
Operational reference - Simmetric Chat v0.28.1 (docs updated 2026-10-02, census SHA `aca5b8ff`).
Cross-link
- Architecture: 02 - Architecture
- Testing: 11 - Testing
- API: 04 - API Reference