Files
erp/crates/erp-core/src/module.rs
iven 14f431efff feat: systematic functional audit — fix 18 issues across Phase A/B
Phase A (P1 production blockers):
- A1: Apply IP rate limiting to public routes (login/refresh)
- A2: Publish domain events for workflow instance state transitions
  (completed/suspended/resumed/terminated) via outbox pattern
- A3: Replace hardcoded nil UUID default tenant with dynamic DB lookup
- A4: Add GET /api/v1/audit-logs query endpoint with pagination
- A5: Enhance CORS wildcard warning for production environments

Phase B (P2 functional gaps):
- B1: Remove dead erp-common crate (zero references in codebase)
- B2: Refactor 5 settings pages to use typed API modules instead of
  direct client calls; create api/themes.ts; delete dead errors.ts
- B3: Add resume/suspend buttons to InstanceMonitor page
- B4: Remove unused EventHandler trait from erp-core
- B5: Handle task.completed events in message module (send notifications)
- B6: Wire TimeoutChecker as 60s background task
- B7: Auto-skip ServiceTask nodes instead of crashing the process
- B8: Remove empty register_routes() from ErpModule trait and modules
2026-04-12 15:22:28 +08:00

77 lines
2.0 KiB
Rust
Raw 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.

use std::any::Any;
use std::sync::Arc;
use uuid::Uuid;
use crate::error::AppResult;
use crate::events::EventBus;
/// 模块注册接口
/// 所有业务模块Auth, Workflow, Message, Config, 行业模块)都实现此 trait
#[async_trait::async_trait]
pub trait ErpModule: Send + Sync {
/// 模块名称(唯一标识)
fn name(&self) -> &str;
/// 模块版本
fn version(&self) -> &str {
env!("CARGO_PKG_VERSION")
}
/// 依赖的其他模块名称
fn dependencies(&self) -> Vec<&str> {
vec![]
}
/// 注册事件处理器
fn register_event_handlers(&self, _bus: &EventBus) {}
/// 租户创建时的初始化钩子
async fn on_tenant_created(&self, _tenant_id: Uuid) -> AppResult<()> {
Ok(())
}
/// 租户删除时的清理钩子
async fn on_tenant_deleted(&self, _tenant_id: Uuid) -> AppResult<()> {
Ok(())
}
/// Downcast support: return `self` as `&dyn Any` for concrete type access.
///
/// This allows the server crate to retrieve module-specific methods
/// (e.g. `AuthModule::public_routes()`) that are not part of the trait.
fn as_any(&self) -> &dyn Any;
}
/// 模块注册器 — 用 Arc 包装使其可 Clone用于 Axum State
#[derive(Clone, Default)]
pub struct ModuleRegistry {
modules: Arc<Vec<Arc<dyn ErpModule>>>,
}
impl ModuleRegistry {
pub fn new() -> Self {
Self {
modules: Arc::new(vec![]),
}
}
pub fn register(mut self, module: impl ErpModule + 'static) -> Self {
tracing::info!(module = module.name(), version = module.version(), "Module registered");
let mut modules = (*self.modules).clone();
modules.push(Arc::new(module));
self.modules = Arc::new(modules);
self
}
pub fn register_handlers(&self, bus: &EventBus) {
for module in self.modules.iter() {
module.register_event_handlers(bus);
}
}
pub fn modules(&self) -> &[Arc<dyn ErpModule>] {
&self.modules
}
}