Skip to main content

mako_engine/
lib.rs

1//! `mako-engine` — event-sourced process runtime for German energy market
2//! communication (MaKo).
3//!
4//! # Architecture
5//!
6//! ```text
7//! Raw EDIFACT bytes (AS4 transport)
8//!         │
9//!         ▼
10//! [edi-energy] parse · validate
11//!         │
12//!         ▼  Command (typed, validated)
13//! EngineContext::spawn / ::resume → Process::execute / ::execute_with / ::execute_with_retry
14//!         │
15//!         ├─ load events → reconstruct state (Workflow::apply + upcast)
16//!         ├─ handle command (Workflow::handle — pure, deterministic)
17//!         └─ append EventEnvelope batch (optimistic concurrency)
18//!
19//! EventStore ──► ProjectionRunner ──► Read models
20//! SnapshotStore ──► Process::state_with_snapshot (O(k) replay)
21//! OutboxStore ──► delivery worker ──► AS4 endpoint
22//! DeadlineStore ──► scheduler ──► TimeoutDeadline command
23//! ProcessRegistry ──► inbound message routing ──► Process
24//! ```
25//!
26//! # Quick start
27//!
28//! ```rust,ignore
29//! use mako_engine::{
30//!     builder::EngineBuilder,
31//!     ids::TenantId,
32//!     version::WorkflowId,
33//!     event_store::InMemoryEventStore,
34//! };
35//!
36//! let ctx = EngineBuilder::new()
37//!     .with_event_store(InMemoryEventStore::new())
38//!     .build();
39//!
40//! // Spawn a new process.
41//! let process = ctx.spawn::<MyWorkflow>(TenantId::new(), WorkflowId::new("…", "FV2024-10-01"));
42//! let envelopes = process.execute(my_command).await?;
43//!
44//! // Reconstruct typed state by replaying all events.
45//! let state = process.state().await?;
46//!
47//! // Persist routing information and resume on the next message.
48//! ctx.registry().register(tenant, &conv_id.to_string(), process.identity()).await?;
49//! let identity = ctx.registry().lookup(tenant, &conv_id.to_string()).await?.unwrap();
50//! let resumed  = ctx.resume::<MyWorkflow>(identity);
51//! ```
52//!
53//! # Crate modules
54//!
55//! | Module | Contents |
56//! |--------|----------|
57//! | [`ids`] | Typed identifier newtypes (`EventId`, `StreamId`, `ProcessId`, `ProcessIdentity`, `DeadlineId`, …) |
58//! | [`types`] | Semantic domain identifiers (`MaLo`, `MeLo`, `MarktpartnerCode`, `MessageRef`, `DeviceId`, `BkvId`, `UenbId`, `BillingPeriod`) |
59//! | [`version`] | `FormatVersion`, `WorkflowId`, and `WorkflowVersionPolicy` |
60//! | [`envelope`] | `EventEnvelope` and `NewEvent` |
61//! | [`error`] | `EngineError`, `WorkflowError` |
62//! | [`event_store`] | `EventStore` trait (with `stream_version`) + `InMemoryEventStore` |
63//! | [`workflow`] | `Workflow` trait, `EventPayload`, `CommandContext` |
64//! | [`message_adapter`] | `MessageAdapter` trait, `AdapterRegistry`, `FnAdapter` — cross-FV command translation |
65//! | [`process`] | `Process<W,S>` — ergonomic typed process handle |
66//! | [`projection`] | `Projection` trait + `ProjectionRunner` (single-stream and multi-stream) + `GlobalProjectionCheckpoint` |
67//! | [`snapshot`] | `Snapshot`, `SnapshotStore` + `InMemorySnapshotStore` / `NoopSnapshotStore` |
68//! | [`outbox`] | `OutboxMessage`, `OutboxStore` + `InMemoryOutboxStore` / `NoopOutboxStore` |
69//! | [`inbox`] | `InboxStore` trait + `InMemoryInboxStore` for AS4 retry deduplication |
70//! | [`deadline`] | `Deadline`, `DeadlineStore` + `InMemoryDeadlineStore` / `NoopDeadlineStore` |
71//! | [`registry`] | `ProcessRegistry` + `InMemoryProcessRegistry` / `NoopProcessRegistry` |
72//! | [`pid_router`] | `PidRouter` — maps `Prüfidentifikator` values to workflow names |
73//! | [`fristen`] | Regulatory deadline helpers: `add_hours` (GPKE 24h), `add_werktage` (WiM/GeLi/MABIS) |
74//! | [`dead_letter`] | `DeadLetterSink` trait + `LogDeadLetterSink` / `NoopDeadLetterSink` |
75//! | [`erp`] | `ErpAdapter`, `ErpCommandSource`, `ErpEvent` — ERP/backend integration contract (BO4E) |
76//! | [`builder`] | `EngineModule` trait, `EngineBuilder`, `EngineContext` |
77
78#![deny(unsafe_code)]
79#![deny(missing_docs)]
80#![warn(clippy::pedantic)]
81#![allow(clippy::module_name_repetitions)]
82// BDEW domain terms (MaKo, GPKE, WiM, GeLi) and product names (PostgreSQL,
83// SlateDB) are not code identifiers — suppress doc_markdown for the crate.
84#![allow(clippy::doc_markdown)]
85
86pub mod builder;
87pub mod dead_letter;
88pub mod deadline;
89pub mod envelope;
90pub mod erp;
91pub mod error;
92pub mod event_store;
93pub mod fristen;
94pub mod ids;
95pub mod inbox;
96pub mod marktrolle;
97pub mod message_adapter;
98pub mod metrics;
99pub mod migration;
100pub mod outbox;
101pub mod partner;
102pub mod pid_router;
103pub mod process;
104pub mod profile;
105pub mod projection;
106pub mod registry;
107pub mod snapshot;
108#[cfg(feature = "slatedb")]
109pub mod store_slatedb;
110pub mod types;
111pub mod version;
112pub mod workflow;