Files
nj/wiki/architecture.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

6.1 KiB
Raw Blame History

title, updated, status, tags
title updated status tags
架构决策 2026-06-02 active
architecture
base
multi-tenant
security
three-tier

架构决策

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 按需引入暖记模块。基座 crateauth/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 + 管理端)

三端架构

nj/
├── crates/                    # 后端 (Rust Axum, :3000)
│   ├── erp-server/            #   入口 + diary feature flag
│   └── erp-diary/             #   暖记业务模块
├── apps/
│   └── web/                   # 管理端 (React + Ant Design, :5174)
│       └── vite.config.ts     #   proxy /api → :3000
├── app/                       # 学生端 (Flutter, :8080)
│   └── lib/features/          #   16 功能模块
├── scripts/dev.sh             # 统一启动脚本 (自动清理端口)
└── config/default.toml        # 环境配置 (CORS=*)

来源追溯

组件 来源 说明
crates/erp-* (基座 6 个) base.git 零开发
crates/erp-diary 新增 ~5100 行 Rust
apps/web/ HMS apps/web/ React 管理面板复用
app/ (Flutter) 新增 ~19500 行 Dart
scripts/dev.sh 新增 三端统一启动

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. 活跃问题 + 陷阱

问题 级别 状态 说明
管理端品牌仍是 HMS HIGH 待做 标题/Logo/颜色需替换为暖记品牌
管理端缺少暖记专用页面 HIGH 待做 班级管理/日记审核/贴纸管理等页面待添加
Docker 部署未验证 HIGH 待做 docker/ 配置完善但 Dockerfile 不存在
上下文窗口耗尽 MEDIUM 已缓解 CLAUDE.md §8 会话交接机制
Windows Defender 锁定 exe MEDIUM 需手动 排除 target/ 目录
erp-plugin 超大文件 LOW 待重构 manifest.rs 1809行 + data_service.rs 1907行
Dashboard 部分数据加载失败 LOW 待做 统计 API 需适配暖记数据模型

历史教训

  • 基座剥离耗时比预期长7 个耦合点需逐一解耦)
  • Isar 3.x 扩展方法不随传递 import 传播,必须显式 import
  • Feature Flag 在基座剥离规划中设计完善,但实际实施时未落地到 Cargo.toml

5. 变更记录

日期 变更
2026-06-02 补充三端架构、管理端复用说明、更新活跃问题
2026-06-01 补充 Feature Flag 状态、超大文件发现
2026-06-01 初始创建 — 架构决策、基座剥离记录、集成契约