角色:客户端直连的收藏薄网关

端口 8013 · 面向客户端 · 无自有数据库,转发到 data_server
collection_server 守护收藏这一独立的限界上下文。按设计(要求 9),客户端直接调用它,不经过控制器。它本身不持有数据库:每个请求先按 JWT 里的 user_id 鉴权,再带着用户 Bearer 与一张短期服务断言(X-Rakull-Service-Assertion)转发给 data_server 的内部接口;所有读写、快照与 SM-2 调度都在 data_server 完成,返回的状态码与响应体与旧的进程内实现保持一致。

接口 /v1/collections/*

方法 / 路径用途下游
GET /v1/collections列出我的收藏夹data_server
POST /v1/collections新建收藏夹data_server
GET /v1/collections/{id}收藏夹详情data_server
PATCH /v1/collections/{id}改名/描述data_server
DELETE /v1/collections/{id}删除data_server
POST /v1/collections/{id}/items加卡片(未传 front/back 则在 data_server 内取快照)data_server
DELETE /v1/collections/{id}/items/{item_id}删卡片data_server
GET /v1/collections/{id}/export/anki导出 Anki(占位 501)data_server
POST /v1/collections/{id}/exercises生成练习(占位 501)data_server
句子复习另有 GET /v1/sentence-reviews/queueGET /v1/sentence-reviews/countsPOST /v1/sentence-reviews。全部端点需要 Bearer——收藏始终需要登录

加卡片与快照

加卡片时若调用方没有显式给出 front/backdata_server 同进程读取对应句子的文本与翻译,存成加入时刻的快照;collection_server 只负责鉴权与转发: 这样做的好处:原句之后被编辑或删除,已收藏的卡片内容保持不变,便于离线复习与 Anki 导出。

数据库归属

收藏的 collectionscollection_items 两张表物理上位于 data_server 独占的 PostgreSQL 收藏库 rakull_collection(独立 schema、独立连接工厂,由 data_server 同进程唯一持有;不与 rakull_data 跨库 JOIN)。完整字段、约束与索引见 数据库表字段参考

服务间鉴权

每次内部调用同时携带:用户 Bearer(决定操作者)与由 CONTROLLER_ASSERTION_SECRET 签发的短期 HS256 断言(iss=collection_serveraud=data_serverscopecollections:data:read|writeactor_user_id 必须等于 Bearer 用户、有效期 60 秒)。data_server 按 scope 白名单与调用方绑定做最小权限校验。

环境变量

下表变量同样是该服务根目录下的 YAML 配置键(键名一致):config.yaml 存非敏感默认值(已提交),config.local.yaml 存密钥与本机覆盖(已 gitignore,可从 config.example.yaml 复制)。优先级(高 → 低):环境变量 > config.local.yaml > config.yaml > 代码默认值。密钥放进 config.local.yaml
变量说明默认
JWT_SECRET校验 Bearer 的共享密钥change-me-in-config-local
CONTROLLER_ASSERTION_SECRET服务断言签名密钥(与 data_server 一致,≥32 字节,≠ JWT_SECRET空;开发态回退进程内随机值,生产/预发必须显式配置
RAKULL_ENVproduction/staging 下缺断言密钥直接启动失败development
DATA_SERVER_URLdata_server 内部 API 地址http://localhost:8014

运行

cd rakull_server/collection_server
JWT_SECRET=dev-secret \
CONTROLLER_ASSERTION_SECRET=$(openssl rand -hex 32) \
DATA_SERVER_URL=http://localhost:8014 \
uv run uvicorn app.main:app --port 8013
本地整栈直接用 ../../scripts/run_all_servers.sh,脚本会给所有服务注入同一个共享断言密钥。