30 minlesson

Capstone Project: Complete Logistics System

Capstone Project: Complete Logistics System

Welcome to your capstone project! You'll build a complete order processing system that integrates all the design patterns you've learned throughout this course.

Project Overview

You're building a production-ready logistics order processing system for an e-commerce platform. The system handles the complete workflow from order placement to shipment tracking:

  1. Order receipt and validation
  2. Address validation through multiple checks
  3. Shipping rate calculation from multiple carriers
  4. Optimal carrier selection
  5. Label generation
  6. Order state management
  7. Real-time tracking notifications

Business Requirements

Core Workflow

1Order Created
2
3Address Validation (Chain of validators)
4
5Rate Calculation (Multiple strategies)
6
7Carrier Selection (Factory-based)
8
9Shipping Options (Decorators for insurance, signature, etc.)
10
11Label Generation
12
13Order State Transitions (Pending → Processing → Shipped → Delivered)
14
15Tracking Notifications (Observer pattern)

Functional Requirements

FR1: Address Validation

  • Validate address format (required fields)
  • Verify postal code format by country
  • Check address against geocoding service
  • Identify undeliverable addresses
  • Accumulate all validation errors

FR2: Rate Calculation

  • Calculate rates based on package weight and dimensions
  • Support multiple pricing strategies:
    • Standard rates (weight-based tiers)
    • Zone-based pricing (distance calculations)
    • Volumetric weight pricing (dimensional weight)
  • Compare rates across carriers
  • Apply business rules (minimum charges, surcharges)

FR3: Carrier Selection

  • Create carrier-specific shipping services
  • Support USPS, FedEx, UPS, DHL
  • Generate carrier-specific labels
  • Handle carrier-specific requirements

FR4: Shipping Options

  • Add insurance (based on declared value)
  • Require signature confirmation
  • Enable Saturday delivery
  • Add tracking notifications
  • Support combinations of options

FR5: Order State Management

  • Track order through lifecycle states
  • Enforce valid state transitions
  • Trigger actions on state changes
  • Maintain state history

FR6: Tracking Notifications

  • Notify subscribers of tracking updates
  • Support multiple notification channels (email, SMS, webhook)
  • Batch notifications efficiently
  • Handle notification failures gracefully

FR7: Unified Interface

  • Provide simple facade for complex operations
  • Hide subsystem complexity from clients
  • Coordinate between multiple subsystems
  • Handle errors consistently

Non-Functional Requirements

NFR1: Extensibility

  • Easy to add new carriers
  • Easy to add new validation rules
  • Easy to add new pricing strategies
  • Easy to add new shipping options

NFR2: Testability

  • All components independently testable
  • Mock external services (geocoding, carrier APIs)
  • Integration tests for complete workflow

NFR3: Type Safety

  • Strong TypeScript typing throughout
  • No any types
  • Compile-time validation of contracts

NFR4: Performance

  • Efficient rate comparison (parallel calculations)
  • Caching for repeated lookups
  • Minimize object creation overhead

Design Patterns to Apply

You'll integrate 7 different design patterns in this project:

1. Chain of Responsibility - Address Validation

typescript
1// Multiple validators in a chain
2FormatValidator → PostalCodeValidator → GeocodingValidator → DeliverabilityValidator

Why this pattern:

  • Each validator handles one concern
  • Easy to add/remove validators
  • Validators can be reordered
  • All validators run (accumulate errors)

2. Strategy Pattern - Rate Calculation

typescript
1interface RateCalculationStrategy {
2 calculateRate(shipment: ShipmentDetails): Money;
3}
4
5class StandardRateStrategy implements RateCalculationStrategy { }
6class ZoneBasedRateStrategy implements RateCalculationStrategy { }
7class VolumetricRateStrategy implements RateCalculationStrategy { }

Why this pattern:

  • Different carriers use different pricing models
  • Strategies can be swapped at runtime
  • Easy to test each strategy independently
  • Business logic encapsulated

3. Factory Method - Carrier Creation

typescript
1abstract class CarrierFactory {
2 abstract createShippingService(): ShippingService;
3 abstract createLabelGenerator(): LabelGenerator;
4}
5
6class USPSFactory extends CarrierFactory { }
7class FedExFactory extends CarrierFactory { }

Why this pattern:

  • Each carrier has specific requirements
  • Factory encapsulates carrier complexity
  • Easy to add new carriers
  • Consistent interface across carriers

4. Decorator Pattern - Shipping Options

typescript
1interface Shipment {
2 getCost(): Money;
3 getDescription(): string;
4}
5
6class BaseShipment implements Shipment { }
7class InsuranceDecorator extends BaseShipment { }
8class SignatureDecorator extends BaseShipment { }
9class SaturdayDeliveryDecorator extends BaseShipment { }

Why this pattern:

  • Options can be combined flexibly
  • New options added without modifying base
  • Each decorator has single responsibility
  • Cost calculation composes naturally

5. State Pattern - Order Lifecycle

typescript
1interface OrderState {
2 process(context: OrderContext): void;
3 cancel(context: OrderContext): void;
4 ship(context: OrderContext): void;
5}
6
7class PendingState implements OrderState { }
8class ProcessingState implements OrderState { }
9class ShippedState implements OrderState { }
10class DeliveredState implements OrderState { }
11class CancelledState implements OrderState { }

Why this pattern:

  • Complex state transitions
  • State-specific behavior
  • Prevents invalid state changes
  • Clear state machine representation

6. Observer Pattern - Tracking Notifications

typescript
1interface TrackingObserver {
2 update(event: TrackingEvent): void;
3}
4
5class EmailNotifier implements TrackingObserver { }
6class SMSNotifier implements TrackingObserver { }
7class WebhookNotifier implements TrackingObserver { }
8
9class TrackingSubject {
10 private observers: TrackingObserver[] = [];
11 notify(event: TrackingEvent): void { }
12}

Why this pattern:

  • Multiple subscribers to tracking events
  • Loose coupling between event source and handlers
  • Easy to add new notification types
  • Subscribers independently manage their logic

7. Facade Pattern - Unified Interface

typescript
1class ShippingFacade {
2 constructor(
3 private addressValidator: ValidationChain,
4 private rateCalculator: RateService,
5 private carrierFactory: CarrierFactoryRegistry,
6 private orderStateMachine: OrderStateManager,
7 private trackingNotifier: TrackingNotifier
8 ) {}
9
10 async processOrder(order: Order): Promise<ShipmentResult> {
11 // Coordinates all subsystems
12 }
13}

Why this pattern:

  • Simplifies complex subsystem interactions
  • Provides high-level API for clients
  • Reduces coupling to subsystems
  • Easier to understand and use

System Architecture

Domain Model

typescript
1// Core entities
2interface Order {
3 id: string;
4 customerId: string;
5 items: OrderItem[];
6 shippingAddress: Address;
7 billingAddress: Address;
8 createdAt: Date;
9}
10
11interface OrderItem {
12 productId: string;
13 quantity: number;
14 weight: Weight;
15 dimensions: Dimensions;
16 declaredValue: Money;
17}
18
19interface Address {
20 street: string;
21 street2?: string;
22 city: string;
23 state: string;
24 postalCode: string;
25 country: string;
26}
27
28interface ShipmentDetails {
29 totalWeight: Weight;
30 dimensions: Dimensions;
31 origin: Address;
32 destination: Address;
33 declaredValue: Money;
34}
35
36interface ShippingRate {
37 carrier: string;
38 service: string;
39 cost: Money;
40 estimatedDays: number;
41 features: string[];
42}
43
44interface TrackingEvent {
45 orderId: string;
46 trackingNumber: string;
47 status: string;
48 location: string;
49 timestamp: Date;
50 description: string;
51}

Value Objects

typescript
1class Money {
2 constructor(
3 public readonly amount: number,
4 public readonly currency: string = 'USD'
5 ) {}
6
7 add(other: Money): Money { }
8 multiply(factor: number): Money { }
9 toString(): string { }
10}
11
12class Weight {
13 constructor(
14 public readonly value: number,
15 public readonly unit: 'lb' | 'kg' | 'oz'
16 ) {}
17
18 toLbs(): number { }
19 toKg(): number { }
20}
21
22class Dimensions {
23 constructor(
24 public readonly length: number,
25 public readonly width: number,
26 public readonly height: number,
27 public readonly unit: 'in' | 'cm'
28 ) {}
29
30 getVolume(): number { }
31 getVolumetricWeight(): Weight { }
32}

Integration Points

How Patterns Work Together

typescript
1// Client code using the facade
2const facade = new ShippingFacade(
3 new ValidationChainBuilder()
4 .add(new FormatValidator())
5 .add(new PostalCodeValidator())
6 .add(new GeocodingValidator())
7 .build(),
8 new RateService([
9 new StandardRateStrategy(),
10 new ZoneBasedRateStrategy()
11 ]),
12 CarrierFactoryRegistry.getInstance(),
13 new OrderStateManager(),
14 new TrackingNotifier()
15);
16
17// Process an order
18const result = await facade.processOrder(order);
19
20// Facade internally:
21// 1. Validates address (Chain of Responsibility)
22// 2. Calculates rates (Strategy)
23// 3. Selects carrier (Factory)
24// 4. Applies options (Decorator)
25// 5. Transitions state (State)
26// 6. Sends notifications (Observer)

Success Criteria

Your implementation must:

  1. Pass all unit tests (each pattern tested independently)
  2. Pass integration tests (complete workflow)
  3. Demonstrate proper pattern usage (no pattern misuse)
  4. Use TypeScript types effectively (no any)
  5. Handle edge cases (empty orders, invalid addresses, etc.)
  6. Be extensible (easy to add new validators, strategies, carriers)

What You'll Build

In the upcoming workshop, you'll implement:

  • 8 classes for address validation chain
  • 4 strategies for rate calculation
  • 4 carrier factories with their services
  • 5 decorators for shipping options
  • 5 state classes for order lifecycle
  • 4 observer implementations for notifications
  • 1 facade to coordinate everything
  • Complete integration tests for the workflow

Time Estimate

  • Reading requirements: 30 minutes (this lesson)
  • Architecture review: 20 minutes (next lesson)
  • Implementation guide: 20 minutes
  • Workshop implementation: 90 minutes
  • Quiz: 10 minutes
  • Total: ~3 hours

Next Steps

In the next lesson, we'll dive deep into the architecture design, showing you:

  • Detailed class diagrams
  • Interface definitions
  • Data flow through the system
  • Extension points for future features

Then you'll get a step-by-step implementation guide before tackling the complete workshop.

Ready to build a production-quality system? Let's go!