feat(workflow): add workflow engine module (Phase 4)
Implement complete workflow engine with BPMN subset support: Backend (erp-workflow crate): - Token-driven execution engine with exclusive/parallel gateway support - BPMN parser with flow graph validation - Expression evaluator for conditional branching - Process definition CRUD with draft/publish lifecycle - Process instance management (start, suspend, terminate) - Task service (pending, complete, delegate) - PostgreSQL advisory locks for concurrent safety - 5 database tables: process_definitions, process_instances, tokens, tasks, process_variables - 13 API endpoints with RBAC protection - Timeout checker framework (placeholder) Frontend: - Workflow page with 4 tabs (definitions, pending, completed, monitor) - React Flow visual process designer (@xyflow/react) - Process viewer with active node highlighting - 3 API client modules for workflow endpoints - Sidebar menu integration
This commit is contained in:
121
crates/erp-workflow/src/module.rs
Normal file
121
crates/erp-workflow/src/module.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
use axum::Router;
|
||||
use axum::routing::{get, post};
|
||||
use uuid::Uuid;
|
||||
|
||||
use erp_core::error::AppResult;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::module::ErpModule;
|
||||
|
||||
use crate::handler::{
|
||||
definition_handler, instance_handler, task_handler,
|
||||
};
|
||||
|
||||
/// Workflow module implementing the `ErpModule` trait.
|
||||
///
|
||||
/// Manages workflow definitions, process instances, tasks,
|
||||
/// and the token-driven execution engine.
|
||||
pub struct WorkflowModule;
|
||||
|
||||
impl WorkflowModule {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
/// Build protected (authenticated) routes for the workflow module.
|
||||
pub fn protected_routes<S>() -> Router<S>
|
||||
where
|
||||
crate::workflow_state::WorkflowState: axum::extract::FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
Router::new()
|
||||
// Definition routes
|
||||
.route(
|
||||
"/workflow/definitions",
|
||||
get(definition_handler::list_definitions)
|
||||
.post(definition_handler::create_definition),
|
||||
)
|
||||
.route(
|
||||
"/workflow/definitions/{id}",
|
||||
get(definition_handler::get_definition)
|
||||
.put(definition_handler::update_definition),
|
||||
)
|
||||
.route(
|
||||
"/workflow/definitions/{id}/publish",
|
||||
post(definition_handler::publish_definition),
|
||||
)
|
||||
// Instance routes
|
||||
.route(
|
||||
"/workflow/instances",
|
||||
post(instance_handler::start_instance)
|
||||
.get(instance_handler::list_instances),
|
||||
)
|
||||
.route(
|
||||
"/workflow/instances/{id}",
|
||||
get(instance_handler::get_instance),
|
||||
)
|
||||
.route(
|
||||
"/workflow/instances/{id}/suspend",
|
||||
post(instance_handler::suspend_instance),
|
||||
)
|
||||
.route(
|
||||
"/workflow/instances/{id}/terminate",
|
||||
post(instance_handler::terminate_instance),
|
||||
)
|
||||
// Task routes
|
||||
.route(
|
||||
"/workflow/tasks/pending",
|
||||
get(task_handler::list_pending_tasks),
|
||||
)
|
||||
.route(
|
||||
"/workflow/tasks/completed",
|
||||
get(task_handler::list_completed_tasks),
|
||||
)
|
||||
.route(
|
||||
"/workflow/tasks/{id}/complete",
|
||||
post(task_handler::complete_task),
|
||||
)
|
||||
.route(
|
||||
"/workflow/tasks/{id}/delegate",
|
||||
post(task_handler::delegate_task),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for WorkflowModule {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ErpModule for WorkflowModule {
|
||||
fn name(&self) -> &str {
|
||||
"workflow"
|
||||
}
|
||||
|
||||
fn version(&self) -> &str {
|
||||
env!("CARGO_PKG_VERSION")
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<&str> {
|
||||
vec!["auth"]
|
||||
}
|
||||
|
||||
fn register_routes(&self, router: Router) -> Router {
|
||||
router
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user