Clean Architecture Guide
This repository follows Clean Architecture principles as defined by Robert C. Martin (Uncle Bob).This is a comprehensive guide to the architectural decisions and patterns used throughout the Send v5 codebase.
Core Principles
1. The Dependency Rule
Dependencies point inward toward business logic:2. Screaming Architecture
The folder structure reveals what the application does, not what frameworks it uses:- ❌
/controllers,/models,/views(framework-centric) - ✅
/games/wheel/wheel-core/entities(domain-centric)
Repository Structure
Clean Architecture Layers
Layer 1: Entities (Domain)
Location:games/wheel/wheel-core/src/entities/, api/wheel/src/domain/
Purpose: Core business rules and domain logic
Rules:
- ✅ Pure business logic
- ✅ Zero external dependencies
- ✅ Framework-agnostic
- ❌ No database imports
- ❌ No UI imports
- ❌ No HTTP imports
Profile.create() validates business rules (name, version format, config hash)
Layer 2: Use Cases (Application Business Rules)
Location:games/wheel/wheel-core/src/use-cases/, api/wheel/src/use_cases/
Purpose: Application-specific business logic
Rules:
- ✅ Orchestrates entities
- ✅ Depends on repository interfaces (not implementations)
- ✅ Contains workflow logic
- ❌ No framework dependencies
- ❌ No database implementation details
CreateProfileUseCase orchestrates profile creation, hashes config, saves to repository
Layer 3: Interface Adapters
Location:- Controllers:
games/wheel/wheel-dashboard/src/app/,api/wheel/src/adapters/ - Repositories:
games/wheel/wheel-infrastructure/src/repositories/
- ✅ Implements repository interfaces from domain
- ✅ Converts HTTP/UI data to domain entities
- ✅ Converts domain entities to HTTP/UI responses
- ❌ No business logic (delegates to use cases)
NileProfileRepository implements IProfileRepository interface
Layer 4: Frameworks & Drivers (Infrastructure)
Location:wheel-infrastructure/src/nile-client.ts, Next.js framework, Axum framework
Purpose: External tools and frameworks
Rules:
- ✅ Database connections
- ✅ Web frameworks
- ✅ UI libraries
- ✅ External APIs
- ❌ No business logic
Testing Strategy
1. Unit Tests (Entities)
Location:wheel-core/src/entities/*.test.ts
Test pure business logic:
- Profile name validation
- Version format validation
- Config hash validation
- Instance state transitions
- Link slug generation
2. Use Case Tests
Location:wheel-core/src/use-cases/*.test.ts
Test application workflows with mocked repositories.
3. Integration Tests
Location:wheel-infrastructure/src/repositories/*.test.ts
Test repository implementations with test database.
4. E2E Tests
Location:wheel-dashboard/e2e/, wheel-instances/e2e/
Test full user workflows.
Adding New Features
Example: Add “Spin History” Feature
Step 1: Domain Layer (wheel-core)
Step 2: Infrastructure Layer (wheel-infrastructure)
Step 3: UI Layer (wheel-dashboard)
Key: Business logic stays in
wheel-core, UI just displays it.Code Review Checklist
Before committing, verify:- No business logic in UI components
- No database imports in
wheel-core - Use cases depend on interfaces, not implementations
- Entities have zero framework dependencies
- Repository implementations live in
wheel-infrastructure - Controllers convert data, don’t contain logic
- All dependencies point inward
Learn More
- Clean Architecture Book: Robert C. Martin
- Domain-Driven Design: Eric Evans
- SOLID Principles: Uncle Bob’s blog
