- wiki/index.md: 更新关键数字、三端架构图、启动命令、症状导航 - wiki/architecture.md: 补充三端架构、来源追溯、活跃问题更新 - wiki/admin-web.md: 新建管理端文档 — 结构/API代理/功能映射/品牌定制清单 - CLAUDE.md: 补充 apps/web 目录、管理端场景化指令、三端启动命令
18 KiB
暖记 (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 闭环工作法
每次改动按顺序完成:
- 现状确认 — 搜索已有代码,明确"已有"和"缺失"
- 理解需求 — 确认改动目标模块和影响范围
- 最小实现 — 只改必要的代码,保持模块边界
- 验证通过:
cargo check— 后端编译无错误cargo test— 所有测试通过flutter analyze— 前端分析无错误 (涉及前端时)
- 提交 + 推送 — 按 §6 规范提交,立即推送
3.2 模块化思维
开发任何功能时先问:
- 它属于哪个 crate? — 后端在
erp-diary,前端在lib/features/ - 它的接口是什么? — 后端先定义 Entity + DTO,前端先定义 freezed model
- 它需要发什么事件? — diary.created / diary.shared 等
- 它影响离线体验吗? — 所有功能必须离线可用
3.3 分步编写文档
超过 200 行的文档必须分步编写:
- 先写大纲 → 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,包含:
## 已完成 (截至 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 应:
- 读取记忆文件 —
~/.claude/projects/g--nj/memory/project-status.md - 确认代码状态 —
git log --oneline -5+cargo check - 读取规划文档 —
plans/hazy-petting-lampson.md中对应阶段 - 直接开始工作 — 不要重复已完成的分析,按记忆中的"下一步工作"推进
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. 开发环境
三端启动
# 一键启动全部 (后端 + 管理端 + 学生端)
./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 |