A pure event-driven graph library where events are the only source of truth. CIM Graph provides specialized graph types for different domains, all built on event sourcing principles with IPLD storage and NATS JetStream persistence.
CIM Graph is now purely event-driven. All state changes MUST go through events. Direct mutations are no longer supported.
See EVENT_DRIVEN_ARCHITECTURE.md for the complete guide.
CIM Graph implements a complete event-sourcing architecture where:
- Events are the ONLY way to change state - No direct mutations
- Projections are ephemeral read models - Rebuilt from events
- IPLD provides content-addressed storage - Every event payload gets a CID
- NATS JetStream handles persistence - Durable event streams
- State machines enforce transitions - Business rules validation
- Policies automate behaviors - CID generation, validation, etc.
- 🎯 Pure Event Sourcing: Complete audit trail with correlation/causation tracking
- 🔒 Immutable by Design: Events are append-only, projections are read-only
- 🌐 Content Addressed: All event payloads stored in IPLD with CIDs
- 📡 NATS Integration: Stream events with JetStream persistence
- 🏗️ Domain-Driven Design: Clear bounded contexts with defined relationships
- 🔄 State Machines: Enforce valid transitions and business rules
- 🤖 Automated Policies: React to events with configurable behaviors
- 📊 Rich Projections: Query current state through type-safe projections
- ✅ Complete Documentation: All public APIs now have comprehensive documentation
- ✅ Debug Implementations: All types now implement Debug for better debugging experience
- ✅ Zero Warnings: Codebase compiles cleanly with all features enabled
- ✅ Working Examples: All 9 examples are fully functional and demonstrate best practices
- ✅ Better Error Messages: Improved error handling and messages throughout
- ✅ Test Coverage: 49 passing tests covering core functionality
Add this to your Cargo.toml:
[dependencies]
cim-graph = "0.1.1"
# Optional features
cim-graph = { version = "0.1.1", features = ["nats", "async"] }use cim_graph::{
events::{GraphEvent, EventPayload, WorkflowPayload},
core::{ProjectionEngine, GraphProjection},
graphs::{WorkflowNode, WorkflowEdge},
};
use uuid::Uuid;
// Create events to build a workflow
let workflow_id = Uuid::new_v4();
let events = vec![
GraphEvent {
event_id: Uuid::new_v4(),
aggregate_id: workflow_id,
correlation_id: Uuid::new_v4(),
causation_id: None,
payload: EventPayload::Workflow(WorkflowPayload::WorkflowDefined {
workflow_id,
name: "Order Processing".to_string(),
version: "1.0.0".to_string(),
}),
},
GraphEvent {
event_id: Uuid::new_v4(),
aggregate_id: workflow_id,
correlation_id: Uuid::new_v4(),
causation_id: None,
payload: EventPayload::Workflow(WorkflowPayload::StateAdded {
workflow_id,
state_id: "submitted".to_string(),
state_type: "initial".to_string(),
}),
},
];
// Build projection from events
let engine = ProjectionEngine::<WorkflowNode, WorkflowEdge>::new();
let projection = engine.project(events);
// Query the projection (read-only)
println!("Nodes: {}", projection.node_count());
println!("Version: {}", projection.version());CIM Graph is organized into 5 bounded contexts:
Content-addressed storage for all data. Every event payload gets a CID.
Data schemas, transformations, and bounded context definitions.
State machines, business processes, and workflow orchestration.
Domain knowledge, semantic reasoning, and ontologies.
Multi-graph orchestration and cross-domain queries.
Command → State Machine → Event → IPLD → NATS → Projection
↓
Policies
↓
Additional Events
Projections are read-only views computed from events:
use cim_graph::core::{ProjectionEngine, GraphProjection};
use cim_graph::graphs::{ConceptNode, ConceptEdge};
// Build projection from events
let engine = ProjectionEngine::<ConceptNode, ConceptEdge>::new();
let projection = engine.project(concept_events);
// Query methods (all read-only)
let node_count = projection.node_count();
let has_node = projection.has_node("customer");
let has_edge = projection.has_edge("order", "customer");Validate commands and enforce business rules:
use cim_graph::core::{GraphStateMachine, GraphCommand};
let mut state_machine = GraphStateMachine::new();
// Commands are validated before creating events
let command = GraphCommand::CreateGraph {
aggregate_id: Uuid::new_v4(),
graph_type: "workflow".to_string(),
metadata: HashMap::new(),
};
let events = state_machine.handle_command(command, &projection)?;Automate behaviors in response to events:
use cim_graph::core::{PolicyEngine, CidGenerationPolicy, StateValidationPolicy};
let mut policy_engine = PolicyEngine::new();
policy_engine.add_policy(Box::new(CidGenerationPolicy));
policy_engine.add_policy(Box::new(StateValidationPolicy));
// Policies can generate additional events
let actions = policy_engine.evaluate(&event, &mut context)?;Persist and stream events:
#[cfg(feature = "nats")]
use cim_graph::nats::JetStreamEventStore;
// Connect to NATS
let store = JetStreamEventStore::new("nats://localhost:4222").await?;
// Publish events with subject hierarchy
store.publish_events(&events).await?;
// Subscribe using subject patterns
let subscription = store.subscribe("cim.graph.workflow.*").await?;All examples are now fully functional and demonstrate different aspects of the event-driven architecture:
- Basic Event-Driven - Introduction to event-driven concepts
- Complete Event-Driven Demo - Comprehensive demonstration of all features
- Workflow Event-Driven - Workflow patterns with state machines
- Order Processing System - Real-world e-commerce example
- NATS Integration - JetStream persistence (requires
--features nats) - Simple Workflow - Core event-driven concepts with CimGraphEvent
- Event-Driven Simple - High-level event API demonstration
- Pure Event-Driven - Pure event patterns
- Collaborative Graph - Collaborative operations
See EXAMPLES.md for details on running the examples.
- Event-Driven Architecture Guide - Complete guide to the new architecture
- Event Design Best Practices - How to design events properly
- API Documentation - Full API reference
- Bounded Contexts - Domain boundaries and relationships
- Migration Guide - Migrating from the old mutable API
The old mutable API (graph.add_node(), graph.add_edge(), etc.) is no longer supported. See the Migration Guide for step-by-step instructions on updating your code to the event-driven architecture.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.