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

154 lines
6.1 KiB
Markdown
Raw Permalink 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.
---
title: 架构决策
updated: 2026-06-02
status: active
tags: [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 | 初始创建 — 架构决策、基座剥离记录、集成契约 |