Files
nj/docs/audit-2026-06-03-full-report.md
iven 38592d61ce
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
refactor(diary): Phase 3 质量提升 — 201 状态码 + OpenAPI 文档 + DiaryEvent 类型安全
前端:
- fix(app): Isar native 文件直接导入 isar_database_native.dart,消除 5 个条件导出类型错误
- chore(app): build_runner 重新生成 .g.dart 文件 (102 outputs)
- fix(app): 移除 secure_token_store_factory 未使用的 kIsWeb import

后端:
- refactor(diary): 所有创建端点 POST 返回 201 Created (9 handler, 11 端点)
- feat(diary): DiaryApiDoc OpenApi derive — 42 路径 + 32 Schema 汇总到 Swagger
- feat(diary): DiaryEvent 枚举添加 event_type/payload/to_domain_event 方法 + 4 测试

测试: 84/84 erp-diary 通过, 509/509 全仓库通过, Flutter analyze 0 error
2026-06-03 17:06:03 +08:00

396 lines
20 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.
# 暖记 (Nuanji) 全系统穷尽审计报告
> **审计日期**: 2026-06-03
> **代码规模**: ~126,000 行 / 560+ 文件
> **审计方法**: 10 维度 × 2 智能体 = 20 个并行审计智能体
> **审计范围**: 安全 → 后端架构 → 前端质量 → 数据库 → API设计 → 基础设施 → 文档 → 性能 → 跨层一致性
---
## 执行摘要
### 总体统计
| 维度 | CRITICAL | HIGH | MEDIUM | LOW/INFO | 合计 |
|------|----------|------|--------|----------|------|
| 🔒 安全 (步骤1) | 3 | 9 | 10 | 6 | 28 |
| 🏗️ 后端架构 (步骤2) | 1 | 11 | 12 | 9 | 33 |
| 📱 前端质量 (步骤3) | 1 | 2 | 17 | 10 | 30 |
| 🗄️ 数据库 (步骤4) | 3 | 8 | 11 | 7 | 29 |
| 🌐 API设计 (步骤5) | 6 | 8 | 10 | 7 | 31 |
| 🐳 基础设施 (步骤6) | 9 | 13 | 16 | 14 | 52 |
| 📚 文档 (步骤7) | 7 | 16 | 17 | 17 | 57 |
| ⚡ 性能 (步骤8) | 5 | 12 | 17 | 13 | 47 |
| 🔗 跨层一致性 (步骤9) | 7 | 11 | 13 | 7 | 38 |
| **合计** | **42** | **90** | **123** | **90** | **345** |
### 风险等级分布
```
CRITICAL ██████████████████████ 42 (12%) — 必须立即修复
HIGH █████████████████████████████████████████████ 90 (26%) — 本周内修复
MEDIUM ██████████████████████████████████████████████████████████████████ 123 (36%) — 规划修复
LOW/INFO ████████████████████████████████████████████ 90 (26%) — 记录跟踪
```
### 系统成熟度评估
| 领域 | 评分 | 说明 |
|------|------|------|
| 架构设计 | ★★★★☆ | 模块边界清晰,多租户架构合理 |
| 安全基础 | ★★★☆☆ | 加密体系完善,但输入验证/权限覆盖有缺口 |
| 数据库设计 | ★★★★☆ | Entity 一致性优秀RLS 有 bug 需修 |
| API 设计 | ★★★☆☆ | DTO 验证系统性缺失REST 不规范 |
| 前端质量 | ★★★☆☆ | 手写引擎优秀,但 BLoC/无障碍需改进 |
| 基础设施 | ★★★☆☆ | Docker/备份设计好CI/CD 和密钥管理弱 |
| 测试覆盖 | ★★☆☆☆ | 单元测试尚可,集成/E2E 严重不足 |
| 文档准确性 | ★★★★☆ | 总体准确,细节有偏差 |
---
## 🔴 CRITICAL 发现汇总 (37 项)
### 按影响域分类
#### A. 数据安全与隐私 (12 项)
| ID | 问题 | 来源 | 影响 |
|----|------|------|------|
| S-02 | **内容安全过滤器为空** — SENSITIVE_WORDS 无词条,所有内容通过检查 | 安全 | 儿童可能接触不安全内容 |
| S-03 | **缺少家长同意验证** — 违反 PIPL 第28条 | 安全 | 法律合规风险 |
| S-10 | **家长绑定无验证** — 任何人可绑定任何孩子 | 安全 | 儿童数据泄露 |
| 6b-C01 | **Flutter 默认 HTTP 明文传输** | 配置 | JWT/日记内容可被截获 |
| 6b-C02 | **Flutter 无 SSL 证书固定** | 配置 | 中间人攻击风险 |
| 6b-C03 | **管理端 JWT 存 localStorage** | 配置 | XSS 可窃取 token |
| 6b-C04 | **Docker 默认密码硬编码** | 配置 | 生产环境安全风险 |
| 6a-C01 | **.env.example 包含默认密码** | Docker | 易被直接用于生产 |
| 6a-C02 | **dev.sh 硬编码 JWT Secret/KEK** | 脚本 | 泄露到版本控制 |
| 6a-C04 | **verify.sh 硬编码生产数据库密码** | 脚本 | 凭据泄露 |
| 5b-C01 | **审计日志端点无权限守卫** | API | 任何用户可查看审计日志 |
| 5b-C02 | **文件上传端点无权限守卫** | API | 任何用户可上传文件 |
#### B. 数据完整性 (10 项)
| ID | 问题 | 来源 | 影响 |
|----|------|------|------|
| 4a-C01 | **RLS 变量名不一致**`app.current_tenant` vs `app.current_tenant_id` | 数据库 | 15 张日记表 RLS 完全失效/锁死 |
| 4a-C02 | **`diary.comment.delete` 权限未定义** | 种子数据 | teacher 永远无删除评语权限 |
| 4b-C01 | 同 4a-C01确认问题存在 | 数据库 | — |
| 4b-C02 | **m000183 使用 FORCE RLS 与基座不一致** | 数据库 | 变量名错误时完全阻断访问 |
| 8a-C01 | **mood_stats 全量加载所有日记** | 性能 | 活跃用户 OOM |
| 8a-C02 | **sync_service 循环内 N+1 查询** | 性能 | 50 条变更 = 100 次 DB 往返 |
| 8a-C03 | **parent_service 逐条软删除** | 性能 | PIPL 删除不原子 |
| 8a-C04 | **sticker_service N+1 查询贴纸数量** | 性能 | 20 个包 = 21 次查询 |
| 8b-R01 | **笔画缓存 use-after-dispose** | Flutter | 撤销/重做后笔画内容丢失 |
| 9a-SYNC-01 | **Flutter 与 Rust 使用两套不兼容同步协议** | 跨层 | 同步机制完全断裂 |
#### C. 输入验证系统性缺失 (8 项)
| ID | 问题 | 来源 | 影响 |
|----|------|------|------|
| 5a-C01 | **erp-diary 所有 DTO 无 Validate derive** | API | 无字段级约束 |
| 5a-C02 | **DTO 字段无长度/范围约束** | API | 儿童/恶意输入可提交超大 payload |
| 5a-C03 | **所有 handler 未调用 .validate()** | API | 即使加 Validate 也形同虚设 |
| 5b-C03 | **OpenAPI 文档完全缺失 Diary 模块** | API | ~30 个端点不在文档中 |
| 7b-C01 | **班级码实际十六进制(16^6)非字母数字(62^6)** | 文档 | 安全强度低 3386 倍 |
| 7b-C02 | 同 5a-C01确认 Validate 缺失 | 文档 | — |
| 9a-AUTH-01 | **Flutter 无 Token 自动刷新** | 跨层 | Token 过期直接踢回登录 |
| 9a-TENANT-01 | **Flutter 不传递 tenant_id** | 跨层 | 多租户上线需大规模改造 |
#### D. 端到端同步断裂 (4 项)
| ID | 问题 | 来源 | 影响 |
|----|------|------|------|
| 9a-SYNC-01 | Flutter SyncEngine 与 Rust SyncService 协议不兼容 | 跨层 | 同步功能完全断裂 |
| 9a-SYNC-02 | SyncEngine 超限后直接丢弃操作 | 跨层 | 用户数据静默丢失 |
| 9a-SYNC-03 | SyncEngine 不使用后端 SyncChange 格式 | 跨层 | 数据格式不兼容 |
| 9a-SYNC-04 | SyncEngine 不发送 version 字段 | 跨层 | 乐观锁失效 |
---
## 🟠 HIGH 发现汇总 (81 项)
### 安全 (9 项)
| ID | 问题 | 文件 |
|----|------|------|
| S-04 | JWT 缺少 iss/aud claims | `token_service.rs` |
| S-05 | RefreshReq 无输入验证 | `dto.rs`, `auth_handler.rs` |
| S-06 | 开发 KEK 硬编码 | `crypto/mod.rs` |
| S-07 | **日记列表 IDOR** — 任何用户可查看他人日记 | `journal_handler.rs` |
| S-08 | 无数据保留策略 | `parent_service.rs` |
| S-09 | **无账号注销机制** | 全局缺失 |
| S-11 | **Flutter API 默认 HTTP** | `api_client.dart` |
| S-12 | 默认存储密钥硬编码 | `config.rs` |
### 后端架构 (11 项)
| ID | 问题 | 文件 |
|----|------|------|
| B-02 | DiaryEvent 枚举是死代码 | `event.rs` |
| B-03 | **所有请求 DTO 缺少 Validate** | `dto.rs` |
| B-04 | DiaryModule 未实现 register_event_handlers | `lib.rs` |
| B-05 | **日记端点缺失于 OpenAPI spec** | `main.rs` |
| B-06 | generate_unique_code 未按 tenant_id 过滤 | `class_service.rs` |
| B-07 | create_class/join_class 两次写入无事务 | `class_service.rs` |
| B-08 | sticker_service 缺少乐观锁 | `sticker_service.rs` |
| B-09 | sync_service 版本冲突丢弃 journal_id | `sync_service.rs` |
| B-10 | sync_service 返回客户端刚提交的数据 | `sync_service.rs` |
| B-11 | parent_service 删除操作无事务 | `parent_service.rs` |
### 数据库 (8 项)
| ID | 问题 | 说明 |
|----|------|------|
| 4a-H01 | journal_entries.class_id 无外键 | Entity 声明但迁移未实现 |
| 4a-H03 | 外键无 tenant_id 联合约束 | 多租户 FK 保护不足 |
| 4a-H04 | class_members.user_id 无外键 | 用户删除后孤儿数据 |
| 4a-H05 | parent_child_bindings 无外键 | Entity Relation 为空 |
| 4b-H01 | processed_events 无 RLS 保护 | 跨租户数据可见 |
| 4b-H03 | diary.comment.delete 权限未定义 | 同 4a-C02 |
| 4b-H05 | 外键列缺少 tenant_id 前缀索引 | RLS 查询效率低 |
| 4b-H06 | domain_events_archive 无 tenant_id 索引 | 归档查询低效 |
### API 设计 (8 项)
| ID | 问题 | 说明 |
|----|------|------|
| 5a-H01 | 创建资源返回 200 而非 201 | ~15 个端点 |
| 5a-H03 | update_user/update_role 未调用 validate() | auth 模块也不完整 |
| 5a-H04 | AssignRolesReq 无 Validate | 空数组可致用户失角色 |
| 5a-H07 | SyncReq.changes 无大小限制 | DoS 风险 |
| 5b-H01 | `user.reset-password` 未在 permissions.yaml 注册 | 权限注册不一致 |
| 5b-H02 | `tenant.manage``system.analytics.submit` 永远 403 | 权限从未注册 |
| 5b-H03 | OpenAPI 缺少 Plugin/upload/crypto_admin 端点 | 文档不完整 |
| 5b-H05 | 微信登录缺速率限制 | API 配额消耗风险 |
### 基础设施 (13 项)
| ID | 问题 | 说明 |
|----|------|------|
| 6a-H01 | **CI 缺少管理端前端检查** | React 代码可未经检查合入 |
| 6a-H02 | 无 CI/CD 部署流程 | 部署全手动 |
| 6a-H03 | CI 不验证 Docker 构建 | Dockerfile 可能无法构建 |
| 6a-H04 | Redis 健康检查暴露密码 | `ps aux` 可见 |
| 6a-H06 | Prometheus 引用不存在的 exporter | 持续报错 |
| 6a-H07 | Grafana provisioning 目录为空 | 无预配置仪表盘 |
| 6b-H01 | 根目录 CORS allowed_origins="*" | 与 erp-server 配置矛盾 |
| 6b-H02 | rand crate 0.8 过时 | 密钥生成应升级 0.9 |
| 6b-H03 | AES-CBC 用于加密 | 应统一 AES-GCM |
| 6b-H04 | Web 依赖未锁定精确版本 | ^ 语义范围 |
| 6b-H05 | 管理端 URL 传递 JWT token | 浏览器历史/日志泄露 |
| 6b-H06 | Grafana 密码默认为空 | 生产环境风险 |
### 文档 (7 项)
| ID | 问题 | 说明 |
|----|------|------|
| 7b-H01 | erp-diary 代码量 7021 行 vs 声明 5800 行 | 超出 21% |
| 7b-H03 | school_class.codeMaxUses 未实现 | 设计规格不一致 |
| 7b-H04 | TeacherProfile.verificationStatus 未实现 | 设计规格不一致 |
| 7b-H05 | 内容安全词库为空 | 与 CLAUDE.md 声明不符 |
| 7b-H06 | discover 功能目录存在但属 Phase 2 | 违反原则 |
| 7b-H07 | Flutter 无 freezed 代码生成 | 与 CLAUDE.md 声明不符 |
### 性能 (12 项)
| ID | 问题 | 说明 |
|----|------|------|
| 8a-H01 | mood_stats 全量加载后内存聚合 | 应使用 SQL GROUP BY |
| 8a-H02 | EventBus 每次 3 次 DB 操作 | 无事务包裹 |
| 8a-H03 | sync_service 无事务 | 多条变更部分成功风险 |
| 8a-H04 | export_child_data 无分页 | 潜在 OOM |
| 8a-H05 | list_all_classes/list_members 无分页 | 数据增长后退化 |
| 8b-D01 | JournalEntryCollection 缺 authorId/dateEpoch 索引 | 全表扫描 |
| 8b-D02 | Isar 分页在 Dart 层而非数据库层 | 内存浪费 |
| 8b-D03 | MonthlyPage N+1 查询元素 | 30 篇 = 31 次查询 |
| 8b-N01 | SyncEngine 串行无合并 | 10 次自动保存 = 10 次 HTTP |
| 8b-N02 | _persistState 每元素单独事务 | 10 元素 = 10 次事务 |
| 8b-M01 | 首页日记列表用 Column 非 ListView.builder | 无懒加载 |
| 8b-M02 | 笔画光栅化用全画布尺寸 | 50 条笔画 = 1.6GB GPU |
### 跨层一致性 (11 项)
| ID | 问题 | 说明 |
|----|------|------|
| 9a-AUTH-02 | Flutter client_type='mobile' 后端不识别 | 潜在不一致 |
| 9a-SYNC-02 | SyncEngine 丢弃冲突数据 | 数据丢失 |
| 9a-SYNC-03 | 同步数据格式不兼容 | 两端协议断裂 |
| 9a-SYNC-04 | SyncEngine 不发送 version | 乐观锁失效 |
| 9a-TENANT-02 | 管理端不传递 tenant_id | 多租户切换缺失 |
| 9a-CROSS-01 | Flutter 无前端权限检查 | 后端 403 用户困惑 |
| 9b (汇总) | erp-diary 无集成测试 | 核心业务无 E2E 验证 |
| 9b (汇总) | Flutter 无 BLoC 测试 | 状态逻辑未验证 |
| 9b (汇总) | 管理端无组件测试 | UI 未验证 |
| 9b (汇总) | 管理端-后端 API 不匹配 | 贴纸更新/班级列表等 |
---
## 🟢 做得好的方面 (亮点)
### 安全
- ✅ AES-256-GCM + KEK/DEK 分层加密架构达到银行级别
- ✅ Argon2 密码哈希 + Refresh Token 轮换
- ✅ 审计日志哈希链防篡改
- ✅ 生产环境拒绝默认密钥启动 (cfg! 宏保护)
- ✅ Flutter 使用 flutter_secure_storage 加密存储 token
### 架构
- ✅ Feature Flag 干净隔离日记模块
- ✅ 所有 15 个 Entity 标准字段完全一致 (id/tenant_id/created_at/.../version)
- ✅ 15 张表迁移字段与 Entity 字段 **100% 一一对应**
- ✅ 模块边界正确: erp-diary 仅依赖 erp-core + erp-auth
- ✅ 统一 ApiResponse/PaginatedResponse 信封格式
### 前端
- ✅ 手写引擎双层 Canvas + Listener 方案达到教科书级
- ✅ shouldRepaint 守卫全部正确
- ✅ 笔画数据保真 (x/y/pressure/timestamp)
- ✅ 掌心抑制已实现
- ✅ 无内存泄漏 (Controller/Stream/Timer 全部正确 dispose)
- ✅ 响应式布局三档正确
### 基础设施
- ✅ Docker 多阶段构建 + 非特权用户
- ✅ Nginx 安全头配置全面 (HSTS/CSP/X-Frame-Options)
- ✅ 备份加密 (AES-256-CBC + GPG) + 自动清理
- ✅ Prometheus 告警规则分类清晰
---
## 🔧 修复路线图
### Phase 0: 紧急修复 (本周)
> 阻断性问题,影响数据安全/完整性
| # | 问题 ID | 修复项 | 预估工时 |
|---|---------|--------|---------|
| 1 | 4a-C01 | **修复 RLS 变量名**: `app.current_tenant``app.current_tenant_id` + 添加空值保护 | 1h |
| 2 | S-02 | **填充内容安全词库** + 在日记创建/同步中调用 | 4h |
| 3 | S-07 | **修复日记列表 IDOR**: 按 author_id 限制访问 | 2h |
| 4 | 5b-C01/02 | **添加权限守卫**: 审计日志 + 文件上传 | 1h |
| 5 | B-01 | **修复 class_service unwrap()**: 替换为安全错误处理 | 0.5h |
| 6 | B-07/B-11 | **添加事务**: create_class/join_class/parent 删除 | 3h |
| 7 | 8b-R01 | **修复笔画缓存 use-after-dispose** | 2h |
| **合计** | | | **~13.5h** |
### Phase 1: 安全加固 (第 1-2 周)
| # | 问题 ID | 修复项 | 预估工时 |
|---|---------|--------|---------|
| 1 | S-03 | 实现家长同意验证流程 | 8h |
| 2 | S-10 | 实现家长绑定实际验证流程 | 4h |
| 3 | S-01 | Token 黑名单改用 SHA-256 | 1h |
| 4 | 5a-C01/02/03 | **为所有 DTO 添加 Validate + handler 调用 validate()** | 8h |
| 5 | 6b-C01 | Flutter 强制 HTTPS + 证书固定 | 4h |
| 6 | 7b-C01 | 班级码改用字母数字混合 | 2h |
| 7 | 9a-AUTH-01 | Flutter 添加 Token 自动刷新拦截器 | 4h |
| **合计** | | | **~31h** |
### Phase 2: 性能优化 (第 3-4 周)
| # | 问题 ID | 修复项 | 预估工时 |
|---|---------|--------|---------|
| 1 | 8a-C01-04 | 修复后端 4 个 N+1 查询 | 8h |
| 2 | 8b-D01-03 | 修复 Isar 索引 + 分页 + N+1 | 6h |
| 3 | 8a-H01 | mood_stats 改用 SQL GROUP BY | 2h |
| 4 | 8b-M02 | 笔画光栅化改为 BBox 裁剪 | 4h |
| 5 | 8b-N01 | SyncEngine 合并同资源操作 | 4h |
| **合计** | | | **~24h** |
### Phase 3: 质量提升 (第 5-8 周)
| # | 问题 ID | 修复项 |
|---|---------|--------|
| 1 | 9b 全部 | 补充后端集成测试 + Flutter BLoC 测试 |
| 2 | 9a-SYNC-01 | 统一同步协议 |
| 3 | 5a-H01 | 创建端点改返回 201 |
| 4 | 5b-C03 | 添加 DiaryApiDoc OpenAPI 文档 |
| 5 | F-01 | 分阶段添加无障碍性 Semantics |
| 6 | B-03 | DiaryEvent 枚举接入 EventBus |
---
## 📊 各模块 CRITICAL+HIGH 热力图
```
CRITICAL HIGH 风险等级
──────────────────────────────────────────
安全 ████████ ████ 🔴 极高
后端架构 ███ ██████ 🟠 高
数据库 █████ ████ 🔴 极高
API 设计 ████████ ████ 🔴 极高
基础设施 ████████ ██████ 🔴 极高
文档 ██ ████ 🟡 中
性能 ██████ ██████ 🔴 极高
跨层一致性 ████████ ██████ 🔴 极高
前端质量 █ █ 🟡 中
```
---
## 结论
暖记项目的**架构设计和基础建设质量优秀**(模块边界、加密体系、多租户框架、手写引擎),但在**实施完整性和工程纪律**方面存在系统性缺口:
1. **输入验证系统性缺失** — erp-diary 全部 DTO 无 Validate是最高频问题
2. **RLS 变量名 bug** — 一个拼写错误导致 15 张表 RLS 失效,是最高优先修复
3. **同步协议断裂** — Flutter 和 Rust 实现了两套不兼容的同步机制
4. **权限覆盖不完整** — 审计日志/文件上传无守卫,多个权限码未注册
5. **性能 N+1 查询** — 后端 4 处 + Flutter 3 处 N+1随数据增长将严重影响体验
**建议**: 按 Phase 0 → Phase 3 路线图推进修复,优先解决数据安全和完整性问题。
---
## 附录 A: 步骤 7a — Wiki + 规划文档准确性审计
> 审计范围: wiki/ (7文件), plans/ (6文件), docs/tech-debt-board.md
### CRITICAL — 文档数字严重过时
| ID | 问题 | 文件 | 说明 |
|----|------|------|------|
| 7a-C1 | **erp-diary 代码量严重过时** | wiki/index.md, architecture.md, erp-diary.md | 三处文档分别声称 5,108/5,100/5,500 行。实际 **7,021 行**。handler/service/dto 行数全部过时 |
| 7a-C2 | **前端测试状态严重错误** | wiki/frontend.md, tech-debt-board.md, project-health.md | 声称"前端测试为零"。实际已有 **8 个测试文件、85 个测试用例** (4c743e1 起存在) |
| 7a-C3 | **Dart 文件数与代码量过时** | wiki/index.md | 声称 74 个文件/19,500 行。实际 **100 个文件/29,617 行**,偏差超 50% |
| 7a-C4 | **Git 提交数过时** | wiki/index.md | 声称 22 次提交。实际 **69 次提交**,基线 8111471 → HEAD d482497 |
| 7a-C5 | **管理端 TS 文件数过时** | wiki/index.md | 声称约 317 个。实际 **143 个**,差异极大 |
### HIGH — 重要不准确
| ID | 问题 | 文件 |
|----|------|------|
| 7a-H1 | Feature Flag 状态自相矛盾 — 实际已落地 | wiki/architecture.md |
| 7a-H2 | Dockerfile 不存在的描述已过时 | architecture.md, erp-diary.md, tech-debt-board.md |
| 7a-H3 | isar_database.dart 行数声称 72 行实际 14 行 | wiki/data-layer.md |
| 7a-H4 | data-layer.md 多个文件行数全部偏低 | wiki/data-layer.md |
| 7a-H5 | erp-diary.md 缺少 parent_handler 和 parent_service | wiki/erp-diary.md |
| 7a-H6 | admin-web.md 描述不存在的目录 (api/ai/, Copilot/) | wiki/admin-web.md |
| 7a-H7 | tech-debt-board TD-5 "前端测试为零" 严重过时 | docs/tech-debt-board.md |
| 7a-H8 | tech-debt-board TD-1 authorId 已部分修复但状态未更新 | docs/tech-debt-board.md |
| 7a-H9 | tech-debt-board TD-3 Docker 部署描述不完整 | docs/tech-debt-board.md |
### 做得好的方面 (文档体系)
- ✅ 文档结构规范 — 所有 wiki 页面遵循 5 节结构(设计决策/关键文件/代码逻辑/活跃问题/变更记录)
- ✅ 交叉引用体系 — `[[wikilink]]` 引用 + 症状导航表构成知识网络
- ✅ 集成契约表 — 清晰描述模块间调用方向、接口和触发时机
- ✅ 不变量标注 — 闪电符号标记开发守则("所有查询带 tenant_id"等)
- ✅ 变更记录 — 每个文档底部有 commit hash 可追溯
- ✅ 历史教训记录 — 记录具体踩坑经历Isar import、GestureDetector 延迟等)
### 文档修复建议
1. 以 wiki/index.md 的"关键数字"表为单一事实来源,其他页面引用而非重复声明
2. 更新 wiki/index.md 关键数字表(提交数 69, Dart 文件 100, erp-diary 行 7,021
3. 更新 wiki/erp-diary.md 的代码量分布表和 Service/Handler 清单
4. 更新 docs/tech-debt-board.md 的 TD-5已有测试、TD-3Dockerfile 已存在)
5. 更新 wiki/architecture.md 的 Feature Flag 状态和 Docker 部署描述
6. 更新 wiki/admin-web.md 的目录树和 API 目录描述