Desarrollo
Guía para contribuir al codebase: setup, estructura monorepo, scripts, convenciones, i18n.
Guía para contribuir al codebase: setup, estructura monorepo, scripts, convenciones, i18n.
Setup
git clone <repo> && cd simmetric-chat
pnpm install # instala las dependencias de todos los packages
cp .env.example .env # .env raíz = única config runtime; luego edita JWT_SECRET, COLLECTOR_SECRET
pnpm db:generate # client Prisma (+ fix symlink Prisma 7/pnpm)
pnpm db:migrate # aplica las migraciones (prisma migrate dev)
pnpm db:seed # roles, permisos, config, admin bootstrap
pnpm dev # arranca server/collector/widget/frontend via turborepoPostgreSQL 16 en local (p. ej. docker compose -f docker/docker-compose.infra.yml up -d postgres). pnpm db:migrate aplica las migraciones Prisma (packages/server/prisma/migrations); pnpm db:seed siembra roles/permisos y el admin bootstrap (admin / admin123, mustChangePassword=true). Las migraciones son additive-only: las destructivas exigen consentimiento explícito (PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION) y pnpm audit:migrations regenera docs/MIGRATION_AUDIT.md para commitear en la misma PR.
Estructura monorepo
pnpm workspaces + Turborepo. 5 package + Tauri:
| Package | Puerto | Stack | Rol |
|---|---|---|---|
shared | - | TS + Zod | Tipos, schema, constantes (leaf, dep solo zod) |
server | 3000 | Express + Prisma | API, RBAC, agent, RAG FTS/RRF, backup |
collector | 3210 | Express | Ingesta, parsing, embedding, vector store |
widget | 3211 | Express + Preact IIFE | Widget embebible |
frontend | 5173 | Vite + React 19 + Tailwind | SPA admin/chat |
src-tauri | - | Rust + Tauri | Desktop app |
Grafo de dependencias: shared ← {server, collector, frontend, widget}. Modularidad strict: server↔collector = HTTP only (COLLECTOR_SECRET); widget↔server = API key (X-Api-Key). Ningún import directo entre server/collector/widget.
Scripts comunes
| Script | Scope | Descripción |
|---|---|---|
pnpm dev | root | Turborepo: arranca todos los servicios en paralelo |
pnpm build | root | Build producción todos los package (depende de ^build) |
pnpm lint | root | ESLint 10 flat config, todos los package |
pnpm typecheck | root | TypeScript strict mode |
pnpm test | root | Jest (5 proyectos, Postgres-free) via Turborepo |
pnpm test:all | root | Las mismas 5 suites via jest.config.cjs (Jest puro) |
pnpm test:e2e | root | Playwright |
pnpm db:generate | root | Regenera el client Prisma |
pnpm db:migrate | server | prisma migrate dev |
pnpm db:seed | server | Seed roles/permisos/config |
pnpm audit:migrations | server | Audit de migraciones destructivas → docs/MIGRATION_AUDIT.md |
pnpm i18n:check | root | Verifica la paridad de traducciones en 8 locale |
pnpm knip | root | Gate dead-code (archivos/dependencias/exports sin usar) |
pnpm license:check | server | Verifica la licencia configurada sin boot del servidor |
Scripts por-package en packages/<pkg>/package.json. Turborepo cachea outputs y dependencias entre tasks. pnpm db:generate debe correr antes de build/lint/typecheck/test (la task turbo build depende de ello).
Convenciones de código
- TypeScript strict en todo; sin
anyno justificado (targetES2022). - Zod para validación de input (
shareddefine schemas reutilizables; valida consafeParseen los route handler → 400 en vez de 500). - Prisma como ORM (Prisma 7, driver adapter); schema en
packages/server/prisma/schema.prisma. Nuncanew PrismaClient(): singleton desdesrc/utils/prisma(pool driver-adapter +withSoftDelete()). - RBAC via middleware:
requirePermission,requireAdmin,requireWorkspaceAccess(31 permisos enshared/src/constants/permissions.ts). - Error handling: respuestas
{ error }(400/401/403/404/409/402/429/500); validación Zod → 400 condetails; license gating →402 { error, feature, tier }. - SSE para streaming chat (
@microsoft/fetch-event-sourceen el frontend). - Logging: env
LOG_LEVEL; usa el logger configurado, noconsole.logdirecto en prod. - Commit: formato Conventional Commits (
feat:,fix:,docs:,refactor:...); un cambio lógico por commit; un bullet[Unreleased]enCHANGELOG.mdpor cada cambio apackages/*/src/**(pnpm changelog:check).
Frontend (React 19)
- State 3-tier (server-persisted / session / local) - TanStack Query para REST/CRUD, React Context para el estado UI, fetchEventSource para SSE.
- shadcn/ui + Tailwind para el admin; el widget usa Preact + Tailwind, NO shadcn (bundle IIFE).
- i18n via hook; archivos en
packages/frontend/src/i18n/<locale>/translation.json. - Shortcuts chat:
/model(paletaCmd+K), comparaciónCmd+Shift+M. - ESLint: React Compiler + rules-of-hooks
erroren el código; formato de módulo ESM (root + frontend) vs CommonJS (server/collector/shared/widget) - respeta el tsconfig por package.
Server (Express)
- Routes en
src/routes/, servicios ensrc/services/, middleware ensrc/middleware/. - Agent en
src/agent/(orchestrator.ts,builtinSkills.ts,mcpClient.ts). - Config env en
src/config/env.ts(Zod,process.exit(1)si inválida). - OpenAPI via anotaciones
@openapiJSDoc → Swagger en/api-docs. - Job queue pg-boss (Postgres-backed): 8 cron scheduler (backup, MCP health-check, reaper, synthesis); los pipelines OCR + synthesis permanecen en un poller setInterval 10s. Multi-instance-ready sin infraestructura extra (ver 02 - Architecture).
i18n
8 locale con archivos concretos: en, it, ru, de, fr, es, zh, pt (EN es la baseline; paridad strict - ningún idioma puede quedarse atrás). Añade las claves en los ocho archivos. pnpm i18n:check (frontend + widget) sale 1 con claves faltantes o extra en cualquier locale respecto a en; el check del widget también falla con valores string vacíos. El conjunto locale del widget está pinnado contra ALL_LANGUAGES del frontend por widgetLocalesParity.test.ts - añade/elimina idiomas en ambos sitios a la vez.
Añadir una feature (workflow)
- Schema shared - tipos/Zod en
packages/shared/src/. - Prisma - modelo + migración (
pnpm db:migrate; audit si es destructiva). - Server - servicio + route + middleware RBAC/license.
- Frontend - UI + hook + i18n (los 8 idiomas).
- Test - unit (mock Prisma) + integration (worker DB) + E2E si es user-facing.
- Docs - actualiza
docs/y OpenAPI@openapi; changelog[Unreleased]si tocasrc/.
Extensiones comunes
- Nueva skill de agente:
registerSkillenserver/src/agent/builtinSkills.ts. - Nuevo endpoint: route en
server/src/routes/+ mount ensrc/index.ts. - Nuevo permiso:
PERMISSION_NAMESenshared/src/constants/permissions.ts+ roles. - Nuevo provider LLM: preset en
shared/src/constants/providerPresets.ts(seed enprovider_presets) + handler enserver/src/agent/llmStreaming.ts+providerService. - Nuevo destino backup: implementa
IBackupDestinationProvideren los providers backup del plugin Enterprise (services/backup/providers/).
Cross-link
- Arquitectura: 02 - Architecture
- Testing: 11 - Testing
- API: 04 - API Reference