- 添加基础crate结构(erp-core, erp-common) - 实现核心模块trait和事件总线 - 配置Docker开发环境(PostgreSQL+Redis) - 添加Tauri桌面端基础框架 - 设置CI/CD工作流 - 编写项目协作规范文档(CLAUDE.md)
486 lines
16 KiB
Markdown
486 lines
16 KiB
Markdown
# ERP 平台底座 — 协作与实现规则
|
||
|
||
> **ERP Platform Base** 是一个模块化的商业 SaaS ERP 底座,目标是提供核心基础设施(身份权限、工作流、消息、配置),使行业业务模块(进销存、生产、财务等)可以快速插接。
|
||
|
||
> **当前阶段: Phase 1 基础设施搭建。** 从零构建 Rust workspace + Web 前端 + 核心共享层。
|
||
|
||
## 1. 项目定位
|
||
|
||
### 1.1 这是什么
|
||
|
||
一个 **底座 + 行业插件** 架构的商业 SaaS ERP 平台:
|
||
|
||
- **全功能底座** — 身份权限、工作流引擎、消息中心、系统配置
|
||
- **渐进式扩展** — 从小微企业起步,逐步支持中大型企业
|
||
- **多租户 + 私有化** — 默认 SaaS 共享数据库隔离,支持独立 schema 私有部署
|
||
- **Web 优先** — 浏览器 SPA 是主力,可选 Tauri 桌面端用于特定行业场景
|
||
|
||
### 1.2 决策原则
|
||
|
||
**任何改动都要问:这对 ERP 底座的模块化和可扩展性有帮助吗?**
|
||
|
||
- ✅ 完善模块接口和 trait 定义 → 最高优先
|
||
- ✅ 确保多租户隔离的正确性 → 最高优先
|
||
- ✅ 按计划推进 Phase 交付物 → 高优先
|
||
- ✅ 清晰的模块边界和事件契约 → 高优先
|
||
- ❌ 跳过 Phase 顺序提前实现远期功能 → 禁止
|
||
- ❌ 在模块间创建直接耦合 → 永远不做
|
||
- ❌ 硬编码租户 ID 或绕过多租户中间件 → 永远不做
|
||
- ❌ 过度设计未来才需要的能力 → 永远不做
|
||
|
||
### 1.3 架构铁律
|
||
|
||
| 约束 | 原因 |
|
||
|------|------|
|
||
| 模块间只通过事件总线和 trait 通信 | 保证模块可独立拆分为微服务 |
|
||
| 所有数据表必须含 `tenant_id` | 多租户是核心能力,不可事后补 |
|
||
| 使用 UUID v7 作为主键 | 时间排序 + 唯一性,分布式友好 |
|
||
| 软删除,不硬删除 | ERP 数据不可丢失,审计追溯需要 |
|
||
| 所有 API 使用 `/api/v1/` 前缀 | 版本化是 SaaS 产品的基本要求 |
|
||
|
||
---
|
||
|
||
## 2. 项目结构
|
||
|
||
```text
|
||
erp/
|
||
├── crates/ # Rust Workspace
|
||
│ ├── erp-core/ # L1: 基础类型、错误、事件、模块 trait
|
||
│ ├── erp-common/ # L1: 共享工具、宏
|
||
│ ├── erp-auth/ # L2: 身份与权限模块
|
||
│ ├── erp-workflow/ # L2: 工作流引擎模块
|
||
│ ├── erp-message/ # L2: 消息中心模块
|
||
│ ├── erp-config/ # L2: 系统配置模块
|
||
│ └── erp-server/ # L3: Axum 服务入口,组装所有模块
|
||
│ └── migration/ # SeaORM 数据库迁移
|
||
├── apps/
|
||
│ └── web/ # Vite + React 18 SPA (主力前端)
|
||
├── packages/
|
||
│ └── ui-components/ # React 共享组件库
|
||
├── desktop/ # (可选) Tauri 桌面端,行业需要时启用
|
||
├── docker/ # Docker 开发环境配置
|
||
├── docs/ # 文档
|
||
│ └── superpowers/
|
||
│ ├── specs/ # 设计规格文档
|
||
│ └── plans/ # 实施计划
|
||
├── Cargo.toml # Workspace root
|
||
└── CLAUDE.md # 本文件 — 协作规则
|
||
```
|
||
|
||
### 2.1 Crate 依赖关系
|
||
|
||
```text
|
||
erp-core (无业务依赖)
|
||
erp-common (无业务依赖)
|
||
↑
|
||
erp-auth (→ core)
|
||
erp-config (→ core)
|
||
erp-workflow (→ core)
|
||
erp-message (→ core)
|
||
↑
|
||
erp-server (→ 所有 crate,组装入口)
|
||
```
|
||
|
||
**规则:**
|
||
- `erp-core` 和 `erp-common` 不依赖任何业务 crate
|
||
- 业务 crate 之间**禁止**直接依赖,只通过事件总线和 `erp-core` trait 通信
|
||
- `erp-server` 是唯一的组装点
|
||
|
||
### 2.2 技术栈
|
||
|
||
| 层级 | 技术 |
|
||
|------|------|
|
||
| 后端框架 | Axum 0.8 + Tokio |
|
||
| ORM | SeaORM (异步、类型安全) |
|
||
| 数据库 | PostgreSQL 16+ |
|
||
| 缓存 | Redis 7+ |
|
||
| 前端框架 | React 18 + TypeScript (Vite) |
|
||
| UI 组件库 | Ant Design 5 |
|
||
| 状态管理 | Zustand |
|
||
| 路由 | React Router 7 |
|
||
| 样式 | TailwindCSS + CSS Variables |
|
||
| API 文档 | utoipa (OpenAPI 3) |
|
||
|
||
---
|
||
|
||
## 3. 工作风格
|
||
|
||
### 3.1 按计划推进
|
||
|
||
- **严格按 Phase 顺序执行** — Phase 2 依赖 Phase 1 的基础设施
|
||
- **每个 Task 完成后立即提交** — 不积压,保持可追溯
|
||
- **先测试后实现** — TDD 流程:写失败测试 → 实现 → 通过 → 提交
|
||
|
||
### 3.2 模块化思维
|
||
|
||
开发任何功能时先问:
|
||
|
||
1. **它属于哪个模块?** — 不确定就放到 `erp-core` 共享层
|
||
2. **它的接口是什么?** — 先定义 trait,再实现
|
||
3. **它需要发什么事件?** — 跨模块通知必须走事件总线
|
||
4. **其他模块怎么发现它?** — 通过 `ErpModule` trait 注册
|
||
|
||
### 3.3 闭环工作法(强制)
|
||
|
||
每次改动**必须**按顺序完成以下步骤,不允许跳过:
|
||
|
||
1. **理解需求** — 确认改动的目标模块和影响范围
|
||
2. **最小实现** — 只改必要的代码,保持模块边界
|
||
3. **自动验证** — `cargo check` / `cargo test` / `pnpm dev` 必须通过
|
||
4. **提交** — 按 §10 规范提交
|
||
5. **文档同步** — 更新相关文档(如果涉及架构变化)
|
||
|
||
**铁律:步骤 4 是任务完成的硬性条件。不允许"等一下再提交"。**
|
||
|
||
---
|
||
|
||
## 4. 实现规则
|
||
|
||
### 4.1 错误处理
|
||
|
||
- **跨 crate 边界**:使用 `thiserror` 定义类型化错误,转换为 `AppError`
|
||
- **crate 内部**:可以使用 `anyhow`,但**永远不**跨越 crate 边界
|
||
- **数据库错误**:通过 `From<sea_orm::DbErr>` 自动转换为 `AppError`
|
||
- **验证错误**:包含字段级详情,方便 UI 渲染
|
||
|
||
### 4.2 数据库操作
|
||
|
||
- 所有 SeaORM Entity 必须包含:`id`, `tenant_id`, `created_at`, `updated_at`, `created_by`, `updated_by`, `deleted_at`, `version`
|
||
- 查询时**始终**带 `tenant_id` 过滤(中间件自动注入)
|
||
- 更新时检查 `version` 字段实现乐观锁
|
||
- 删除使用软删除(设置 `deleted_at`)
|
||
|
||
### 4.3 API 设计
|
||
|
||
- 所有端点使用 `/api/v1/` 前缀
|
||
- 响应统一使用 `ApiResponse<T>` 包装
|
||
- 分页使用 `Pagination` + `PaginatedResponse<T>`
|
||
- utoipa 自动生成 OpenAPI 文档
|
||
- 租户 ID 从 JWT 中间件注入,**不在** API 路径中传递(管理员接口除外)
|
||
|
||
### 4.4 事件总线
|
||
|
||
- 模块间通信**只能**通过 `EventBus`
|
||
- 事件必须持久化到 `domain_events` 表(outbox 模式)
|
||
- 事件处理失败记录到 dead-letter 存储
|
||
- 事件类型命名:`{模块}.{动作}` 如 `user.created`, `workflow.task.completed`
|
||
|
||
### 4.5 Rust 代码规范
|
||
|
||
```rust
|
||
// 命名:snake_case (函数/变量), PascalCase (类型/trait), SCREAMING_SNAKE (常量)
|
||
// 模块公开接口通过 lib.rs 统一导出
|
||
// 每个 public 函数和 trait 必须有文档注释
|
||
// 异步函数返回 Result 时使用 AppResult<T> 类型别名
|
||
// 数据库操作使用 SeaORM 的 Entity + Model + Relation 模式
|
||
```
|
||
|
||
### 4.6 TypeScript / React 代码规范
|
||
|
||
```typescript
|
||
// 避免 any,优先 unknown + 类型守卫
|
||
// 函数组件 + hooks
|
||
// 复杂状态收敛到 Zustand store
|
||
// API 调用封装到独立的 service 层,不在组件中直接 fetch
|
||
// 使用 Ant Design 组件,不自行实现已有组件
|
||
// 国际化文案使用 i18n key,不硬编码中文
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 模块开发规范
|
||
|
||
### 5.1 新建业务模块清单
|
||
|
||
每个新模块(如 erp-auth, erp-workflow)**必须**包含:
|
||
|
||
1. `Cargo.toml` — 依赖 `erp-core`
|
||
2. `src/lib.rs` — 模块入口,实现 `ErpModule` trait
|
||
3. `src/error.rs` — 模块错误类型,wrap `AppError`
|
||
4. `src/entity/` — SeaORM Entity 定义
|
||
5. `src/service/` — 业务逻辑层
|
||
6. `src/handler/` — Axum 路由处理器
|
||
7. `src/event.rs` — 模块事件定义和处理器
|
||
|
||
### 5.2 ErpModule trait 实现
|
||
|
||
```rust
|
||
pub struct AuthModule;
|
||
|
||
impl ErpModule for AuthModule {
|
||
fn name(&self) -> &str { "auth" }
|
||
fn version(&self) -> &str { env!("CARGO_PKG_VERSION") }
|
||
fn dependencies(&self) -> Vec<&str> { vec![] } // auth 是基础模块,无依赖
|
||
|
||
fn register_routes(&self, router: Router) -> Router {
|
||
router.nest("/api/v1", auth_routes())
|
||
}
|
||
|
||
fn register_event_handlers(&self, bus: &EventBus) {
|
||
// 订阅其他模块的事件
|
||
}
|
||
|
||
async fn on_tenant_created(&self, tenant_id: Uuid) -> AppResult<()> {
|
||
// 初始化默认角色、管理员等
|
||
Ok(())
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3 数据库迁移
|
||
|
||
- 迁移文件放在 `crates/erp-server/migration/src/`
|
||
- 命名格式:`m{YYYYMMDD}_{6位序号}_{描述}.rs`
|
||
- 迁移必须可回滚(实现 `down` 方法)
|
||
- 新增表必须包含所有标准字段(§1.3)
|
||
- 迁移必须幂等(使用 `if_not_exists`)
|
||
|
||
---
|
||
|
||
## 6. 测试与验证
|
||
|
||
### 6.1 测试要求
|
||
|
||
| 测试类型 | 覆盖目标 | 工具 |
|
||
|----------|---------|------|
|
||
| 单元测试 | 每个 service 函数 | `#[cfg(test)]` + `tokio::test` |
|
||
| 集成测试 | API 端点 → 数据库 | `cargo test` + 真实 PostgreSQL |
|
||
| 多租户测试 | 数据隔离验证 | 独立测试 crate |
|
||
| 前端测试 | 组件交互 | Vitest (未来) |
|
||
|
||
### 6.2 验证命令
|
||
|
||
```bash
|
||
# Rust 编译检查
|
||
cargo check
|
||
|
||
# Rust 全量测试
|
||
cargo test --workspace
|
||
|
||
# 后端服务启动
|
||
cd crates/erp-server && cargo run
|
||
|
||
# Docker 环境
|
||
cd docker && docker compose up -d
|
||
|
||
# 桌面端开发
|
||
cd apps/desktop && pnpm tauri dev
|
||
|
||
# 数据库迁移检查
|
||
docker exec erp-postgres psql -U erp -c "\dt"
|
||
```
|
||
|
||
### 6.3 Phase 完成标准
|
||
|
||
每个 Phase 完成时必须满足:
|
||
|
||
- [ ] `cargo check` 全 workspace 通过
|
||
- [ ] `cargo test` 全部通过
|
||
- [ ] Docker 环境正常启动
|
||
- [ ] 所有迁移可正/反向执行
|
||
- [ ] API 端点可通过 Swagger UI 测试
|
||
- [ ] 桌面端可正常启动并展示对应 UI
|
||
- [ ] 所有代码已提交
|
||
|
||
---
|
||
|
||
## 7. 安全注意事项
|
||
|
||
### 7.1 认证安全
|
||
|
||
- **密码存储**: Argon2 哈希,禁止明文
|
||
- **JWT**: access token 15min + refresh token 7d
|
||
- **Refresh Token 轮换**: 每次使用后签发新的,旧的作废
|
||
- **Token 存储**: 桌面端使用 Tauri secure store
|
||
- **密码修改**: 使所有已签发的 JWT 失效
|
||
|
||
### 7.2 多租户安全
|
||
|
||
- **中间件注入**: `tenant_id` 从 JWT 中提取,应用层不可伪造
|
||
- **数据隔离**: 所有查询自动过滤 `tenant_id`
|
||
- **越权防护**: 禁止跨租户数据访问
|
||
- **租户 provisioning**: `on_tenant_created` 钩子初始化数据
|
||
|
||
### 7.3 通用安全
|
||
|
||
- **不硬编码密钥** — 使用环境变量或配置文件
|
||
- **用户输入验证** — 所有 API 端点验证输入
|
||
- **SQL 注入防护** — SeaORM 参数化查询
|
||
- **限流** — Redis token bucket,登录等敏感接口限流
|
||
- **CORS** — 白名单制,默认拒绝
|
||
- **审计日志** — 所有关键操作记录变更前后状态
|
||
|
||
---
|
||
|
||
## 8. 桌面端 UI 规范
|
||
|
||
### 8.1 布局结构
|
||
|
||
经典 SaaS 后台管理布局(响应式,支持移动端):
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ LOGO 搜索... 🔔 5 👤 Admin ▾ │ ← 顶部导航栏
|
||
├─────────┬───────────────────────────────────┤
|
||
│ 📊 首页 │ │
|
||
│ 👥 用户 │ 主内容区域 │
|
||
│ 🔐 权限 │ (多标签页切换) │
|
||
│ 📋 流程 │ │
|
||
│ 💬 消息 │ │
|
||
│ ⚙️ 设置 │ │
|
||
│─────────│ │
|
||
│ 📦 进销存│ │
|
||
│ 🏭 生产 │ │
|
||
│ 💰 财务 │ │
|
||
│─────────│ │
|
||
│ ▸ 更多 │ │
|
||
└─────────┴───────────────────────────────────┘
|
||
```
|
||
|
||
### 8.2 UI 规则
|
||
|
||
- 使用 Ant Design 组件库,不自造轮子
|
||
- 中文优先,所有文案通过 i18n key 引用
|
||
- 支持暗色/亮色主题切换
|
||
- 侧边栏按模块分组:基础模块 / 行业模块
|
||
- 表单验证使用 Ant Design Form 的 validateRules
|
||
|
||
---
|
||
|
||
## 9. 常用命令
|
||
|
||
```bash
|
||
# === Rust ===
|
||
cargo check # 编译检查
|
||
cargo test --workspace # 运行所有测试
|
||
cargo run -p erp-server # 启动后端服务
|
||
cargo fmt --check # 检查格式
|
||
cargo clippy -- -D warnings # Lint 检查
|
||
|
||
# === Docker ===
|
||
cd docker && docker compose up -d # 启动 PostgreSQL + Redis
|
||
docker compose -f docker/docker-compose.yml ps # 查看服务状态
|
||
docker compose -f docker/docker-compose.yml down # 停止服务
|
||
|
||
# === 前端 ===
|
||
cd apps/web && pnpm install # 安装依赖
|
||
cd apps/web && pnpm dev # 开发模式
|
||
cd apps/web && pnpm build # 构建生产版本
|
||
|
||
# === 数据库 ===
|
||
docker exec -it erp-postgres psql -U erp # 连接数据库
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 提交规范
|
||
|
||
```
|
||
<type>(<scope>): <description>
|
||
```
|
||
|
||
**类型:**
|
||
- `feat` — 新功能
|
||
- `fix` — 修复问题
|
||
- `refactor` — 重构
|
||
- `docs` — 文档更新
|
||
- `test` — 测试相关
|
||
- `chore` — 杂项(构建、配置等)
|
||
- `perf` — 性能优化
|
||
|
||
**Scope 对应 crate 或模块名:**
|
||
|
||
| scope | 范围 |
|
||
|-------|------|
|
||
| `core` | erp-core |
|
||
| `common` | erp-common |
|
||
| `auth` | erp-auth |
|
||
| `workflow` | erp-workflow |
|
||
| `message` | erp-message |
|
||
| `config` | erp-config |
|
||
| `server` | erp-server |
|
||
| `web` | Web 前端 |
|
||
| `ui` | React 组件 |
|
||
| `db` | 数据库迁移 |
|
||
| `docker` | Docker 配置 |
|
||
|
||
**示例:**
|
||
|
||
```
|
||
feat(auth): 添加用户管理 CRUD
|
||
feat(core): 实现事件总线和模块注册
|
||
fix(server): 修复数据库连接池配置
|
||
refactor(auth): 拆分 RBAC 和 ABAC 权限模型
|
||
chore(docker): 添加 PostgreSQL 健康检查
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 设计文档索引
|
||
|
||
| 文档 | 说明 |
|
||
|------|------|
|
||
| `docs/superpowers/specs/2026-04-10-erp-platform-base-design.md` | 平台底座设计规格 |
|
||
| `docs/superpowers/plans/2026-04-10-erp-platform-base-plan.md` | 平台底座实施计划 |
|
||
|
||
所有设计决策以设计规格文档为准。实施计划按阶段拆分,每阶段开始前细化。
|
||
|
||
---
|
||
|
||
<!-- ARCH-SNAPSHOT-START -->
|
||
<!-- 此区域随开发进度更新 -->
|
||
|
||
## 12. 当前架构快照
|
||
|
||
### 开发进度
|
||
|
||
| Phase | 内容 | 状态 |
|
||
|-------|------|------|
|
||
| Phase 1 | 基础设施 (workspace + core + Docker + 桌面端) | 🚧 进行中 |
|
||
| Phase 2 | 身份与权限 (Auth) | ⏳ 待开始 |
|
||
| Phase 3 | 系统配置 (Config) | ⏳ 待开始 |
|
||
| Phase 4 | 工作流引擎 (Workflow) | ⏳ 待开始 |
|
||
| Phase 5 | 消息中心 (Message) | ⏳ 待开始 |
|
||
| Phase 6 | 整合与打磨 | ⏳ 待开始 |
|
||
|
||
### 已实现模块
|
||
|
||
| Crate | 功能 | 状态 |
|
||
|-------|------|------|
|
||
| erp-core | 错误类型、共享类型、事件总线、ErpModule trait | 🚧 进行中 |
|
||
| erp-common | 共享工具 | 🚧 进行中 |
|
||
| erp-server | Axum 服务入口、配置、数据库连接 | 🚧 进行中 |
|
||
| erp-auth | 身份与权限 | ⏳ 待开始 |
|
||
| erp-workflow | 工作流引擎 | ⏳ 待开始 |
|
||
| erp-message | 消息中心 | ⏳ 待开始 |
|
||
| erp-config | 系统配置 | ⏳ 待开始 |
|
||
|
||
<!-- ARCH-SNAPSHOT-END -->
|
||
|
||
---
|
||
|
||
<!-- ANTI-PATTERN-START -->
|
||
|
||
## 13. 反模式警告
|
||
|
||
- ❌ **不要**在业务 crate 之间创建直接依赖 — 只通过事件和 trait 通信
|
||
- ❌ **不要**跳过多租户中间件 — 所有数据操作必须带 `tenant_id` 过滤
|
||
- ❌ **不要**硬编码配置值 — 使用 config.toml + 环境变量
|
||
- ❌ **不要**跳过迁移直接建表 — 所有 schema 变更通过 SeaORM Migration
|
||
- ❌ **不要**在前端组件中直接调用 HTTP — 封装到 service 层
|
||
- ❌ **不要**使用 `anyhow` 跨越 crate 边界 — 内部可用,对外必须转 `AppError`
|
||
- ❌ **不要**假设只有单租户 — 从第一天就按多租户设计
|
||
- ❌ **不要**提前实现远期功能 — 严格按 Phase 计划推进
|
||
- ❌ **不要**忽略 `version` 字段 — 所有更新操作必须检查乐观锁
|
||
|
||
### 场景化指令
|
||
|
||
- 当遇到**新增模块** → 实现 `ErpModule` trait,在 `erp-server` 注册
|
||
- 当遇到**跨模块通信** → 定义事件类型,通过 `EventBus` 发布/订阅
|
||
- 当遇到**数据查询** → 确保包含 `tenant_id` 过滤,检查软删除条件
|
||
- 当遇到**新增 API** → 添加 utoipa 注解,确保 OpenAPI 文档同步
|
||
- 当遇到**新增表** → 创建 SeaORM migration + Entity,包含所有标准字段
|
||
- 当遇到**新增页面** → 使用 Ant Design 组件,i18n key 引用文案
|
||
|
||
<!-- ANTI-PATTERN-END -->
|