1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Event-sourced workflow engine for durable, long-running processes.
//!
//! Ironflow provides a minimal, type-safe framework for building workflows where:
//!
//! - **Pure functional core** — [`Workflow::evolve`] and [`Workflow::decide`] are
//! deterministic with no side effects
//! - **Event sourcing** — State is reconstructed by replaying events
//! - **Async effects** — Side effects are queued to an outbox for external processing
//!
//! # Architecture
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────────────────┐
//! │ Decider<W, S> │
//! │ │
//! │ 1. Begin unit of work (acquires lock) │
//! │ 2. Replay events → state │
//! │ 3. decide(now, state, input) → events + effects │
//! │ 4. Append events to store │
//! │ 5. Enqueue effects to outbox │
//! │ 6. Commit unit of work │
//! └─────────────────────────────────────────────────────────────────────────┘
//! ```
//!
//! # Example
//!
//! ```ignore
//! use ironflow::{
//! Decision, HasWorkflowId, Never, PgStore, Workflow, WorkflowId,
//! WorkflowRuntime, WorkflowServiceConfig,
//! };
//!
//! struct CounterWorkflow;
//!
//! impl Workflow for CounterWorkflow {
//! type State = i32;
//! type Input = CounterInput;
//! type Event = CounterEvent;
//! type Effect = ();
//! type Rejection = Never;
//!
//! const TYPE: &'static str = "counter";
//!
//! fn evolve(state: Self::State, event: Self::Event) -> Self::State {
//! match event {
//! CounterEvent::Incremented => state + 1,
//! }
//! }
//!
//! fn decide(
//! _now: time::OffsetDateTime,
//! _state: &Self::State,
//! _input: &Self::Input,
//! ) -> Decision<Self::Event, Self::Effect, Self::Input, Self::Rejection> {
//! Decision::accept(CounterEvent::Incremented)
//! }
//! }
//!
//! // Build the service and execute a workflow input.
//! let store = PgStore::new(pool);
//! let service = WorkflowRuntime::builder(store, WorkflowServiceConfig::default())
//! .register_without_effects::<CounterWorkflow>()
//! .build_service()?;
//! service
//! .execute::<CounterWorkflow>(&CounterInput::Increment { id: "counter-1".into() })
//! .await?;
//! ```
//!
//! # Feature Flags
//!
//! - `postgres` — Enables [`PgStore`] for production use with PostgreSQL
//!
//! # Design Documentation
//!
//! See `DESIGN.md` for architectural decisions and future work.
// Allow the crate to reference itself as `ironflow` for macro-generated code
extern crate self as ironflow;
pub use ;
pub use WorkflowEngine;
pub use ;
pub use NonEmpty;
pub use ;
pub use ;
pub use ;
pub use PgStore;
pub use ;
pub use Timer;
pub use ;
pub use ;
// Re-export derive macros
pub use HasWorkflowId;