Files
nj/wiki/erp-diary.md
iven d1a07229e2 docs: 项目 Wiki 知识库 — 7 文件覆盖架构/手写/数据/前端/后端/技术债
新增 wiki/ 知识库 (遵循 HMS wiki-methodology.md 5 节结构):
- index.md (84 行) — 症状导航 13 条 + 模块索引 + 系统数据流
- architecture.md (120 行) — 基座剥离 7 耦合点 + Feature Flag + PIPL 合规
- handwriting-engine.md (124 行) — 双层 Canvas + O(1) 点缓冲 + 光栅化缓存
- data-layer.md (127 行) — Isar + SyncEngine 离线同步 + 踩坑记录
- frontend.md (118 行) — 16 模块地图 + BLoC 注入链 + 设计系统
- erp-diary.md (101 行) — 15 Entity / 10 Service / 8 Handler + API 端点

新增 docs/:
- tech-debt-board.md (110 行) — 10 条技术债 + 偿还优先级排名

其他更新:
- .gitignore: 添加 .understand-anything/ (待初始化)
- CLAUDE.md §9: 添加 wiki 参考文档链接
2026-06-01 15:08:21 +08:00

102 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: erp-diary 后端模块
updated: 2026-06-01
status: active
tags: [rust, axum, seaorm, diary, api]
---
# erp-diary — 暖记后端业务模块
> 从 [[index]] 导航。关联: [[architecture]] [[data-layer]]
## 1. 设计决策
### Q: 为什么独立 erp-diary crate
基座解耦原则erp-diary 通过 Feature Flag (`cargo build --features diary`) 按需引入。基座 crate 不依赖业务模块,其他项目可复用基座而不引入日记功能。
### Q: DiaryError 设计?
15 种变体枚举NotFound / VersionConflict / Unauthorized / ContentUnsafe 等),实现 `Into<AppError>` 转换为 HTTP 状态码映射。集成测试验证每个错误码的正确 HTTP 响应。
### Q: 为什么内容安全过滤在 Service 层?
日记标题、文字元素的文本需要敏感词检查(含谐音/拼音变体)。放在 Service 层而非 Handler 层,确保即使有新的入口点(事件消费、管理 API也不会绕过检查。
## 2. 关键文件 + 数据流
### 模块结构
```
crates/erp-diary/src/
├── lib.rs (206 行) — DiaryModule 实现 + Feature Flag 注册
├── dto.rs (569 行) — 请求/响应 DTO + Validate 注解
├── error.rs (193 行) — DiaryError 15 种变体 → HTTP 状态码
├── event.rs (61 行) — 事件定义 (diary.created 等)
├── state.rs (13 行) — DiaryState (DiaryModule 专用状态)
├── entity/ (15 文件) — SeaORM Entity
├── service/ (10 文件) — 业务逻辑
└── handler/ (8 文件) — HTTP Handler + utoipa 注解
```
### Entity 清单 (15 个)
achievement, class_member, comment, handwriting_stroke, journal_element, journal_entry, parent_child_binding, school_class, sticker, sticker_pack, teacher_profile, template, topic_assignment, user_achievement, user_settings
### Service 清单 (10 个)
journal, class, comment, content_safety, achievement, mood_stats, notification, sticker, sync, topic
### API 端点
| 端点前缀 | Handler | 主要操作 |
|---------|---------|---------|
| `/api/v1/diary/journals` | journal_handler | CRUD + 列表过滤 |
| `/api/v1/diary/journals/:id/elements` | journal_handler (同) | 元素 CRUD |
| `/api/v1/diary/classes` | class_handler | 班级 CRUD + 班级码 |
| `/api/v1/diary/comments` | comment_handler | 评论 CRUD |
| `/api/v1/diary/topics` | topic_handler | 主题布置 |
| `/api/v1/diary/achievements` | achievement_handler | 成就系统 |
| `/api/v1/diary/stickers` | sticker_handler | 贴纸管理 |
| `/api/v1/diary/stats` | stats_handler | 心情/写作统计 |
| `/api/v1/diary/sync` | sync_handler | 增量同步 API |
### 集成契约
| 方向 | 模块 | 接口 | 触发时机 |
|------|------|------|---------|
| 提供 → | erp-server | `DiaryModule::routes()` | 启动 feature=diary |
| 调用 → | erp-core | `EventBus::publish()` | 日记创建/更新/删除 |
| 调用 → | erp-auth | `require_permission()` | 每个 handler 入口 |
| 调用 → | erp-message | 通知服务 | 评论/班级事件 |
## 3. 代码逻辑
### 不变量
**所有 Entity 含标准字段** — id / tenant_id / created_at / updated_at / created_by / updated_by / deleted_at / version
**软删除** — 查询带 `deleted_at IS NULL` 过滤,不做硬删除
**多租户隔离** — 中间件注入 tenant_idhandler 不从 API 路径获取
**权限守卫** — 每个 handler 方法第一行 `require_permission("diary.xxx")`
**输入验证** — DTO 使用 `#[derive(Validate)]` + handler 层调 `.validate()`
**内容安全** — 日记标题/文字通过 ContentSafetyService 检查
## 4. 活跃问题 + 陷阱
| 问题 | 级别 | 状态 | 说明 |
|------|------|------|------|
| Docker 部署未验证 | HIGH | 待做 | docker/ 目录存在但未实际运行 |
| CI/CD 未建立 | MEDIUM | 待做 | 无自动化构建/测试/部署 |
| 文件上传未实现 | MEDIUM | 待做 | 照片/贴纸文件上传参考健康模块 |
## 5. 变更记录
| 日期 | 变更 |
|------|------|
| 2026-06-01 | 初始创建 — Entity/Service/Handler 清单、API 端点、集成契约 |