暖记 (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 |
风险等级分布
系统成熟度评估
| 领域 |
评分 |
说明 |
| 架构设计 |
★★★★☆ |
模块边界清晰,多租户架构合理 |
| 安全基础 |
★★★☆☆ |
加密体系完善,但输入验证/权限覆盖有缺口 |
| 数据库设计 |
★★★★☆ |
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 热力图
结论
暖记项目的架构设计和基础建设质量优秀(模块边界、加密体系、多租户框架、手写引擎),但在实施完整性和工程纪律方面存在系统性缺口:
- 输入验证系统性缺失 — erp-diary 全部 DTO 无 Validate,是最高频问题
- RLS 变量名 bug — 一个拼写错误导致 15 张表 RLS 失效,是最高优先修复
- 同步协议断裂 — Flutter 和 Rust 实现了两套不兼容的同步机制
- 权限覆盖不完整 — 审计日志/文件上传无守卫,多个权限码未注册
- 性能 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 延迟等)
文档修复建议
- 以 wiki/index.md 的"关键数字"表为单一事实来源,其他页面引用而非重复声明
- 更新 wiki/index.md 关键数字表(提交数 69, Dart 文件 100, erp-diary 行 7,021)
- 更新 wiki/erp-diary.md 的代码量分布表和 Service/Handler 清单
- 更新 docs/tech-debt-board.md 的 TD-5(已有测试)、TD-3(Dockerfile 已存在)
- 更新 wiki/architecture.md 的 Feature Flag 状态和 Docker 部署描述
- 更新 wiki/admin-web.md 的目录树和 API 目录描述