Files
nj/CLAUDE.md
iven 0a9e5b1cb3
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
docs: 更新 wiki + CLAUDE.md — 三端架构和管理端集成
- wiki/index.md: 更新关键数字、三端架构图、启动命令、症状导航
- wiki/architecture.md: 补充三端架构、来源追溯、活跃问题更新
- wiki/admin-web.md: 新建管理端文档 — 结构/API代理/功能映射/品牌定制清单
- CLAUDE.md: 补充 apps/web 目录、管理端场景化指令、三端启动命令
2026-06-02 10:11:03 +08:00

481 lines
18 KiB
Markdown
Raw Permalink 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.
# 暖记 (Warm Notes) — 项目协作规则
> **Nuanji** — 温暖治愈风格的手账日记 app以手写/涂鸦为核心输入,面向小学生首发。
> **当前阶段: Phase 1 实施。** 基座剥离 + 项目初始化已完成,开始功能开发。
整个项目对话都使用中文进行,包括文档、代码注释、提交信息等。
---
## 1. 项目定位
### 1.1 这是什么
一个**手写优先的手账日记 app**,核心价值是保留用户真实笔迹:
- **手写引擎** — CustomPainter + perfect_freehand< 16ms 延迟,掌心抑制,四种画笔
- **手账体验** — 贴纸、涂鸦、照片、和纸胶带——不只是打字,是可以装饰的手账
- **班级连接** — 老师布置主题 → 学生写作 → 老师点评,培养写作习惯
- **成长记录** — 心情追踪、成就徽章、日历回顾,看见自己的变化
### 1.2 架构概览
```
nj/ (一个仓库)
├── crates/ # Rust 后端 (Cargo Workspace)
│ ├── erp-core/ # 基座 — 模块系统/事件/加密/错误
│ ├── erp-auth/ # 基座 — JWT/RBAC/用户/角色
│ ├── erp-config/ # 基座 — 字典/菜单/设置
│ ├── erp-message/ # 基座 — 消息/通知/SSE
│ ├── erp-workflow/ # 基座 — BPMN 工作流
│ ├── erp-plugin/ # 基座 — WASM 插件运行时
│ ├── erp-server/ # Axum 入口 + 迁移 + 路由组装
│ │ └── migration/ # SeaORM 迁移 (53 基座 + 暖记迁移)
│ └── erp-diary/ # 🆕 暖记业务模块 (~5800 行新增)
│ ├── src/entity/ # ~15 Entity (日记/班级/贴纸/心情...)
│ ├── src/service/ # ~12 Service
│ ├── src/handler/ # ~10 Handler
│ └── src/{dto,error,event,state}.rs
├── apps/ # 🆕 管理端前端 (从 HMS 基座复用)
│ └── web/ # React + Ant Design + Vite (:5174)
│ ├── src/pages/ # 管理页面 (用户/角色/权限/审计...)
│ └── vite.config.ts # API 代理 → localhost:3000
├── app/ # Flutter 学生端 (:8080)
├── scripts/dev.sh # 🆕 统一启动脚本 (自动清理端口)
├── config/ # 服务器配置 (CORS=*)
├── docker/ # Docker Compose (PG + Redis)
├── docs/ # 产品文档
│ └── superpowers/specs/ # 设计规格 v1.2
└── plans/ # 实施规划
```
### 1.3 基座继承 vs 新增开发
基座从 HMS (G:\hms) 剥离,推送到 `base.git`nj 项目克隆后添加 `erp-diary`
| 能力 | 来源 | 工作量 |
|------|------|--------|
| 用户/角色/权限 CRUD | erp-auth 继承 | 零开发 |
| JWT + Token 轮换 | erp-auth 继承 | 零开发 |
| RBAC 权限码守卫 | erp-auth 继承 | 零开发 |
| 事件总线 + Outbox | erp-core 继承 | 零开发 |
| PII 加密 + 盲索引 | erp-core 继承 | 零开发 |
| 审计日志(哈希链) | erp-core 继承 | 零开发 |
| 多租户隔离 (RLS) | erp-core 继承 | 零开发 |
| 字典/菜单/设置 | erp-config 继承 | 零开发 |
| 消息/通知/SSE | erp-message 继承 | 零开发 |
| BPMN 工作流 | erp-workflow 继承 | 零开发 |
| SeaORM 迁移框架 | erp-server 继承 | 零开发 |
| OpenAPI 文档 | utoipa 继承 | 零开发 |
| 管理端 Web 前端 | HMS apps/web/ 复用 | 零开发 (品牌替换待做) |
| student/teacher/parent 角色 | erp-auth 扩展 | 🆕 ~200 行 |
| 班级码认证 | erp-auth 扩展 | 🆕 ~500 行 |
| 日记 CRUD + 同步 | erp-diary 新增 | 🆕 ~2000 行 |
| 班级管理 | erp-diary 新增 | 🆕 ~800 行 |
| 贴纸/模板管理 | erp-diary 新增 | 🆕 ~600 行 |
| 心情/统计 API | erp-diary 新增 | 🆕 ~500 行 |
| 内容安全过滤 | erp-diary 新增 | 🆕 ~300 行 |
| 文件上传(照片/贴纸) | 参考健康模块 | 🆕 ~500 行 |
| **新增合计** | | **~5800 行 Rust** |
### 1.4 仓库关系
```
HMS (G:\hms) [只读,使用中的生产项目]
└─复制→ base.git https://git.stableeasy.com/iven/base.git
│ (通用 ERP 基座,所有新项目的基础)
└─克隆→ nj.git https://git.stableeasy.com/iven/nj.git
(暖记项目 = 基座 + erp-diary + Flutter 前端)
```
**关键约束G:\hms 只读,绝不修改。**
### 1.5 决策原则
**任何改动都要问:这对小学生的手写日记体验和数据安全有帮助吗?**
- ✅ 手写引擎性能优化 → 最高优先(核心价值)
- ✅ 儿童数据安全与 PIPL 合规 → 最高优先
- ✅ 离线优先体验 → 高优先
- ✅ 模块边界清晰 → 高优先
- ❌ 提前实现 Phase 2+ 功能 → 禁止
- ❌ 在模块间创建直接耦合 → 永远不做
- ❌ 硬编码密钥或绕过多租户中间件 → 永远不做
---
## 2. 技术栈
### 2.1 后端 (Rust)
| 层级 | 技术 | 用途 |
|------|------|------|
| 框架 | Axum 0.8 | HTTP 服务 |
| ORM | SeaORM 1.1 | 数据库操作 |
| 数据库 | PostgreSQL 16 | 主存储 |
| 缓存 | Redis 7 | 速率限制/会话 |
| 认证 | JWT + Argon2 + RBAC | 继承基座 |
| 加密 | AES-256-GCM + KEK/DEK | 儿童数据加密 |
| 文档 | utoipa (OpenAPI) | API 文档 |
| 事件 | EventBus + Outbox | 模块间通信 |
### 2.2 前端 (Flutter)
| 层级 | 技术 | 用途 |
|------|------|------|
| UI | Flutter 3.x | 跨平台 (Android/iOS 首发) |
| 状态 | flutter_bloc (BLoC) | 复杂交互状态管理 |
| 存储 | Isar | 本地数据库 + FTS + 加密 |
| 手写 | CustomPainter + perfect_freehand | 笔迹保真 |
| 图表 | fl_chart | 心情趋势/统计 |
| 路由 | go_router | 声明式路由 |
| 网络 | dio + connectivity_plus | API + 离线检测 |
| 模型 | freezed + json_serializable | 不可变数据模型 |
### 2.3 设计系统
| Token | 浅色 | 深色 | 用途 |
|-------|------|------|------|
| bg | #FFF8F0 | #1A1614 | 奶油白背景 |
| accent | #E07A5F | #E8907A | 珊瑚色主色 |
| secondary | #81B29A | #8FBF9E | 鼠尾草绿 |
| tertiary | #F2CC8F | #D4B878 | 暖金 |
| fg | #2D2420 | #F0E8DF | 主文字 |
| surface | #FFFFFF | #2A2520 | 卡片背景 |
| rose | #D4A5A5 | #C4A0A0 | 玫瑰粉 |
字体Noto Sans SC (显示+正文) / Caveat (手写风格) / JetBrains Mono (等宽)
圆角10/16/22/28/pill | 触摸目标 ≥ 44px | 动画曲线 cubic-bezier(0.34, 1.56, 0.64, 1)
---
## 3. 工作风格
### 3.1 闭环工作法
每次改动按顺序完成:
1. **现状确认** — 搜索已有代码,明确"已有"和"缺失"
2. **理解需求** — 确认改动目标模块和影响范围
3. **最小实现** — 只改必要的代码,保持模块边界
4. **验证通过**
- `cargo check` — 后端编译无错误
- `cargo test` — 所有测试通过
- `flutter analyze` — 前端分析无错误 (涉及前端时)
5. **提交 + 推送** — 按 §6 规范提交,立即推送
### 3.2 模块化思维
开发任何功能时先问:
1. **它属于哪个 crate** — 后端在 `erp-diary`,前端在 `lib/features/`
2. **它的接口是什么?** — 后端先定义 Entity + DTO前端先定义 freezed model
3. **它需要发什么事件?** — diary.created / diary.shared 等
4. **它影响离线体验吗?** — 所有功能必须离线可用
### 3.3 分步编写文档
超过 200 行的文档必须分步编写:
1. 先写大纲 → 2. 逐章编写 → 3. 最终整合
---
## 4. 实现规则
### 4.1 后端 (Rust/erp-diary)
#### 错误处理
- 使用 `DiaryError` 枚举,转换为 `AppError`
- 集成测试验证每个错误码的 HTTP 状态映射
#### 数据库
- 所有 Entity 包含标准字段:`id`, `tenant_id`, `created_at`, `updated_at`, `created_by`, `updated_by`, `deleted_at`, `version`
- 所有查询带 `tenant_id` 过滤(中间件注入)
- 软删除,不硬删除
- `version` 字段乐观锁(同步冲突检测核心)
#### API 设计
- 端点使用 `/api/v1/diary/` 前缀
- 权限守卫 `require_permission` 在 handler 层
- utoipa 注解所有端点
- 租户 ID 从 JWT 中间件注入,不在 API 路径中传递
#### 新增 Entity 检查清单
- [ ] 包含所有标准字段id/tenant_id/created_at/.../version
- [ ] handler 有 `require_permission` 权限守卫
- [ ] 权限码写入 seed 迁移
- [ ] utoipa 注解已添加
- [ ] 多租户隔离正确
- [ ] 输入验证完整Validate derive
### 4.2 前端 (Flutter)
#### 目录约定
```
lib/features/{feature}/
├── bloc/ # BLoC (event + state + bloc)
├── views/ # 页面
└── widgets/ # 组件
```
#### 状态管理
- 每个功能模块一个 BLoC
- Event/State 使用 freezed 生成不可变类
- Repository 模式:抽象接口 + Isar 本地实现 + Dio 远程实现
#### 响应式布局
- 手机 < 600px底部 TabBar单列
- 平板 600-1024px侧边导航双栏
- 桌面 > 1024px三栏布局
#### 离线优先
- 所有数据先写 Isar离线完全可用
- SyncEngine 管理 WiFi 增量同步
- 版本号冲突检测,本地优先策略
### 4.3 安全PIPL 合规,最高优先)
#### 儿童数据保护
- **未满 14 岁必须家长授权** — 注册时验证,分享功能锁定
- **最小必要数据** — 仅收集昵称+年级,无需真实姓名/身份证
- **数据加密** — Isar 内置加密 + AES-256-GCM 云端 + TLS 传输
- **家长数据管理权** — 可查阅/更正/删除/导出孩子数据
- **账号注销** — 30 天内删除所有关联数据
#### 班级码安全
- 6 位字母数字混合62^6 ≈ 568 亿种组合)
- 有效期控制(学期结束自动失效)
- 连续 5 次错误锁定 30 分钟
- 老师可随时重置
#### 内容安全
- 本地敏感词库过滤(含谐音/拼音变体)
- 分享前自动检查
- 老师可审核班级内容
- 举报机制
---
## 5. 性能目标
| 指标 | 目标 | 测试条件 |
|------|------|---------|
| 手写延迟 (p99) | < 16ms | Samsung Tab A9 / iPad 10th |
| 日记列表滚动 | 60fps | 500 条数据 |
| 冷启动 | < 2s | 100 条 Isar 文档 |
| 全量同步 | < 10s | 100 篇日记 |
| 照片压缩质量 | ≥ 85% SSIM | flutter_image_compress |
| 单篇日记存储 | < 5MB | 含照片 |
| 贴纸包大小 | < 5MB/包 | |
---
## 6. 提交规范
```
<type>(<scope>): <description>
```
**类型:** feat / fix / refactor / docs / test / chore / perf
**Scope:**
| scope | 范围 |
|-------|------|
| `diary` | erp-diary |
| `auth` | erp-auth |
| `core` | erp-core |
| `server` | erp-server |
| `config` | erp-config |
| `message` | erp-message |
| `workflow` | erp-workflow |
| `plugin` | erp-plugin |
| `app` | Flutter 前端 |
| `db` | 数据库迁移 |
| `docker` | Docker 配置 |
**示例:**
```
feat(diary): 添加日记 CRUD API
feat(app): 实现手写引擎 Canvas 组件
feat(auth): 添加 student/teacher/parent 角色支持
fix(diary): 修复同步版本冲突检测逻辑
chore(docker): 添加 PostgreSQL 16 + Redis 7 开发环境
```
---
## 7. 反模式警告
- ❌ **不要**修改 G:\hms — 那是使用中的生产项目,所有操作在 nj 仓库进行
- ❌ **不要**在业务 crate 间创建直接依赖 — 只通过事件和 trait 通信
- ❌ **不要**跳过多租户中间件 — 所有数据操作必须带 `tenant_id` 过滤
- ❌ **不要**忽略儿童数据安全 — PIPL 合规是法律要求,不是可选项
- ❌ **不要**过度平滑笔迹 — 笔迹保真是核心价值,保留个人书写特征
- ❌ **不要**假设网络始终可用 — 所有功能必须离线可用
- ❌ **不要**使用 `anyhow` 跨越 crate 边界 — 内部可用,对外转 `AppError`/`DiaryError`
- ❌ **不要**提前实现 Phase 2+ 功能 — 严格按规划推进
- ❌ **不要**跳过验证直接提交 — cargo check + cargo test + flutter analyze 必须通过
- ❌ **不要**在 Flutter 中直接用 GestureDetector 处理手写 — 用 Listener 降低延迟
- ❌ **不要**硬编码密钥 — 通过 config/default.toml + 环境变量注入
### 场景化指令
- 当遇到**新增 API 端点** → 在 erp-diary/src/handler/ 添加,加 utoipa 注解 + 权限守卫
- 当遇到**新增数据表** → 创建 SeaORM migration + Entity包含所有标准字段
- 当遇到**跨模块通信** → 定义事件类型到 erp-diary/src/event.rs通过 EventBus 发布
- 当遇到**新增 Flutter 功能** → 创建 features/{name}/ 目录bloc/views/widgets 分层
- 当遇到**管理端修改** → 在 apps/web/ 中修改 React 组件,`pnpm dev` 启动开发服务器
- 当遇到**管理端新增页面** → 在 apps/web/src/pages/ 添加,更新 routeConfig.ts + 侧边栏菜单
- 当遇到**手写性能问题** → 检查 shouldRepaint 守卫 + 笔画光栅化缓存 + Listener 替代 GestureDetector
- 当遇到**同步冲突** → 版本号比对Phase 1 使用"本地优先"简单策略
- 当遇到**儿童数据** → 确认 PIPL 合规检查清单(家长授权/最小数据/加密/注销机制)
- 当遇到**启动端口占用** → `./scripts/dev.sh stop` 清理所有旧进程
---
## 8. 上下文管理与会话交接
> **核心问题:** 长时间开发会话会触发 "API Error: The model has reached its context window limit.",导致工作中断。
> **解决方案:** 在上下文即将耗尽前,主动执行会话交接,确保新会话能无缝续接。
### 8.1 触发条件
当出现以下**任一**信号时,立即执行 §8.2 交接流程:
- 感觉对话已经很长,处理速度明显变慢
- 已经完成了 2 个以上独立的功能开发步骤
- 单次会话中修改了 10+ 个文件
- 用户提醒上下文快满了
### 8.2 会话交接流程
**不要等到报错才交接!** 主动在合适的节点(完成一个 Phase、通过测试后执行
**步骤 1 — 收尾当前工作:**
- 确保当前代码改动已提交(`git add` + `git commit`
- 确认 `cargo check``cargo test`(涉及前端时 `flutter analyze`)通过
- 未完成的工作不要提交到 main — 用 stash 或临时分支暂存
**步骤 2 — 更新项目记忆文件:**
更新 `~/.claude/projects/g--nj/memory/project-status.md`,包含:
```markdown
## 已完成 (截至 YYYY-MM-DD)
- [x] Phase X: 具体完成内容 (commit hash)
- [x] Phase Y: 具体完成内容 (commit hash)
## 当前进行中 / 未完成
- 正在做的事情,描述到什么程度了,还剩什么
- 例如:"F2 认证模块 — Auth BLoC 已完成,角色选择页未开始"
## 下一步工作 (按优先级)
1. 具体的下一个任务,写清楚要做什么、在哪个文件
2. 第二个任务
3. 第三个任务
## 本会话的关键决策/发现
- 记录影响后续工作的决策、踩过的坑、发现的注意事项
```
**步骤 3 — 向用户输出交接摘要:**
用以下格式明确告诉用户,方便在新会话中说"按计划继续"
```
## 交接摘要
### 本会话完成
- ...
### 下一步 (新会话直接做)
1. ...
2. ...
### 注意事项
- ...
```
### 8.3 新会话启动指南
新会话启动时AI 应:
1. **读取记忆文件**`~/.claude/projects/g--nj/memory/project-status.md`
2. **确认代码状态**`git log --oneline -5` + `cargo check`
3. **读取规划文档**`plans/hazy-petting-lampson.md` 中对应阶段
4. **直接开始工作** — 不要重复已完成的分析,按记忆中的"下一步工作"推进
### 8.4 交接质量标准
一份合格的交接必须让新会话**无需猜测**就能继续工作:
- ✅ 下一步是具体的文件和功能,不是模糊的方向
- ✅ 未完成的工作状态清晰(做了多少、还差什么)
- ✅ 关键决策已记录(为什么这样做、有哪些备选方案被否决)
- ✅ 所有代码已提交,工作区干净
---
## 9. 参考文档
| 文档 | 位置 |
|------|------|
| **知识库首页** | `wiki/index.md` — 症状导航 + 模块索引 |
| 架构决策 | `wiki/architecture.md` — 基座剥离 + Feature Flag + 多租户 |
| 手写引擎 | `wiki/handwriting-engine.md` — 双层 Canvas + 光栅化缓存 |
| 数据层 | `wiki/data-layer.md` — Isar + SyncEngine 离线同步 |
| Flutter 前端 | `wiki/frontend.md` — 16 模块 + BLoC + 设计系统 |
| 管理端前端 | `wiki/admin-web.md` — React + Ant Design + 品牌定制清单 |
| 后端模块 | `wiki/erp-diary.md` — Entity/Service/Handler 清单 |
| 技术债看板 | `docs/tech-debt-board.md` — 10 条待偿还债务 |
| 产品设计规格 v1.2 | `docs/superpowers/specs/2026-05-31-nuanji-warm-notes-design.md` |
| 实施规划 v2.1 | `plans/hazy-petting-lampson.md` |
| 头脑风暴文档 (8 份) | `.superpowers/brainstorm/734-1780218658/` |
| 基座仓库 | https://git.stableeasy.com/iven/base.git |
| HMS 源码 (只读参考) | G:\hms |
---
## 10. 开发环境
### 三端启动
```bash
# 一键启动全部 (后端 + 管理端 + 学生端)
./scripts/dev.sh
# 单独启动
./scripts/dev.sh backend # Rust Axum → :3000
./scripts/dev.sh admin # React Vite → :5174
./scripts/dev.sh app # Flutter Web → :8080
# 停止所有 (自动清理端口)
./scripts/dev.sh stop
```
管理端默认账号: `admin / admin123`
### 环境依赖
| 服务 | 地址 | 说明 |
|------|------|------|
| PostgreSQL 16 | localhost:5432 | 数据库 `nuanji` |
| Redis 7 | localhost:6379 | 缓存/速率限制 |
| Flutter SDK | D:\flutter\bin\flutter.bat | 学生端 |
| Node.js + pnpm | - | 管理端 |
| Rust toolchain | stable | 后端 |
### 参考文档
| 文档 | 位置 |
|------|------|
| 产品设计规格 v1.2 | `docs/superpowers/specs/2026-05-31-nuanji-warm-notes-design.md` |
| 实施规划 v2.1 | `plans/hazy-petting-lampson.md` |
| 头脑风暴文档 (8 份) | `.superpowers/brainstorm/734-1780218658/` |
| 基座仓库 | https://git.stableeasy.com/iven/base.git |
| HMS 源码 (只读参考) | G:\hms |