| title | Clean Architecture Guide | ||
|---|---|---|---|
| status | CURRENT | ||
| last_updated | 2026-02-02 | ||
| version | 1.0 | ||
| related |
|
This guide documents the Clean Architecture pattern applied to the AllSource event store, covering implementation in Rust, Go, and (planned) Clojure.
Pure business logic with zero external dependencies.
Rust Example (services/core/src/domain/):
// domain/entities/event.rs
pub struct Event {
pub id: Uuid,
pub event_type: String,
pub entity_id: String,
pub tenant_id: String,
pub payload: serde_json::Value,
pub timestamp: DateTime<Utc>,
pub metadata: Option<serde_json::Value>,
pub version: i64,
}
impl Event {
pub fn new(event_type: String, entity_id: String, payload: serde_json::Value) -> Self {
// Direct construction for performance
}
pub fn new_validated(...) -> Result<Self> {
// With validation for use cases
}
// Domain behavior
pub fn belongs_to_tenant(&self, tenant_id: &str) -> bool {
self.tenant_id == tenant_id
}
}Use cases that orchestrate domain logic.
Rust Example (services/core/src/application/):
// application/use_cases/ingest_event.rs
pub struct IngestEventUseCase {
repository: Arc<dyn EventRepository>,
}
impl IngestEventUseCase {
pub async fn execute(&self, request: IngestEventRequest) -> Result<IngestEventResponse> {
// Create domain event
let event = Event::new(request.event_type, request.entity_id, request.payload);
// Persist via repository
self.repository.save(&event).await?;
// Return response
Ok(IngestEventResponse::from_event(&event))
}
}Concrete implementations of domain abstractions.
Planned (services/core/src/infrastructure/):
// infrastructure/persistence/parquet_repository.rs
pub struct ParquetEventRepository {
storage: Arc<ParquetStorage>,
}
#[async_trait]
impl EventRepository for ParquetEventRepository {
async fn save(&self, event: &Event) -> Result<()> {
// Parquet-specific implementation
}
}External frameworks, databases, web frameworks.
✅ Dependencies point inward only
- Domain ← knows nothing
- Application ← depends on Domain
- Infrastructure ← depends on Application & Domain
- Frameworks ← depends on all layers
- ✅ Domain layer complete
- ✅ Application layer complete
- ⏳ Infrastructure layer (30% - structure created)
- ⏳ Migration of existing code (ongoing)
- ❌ Domain layer (planned)
- ❌ Application layer (planned)
- ❌ Infrastructure layer (planned)
- Testability: Use cases testable with mock repositories (100% coverage)
- Flexibility: Can swap storage backends without changing business logic
- Maintainability: Clear separation of concerns
- Performance: Public fields in domain for zero-cost access
✅ Keep domain pure (no external dependencies) ✅ Define interfaces in domain, implement in infrastructure ✅ Use DTOs at application boundaries ✅ Test use cases with mocks
❌ Import infrastructure code in domain ❌ Put business logic in infrastructure ❌ Skip the application layer ❌ Mix layers
See Phase 1.5 TDD Results for detailed migration approach.
Full implementation guide: See original CLEAN_ARCHITECTURE.md for complete examples in all three languages.