A complete React + TypeScript application demonstrating Domain-Driven Design (DDD) principles with Domain Events, built with a clean architecture.
This application demonstrates advanced DDD concepts:
- โ Value Objects - Encapsulated business rules (TaskId, TaskTitle, TaskPriority, etc.)
- โ Entities - Rich domain models with business logic (Task entity)
- โ Domain Events - Decoupled side effects (TaskCompleted, TaskAssigned, TaskPriorityEscalated)
- โ Domain Services - Multi-entity operations (TaskDependencyService)
- โ Repositories - Data persistence abstraction
- โ Use Cases - Application layer orchestration
- โ Event-Driven Architecture - Publisher/Subscriber pattern
- โ Dependency Injection - Service container pattern
- โ Clean Architecture - Layered separation of concerns
src/
โโโ domain/ # Business logic (Framework-independent)
โ โโโ entities/
โ โ โโโ Task.ts # Rich domain entity with business rules
โ โโโ valueObjects/ # Immutable value objects
โ โ โโโ TaskId.ts
โ โ โโโ TaskTitle.ts
โ โ โโโ TaskStatus.ts
โ โ โโโ TaskPriority.ts
โ โ โโโ TaskAssignment.ts
โ โ โโโ TaskDependency.ts
โ โ โโโ UserId.ts
โ โโโ events/ # Domain events
โ โ โโโ DomainEvent.ts
โ โ โโโ TaskCompletedEvent.ts
โ โ โโโ TaskAssignedEvent.ts
โ โ โโโ TaskPriorityEscalatedEvent.ts
โ โโโ services/ # Domain services
โ โ โโโ TaskDependencyService.ts
โ โโโ repositories/ # Repository interfaces
โ โโโ ITaskRepository.ts
โ
โโโ application/ # Application logic
โ โโโ useCases/ # Business use cases
โ โ โโโ CreateTaskUseCase.ts
โ โ โโโ AssignTaskUseCase.ts
โ โ โโโ CompleteTaskUseCase.ts
โ โ โโโ GetAllTasksUseCase.ts
โ โโโ services/ # Application services
โ โ โโโ DomainEventPublisher.ts
โ โโโ eventHandlers/ # Event handlers (side effects)
โ โโโ TaskCompletedEventHandler.ts
โ โโโ TaskAssignedEventHandler.ts
โ โโโ TaskPriorityEscalatedEventHandler.ts
โ
โโโ infrastructure/ # External concerns
โ โโโ repositories/
โ โ โโโ LocalStorageTaskRepository.ts
โ โโโ events/
โ โ โโโ EventPublisherFactory.ts
โ โโโ di/
โ โโโ ServiceContainer.ts
โ
โโโ presentation/ # UI layer
โโโ components/
โ โโโ TaskManagementApp.tsx
โโโ hooks/
โโโ useTaskManagement.ts
- Node.js 18+
- npm or yarn
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run buildThe application will be available at http://localhost:5173
- Task titles are validated (1-200 characters)
- Priority levels: Low, Medium, High, Critical
- Domain events are automatically triggered
- Assign tasks to users
- Only assigned users can complete tasks
- Assignment events trigger notifications
- Complete tasks and see completion events
- Completed tasks cannot be modified
- Completion triggers multiple event handlers
- Real-time event log in the sidebar
- See all domain events as they occur
- Console shows detailed event information
- Tasks must be assigned before starting
- Completed tasks cannot be reassigned
- Dependency management prevents circular dependencies
- Priority auto-escalation based on age
// TaskTitle enforces business rules
const title = TaskTitle.create("My Task"); // โ
Valid
const invalid = TaskTitle.create(""); // โ Throws error// Business logic lives in the domain
task.assignTo(userId, assignedBy);
task.complete(userId);
task.checkAndEscalatePriority();// Events are created in domain logic
task.complete(userId); // Creates TaskCompletedEvent
// Event handlers respond independently
TaskCompletedEventHandler โ Send notifications
TaskCompletedEventHandler โ Update analytics// Easy to swap implementations
const repository = new LocalStorageTaskRepository();
// Could easily become: new ApiTaskRepository()Code uses business terms: Task, Assignment, Priority, Dependencies
Task Management is a complete bounded context
Task is an aggregate root managing its own consistency
Business events trigger cross-cutting concerns
Immutable, validated objects with business meaning
Objects with identity and lifecycle
Operations spanning multiple entities
The domain layer is completely framework-independent and easily testable:
describe('Task', () => {
it('should not allow completing a task twice', () => {
const task = Task.create(TaskTitle.create('Test'));
const userId = UserId.create('user-1');
task.complete(userId);
expect(() => task.complete(userId))
.toThrow('Task is already completed');
});
});yarn test:coverage: Runs the test suite and generates a coverage report.
The test coverage report is automatically generated and published to GitHub Pages on every push to the main branch.
This application demonstrates patterns from:
- Eric Evans' "Domain-Driven Design"
- Vaughn Vernon's "Implementing Domain-Driven Design"
- Martin Fowler's "Patterns of Enterprise Application Architecture"
To extend this application:
- Add More Domain Logic: Task dependencies, subtasks, time tracking
- Implement API Repository: Replace localStorage with REST API
- Add Authentication: Real user management
- Create More Events: TaskStarted, TaskBlocked, etc.
- Add Specifications: Complex query patterns
- Implement CQRS: Separate read and write models
This is a demonstration project for learning DDD principles. Feel free to:
- Fork and experiment
- Add new features following DDD patterns
- Share improvements
MIT
Built with โค๏ธ to demonstrate Domain-Driven Design in React + TypeScript