项目架构
了解 Multica 的客户端、Go 服务、执行守护进程和共享前端包如何协作。
Multica 由一个 Go backend、多种客户端和运行在执行电脑上的守护进程组成。PostgreSQL 保存协作数据;守护进程领取 task,并调用本机的 AI 编程工具。
Web / Desktop / Mobile / CLI
│
HTTP + WebSocket
│
Go API ───────── PostgreSQL
│
daemon WebSocket
│
本机守护进程 ─── AI 编程工具面向产品用户的解释见 Multica 的工作方式。本页关注代码如何分层。
仓库结构
| 目录 | 职责 | 主要技术 |
|---|---|---|
server/ | API、认证、任务调度、集成、CLI 和守护进程 | Go、Chi、sqlc、gorilla/websocket |
apps/web/ | 浏览器客户端和 landing page | Next.js App Router |
apps/desktop/ | 桌面客户端和本机进程管理 | Electron、electron-vite |
apps/mobile/ | 独立的 iOS 客户端 | Expo、React Native |
apps/docs/ | 多语言文档站 | Next.js、Fumadocs |
packages/core/ | API client、类型、查询、mutation 和平台无关业务逻辑 | TanStack Query、Zustand |
packages/ui/ | 不包含业务逻辑的基础 UI | shadcn、Base UI |
packages/views/ | Web 与 Desktop 共用的业务页面和组件 | React |
packages/tsconfig/、packages/eslint-config/ | 共享工具配置 | TypeScript、ESLint |
共享包直接导出 .ts 和 .tsx 源文件,由使用它们的应用编译。依赖方向是 views → core + ui;core 和 ui 互不依赖。
Web 与 Desktop 的代码共享
Web 和 Desktop 共用三层:
packages/core处理 API、缓存、权限和平台无关状态;packages/ui提供基础组件;packages/views组合业务页面。
路由、cookie 和 Electron IPC 等平台能力留在应用层。共享页面通过 NavigationAdapter 导航,不直接导入 next/* 或 react-router-dom。
例如,一项 Web 与 Desktop 都需要的 issue 功能通常会涉及:
packages/core/issues/ 查询、mutation、缓存更新
packages/views/issues/ 页面和业务组件
apps/web/platform/ Next.js 路由适配
apps/desktop/.../platform/ Electron 路由适配Mobile 不复用这些 React 页面。它可以导入 @multica/core 的类型和纯函数,但拥有自己的 UI、query key、状态、实时订阅和发布流程。
前端状态
服务端数据和客户端状态分开管理:
- TanStack Query 保存 issue、智能体、成员、收件箱等服务端数据;
- Zustand 保存筛选条件、草稿、弹窗和布局等客户端状态;
- 当前工作区由路由决定,只在平台层为请求、持久化命名空间和重连做必要镜像;
- React Context 只传递工作区 ID、导航适配器等平台 plumbing。
WebSocket 事件应更新或失效 TanStack Query cache,不能把服务端对象复制进 Zustand。创建、删除或离开工作区这类会导航的 mutation,需要等待服务端确认后再清理本地状态。
API 返回值在 packages/core/api/ 边界通过 zod schema 解析。已安装的 Desktop 可能连接更新的 backend,因此不能直接把网络 JSON 强制转换成 TypeScript 类型。
Backend 分层
主要入口位于 server/cmd/:
| 入口 | 作用 |
|---|---|
server | 启动 HTTP API、WebSocket、调度器和集成 worker |
multica | CLI 与本机守护进程 |
migrate | 执行数据库 migration |
backfill_* | 特定版本的数据回填工具 |
请求通常按以下方向流动:
router → middleware → handler → service → sqlc query → PostgreSQLinternal/middleware/处理认证、工作区和请求边界;internal/handler/解析 HTTP 输入并生成响应;internal/service/负责跨查询的业务流程和事务;pkg/db/queries/保存手写 SQL;pkg/db/generated/由 sqlc 生成,不能直接编辑;internal/integrations/处理 GitHub、Slack、飞书等外部事件;internal/storage/处理本地或 S3 附件。
PostgreSQL 是业务数据的权威来源。Redis 是可选组件,用于跨实例实时事件、缓存或临时协调;没有配置时,单实例开发环境使用进程内实现。
实时连接
Multica 有两条不同的 WebSocket 路径:
internal/realtime/把 issue、评论、收件箱等变化推送给用户客户端;internal/daemonws/连接守护进程,用于唤醒运行时和执行 daemon RPC。
WebSocket 负责降低延迟,数据库仍然是最终状态。客户端重连后需要通过查询重新校准;守护进程也保留轮询路径,避免一次断线让 queued task 永久停住。
一次执行的代码路径
- 用户分配 issue、提及智能体,或由自动化触发;
TaskService创建 queued task,并通知对应运行时;- 守护进程通过 daemon API 领取 task;
- 服务端签发绑定 task 和智能体的临时凭据;
- 守护进程准备本地目录,调用
pkg/agent中对应的 provider backend; - 工具在本地运行,守护进程上传进度、消息和最终状态;
- 服务端更新 task 与 issue,并通过实时事件刷新客户端。
provider 适配层统一了不同 AI 编程工具的启动、流式事件、取消和用量数据,但本地目录与会话仍由守护进程管理。
多工作区边界
业务查询必须限定 workspace_id,请求进入工作区路由前会检查成员身份。X-Workspace-ID 选择当前工作区,但不能替代权限检查。
Issue 的负责人是多态关系,可以指向成员、智能体或小队。新增查询、缓存 key 或实时事件时,都要保留工作区与负责人类型,不能只按资源 ID 假设全局唯一上下文。