架构
Simmetric Chat 是一个模块化的 TypeScript monorepo,包含 5 个 package 以及一个 Tauri 桌面应用。指导原则是边界分离:每个 package 都有各自独立的职责,并且只通过定义良好的接口(HTTP 或 shared package)与其他 package 通信。
Simmetric Chat 是一个模块化的 TypeScript monorepo,包含 5 个 package 以及一个 Tauri 桌面应用。指导原则是边界分离:每个 package 都有各自独立的职责,并且只通过定义良好的接口(HTTP 或 shared package)与其他 package 通信。
总览
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ frontend │ │ widget │ │ src-tauri │
│ React 19 │ │ Preact IIFE │ │ Desktop app │
│ Vite :5173 │ │ Express:3211│ │ │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ /api (JWT) │ /api/internal/widget (X-Api-Key) │
│ │ │
▼ ▼ │
┌────────────────────────────────────┐ │
│ server │◄──── Tauri usa il ────┘
│ Express :3000 (RBAC, agent, RAG) │ server via HTTP
└──────┬──────────────────┬──────────┘
│ HTTP (COLLECTOR_SECRET) │ HTTP (status callback)
▼ ▼
┌──────────────┐ ┌──────────────┐
│ collector │ │ PostgreSQL │
│ Express:3210│ │ (Prisma) │
│ parse/embed │ └──────────────┘
└──────────────┘
│
▼
┌──────────────────────────┐
│ Vector DB (LanceDB/ │
│ Qdrant) + LLM (Ollama/ │
│ OpenAI/Anthropic) │
└──────────────────────────┘5 个 package
shared - 叶子节点
类型、Zod schema 和常量。零业务逻辑,唯一的运行时依赖是 zod。它被 server、collector、frontend 导入。绝不从其他 package 导入:方向始终是 * → shared。这保证了 Turborepo 的构建顺序并防止出现循环。
src/types/- 实体接口(User、Workspace、Chat、Document、Provider、Widget、BackupDestination、Archive、OcrJob、SynthesisRun 等)。src/schemas/- Zod(auth、chat、document、widget、mcpConnection、license、backup、archive、wiki、ocr、synthesis、provider)。每个领域一个 schema,使用z.infer进行类型推断。src/constants/-permissions.ts(31 个 RBAC 权限)、license.ts(11 个 enterprise feature flag;8 个 commodity flag 在 Community 中始终启用)。
server - 核心(Express :3000)
REST API + RBAC + agent 编排器。参见 packages/server/CLAUDE.md。
src/routes/- 每个领域一个文件(auth、users、roles、projects、workspaces、documents、agent、chat、providers、apiKeys、eventLogs、analytics、backups、backupJobs、backupDestinations、webhooks、push、license、sso、templates、settings、mcpConnections、marketplace、widgets、internalWidget、health、ocr、archives、wiki、synthesis)。src/middleware/-auth.ts(JWT + API key)、rbac.ts(权限 + 防 IDOR)、rateLimit.ts(200/min 通用、10/min auth、10/min probe - 没有专门的聊天限流器:agent 在内部施加并发/预算/超时限制)、license.ts(feature flag gating)、widgetCors.ts(按 origin 的动态 CORS)。src/services/- authService、providerService(模型解析 + capability)、hybridSearchService(RRF)、ftsService(tsvector)、encryptionService(AES-256-GCM)、backupSchedulerService(Bree)、eventLogService(+ webhook 分发)、dlpFilter 等。src/agent/-orchestrator.ts(ReAct 循环)、builtinSkills.ts(rag_search、workspace_memory、document_temp_process)、llmStreaming.ts(Ollama/OpenAI/Anthropic)、mcpClient.ts(出站 MCP 连接)、mcpServer.ts(将 RAG 作为 MCP tool 提供给 IDE)。src/config/env.ts- 所有 env var 的 Zod schema;无效时process.exit(1)。
collector - 摄取微服务(Express :3210)
仅通过 HTTP 与服务器通信(密钥 COLLECTOR_SECRET)。不导入 Prisma,也不导入服务器服务:这是 air-gap 部署到独立节点的关键边界。
src/routes/ingest.ts- 上传(multer)、query、youtube、delete。src/services/- parser(PDF/DOCX/PPTX/XLSX/TXT/CSV/YouTube)、chunker(RecursiveCharacterTextSplitter)、embeddings(本地 Xenova / OpenAI)、vectorStore(LanceDB / Qdrant)。- 流程:server → collector
POST /api/ingest/upload→ parse → chunk → embed → store → collector 回调PUT /api/documents/:id/status→ 服务器更新 DB。
widget - 可嵌入聊天(Express :3211)
Express CommonJS + Preact IIFE bundle。通过 X-Api-Key 向服务器进行身份验证。
src/index.ts-createApp()工厂;static/widget/app.js+ loader routes + API。src/routes/- chat(SSE 代理)、session、config、loader、lead。src/widget/- sandboxed iframe 中的 Preact 组件(12 个组件)。- 透明 SSE 代理:server→iframe 的原始字节中继,零解析。
frontend - SPA(Vite + React 19 :5173)
没有 Next.js。代理 /api → server。
- 三层 state 管理:TanStack Query(REST/CRUD)、React Context(UI 状态)、fetchEventSource + useState/useRef(SSE,不是 TanStack Query)。
src/queries/(22 个 hook)、src/contexts/、src/hooks/useChat.ts(流式)。- i18n:8 种语言(en、it、ru、de、fr、es、zh、pt)。
src-tauri - 桌面应用
Tauri wrapper,将前端打包为桌面应用;通过 HTTP 与服务器通信(同一套 API)。专为没有浏览器的机器上的 air-gap 部署而设计。
主要 Data Flow
聊天流式(内部用户)
Frontend useChat → POST /api/workspaces/:id/chat/stream (SSE)
→ requireWorkspaceAccess (RBAC/IDOR)
→ agent orchestrator (ReAct loop)
├─ resolveSkillsForChat (builtin + MCP pinned)
├─ rag_search (vector + tsvector → RRF merge) se serve
├─ llmStreaming (provider risolto: per-chat → workspace → global → ENV)
└─ tool execution (sandboxed)
→ SSE: token | status | citations | done(modelUsed,providerUsed,mcpSources) | error模型解析:per-chat override → workspace default → global default → ENV。如果模型不可用,则进行 3 级优雅回退。
文档摄取
Frontend dropzone → POST /api/documents (server, multer)
→ server salva Document(status=pending) + forwarda file a collector
→ collector: parse → chunk → embed → store(vector) → ritorna chunks con text
→ collector callback PUT /api/documents/:id/status { status, chunkCount }
→ server scrive document_chunks + popola searchVector (tsvector) lato DB
→ frontend polla stato fino a completedWidget 聊天(匿名访客)
Pagina host → <script src="/widget/:id.js"> (loader)
→ iframe sandboxed → Preact app
→ POST /api/sessions (widget) → server crea WidgetSession (256-bit token, 24h)
→ GET /api/config/:widgetId (branding, trigger, lead)
→ user messaggio → POST /api/chat/:widgetId/stream (widget, x-session-token)
→ sessionMiddleware valida → pre-search RAG (whitelist workspaces, IDOR-safe)
→ proxy a server /api/workspaces/:id/chat/stream (X-Api-Key)
→ relay SSE byte verbatim → Preact parse token/citations/done/error边界与架构规则
- `shared` 是叶子 - 不向其他 package 导入,连
import type也不行。 - Server ↔ collector = 仅 HTTP - 没有跨 package 的运行时导入;collector 不能直接访问 DB。允许将 collector 扩展到独立节点。
- Widget = 独立服务 - 不与 React 前端共享代码;使用 Preact 以在 sandboxed iframe 中保持小体积 bundle。
- Prisma singleton - 始终从
src/utils/prisma导入,绝不new PrismaClient()。 - 通用软删除 - 可删除实体使用
deletedAt;所有查询过滤where: { deletedAt: null }。 - Config resolution -
ALWAYS_READONLY(JWT_SECRET、DATABASE_URL、端口、URL):ENV > Default。所有其他键:DB > ENV > Default(可从 UI 修改)。
扩展架构
- 新实体/endpoint → 在
shared中添加 Zod schema、Prisma 模型、server/src/routes/中的路由、frontend/src/queries/中的 TanStack hook。 - 新 agent skill → 在
server/src/agent/builtinSkills.ts中注册(sandboxed,不执行任意代码)。 - 新语言 → 添加
frontend/src/i18n/<lang>/translation.json+ 更新i18n-check.cjs(见 10 - Development)。 - 新 LLM provider → 扩展
shared中的providerTypeSchema+server/src/agent/llmStreaming.ts中的 handler +providerService。
交叉链接
- Env/config 细节:03 - Configuration
- 按领域的 endpoint:04 - API Reference
- 功能内部实现:05 - Feature Guide