A practical implementation of Domain-Driven Design (DDD) principles using JavaScript/Node.js, demonstrating tactical patterns through a healthcare management system.
Rocket Medic is an educational project showcasing how to implement Domain-Driven Design patterns in a real-world healthcare domain. This implementation follows modern software architecture principles with clean separation of concerns.
# Install dependencies
npm install
# Run all tests
npm test
# Run tests with coverage
npm run coverage
# Start the API server
npm start
# Development mode (with auto-reload)
npm run dev
# Visit health check
curl http://localhost:3000/health- Quick Start Guide - Get up and running in minutes
- API Documentation - REST API endpoints and usage
- Project Structure - Code organization and architecture
- What is Domain-Driven Design? - Introduction to DDD
- Domain Concepts - Understanding business domains
- Model Elements - Entities, Value Objects, Services
- Aggregates - Aggregate patterns and boundaries
- Domain Services - Business logic organization
- Hexagonal Architecture - Ports and Adapters
- Layered Architecture - Layer separation
- Anticorruption Layer - Protecting your domain from external systems
- Implementation Summary - Quick reference guide
- Domain Model - Detailed domain structure
- Development Guide - Contributing and best practices
- Q&A - Common questions and answers (PT-BR & EN)
The project follows Hexagonal Architecture (Ports & Adapters) with clear separation:
src/
βββ domain/ # Core business logic (no dependencies)
β βββ entities/ # Domain entities (Patient, Doctor, Appointment)
β β βββ record/ # Medical record entities
β βββ value-objects/ # Immutable value objects (Address, WorkingHours)
β βββ services/ # Domain services (business rules)
β β βββ doctor-service/ # Doctor-specific services
β βββ repositories/ # Repository interfaces
βββ application/ # Use cases and application services
β βββ services/ # Application services
βββ infrastructure/ # External concerns (DB, notifications)
β βββ persistance/ # Repository implementations
β βββ notification/ # Notification services
βββ interfaces/ # Entry points (REST API, controllers)
β βββ controllers/ # HTTP request handlers
β β βββ doctor-controllers/ # Doctor-specific controllers
β βββ routes/ # API route definitions
β βββ main.js # Application bootstrap
βββ testCase/ # Manual test examples
tests/
βββ unit/ # Unit tests
β βββ domain/ # Domain layer tests
β β βββ entities/
β β βββ value-objects/
β β βββ services/
β βββ infrastructure/ # Infrastructure tests
βββ integration/ # Integration tests
β βββ controllers/ # Controller integration tests
β βββ repositories/ # Repository integration tests
β βββ workflows/ # Full workflow tests
βββ domain/ # Domain-focused tests
βββ asyncronous/ # Async pattern tests
βββ TESTING_TOOLS.md # Testing documentation
concepts/ # DDD learning resources
βββ architecture/ # Architecture pattern docs
docs/ # Project documentation
.github/
βββ workflows/ # CI/CD pipelines
βββ ci.yml # GitHub Actions workflow
Patient Aggregate - Manages patient information and medical history
- Patient (root entity)
- Medical Record
- Allergies, Diagnoses, Treatments
- Medications
- Appointments and Examinations
Doctor Aggregate - Manages doctor information and availability
- Doctor (root entity)
- Working Hours
- Specialties (array)
- Availability management
Appointment Aggregate - Manages appointment scheduling
- Appointment (root entity)
- Patient reference
- Doctor reference
- Status tracking
- β Patient management with comprehensive medical records
- β Doctor scheduling and availability tracking
- β Appointment booking with validation
- β Medical examination tracking
- β Diagnosis and medication management
- β Email notifications
- β RESTful API with Express.js
- β Automated testing with 60%+ coverage
- β CI/CD with GitHub Actions
- Runtime: Node.js 20+
- Language: JavaScript (ES6+ modules)
- Web Framework: Express.js 4.18.2
- Architecture: Hexagonal/Clean Architecture with DDD patterns
- Test Runner: Mocha 11.7.5
- Assertions: Chai 6.2.2 (BDD style)
- Test Doubles: Sinon 21.0.1 (stubs, spies, mocks)
- Coverage: c8 10.1.3 (HTML, LCOV, text reporters)
- Linter: ESLint 8.57.0
- Formatter: Prettier 3.1.1
- GitHub Actions: Automated testing and coverage checks
- Coverage Threshold: 50% (lines, functions, branches, statements)
- Start with Quick Start Guide
- Read What is Domain-Driven Design?
- Explore Domain Model
- Run the examples in
src/testCase/
- Study Aggregates patterns
- Understand Hexagonal Architecture
- Review Implementation Summary
- Examine the domain services
- Read Development Guide
- Study repository implementations
- Extend the domain with new features
- Implement additional bounded contexts
# Run all tests
npm test
# Run tests with coverage (60.68% overall)
npm run coverage
# Open HTML coverage report
open coverage/index.html
# Run specific test file
npm test -- tests/integration/workflows/patient-appointment-workflow.test.js- Entities: Patient, Doctor, Appointment (100% covered)
- Value Objects: Address, EmergencyContact, Allergy (100% covered)
- Repositories: Repository pattern with Map storage
- Services: PatientService, DoctorService (32-66% covered)
- Controllers: PatientController integration tests
- Workflows: Full patient appointment workflow test
# Run manual test examples
cd src && node testCase/testHospital.js
# Test API endpoints
npm start &
curl http://localhost:3000/api/patients
curl http://localhost:3000/api/doctorsGitHub Actions automatically runs:
- All tests on every push
- Coverage checks (minimum 50%)
- ESLint validation
- Runs on Node.js 18
# Lint code
npm run lint
# Auto-fix issues
npm run lint:fix
# Format code
npm run format
# Check formatting
npm run format:check
# Run full quality check
npm run lint && npm run format:check && npm test- ESLint: Catches common errors and enforces coding standards
- Prettier: Ensures consistent code formatting
- Mocha + Chai: Comprehensive test coverage
- c8: Istanbul-based code coverage reporting
See Development Guide for:
- Coding standards
- Adding new features
- Domain modeling guidelines
- Testing strategies
This is an educational project for learning Domain-Driven Design principles.
Made with β€οΈ for learning Domain-Driven Design
Entities have unique identity that persists over time:
- Patient - Identified by
idandidentificationDocument - Doctor - Identified by
idandrcm(medical license) - Appointment - Identified by
id - Examination - Identified by
id - MedicalRecord - Internal entity within Patient aggregate
Value Objects are defined by their attributes, not identity:
class Address {
constructor(street, number, city, state, zipCode) {
this.street = street;
this.number = number;
this.city = city;
this.state = state;
this.zipCode = zipCode;
}
equals(otherAddress) {
return (
this.street === otherAddress.street &&
this.number === otherAddress.number &&
this.city === otherAddress.city &&
this.state === otherAddress.state &&
this.zipCode === otherAddress.zipCode
);
}
}class EmergencyContact {
constructor(name, phone) {
this.name = name;
this.phone = phone;
}
equals(otherContact) {
return this.name === otherContact.name && this.phone === otherContact.phone;
}
}class WorkingHours {
constructor() {
this.hours = [];
}
addHours(day, timeSlot) {
this.hours.push({ day, timeSlot });
}
removeHours(day, timeSlot) {
this.hours = this.hours.filter(
(hour) => hour.day !== day || hour.timeSlot !== timeSlot
);
}
listHours() {
return this.hours;
}
}- Node.js 14+ (for ES6 module support)
# Install dependencies
npm install
# Run linting
npm run lint
# Auto-fix formatting issues
npm run lint:fix
# Format all files
npm run format
# Run the test example
cd rocket-medic
node testHospital.jsAllergy Penicillin added to patient John Doe
Appointment on 2024-07-01 scheduled for patient John Doe
Patient {
id: '1',
identificationDocument: '123.123.123-12',
name: 'John Doe',
dateOfBirth: '1990-01-01',
gender: 'Male',
bloodType: 'O+',
address: Address { ... },
phoneNumber: '+1234567890',
email: 'johndoe@example.com',
emergencyContact: EmergencyContact { ... },
allergies: [ Allergy { type: 'Penicillin' } ],
appointments: [ Appointment { ... } ],
examinations: [ ... ],
medicalRecord: MedicalRecord { ... }
}This project uses ESLint and Prettier to enforce code quality and consistent formatting:
- Function parameters on new lines for better readability
- Maximum line length of 80 characters
- 2-space indentation
- Single quotes
- Semicolons required
.eslintrc.json- ESLint configuration.prettierrc.json- Prettier configuration
-
Start with concepts:
- Read Domain-Driven Design Explained
- Understand What is Domain?
-
Learn tactical patterns:
- Study Model Elements
- Deep dive into Aggregates
-
Explore architecture:
- Review Hexagonal Architecture
- Compare with Layered Architecture
-
Study the implementation:
- Examine the
rocket-medic/folder - Run and modify
testHospital.js - Experiment with adding new features
- Examine the
- Patient and Doctor are separate aggregates with clear boundaries
- MedicalRecord is an internal entity, not a separate aggregate
- Aggregates protect business invariants through encapsulation
- Address, EmergencyContact, and WorkingHours have no identity
- Equality is based on attribute values
- Can be freely shared across entities
- Business rules are enforced through aggregate methods
- Direct manipulation of internal state is prevented
- Validation happens at the aggregate boundary
- Each aggregate maintains its own consistency
- References between aggregates should ideally use IDs (simplified in this example)
- One transaction per aggregate
To make this a production-ready system, consider:
- Reference by ID: Change appointments to reference Patient and Doctor by ID
- Domain Events: Implement events for cross-aggregate communication
- Repositories: Add persistence layer with repository pattern
- Application Services: Create application layer for use case orchestration
- Validation: Add comprehensive validation for all value objects
- Testing: Add unit and integration tests
- Error Handling: Implement robust error handling and domain exceptions
- Eric Evans - "Domain-Driven Design: Tackling Complexity in the Heart of Software"
- Vaughn Vernon - "Implementing Domain-Driven Design"
- Martin Fowler - Domain-Driven Design
This is an educational project for demonstrating DDD concepts.

