- 添加基础crate结构(erp-core, erp-common) - 实现核心模块trait和事件总线 - 配置Docker开发环境(PostgreSQL+Redis) - 添加Tauri桌面端基础框架 - 设置CI/CD工作流 - 编写项目协作规范文档(CLAUDE.md)
20 KiB
ERP Platform Base - Design Specification
Date: 2026-04-10 Status: Draft (Review Round 2) Author: Claude + User
Context
Build a commercial SaaS ERP product from scratch using a "platform base + industry plugins" architecture. The base provides core infrastructure (auth, workflow, messaging, configuration), enabling rapid deployment of industry-specific modules (inventory, manufacturing, finance, HR, etc.) on top.
The system targets progressive scaling: start with small businesses, expand to mid and large enterprises. Multi-tenant SaaS deployment is the default, with private deployment as an option.
Architecture
Overall: Modular Monolith (Progressive)
Start as a single Rust backend service with well-defined module boundaries. Modules communicate through an internal event bus and shared traits. When a module needs independent scaling, it can be extracted into a standalone service without changing interfaces.
System Layers
Web Frontend (Vite + React 18 + Ant Design 5)
├── Shell / Layout / Navigation
└── Module UI (dynamically loaded per tenant config)
│
API Layer (REST + WebSocket)
│
Rust Backend Service (Axum + Tokio)
├── Auth Module (identity, roles, permissions, tenants)
├── Workflow Engine (BPMN processes, tasks, approvals)
├── Message Center (notifications, templates, channels)
└── Config Module (menus, dictionaries, settings, numbering)
│
Core Shared Layer (tenant context, audit, events, caching)
│
PostgreSQL (primary) + Redis (cache + session + pub/sub)
Note: Tauri 桌面端为可选方案,未来行业模块(如工厂仓库)需要硬件集成时启用。主力前端为 Web SPA。
Design Principles
- Module isolation: Each business module is an independent Rust crate, interfaces defined via traits
- Multi-tenant built-in: All data tables include
tenant_id, middleware auto-injects tenant context - Event-driven: Modules communicate via event bus, no direct coupling
- Plugin extensibility: Industry modules register through standard interfaces, support dynamic enable/disable
Error Handling Strategy
// erp-core defines the unified error hierarchy
// Uses thiserror for typed errors across crate boundaries
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("Not found: {0}")]
NotFound(String),
#[error("Validation error: {0}")]
Validation(String),
#[error("Unauthorized")]
Unauthorized,
#[error("Forbidden: {0}")]
Forbidden(String),
#[error("Conflict: {0}")]
Conflict(String),
#[error("Internal error: {0}")]
Internal(String),
}
// Axum IntoResponse impl maps to HTTP status codes
// Validation errors include field-level detail for UI rendering
Decision: thiserror for crate boundaries (typed, catchable), anyhow never crosses crate boundaries (internal use only for prototyping). Each module defines its own error variants that wrap AppError.
Event Bus Specification
EventBus (tokio::sync::broadcast based, in-process)
Event {
id: UUID v7
event_type: String (e.g., "user.created", "workflow.task.completed")
tenant_id: UUID
payload: serde_json::Value
timestamp: DateTime<Utc>
correlation_id: UUID (for tracing)
}
Delivery Guarantees:
- At-least-once delivery within the process
- Events persisted to `domain_events` table before dispatch (outbox pattern)
- Failed handlers log to dead-letter storage, trigger alert
- No cross-process delivery in Phase 1 (single binary)
Plugin / Module Registration Interface
// erp-core defines the plugin trait
pub trait ErpModule: Send + Sync {
fn name(&self) -> &str;
fn version(&self) -> &str;
fn dependencies(&self) -> Vec<&str>; // required modules
fn register_routes(&self, router: Router) -> Router;
fn register_event_handlers(&self, bus: &EventBus);
fn on_tenant_created(&self, tenant_id: Uuid) -> Result<()>;
fn on_tenant_deleted(&self, tenant_id: Uuid) -> Result<()>;
}
// erp-server assembles modules at startup
fn build_app(modules: Vec<Box<dyn ErpModule>>) -> Router { ... }
Industry modules implement ErpModule and are discovered via configuration, not compile-time.
API Versioning & Contract Governance
- Code-first with utoipa: derive OpenAPI from Rust types
- Auto-generated Swagger UI at
/docsin development /api/v1/prefix for all endpoints; v2 only when breaking changes needed- Client sends
X-API-Version: 1header; server rejects unsupported versions - Tauri client version and server version must be compatible (checked on connect)
Concurrency & Transaction Strategy
- Optimistic locking: All mutable entities carry
versioncolumn; updates fail on mismatch - Idempotency: Write endpoints accept optional
Idempotency-Keyheader - Cross-module transactions: Avoided by design; event bus + saga pattern for consistency
- Numbering sequences: PostgreSQL sequences with
advisory_lockper tenant per rule
Audit Logging
AuditLog {
id: UUID v7
tenant_id: UUID
user_id: UUID
action: String (e.g., "user.update", "role.create")
resource_type: String
resource_id: UUID
changes: JSONB { before: {}, after: {} }
ip_address: String
user_agent: String
timestamp: DateTime<Utc>
}
Retention: 90 days hot, archive to cold storage after
Query API: GET /api/v1/audit-logs?resource_type=user&from=...
Frontend-Backend Communication
| Aspect | Decision |
|---|---|
| Auth flow | Login via REST → JWT stored in httpOnly cookie (web) → sent as Bearer header |
| REST calls | Standard fetch/axios from browser to backend |
| WebSocket | Connect on page load, auth via first message with JWT, auto-reconnect with exponential backoff |
| File upload/download | Standard HTTP multipart + blob download |
| CORS | Whitelist per tenant, deny by default |
Security Measures
- CORS: Whitelist per tenant, deny by default
- Rate limiting: Per-IP + per-user via Redis token bucket
- Secret management: Environment variables + vault (HashiCorp Vault for production)
- Data encryption: TLS in transit, AES-256 at rest for PII fields (optional per tenant config)
- Input validation: Schema-based (JSON Schema for complex inputs, types for simple)
- SQL injection: Prevented by SeaORM parameterized queries
Tech Stack
Backend (Rust)
| Component | Choice | Rationale |
|---|---|---|
| Web framework | Axum 0.8 | Tokio-team maintained, best ecosystem |
| Async runtime | Tokio | Rust async standard |
| ORM | SeaORM | Async, type-safe, migration support |
| DB migration | SeaORM Migration | Versioned schema management |
| Cache | redis-rs | Official Redis client |
| JWT | jsonwebtoken | Lightweight, reliable |
| Serialization | serde + serde_json | Rust standard |
| Logging | tracing + tracing-subscriber | Structured logging |
| Config | config-rs | Multi-format support |
| API docs | utoipa (OpenAPI 3) | Auto-generate Swagger |
| Testing | Built-in + tokio-test | Unit + integration |
Web Frontend
| Layer | Technology |
|---|---|
| Build tool | Vite 6 |
| UI framework | React 18 + TypeScript |
| Component library | Ant Design 5 |
| State management | Zustand |
| Routing | React Router 7 |
| Styling | TailwindCSS + CSS Variables |
Infrastructure
| Component | Technology |
|---|---|
| Primary database | PostgreSQL 16+ |
| Cache / Session / PubSub | Redis 7+ |
| Containerization | Docker + Docker Compose (dev) |
Crate Structure
erp/
├── crates/
│ ├── erp-core/ # Shared: error handling, types, traits, events
│ ├── erp-auth/ # Identity & permissions module
│ ├── erp-workflow/ # Workflow engine module
│ ├── erp-message/ # Message center module
│ ├── erp-config/ # System configuration module
│ ├── erp-server/ # Axum server entry, assembles all modules
│ └── erp-common/ # Shared utilities, macros
├── apps/
│ └── web/ # Vite + React SPA (primary frontend)
├── desktop/ # (Optional) Tauri desktop, enabled per industry need
├── packages/
│ └── ui-components/ # React shared component library
├── migrations/ # Database migrations
├── docs/ # Documentation
└── docker/ # Docker configurations
Module 1: Identity & Permissions (Auth)
Data Model
Tenant
├── Organization
│ └── Department
│ └── Position
├── User
│ ├── UserCredential (password / OAuth / SSO)
│ ├── UserProfile
│ └── UserToken (session)
├── Role
│ └── Permission
└── Policy (ABAC rules)
Permission Model: RBAC + ABAC Hybrid
- RBAC: User -> Role -> Permission, for standard scenarios
- ABAC: Attribute-based rules (e.g., "department manager can only approve own department's requests")
- Data-level: Row filtering (e.g., "only see own department's data")
Authentication Methods
| Method | Description |
|---|---|
| Username/Password | Basic auth, Argon2 hash |
| OAuth 2.0 | Third-party login (WeChat, DingTalk, WeCom) |
| SSO (SAML/OIDC) | Enterprise SSO, required for private deployment |
| TOTP | Two-factor authentication |
Key APIs
POST /api/v1/auth/login
POST /api/v1/auth/logout
POST /api/v1/auth/refresh
POST /api/v1/auth/revoke # Revoke a specific token
GET /api/v1/users
POST /api/v1/users
PUT /api/v1/users/:id
DELETE /api/v1/users/:id (soft delete)
GET /api/v1/roles
POST /api/v1/roles
PUT /api/v1/roles/:id
DELETE /api/v1/roles/:id
POST /api/v1/roles/:id/permissions
GET /api/v1/permissions # List all available permissions
GET /api/v1/tenants/:id/users
GET /api/v1/organizations
POST /api/v1/organizations
PUT /api/v1/organizations/:id
DELETE /api/v1/organizations/:id
GET /api/v1/organizations/:id/departments
POST /api/v1/organizations/:id/departments
GET /api/v1/positions
POST /api/v1/positions
GET /api/v1/policies
POST /api/v1/policies
PUT /api/v1/policies/:id
DELETE /api/v1/policies/:id
Multi-tenant Isolation
- Default: Shared database +
tenant_idcolumn isolation (cost-optimal) - Switchable: Independent schema per tenant (for private deployment)
- Middleware auto-injects
tenant_id, application code is tenant-agnostic
Multi-tenant Migration Strategy
- Schema migrations run once globally, affect all tenants' rows
- New tenant provisioning: seed data script (default roles, admin user, org structure, menus)
- Migrations are versioned and idempotent; failed migrations halt startup
- Per-tenant data migrations (e.g., adding default config) trigger on
on_tenant_createdhook
Module 2: Workflow Engine
Design Goals
- BPMN 2.0 subset compatible visual process designer
- Low latency, high throughput (Rust advantage)
- Support conditional branches, parallel gateways, sub-processes
- Embeddable into any business module
BPMN Subset Scope (Phase 4)
Included in Phase 4:
- Start/End events
- User Tasks (with assignee, candidate groups)
- Service Tasks (HTTP call, script execution)
- Exclusive Gateways (conditional branching)
- Parallel Gateways (fork/join)
- Sequence Flows with conditions
- Process variables (basic types: string, number, boolean, date)
Deferred to later phases:
- Inclusive Gateways
- Sub-Processes (call activity)
- Timer events (intermediate, boundary)
- Signal/Message events
- Error boundary events
- Multi-instance (loop) activities
- Data objects and stores
Core Concepts
ProcessDefinition
├── Node Types
│ ├── StartNode
│ ├── EndNode
│ ├── UserTask (human task)
│ ├── ServiceTask (system task)
│ ├── Gateway (exclusive / parallel / inclusive)
│ └── SubProcess
├── Flow (connections)
│ └── Condition (expressions)
└── ProcessInstance
├── Token (tracks execution position)
├── Task (pending tasks)
└── Variable (process variables)
Key Features
| Feature | Description |
|---|---|
| Visual designer | React flowchart editor, drag-and-drop |
| Condition expressions | EL expressions: amount > 10000 && dept == "finance" |
| Countersign / Or-sign | Multi-person approval: all approve / any approve |
| Delegate / Transfer | Tasks can be delegated to others |
| Reminder / Timeout | Auto-remind, auto-handle on timeout |
| Version management | Process definitions versioned, running instances use old version |
Key APIs
POST /api/v1/workflow/definitions
GET /api/v1/workflow/definitions/:id
PUT /api/v1/workflow/definitions/:id
POST /api/v1/workflow/instances
GET /api/v1/workflow/instances/:id
GET /api/v1/workflow/tasks (my pending)
POST /api/v1/workflow/tasks/:id/approve
POST /api/v1/workflow/tasks/:id/reject
POST /api/v1/workflow/tasks/:id/delegate
GET /api/v1/workflow/instances/:id/diagram (highlighted)
Integration Points
- Auth: Task assignment based on roles/org structure
- Message: Pending task notifications, reminders, approval results
- Config: Process categories, numbering rules
Module 3: Message Center
Message Channels
| Channel | Use Case |
|---|---|
| In-app notifications | Foundation for all messages |
| WebSocket | Real-time push, instant desktop alerts |
| Important approvals, scheduled reports | |
| SMS | Verification codes, urgent alerts |
| WeCom / DingTalk | Enterprise messaging integration |
Data Model
MessageTemplate
├── Channel type
├── Template content (variable interpolation: {{user_name}})
└── Multi-language versions
Message
├── Sender (system / user)
├── Recipient (user / role / department / all)
├── Priority (normal / important / urgent)
├── Read status
└── Business reference (deep link to specific page)
MessageSubscription
├── User notification preferences
├── Do-not-disturb periods
└── Channel preferences (e.g., approvals via in-app + WeCom, reports via email)
Key Features
- Message aggregation: Group similar messages (e.g., "You have 5 pending approvals")
- Read/unread: Read receipts, unread count query
- Message recall: Sender can recall unread messages
- Scheduled sending: Set delivery time
- Message archive: Auto-archive history, searchable
Key APIs
GET /api/v1/messages (list with pagination)
GET /api/v1/messages/unread-count
PUT /api/v1/messages/:id/read
PUT /api/v1/messages/read-all
DELETE /api/v1/messages/:id
POST /api/v1/messages/send
GET /api/v1/message-templates
POST /api/v1/message-templates
PUT /api/v1/message-subscriptions (update preferences)
WS /ws/v1/messages (real-time push)
Module 4: System Configuration
Configuration Hierarchy
Platform (global)
└── Tenant
└── Organization
└── User
Lower-level overrides higher-level. Priority: User > Organization > Tenant > Platform.
Capabilities
| Capability | Description |
|---|---|
| Dynamic menus | Tenants customize menu structure, display by role |
| Data dictionaries | System-level and tenant-level enum management |
| Numbering rules | Document number generation with concurrency-safe sequences |
| Multi-language | i18n resource management, runtime switching |
| System parameters | Key-value general configuration |
| Theme customization | Tenant-level UI theme (colors, logo) |
Key APIs
GET /api/v1/config/menus # Tenant from middleware
PUT /api/v1/config/menus
GET /api/v1/config/dictionaries
POST /api/v1/config/dictionaries
PUT /api/v1/config/dictionaries/:id
GET /api/v1/config/settings/:key
PUT /api/v1/config/settings/:key
GET /api/v1/config/numbering-rules
POST /api/v1/config/numbering-rules
PUT /api/v1/config/numbering-rules/:id
GET /api/v1/config/languages
PUT /api/v1/config/languages/:code
GET /api/v1/config/themes # Tenant theme
PUT /api/v1/config/themes
Database Design Principles
- All tables include:
tenant_id,created_at,updated_at,created_by,updated_by - Soft delete via
deleted_at(no hard deletes) - UUID v7 as primary keys (time-sortable + unique)
- JSONB columns for flexible extension data
- Indexes on
tenant_id+ business keys for multi-tenant queries
Web UI Design
Layout
Classic SaaS admin panel layout (responsive, mobile-friendly):
+----------------------------------------------+
| LOGO Search... 🔔 5 👤 Admin ▾ | ← Top nav bar
+--------+-------------------------------------+
| Home | |
| Users | Main Content Area |
| Roles | (Dynamic per menu selection) |
| Flows | Multi-tab support |
| Messages| |
| Settings| |
|--------| |
| Inv. | |
| Mfg. | |
| Finance| |
|--------| |
| More > | |
+--------+-------------------------------------+
Key UI Features
- Collapsible sidebar: Multi-level menus, grouped (base modules / industry modules)
- Multi-tab content: Switch between open pages like browser tabs
- Global search: Search menus, users, documents
- Notification panel: Click bell icon to expand message list
- Dark/Light theme: Toggle support, follow system preference
- Responsive: Mobile/tablet adaptive layout
- Browser notifications: Web Notification API for real-time alerts
Development Roadmap
Phase 1 - Foundation (2-3 weeks)
- Rust workspace scaffolding + Vite + React setup
- erp-core: error types, shared types, trait definitions, event bus
- ErpModule trait + module registration system
- Database migration framework (SeaORM) with tenant provisioning
- Docker dev environment (PostgreSQL + Redis)
- CI/CD pipeline setup
Phase 2 - Identity & Permissions (2-3 weeks)
- User, Role, Organization, Department, Position CRUD
- RBAC + ABAC permission model
- JWT auth (access + refresh tokens, token revocation)
- httpOnly cookie for web JWT storage
- Multi-tenant middleware
- Login page UI + user management pages
Phase 3 - System Configuration (1-2 weeks)
- Data dictionaries
- Dynamic menus
- System parameters (hierarchical override)
- Numbering rules (concurrency-safe PostgreSQL sequences)
- i18n framework
- Settings pages UI
Phase 4 - Workflow Engine (4-6 weeks)
- Process definition storage and versioning
- BPMN subset parser (start/end, user/service tasks, exclusive/parallel gateways)
- Execution engine with token tracking
- Task assignment, countersign, delegation
- Condition expression evaluator
- React visual flowchart designer
- Process diagram viewer (highlighted current node)
- Reminder and timeout handling
Phase 5 - Message Center (2 weeks)
- Message templates with variable interpolation
- In-app notification CRUD
- WebSocket real-time push (auth, reconnect)
- Notification panel UI
- Message aggregation and read tracking
Phase 6 - Integration & Polish (2-3 weeks)
- Cross-module integration testing
- Audit logging verification
- Web app deployment and optimization
- Performance optimization
- Documentation
Verification Plan
- Unit tests: Each module has comprehensive unit tests (80%+ coverage target)
- Integration tests: API endpoint tests against real PostgreSQL/Redis
- E2E tests: Desktop client test automation via Tauri WebDriver
- Multi-tenant tests: Verify data isolation between tenants
- Workflow tests: Full process lifecycle (define -> start -> approve -> complete)
- Performance benchmarks: API response time < 100ms (p99), WebSocket push < 50ms
- Security audit: OWASP top 10 check before release