
这页讲的是运行时架构(服务怎么分层、怎么协作)。至于代码怎么组织——全部源码都在一个 monorepo 里,每个服务另有一个只读的下游镜像——见仓库模型。
核心约定
数据优先
先把数据模型、数据流和存储契约定下来,再做路由、Agent 和 UI。
Agent 是黑盒
只建模 Agent 产出的数据并持久化,不建模其内部。整套系统可用 mock agent 跑通。
当前存储边界
user_manager 仍用 SQLite;data_server 已改为 PostgreSQL,持有 rakull_data、rakull_collection 两个物理隔离的库;只有 data_server 定义了 Repository / ObjectStore Protocol,对象存储另有 local / COS 两种实现。共享 JWT
user_manager 签发 HS256 JWT;其余服务用同一个 JWT_SECRET 本地校验。MVC 分层
第一次接触 MVC?先阅读 MVC 是什么,再回到这里看本项目的服务映射。| 层 | 组件 | 职责 |
|---|---|---|
| View | rakullapp_core(Flutter)、rakull_manager(管理端 webview) | 渲染 + 用户输入,不含业务逻辑 |
| Controller | immersive_study_server(App Server)、manager_server(Admin Server) | 请求处理、权限/可见性规则、编排、SSE;无数据库 |
| Model | data_server、user_manager、collection_server | 各自拥有实体;当前持久化边界因服务而异 |
| 黑盒 | agent_server | 不透明计算,产出由 Model 存储的数据 |
服务清单
| 服务 | 端口 | 层 | 是否拥有数据 | 一句话职责 |
|---|---|---|---|---|
user_manager | 8010 | Model | 是(用户/邀请码/注册/用量) | 本地账号鉴权与管理,签发 JWT |
agent_server | 8011 | 黑盒 | 否 | 无状态 AI 计算(断句/翻译/讲解/语音/转写) |
immersive_study_server | 8012 | Controller | 否 | 编排全部学习功能,推送任务进度 |
collection_server | 8013 | Model | 是(收藏) | 收藏夹与卡片的增删改查 |
data_server | 8014 | Model | 是(文章/句子/音频/反馈/每周推荐) | 持久化与媒体存储 |
manager_server | 8015 | Controller(管理端) | 否 | Admin Server:聚合管理 + 数据采集,托管管理控制台 |
运行时拓扑
经验法则:客户端只碰UM、ISS、COL;管理端只碰 MGR,由 MGR 向 UM(用户/用量)与 ISS(文章)扇入;ISS 向 AG/DS/UM 扇出;COL 是无状态薄网关,凭用户 Bearer + 短期服务断言把全部收藏读写转给 DS(front/back 快照在 DS 同进程内完成)。AG 是纯叶子,不调用任何服务。
接口版本约定
不熟悉方法、路由或端点?参阅 HTTP、API 与 CRUD。- 公开接口:
/api/*,与原单体应用逐字节一致,客户端直接调用。 - 内部接口:
/v1/*,只由其他服务调用,客户端不应直连。
共享 JWT(移植阶段)
所有服务用同一个 HS256JWT_SECRET 校验 token:user_manager 签发,其余服务本地解码(暂无服务间内省)。不了解 token、签名或 Bearer 的含义,可先阅读 JWT 是什么;项目规则详见 鉴权与权限。
为什么这么拆
最“硬核”、生命周期最长的部分是数据(文章、句子、讲解、音频、收藏、用户)及其流动方式。计算(Agent)和 UI(客户端)是可替换的,而 schema 与数据访问边界是长期稳定的。因此设计顺序是:先定实体与数据流、再明确持久化边界,最后才是路由 / Agent / UI。领域模型与数据归属
业务数据、服务所有权与跨服务引用。
数据流
端到端的请求时序图。