A Node.js checkout system built with TypeScript following Domain-Driven Design (DDD) and Hexagonal Architecture principles.
- Backend review: the checkout system in
src/ - Frontend review: a separate React/Next-style exercise in
frontend/README.md
The frontend folder is intentionally lightweight and can be used as a PR-style review exercise without running the app.
- Stock Reservation: 15-minute automatic lock on items during checkout
- Dynamic Pricing: Supports coupons (percentage & fixed) and payment method fees
- Shipping Calculation: Region-based shipping costs (EU/USA)
- Payment Methods: PayPal, Bank Transfer, Pay Later (installments)
- Background Jobs: Automatic cleanup of expired reservations
- MongoDB: Persistent storage with Mongoose ODM
The project follows Hexagonal Architecture with clear separation of concerns:
├── domain/ # Core business logic
│ ├── entities/ # Order, Product, OrderItem
│ ├── value-objects/ # Money, Address, PaymentMethod, Coupon
│ ├── services/ # PricingService, ShippingCalculator
│ └── repositories/ # Repository interfaces (ports)
├── application/ # Use cases & DTOs
│ ├── use-cases/ # Business workflows
│ └── dtos/ # Data transfer objects
└── infrastructure/ # External adapters
├── adapters/ # MongoDB repositories
├── api/ # REST controllers & routes
├── jobs/ # Background jobs
└── config/ # Database & seeding
- Node.js 18+
- MongoDB 6+
npm installCreate a .env file (see .env.example):
PORT=3000
MONGODB_URI=mongodb://localhost:27017/checkoutSeed the database with sample products and coupons:
npm run seedThis creates:
- 4 sample products (including D.O.N ISSUE #6 from the UI)
- 4 sample coupons (SAVE10, SAVE20, FLAT15, SUMMER25)
# Development mode (with auto-reload)
npm run dev
# Production mode
npm run build
npm startThe API will be available at http://localhost:3000/api
Start a new checkout session with 15-minute stock reservation.
Request:
{
"customerId": "customer123",
"items": [
{
"productId": "BD23672983",
"quantity": 1
}
],
"address": {
"street": "82 Melora Street",
"city": "Westbridge",
"state": "CA",
"country": "USA",
"postalCode": "92841",
"phone": "+1 (555) 1123-4456"
}
}Response:
{
"orderId": "uuid",
"customerId": "customer123",
"items": [...],
"address": {...},
"status": "RESERVED",
"totals": {
"subtotal": { "amount": 123.38, "currency": "USD" },
"discount": { "amount": 0, "currency": "USD" },
"shippingCost": { "amount": 10, "currency": "USD" },
"paymentFee": { "amount": 0, "currency": "USD" },
"total": { "amount": 133.38, "currency": "USD" }
},
"reservationExpiresAt": "2025-12-05T10:30:00.000Z",
"createdAt": "2025-12-05T10:15:00.000Z"
}Apply a coupon code to the order.
Request:
{
"couponCode": "SAVE10"
}Response: Updated totals with discount applied
Update payment method and recalculate fees.
Request:
{
"type": "PAYPAL",
"installments": null
}For Pay Later:
{
"type": "PAY_LATER",
"installments": 4
}Response: Updated totals with payment fees
Retrieve complete order summary.
Complete the purchase (mark as paid).
Response:
{
"success": true,
"orderId": "uuid",
"message": "Payment processed successfully"
}- EU: $4 for purchases < $100, free otherwise
- USA: $10 for purchases < $150, free otherwise
- Other regions: Not supported
- PayPal: 3.5% fee
- Bank Transfer: No fee
- Pay Later: 2% fee (requires 2+ installments)
- Percentage: Discount as % of subtotal (e.g., 10% off)
- Fixed: Fixed amount off (e.g., $15 off)
- Validates expiration date
- 15-minute automatic lock when checkout initiated
- Background job runs every minute to release expired reservations
- Stock permanently reduced only after payment completion
# Run all tests
npm test
# Watch mode
npm run test:watch
# With coverage
npm run test:coverageTests cover:
- Domain services (pricing, shipping calculations)
- Business logic (coupons, fees, thresholds)
- Edge cases (expired reservations, invalid regions)
# Lint code
npm run lint
# Auto-fix linting issues
npm run lint:fix
# Format code
npm run format
# Check formatting
npm run format:checkKey files:
src/index.ts- Application entry point with dependency injectionsrc/domain/- Core business logic (entities, value objects, services)src/application/- Use cases coordinating domain logicsrc/infrastructure/- External adapters (MongoDB, REST API, jobs)
- Clean Architecture: Dependencies point inward (Infrastructure → Application → Domain)
- Repository Pattern: Domain defines interfaces, infrastructure implements
- Value Objects: Immutable objects like Money, Address enforce business rules
- Aggregate Root: Order entity manages consistency of its items
- Domain Services: Stateless services for complex calculations
ISC