Skip to content
Clone

docs: add standalone lib/post implementation plan

zhenyi committed
parent 64fca87 commit c18051b Browse files

1 file changed

+79 −0

Added wiki/lib-post-plan.md View wiki/lib-post-plan.md
@@ -0,0 +1,79 @@
1# lib/post 实施计划
2
3> 状态:已确认,待执行(2026-08-09)
4> 依据:`wiki/refactor-channel-to-space.md` 41/83 行「post ← DB schema 已有,业务层尚未实现」、523 行「post / meet 业务层 + HTTP 层(独立排期,类比 PR)」、255 行 URL 表 `/posts/{space_name}`、265 行子资源自动正确、385 行 `channel_for_post`、537 行子资源 = post 模块聚合。
5
6## 1. 目标
7
8新建 `lib/post` crate:帖子 board(collection)+ 单篇帖子 + 子资源的业务层(features)与 HTTP 层(handler),URL 采用 `{space_name}` 形态,接入 webapi 装配,补 401 集成测试。复用已建基础设施:`SpaceDb` trait、`lookup_space_by_name`、`require_active_member`、`channel_for_space`、`From<SpaceError> for PostError` 错误转换。
9
10## 2. 文件目录树(新建,类比 lib/issues)
11
12```
13lib/post/
14├── Cargo.toml # deps 同 lib/issues;dev-deps: http + tower="0.5"
15├── lib.rs # pub mod error/features/handler/metrics/service
16│ # pub use error::{PostError, PostResult}
17│ # pub use features::PostService
18│ # pub use handler::{PostsApiDoc, router as posts_router}
19├── error.rs # PostError 九变体(Forbidden(String) derive "forbidden: {0}")+ From<SpaceError>
20├── service.rs # PostService::new(db, kv, jwt, storage) + impl space::SpaceDb
21├── features/
22│ ├── mod.rs # pub mod authz/lookup/post/posts/post_label/post_mention/
23│ │ # post_reaction/post_reply/post_watch
24│ ├── authz.rs # 复用 require_active_member + 反查
25│ ├── lookup.rs # channel_for_post(两级反查)+ channel_for_post_board
26│ ├── posts/ # board 级(collection):impls.rs + mod.rs + usecase/
27│ ├── post/ # 单篇:impls.rs + mod.rs + usecase/
28│ ├── post_label/ # board 级标签 CRUD
29│ ├── post_mention/ # 提及(Post/Reply target)
30│ ├── post_reaction/ # 表情(Post/Reply target)
31│ ├── post_reply/ # 回复(维护 reply_count/last_reply_at/last_reply_by)
32│ └── post_watch/ # 关注
33├── handler/
34│ ├── mod.rs
35│ ├── routes.rs # protected scope:/posts/{space_name}...
36│ ├── openapi.rs # paths(...) 全部 handler + components(schemas)
37│ ├── middleware/
38│ └── posts/ post/ post_label/ post_mention/ post_reaction/ post_reply/ post_watch/
39└── tests/posts/
40 ├── main.rs # try_router(redis kv + JwtState + LocalStorage + PostService::new)+ expect_unauthorized
41 └── get.rs # GET /posts/test-space/1 未认证 → 401
42lib/export/post/ # mod.rs + views.rs(PostView/PostPage/PostReplyView/... ToSchema)
43```
44
45## 3. 关键设计决策
46
47| 决策点 | 方案 | 依据 |
48| --- | --- | --- |
49| URL 形态 | `/posts/{space_name}`(board 列表/建帖)、`/posts/{space_name}/{number}`(单篇)、子资源挂单篇 | wiki 255 行 |
50| 单篇参数 | `{number}`(i64,collection_id+autoincrement_id 组合唯一键),同 PR/issues 模式 | lib/db/post/post.rs 组合唯一键 |
51| 三级反查 | board 级:lookup_space_by_name → require_active_member → channel_for_space;单篇:→ channel_for_post 两级反查(post.collection_id → posts.channel_id) | wiki 385 行 + 阶段 3 模式 |
52| 鉴权 | 全部 AuthUser(同 issues),board 公开读由业务层控制 | 类比 issues |
53| 附件 | 不做(无 attachment 表;chat AttachmentKind::Post 为语义预留,不影响) | — |
54| workspace | members 加 `"lib/post"`;workspace.dependencies 加 `post = { path = "lib/post" }` | 现状缺失 |
55
56## 4. 实施步骤
57
581. 脚手架:workspace 注册 lib/post + export/post;Cargo.toml;lib.rs;error.rs(PostError 九变体 + From<SpaceError>);service.rs(PostService::new + SpaceDb impl)。
592. features 业务层(类比 PR/issues usecase 模式,事务 + 现有错误语义):
60 - lookup.rs:`channel_for_post(svc, post_id)`(两级反查)+ `channel_for_post_board(svc, space_id)`
61 - posts(board):create/list board、post CRUD(create/update/close/reopen/archive/delete)
62 - 子资源:post_reply(create/list,维护 reply_count/last_reply_at/last_reply_by)、post_reaction(create/delete)、post_mention(list/create)、post_watch(upsert/get/delete)、post_label(board 级 CRUD + 单篇 bind/unbind)
633. handler 层:routes.rs(protected scope,inject_jwt_ctx::<PostService> + ratelimit)、每端点 handler(Path<(String, Uuid/i64)> + 三步反查 + `let _channel_id` 防 unused)、openapi.rs。
644. 装配:lib/webapi/services.rs 加 `pub posts: PostService` + `PostService::new(db.clone(), kv.clone(), jwt.clone(), storage.clone())`;router.rs `.merge(post::posts_router(services.posts))`。
655. 测试:tests/posts/ 401 集成测试 + openapi 反射测试。
666. openapi.json 重生成(`cargo build -p apihost && ./target/debug/apihost openapi -o openapi.json`)。
67
68## 5. 验收标准
69
70- `cargo build --workspace` 零警告
71- `cargo test -p post`(+ 相关包)全绿;401 集成测试真跑(redis 容器存活)
72- openapi.json:`/posts/{space_name}` 前缀路径存在;`channel_id` 计数 ≤60(新增 schema 字段按 wiki 豁免口径核对)
73- 提交至新分支 `stage-post`(基线 64fca87)
74
75## 6. 已确认决策(2026-08-09)
76
77- [x] board(collection)管理端点(重命名/改 icon/description)暂不做,schema 字段保留
78- [x] close/reopen 端点做(类比 PR);archive/lock 端点不做(可由 PATCH 覆盖)
79- [x] 整个 lib/post 一个 goal 执行(类比阶段 0 PR,规模相当)