新增 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 参考文档链接
4.5 KiB
title, updated, status, tags
| title | updated | status | tags | ||||
|---|---|---|---|---|---|---|---|
| 架构决策 | 2026-06-01 | active |
|
架构决策
从 index 导航。关联: data-layer erp-diary frontend
1. 设计决策
Q: 为什么从 HMS 剥离而不是 fork?
独立 base.git 仓库(https://git.stableeasy.com/iven/base.git)作为通用 ERP 基座,多个项目可独立克隆后添加业务模块。fork 会将两个项目的 git 历史绑定,无法独立演进。
Q: 为什么用 Feature Flag 组装模块?
cargo build --features diary 按需引入暖记模块。基座 crate(auth/config/message/workflow/plugin)不需要 diary 功能时零开销。
Q: 为什么选 Flutter 而不是原生?
Android + iOS 跨平台首发。CustomPainter + Listener 手写性能满足 <16ms 目标,一套代码双端覆盖。
Q: 为什么选 BLoC 不是 Provider/Riverpod?
编辑器、日历、同步引擎等复杂交互需要 Event/State 显式建模。BLoC 的单向数据流在复杂场景下比 Provider 更可控。
基座剥离 — 7 个耦合点
从 HMS 剥离到 base.git 时遇到的耦合及解决方案:
| 耦合点 | 问题 | 解决 |
|---|---|---|
| main.rs 业务初始化 | 硬编码 health 模块注册 | 改为 Feature Flag 动态注册 |
| AppState 业务字段 | 嵌入 HealthState 等 | 改为 trait object / AnyMap |
| 迁移文件混合 | 基座 + 业务迁移在同一目录 | 按 prefix 分类,业务迁移独立 |
| 路由注册 | 业务路由写死在基座 | Module trait 的 routes() 方法 |
| 事件定义 | 业务事件在基座 crate | 各模块自定义 event.rs |
| 权限 seed | 业务权限码在基座迁移 | 各模块自带 seed 迁移 |
| Cargo.toml | 业务依赖在 workspace 根 | 各业务 crate 独立管理 |
2. 关键文件 + 数据流
仓库拓扑
HMS (G:\hms) [只读]
└─复制→ base.git (https://git.stableeasy.com/iven/base.git)
└─克隆→ nj.git (暖记 = 基座 + erp-diary + Flutter)
Cargo Workspace
nj/crates/
├── erp-core/ # 基座 — 模块系统/事件/加密/错误
├── erp-auth/ # 基座 — JWT/RBAC/用户/角色
├── erp-config/ # 基座 — 字典/菜单/设置
├── erp-message/ # 基座 — 消息/通知/SSE
├── erp-workflow/ # 基座 — BPMN 工作流
├── erp-plugin/ # 基座 — WASM 插件运行时
├── erp-server/ # Axum 入口 + 迁移 + 路由组装
└── erp-diary/ # 暖记业务模块 (~5,500 行新增)
集成契约
| 方向 | 模块 | 接口 | 触发时机 |
|---|---|---|---|
| 被调用 ← | erp-server | DiaryModule::new() |
启动时 feature=diary |
| 调用 → | erp-core | EventBus |
diary.created 等事件 |
| 调用 → | erp-auth | require_permission() |
handler 层权限守卫 |
| 提供 → | erp-server | routes() + entities() |
Axum 路由注册 |
3. 代码逻辑
不变量
⚡ G:\hms 只读 — 绝不修改 HMS 源码,所有操作在 nj 仓库进行
⚡ 业务 crate 间无直接依赖 — erp-diary 不 import erp-health,只通过 EventBus 通信
⚡ 所有查询带 tenant_id — 多租户中间件自动注入,API 路径不含 tenant_id
⚡ 软删除不硬删 — 所有 delete 操作设置 deleted_at,不做 DELETE FROM
⚡ version 乐观锁 — 所有 Entity 的 version 字段用于同步冲突检测
多租户隔离策略
中间件从 JWT 提取 tenant_id → 注入请求扩展 → handler/service 层自动过滤。API 路径不含 tenant_id(/api/v1/diary/... 而非 /{tenant}/diary/...)。
PIPL 合规
- 未满 14 岁必须家长授权
- 最小必要数据(昵称 + 年级,无需真实姓名)
- AES-256-GCM 加密 + TLS 传输
- 30 天内注销删除所有关联数据
- 班级码:6 位混合码,5 次错误锁定 30 分钟
4. 活跃问题 + 陷阱
| 问题 | 级别 | 状态 | 说明 |
|---|---|---|---|
| 上下文窗口耗尽 | HIGH | 已缓解 | CLAUDE.md §8 会话交接机制 |
| Windows Defender 锁定 exe | MEDIUM | 需手动 | 排除 target/ 目录 |
| Docker 部署未验证 | MEDIUM | 待做 | docker/ 目录存在但未测试 |
历史教训
- 基座剥离耗时比预期长(7 个耦合点需逐一解耦)
- Isar 3.x 扩展方法不随传递 import 传播,必须显式 import
5. 变更记录
| 日期 | 变更 |
|---|---|
| 2026-06-01 | 初始创建 — 架构决策、基座剥离记录、集成契约 |