为 codebase 贡献的指南:setup、monorepo 结构、脚本、约定、i18n。
Setup
git clone <repo> && cd simmetric-chat
pnpm install # 安装所有 package 的依赖
cp .env.example .env # 根 .env = 唯一的 runtime config;然后编辑 JWT_SECRET、COLLECTOR_SECRET
pnpm db:generate # Prisma client(+ 修复 Prisma 7/pnpm symlink)
pnpm db:migrate # 应用迁移(prisma migrate dev)
pnpm db:seed # 角色、权限、config、bootstrap admin
pnpm dev # 通过 turborepo 启动 server/collector/widget/frontendPostgreSQL 16 本地实例(例如 docker compose -f docker/docker-compose.infra.yml up -d postgres)。pnpm db:migrate 应用 Prisma 迁移(packages/server/prisma/migrations);pnpm db:seed 播种角色/权限和 bootstrap admin(admin / admin123,mustChangePassword=true)。迁移是 additive-only:破坏性迁移需要明确同意(PRISMA_USER_CONSENT_FOR_DANGEROUS_AI_ACTION),并且 pnpm audit:migrations 重新生成 docs/MIGRATION_AUDIT.md 以便在同一 PR 中提交。
Monorepo 结构
pnpm workspaces + Turborepo。5 个 package + Tauri:
| Package | 端口 | Stack | 作用 |
|---|---|---|---|
shared | - | TS + Zod | 类型、schema、常量(leaf,仅依赖 zod) |
server | 3000 | Express + Prisma | API、RBAC、agent、RAG FTS/RRF、backup |
collector | 3210 | Express | 摄取、解析、embedding、vector store |
widget | 3211 | Express + Preact IIFE | 可嵌入 widget |
frontend | 5173 | Vite + React 19 + Tailwind | SPA admin/chat |
src-tauri | - | Rust + Tauri | 桌面应用 |
依赖图:shared ← {server, collector, frontend, widget}。严格模块化:server↔collector = 仅 HTTP(COLLECTOR_SECRET);widget↔server = API key(X-Api-Key)。server/collector/widget 之间没有直接 import。
常用脚本
| 脚本 | Scope | 描述 |
|---|---|---|
pnpm dev | root | Turborepo:并行启动所有服务 |
pnpm build | root | 所有 package 的生产构建(依赖 ^build) |
pnpm lint | root | ESLint 10 flat config,所有 package |
pnpm typecheck | root | TypeScript strict mode |
pnpm test | root | Jest(5 个项目,Postgres-free)via Turborepo |
pnpm test:all | root | 同样 5 个 suite via jest.config.cjs(纯 Jest) |
pnpm test:e2e | root | Playwright |
pnpm db:generate | root | 重新生成 Prisma client |
pnpm db:migrate | server | prisma migrate dev |
pnpm db:seed | server | Seed 角色/权限/config |
pnpm audit:migrations | server | 破坏性迁移审计 → docs/MIGRATION_AUDIT.md |
pnpm i18n:check | root | 校验 8 个 locale 的翻译对等性 |
pnpm knip | root | Dead-code gate(未使用的文件/依赖/export) |
pnpm license:check | server | 不启动 server 校验已配置的 license |
每个 package 的脚本在 packages/<pkg>/package.json 中。Turborepo 缓存 task 之间的 output 和依赖。pnpm db:generate 必须在 build/lint/typecheck/test 之前运行(turbo task build 依赖它)。
代码约定
- 全局 TypeScript strict;无不合理的
any(targetES2022)。 - Zod 用于输入校验(
shared定义可复用 schema;在 route handler 中用safeParse校验 → 400 而非 500)。 - Prisma 作为 ORM(Prisma 7,driver adapter);schema 在
packages/server/prisma/schema.prisma。绝不new PrismaClient():从src/utils/prisma使用 singleton(driver-adapter pool +withSoftDelete())。 - RBAC via middleware:
requirePermission、requireAdmin、requireWorkspaceAccess(31 个权限在shared/src/constants/permissions.ts)。 - Error handling:响应
{ error }(400/401/403/404/409/402/429/500);Zod 校验 → 400 带details;license gating →402 { error, feature, tier }。 - SSE 用于聊天 streaming(前端使用
@microsoft/fetch-event-source)。 - Logging:env
LOG_LEVEL;使用配置好的 logger,生产环境不要直接console.log。 - Commit:Conventional Commits 格式(
feat:、fix:、docs:、refactor:...);每次 commit 一次逻辑变更;对packages/*/src/**的每处变更在CHANGELOG.md中添加一个[Unreleased]bullet(pnpm changelog:check)。
Frontend(React 19)
- 3-tier state(server-persisted / session / local)- REST/CRUD 用 TanStack Query,UI 状态用 React Context,SSE 用 fetchEventSource。
- admin 使用 shadcn/ui + Tailwind;widget 使用 Preact + Tailwind,不用 shadcn(IIFE bundle)。
- i18n via hook;文件在
packages/frontend/src/i18n/<locale>/translation.json。 - 聊天快捷键:
/model(paletteCmd+K)、对比Cmd+Shift+M。 - ESLint:源码中 React Compiler + rules-of-hooks
error;模块格式 ESM(root + frontend)vs CommonJS(server/collector/shared/widget)- 遵守每个 package 的 tsconfig。
Server(Express)
- Route 在
src/routes/,service 在src/services/,middleware 在src/middleware/。 - Agent 在
src/agent/(orchestrator.ts、builtinSkills.ts、mcpClient.ts)。 - Config env 在
src/config/env.ts(Zod,无效时process.exit(1))。 - OpenAPI 通过
@openapiJSDoc 注解 → Swagger 于/api-docs。 - Job queue pg-boss(Postgres-backed):8 个 cron scheduler(backup、MCP health-check、reaper、synthesis);OCR + synthesis 管道保留在 setInterval 10s poller 上。无需额外基础设施即可 multi-instance-ready(见 02 - Architecture)。
i18n
8 个 locale 带具体文件:en、it、ru、de、fr、es、zh、pt(EN 是 baseline;严格对等 - 任何语言都不能落后)。在全部八个文件中添加 key。pnpm i18n:check(frontend + widget)在任何 locale 相对 en 缺少 或多余 key 时退出 1;widget check 在空字符串值上也会失败。widget 的 locale 集合由 widgetLocalesParity.test.ts 对照 frontend 的 ALL_LANGUAGES 固定 - 在两个位置一起添加/移除语言。
添加功能(workflow)
- Shared schema - 类型/Zod 在
packages/shared/src/。 - Prisma - 模型 + 迁移(
pnpm db:migrate;破坏性则 audit)。 - Server - service + route + RBAC/license middleware。
- Frontend - UI + hook + i18n(全部 8 种语言)。
- Test - unit(Prisma mock)+ integration(worker DB)+ E2E(若 user-facing)。
- Docs - 更新
docs/和 OpenAPI@openapi;若触及src/则更新 changelog[Unreleased]。
常见扩展
- 新 agent skill:在
server/src/agent/builtinSkills.ts中registerSkill。 - 新 endpoint:route 在
server/src/routes/+ 在src/index.ts中 mount。 - 新权限:
PERMISSION_NAMES在shared/src/constants/permissions.ts+ 角色。 - 新 LLM provider:preset 在
shared/src/constants/providerPresets.ts(seed 到provider_presets)+ handler 在server/src/agent/llmStreaming.ts+providerService。 - 新 backup destination:在 Enterprise 插件的 backup provider 中实现
IBackupDestinationProvider(services/backup/providers/)。
交叉链接
- 架构:02 - Architecture
- Testing:11 - Testing
- API:04 - API Reference