xpeditis2.0/CLAUDE.md
2025-12-16 14:15:06 +01:00

33 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Xpeditis is a B2B SaaS maritime freight booking and management platform (maritime equivalent of WebCargo). The platform allows freight forwarders to search and compare real-time shipping rates, book containers online, and manage shipments from a centralized dashboard.

Current Status: Phase 4 - Production-ready with security hardening, monitoring, and comprehensive testing infrastructure.

Active Branch: Check git status for current feature branch. Recent features include the Carrier Portal and notifications system.

Repository Structure

This is a monorepo containing both backend and frontend applications:

/Users/david/Documents/xpeditis/dev/xpeditis2.0/
├── apps/
│   ├── backend/              # NestJS API (Node.js 20+, TypeScript 5+)
│   │   ├── src/
│   │   │   ├── domain/       # Pure business logic (no framework deps)
│   │   │   ├── application/  # Controllers, DTOs, Guards
│   │   │   └── infrastructure/ # ORM, Cache, External APIs
│   │   ├── test/             # Integration & E2E tests
│   │   ├── load-tests/       # K6 load testing scripts
│   │   └── package.json      # Backend dependencies
│   └── frontend/             # Next.js 14 App Router (React 18)
│       ├── app/              # Next.js App Router pages
│       ├── src/              # Components, hooks, utilities
│       ├── e2e/              # Playwright E2E tests
│       └── package.json      # Frontend dependencies
├── infra/
│   └── postgres/             # PostgreSQL init scripts
├── docker/                   # Docker build & deployment configs
├── docker-compose.yml        # Local development infrastructure
├── package.json              # Root monorepo package.json (workspace scripts)
├── .prettierrc              # Prettier configuration (shared)
├── .github/workflows/       # GitHub Actions CI/CD pipelines
└── CLAUDE.md                # This file (architecture guide)

Workspace Management:

  • Root package.json contains monorepo-level scripts
  • Each app has its own package.json with specific dependencies
  • Use root-level commands (npm run backend:dev) for convenience
  • Or navigate to specific app and run commands directly

Development Commands

Local Development Setup

# Install all dependencies (monorepo)
npm install
cd apps/backend && npm install
cd ../frontend && npm install

# Start infrastructure (PostgreSQL + Redis + MinIO)
docker-compose up -d

# Verify all services are running
docker-compose ps
# Expected: xpeditis-postgres, xpeditis-redis, xpeditis-minio

# Run database migrations
cd apps/backend
npm run migration:run

# Start backend development server (with hot reload)
npm run backend:dev          # From root, or:
cd apps/backend && npm run dev

# Start frontend development server
npm run frontend:dev         # From root, or:
cd apps/frontend && npm run dev

Access Points:

Monorepo Scripts (from root)

# Development
npm run backend:dev          # Start backend dev server
npm run frontend:dev         # Start frontend dev server

# Testing
npm run backend:test         # Run backend unit tests
npm run frontend:test        # Run frontend tests
npm run backend:lint         # Lint backend code
npm run frontend:lint        # Lint frontend code

# Code Quality
npm run format               # Format all code (Prettier)
npm run format:check         # Check formatting

# Build
npm run backend:build        # Build backend for production
npm run frontend:build       # Build frontend for production

# Utilities
npm run install:all          # Install deps for all workspaces
npm run clean                # Clean all node_modules and build artifacts

Testing Commands

Backend Tests

cd apps/backend

# Unit tests (domain layer - no external dependencies)
npm test                          # Run all unit tests
npm run test:watch                # Run in watch mode
npm run test:cov                  # With coverage report

# Integration tests (infrastructure layer with real DB/Redis)
npm run test:integration          # Run all integration tests
npm run test:integration:watch    # Run in watch mode
npm run test:integration:cov      # With coverage report

# E2E tests (full API workflow)
npm run test:e2e                  # Run end-to-end tests

# Run a single test file
npm test -- booking.service.spec.ts
npm run test:integration -- redis-cache.adapter.spec.ts
npm run test:e2e -- carrier-portal.e2e-spec.ts

Load Testing (K6)

cd apps/backend

# Install k6 (macOS)
brew install k6

# Run rate search load test (100 virtual users)
k6 run load-tests/rate-search.test.js

# Run with custom parameters
k6 run --vus 50 --duration 60s load-tests/rate-search.test.js

E2E Testing (Playwright)

cd apps/frontend

# Install Playwright
npx playwright install

# Run E2E tests (booking workflow)
npx playwright test e2e/booking-workflow.spec.ts

# Run with UI mode
npx playwright test --ui

# Run specific browser
npx playwright test --project=chromium

API Testing (Postman/Newman)

# Install Newman globally
npm install -g newman

# Run Postman collection
newman run postman/Xpeditis_API.postman_collection.json

Database Migrations

cd apps/backend

# Generate new migration (after changing ORM entities)
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/MigrationName

# Run pending migrations
npm run migration:run

# Revert last migration
npm run migration:revert

# Check applied migrations (query database directly)
# Note: TypeORM doesn't have a built-in 'show' command
# Check the migrations table in the database to see applied migrations

Important Migration Notes:

  • Migration files use Unix timestamp format: 1733185000000-DescriptiveName.ts
  • Always test migrations in development before running in production
  • Migrations run automatically via TypeORM DataSource configuration
  • Never modify existing migrations that have been applied to production

Build & Production

# Backend build (uses tsc-alias to resolve path aliases)
cd apps/backend
npm run build          # Compiles TypeScript and resolves @domain, @application, @infrastructure aliases
npm run start:prod     # Runs the production build

# Frontend build
cd apps/frontend
npm run build          # Next.js production build
npm start              # Start production server

Architecture

Hexagonal Architecture (Ports & Adapters)

The backend follows strict hexagonal architecture with three isolated layers:

apps/backend/src/
├── domain/            # 🔵 CORE - Pure business logic (NO framework dependencies)
│   ├── entities/      # Business entities (Booking, RateQuote, User, CarrierProfile)
│   ├── value-objects/ # Immutable VOs (Money, Email, BookingNumber, Port)
│   ├── services/      # Domain services (pure TypeScript)
│   ├── ports/
│   │   ├── in/       # API Ports (use cases exposed by domain)
│   │   └── out/      # SPI Ports (interfaces required by domain)
│   └── exceptions/   # Domain exceptions
│
├── application/       # 🔌 Controllers & DTOs (depends ONLY on domain)
│   ├── auth/         # JWT authentication module
│   ├── rates/        # Rate search endpoints
│   ├── bookings/     # Booking management
│   ├── csv-bookings.module.ts  # CSV booking imports
│   ├── modules/
│   │   └── carrier-portal.module.ts  # Carrier portal feature
│   ├── controllers/  # REST endpoints
│   │   ├── carrier-auth.controller.ts
│   │   └── carrier-dashboard.controller.ts
│   ├── dto/          # Data transfer objects with validation
│   │   └── carrier-auth.dto.ts
│   ├── services/     # Application services
│   │   ├── carrier-auth.service.ts
│   │   └── carrier-dashboard.service.ts
│   ├── guards/       # Auth guards, rate limiting, RBAC
│   └── mappers/      # DTO ↔ Domain entity mapping
│
└── infrastructure/   # 🏗️ External integrations (depends ONLY on domain)
    ├── persistence/typeorm/  # PostgreSQL repositories
    │   ├── entities/
    │   │   ├── carrier-profile.orm-entity.ts
    │   │   ├── carrier-activity.orm-entity.ts
    │   │   ├── csv-booking.orm-entity.ts
    │   │   └── organization.orm-entity.ts
    │   ├── repositories/
    │   │   ├── carrier-profile.repository.ts
    │   │   └── carrier-activity.repository.ts
    │   ├── mappers/  # Domain ↔ ORM entity mappers
    │   └── migrations/
    │       ├── 1733185000000-CreateCarrierProfiles.ts
    │       ├── 1733186000000-CreateCarrierActivities.ts
    │       ├── 1733187000000-AddCarrierToCsvBookings.ts
    │       └── 1733188000000-AddCarrierFlagToOrganizations.ts
    ├── cache/        # Redis adapter
    ├── carriers/     # Maersk, MSC, CMA CGM connectors
    │   └── csv-loader/  # CSV-based rate connector
    ├── email/        # MJML email service (carrier notifications)
    ├── storage/      # S3 storage adapter
    ├── websocket/    # Real-time carrier updates
    └── security/     # Helmet.js, rate limiting, CORS

Critical Rules:

  1. Domain layer: No imports of NestJS, TypeORM, Redis, or any framework - pure TypeScript only
  2. Dependencies flow inward: Infrastructure → Application → Domain (never the reverse)
  3. TypeScript path aliases: Use @domain/*, @application/*, @infrastructure/*
  4. Testing: Domain tests must run without NestJS TestingModule
  5. Mappers: Use dedicated mapper classes for Domain ↔ ORM and Domain ↔ DTO conversions

Example - Domain Entity Structure:

// apps/backend/src/domain/entities/booking.entity.ts
export class Booking {
  private readonly props: BookingProps;

  static create(props: Omit<BookingProps, 'bookingNumber' | 'status'>): Booking {
    const bookingProps: BookingProps = {
      ...props,
      bookingNumber: BookingNumber.generate(),
      status: BookingStatus.create('draft'),
    };
    Booking.validate(bookingProps);
    return new Booking(bookingProps);
  }

  updateStatus(newStatus: BookingStatus): Booking {
    if (!this.status.canTransitionTo(newStatus)) {
      throw new InvalidStatusTransitionException();
    }
    return new Booking({ ...this.props, status: newStatus });
  }
}

Frontend Architecture (Next.js 14 App Router)

apps/frontend/
├── app/                # Next.js 14 App Router (routing)
│   ├── page.tsx       # Landing page
│   ├── layout.tsx     # Root layout
│   ├── login/         # Auth pages
│   ├── register/
│   ├── dashboard/     # Protected dashboard routes
│   └── carrier/       # 🚛 Carrier portal routes (in development)
│       ├── login/
│       ├── dashboard/
│       └── bookings/
├── src/
│   ├── components/    # React components
│   │   ├── ui/       # shadcn/ui components (Button, Dialog, etc.)
│   │   ├── bookings/ # Booking components
│   │   └── admin/    # Admin components
│   ├── hooks/        # Custom React hooks
│   │   ├── useBookings.ts
│   │   ├── useCompanies.ts
│   │   └── useNotifications.ts
│   ├── lib/          # Utilities and API client
│   │   ├── api/      # API client modules
│   │   │   ├── auth.ts
│   │   │   ├── bookings.ts
│   │   │   ├── csv-rates.ts
│   │   │   └── dashboard.ts
│   │   ├── context/  # React contexts
│   │   └── providers/ # React Query and other providers
│   ├── types/        # TypeScript type definitions
│   │   ├── booking.ts
│   │   ├── carrier.ts
│   │   └── rates.ts
│   ├── utils/        # Helper functions
│   │   └── export.ts  # Excel/CSV/PDF export utilities
│   └── pages/        # Legacy page components
└── public/           # Static assets (logos, images)

Frontend Patterns:

  • Server Components by default, Client Components when needed ("use client")
  • React Hook Form + Zod for form validation
  • TanStack Query for server state management
  • Zustand for client state management
  • shadcn/ui for accessible UI components

TypeScript Path Aliases (Frontend):

  • @/* - Maps to ./src/*
  • @/components/* - Maps to ./src/components/*
  • @/lib/* - Maps to ./src/lib/*
  • @/app/* - Maps to ./app/*
  • @/types/* - Maps to ./src/types/*
  • @/hooks/* - Maps to ./src/hooks/*
  • @/utils/* - Maps to ./src/utils/*
  • @/pages/* - Maps to ./src/pages/*

Tech Stack

Backend:

  • NestJS 10+ (framework)
  • TypeScript 5+ (strict mode)
  • PostgreSQL 15+ (database)
  • TypeORM 0.3+ (ORM)
  • Redis 7+ (cache, 15min TTL for rates)
  • Passport + JWT (authentication)
  • Argon2 (password hashing)
  • Helmet.js (security headers)
  • Pino (structured logging)
  • Sentry (error tracking + APM)

Frontend:

  • Next.js 14+ App Router
  • TypeScript 5+
  • React 18+
  • TanStack Table (data grids)
  • TanStack Query (server state)
  • React Hook Form + Zod (forms)
  • Socket.IO (real-time updates)
  • Tailwind CSS + shadcn/ui
  • Framer Motion (animations)

Infrastructure:

  • Docker + Docker Compose
  • GitHub Actions (CI/CD)
  • AWS RDS (PostgreSQL)
  • AWS ElastiCache (Redis)
  • AWS S3 (document storage)
  • MinIO (local S3-compatible storage for development)

Testing Strategy

Test Coverage Targets

  • Domain layer: 90%+ (currently ~100% for value objects and entities)
  • Application layer: 80%+
  • Infrastructure layer: 70%+ (currently ~82% for Phase 3 services)

Test File Locations

apps/backend/
├── src/
│   ├── application/
│   │   └── services/
│   │       ├── carrier-auth.service.spec.ts
│   │       └── carrier-dashboard.service.spec.ts
│   └── domain/
│       ├── entities/
│       │   └── rate-quote.entity.spec.ts
│       └── value-objects/
│           ├── email.vo.spec.ts
│           └── money.vo.spec.ts
├── test/
│   ├── integration/
│   │   ├── booking.repository.spec.ts
│   │   ├── redis-cache.adapter.spec.ts
│   │   └── maersk.connector.spec.ts
│   ├── carrier-portal.e2e-spec.ts     # Carrier portal E2E tests
│   ├── app.e2e-spec.ts
│   ├── jest-integration.json
│   ├── jest-e2e.json
│   └── setup-integration.ts
└── load-tests/
    └── rate-search.test.js

apps/frontend/
└── e2e/
    └── booking-workflow.spec.ts

Running Tests in CI

Tests run automatically on GitHub Actions for all PRs:

  • Linting & formatting check
  • Backend unit tests
  • Backend integration tests (with PostgreSQL + Redis services)
  • Backend E2E tests
  • Frontend tests
  • Security scans

See .github/workflows/ci.yml for full pipeline.

Security Features (Phase 4)

OWASP Top 10 Compliance:

  • Helmet.js security headers (CSP, HSTS, X-Frame-Options)
  • Rate limiting (global: 100/min, auth: 5/min, search: 30/min)
  • Brute-force protection (exponential backoff after 3 failed attempts)
  • File upload validation (MIME, magic number, size limits)
  • Password policy (12+ chars, complexity requirements, Argon2 hashing)
  • CORS with strict origin validation
  • SQL injection prevention (TypeORM parameterized queries)
  • XSS protection (CSP headers + input sanitization)

Monitoring & Observability:

  • Sentry error tracking + APM (10% trace sampling)
  • Performance monitoring interceptor (slow request alerts)
  • Structured JSON logging with Pino
  • WebSocket real-time notifications (NotificationsGateway)
  • WebSocket carrier status updates

Database Schema

Key Tables:

  • organizations - Freight forwarders and carriers (has is_carrier flag)
  • users - User accounts with RBAC roles (Argon2 password hashing)
  • carriers - Shipping line integrations (Maersk, MSC, CMA CGM, etc.)
  • carrier_profiles - Carrier profile metadata and settings
  • carrier_activities - Audit trail for carrier actions (accept/reject bookings, etc.)
  • ports - 10k+ global ports (UN LOCODE)
  • rate_quotes - Cached shipping rates (15min TTL)
  • bookings - Container bookings (status workflow)
  • containers - Container details (type, VGM, seal numbers)
  • shipments - Real-time shipment tracking
  • audit_logs - Compliance audit trail
  • csv_rates - CSV-based rate data for offline/bulk rate loading
  • csv_bookings - CSV-based booking imports (has carrier_id foreign key)
  • notifications - User notifications (email, in-app)
  • webhooks - Webhook configurations for external integrations

Migrations: Located in apps/backend/src/infrastructure/persistence/typeorm/migrations/

See apps/backend/DATABASE-SCHEMA.md for complete schema documentation.

Environment Variables

Required Variables

Backend (apps/backend/.env):

NODE_ENV=development
PORT=4000
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=xpeditis
DATABASE_PASSWORD=xpeditis_dev_password
DATABASE_NAME=xpeditis_dev
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=xpeditis_redis_password
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_ACCESS_EXPIRATION=15m
JWT_REFRESH_EXPIRATION=7d

# Email configuration (for carrier notifications)
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_USER=noreply@xpeditis.com
EMAIL_PASSWORD=your-email-password
EMAIL_FROM=noreply@xpeditis.com

Frontend (apps/frontend/.env.local):

NEXT_PUBLIC_API_URL=http://localhost:4000
NEXT_PUBLIC_WS_URL=ws://localhost:4000

See apps/backend/.env.example and apps/frontend/.env.example for all available variables.

API Documentation

OpenAPI/Swagger: http://localhost:4000/api/docs (when backend running)

Key Endpoints:

Client Portal

  • POST /api/v1/auth/login - JWT authentication
  • POST /api/v1/auth/register - User registration
  • POST /api/v1/rates/search - Search shipping rates (cached 15min)
  • POST /api/v1/rates/csv-search - Search rates from CSV data
  • POST /api/v1/bookings - Create booking
  • GET /api/v1/bookings - List bookings (paginated)
  • GET /api/v1/bookings/:id - Get booking details
  • POST /api/v1/bookings/csv-import - Bulk import bookings from CSV

Carrier Portal (New)

  • POST /api/v1/carrier/auth/auto-login - Auto-login via magic link token
  • POST /api/v1/carrier/auth/login - Standard carrier login
  • GET /api/v1/carrier/dashboard/stats - Carrier dashboard statistics
  • GET /api/v1/carrier/bookings - List bookings assigned to carrier
  • GET /api/v1/carrier/bookings/:id - Get booking details
  • PATCH /api/v1/carrier/bookings/:id/accept - Accept booking request
  • PATCH /api/v1/carrier/bookings/:id/reject - Reject booking request
  • GET /api/v1/carrier/profile - Get carrier profile
  • PATCH /api/v1/carrier/profile - Update carrier profile

Common

  • GET /api/v1/carriers/:id/status - Real-time carrier status
  • GET /api/v1/notifications - Get user notifications
  • WS /notifications - WebSocket for real-time notifications
  • WS /carrier-status - WebSocket for carrier status updates

See apps/backend/docs/CARRIER_PORTAL_API.md for complete carrier portal API documentation.

Business Rules

Critical Constraints:

  • Rate quotes expire after 15 minutes (Redis TTL)
  • Carrier API timeout: 5 seconds per carrier
  • Booking workflow: Maximum 4 steps
  • Session timeout: 2 hours inactivity
  • Rate search: <2s response time (90% with cache)
  • Booking number format: WCM-YYYY-XXXXXX (6 alphanumeric chars)
  • Cache hit target: >90% for common routes
  • Multi-currency support: USD, EUR

RBAC Roles:

  • ADMIN - Full system access
  • MANAGER - Manage organization bookings + users
  • USER - Create and view own bookings
  • VIEWER - Read-only access
  • CARRIER - Carrier portal access (view assigned bookings, accept/reject)

Carrier Portal Workflow:

  1. Admin creates CSV booking and assigns carrier
  2. Email sent to carrier with magic link (auto-login token, valid 1 hour)
  3. Carrier clicks link → auto-login → redirected to dashboard
  4. Carrier can accept/reject booking, download documents
  5. Activity logged in carrier_activities table
  6. Client notified of carrier decision

Real-Time Features (WebSocket)

The platform uses WebSocket connections for real-time updates:

Notifications Gateway (application/gateways/notifications.gateway.ts):

  • Real-time user notifications (booking updates, system alerts)
  • JWT-authenticated WebSocket connections
  • Auto-reconnect with exponential backoff
  • Connect to ws://localhost:4000/notifications

Carrier Status Updates:

  • Real-time carrier API status monitoring
  • Live shipment tracking updates
  • Connection status: online/offline/degraded
  • Connect to ws://localhost:4000/carrier-status

Frontend Integration:

  • Socket.IO client for WebSocket connections
  • Context providers in lib/providers/
  • Real-time notification dropdown component
  • Auto-refresh on status changes

CSV Import/Export Features

The platform supports CSV-based operations for bulk data management:

CSV Rate Search:

  • Upload CSV files with rate data for offline/bulk rate loading
  • CSV-based carrier connectors in infrastructure/carriers/csv-loader/
  • Stored in csv_rates table
  • Accessible via admin dashboard at /admin/csv-rates

CSV Booking Import:

  • Bulk import bookings from CSV files
  • Validation and mapping to domain entities
  • Stored in csv_bookings table
  • CSV parsing with csv-parse library
  • Automatic carrier assignment and email notification

Export Features:

  • Export bookings to Excel (.xlsx) using exceljs
  • Export to CSV format
  • Export to PDF documents using pdfkit
  • File downloads using file-saver on frontend

Admin User Management

The platform includes a dedicated admin interface for user management:

Admin Features (Branch: users_admin):

  • User CRUD operations (Create, Read, Update, Delete)
  • Organization management
  • Role assignment and permissions
  • Argon2 password hash generation for new users
  • Accessible at /admin/users (ADMIN role required)

Password Hashing Utility:

  • Use apps/backend/generate-hash.js to generate Argon2 password hashes
  • Example: node apps/backend/generate-hash.js mypassword

Deployment

Docker Build

# Build backend image
docker build -t xpeditis-backend:latest -f apps/backend/Dockerfile .

# Build frontend image
docker build -t xpeditis-frontend:latest -f apps/frontend/Dockerfile .

# Run with Docker Compose (development)
docker-compose up -d

Production Deployment (Portainer)

See docker/PORTAINER_DEPLOYMENT_GUIDE.md for complete instructions:

  • Scaleway Container Registry (rg.fr-par.scw.cloud/weworkstudio)
  • Docker Swarm stack deployment
  • Traefik reverse proxy configuration
  • Environment-specific configs (staging/production)

CI/CD: Automated via GitHub Actions

  • Build and push Docker images to Scaleway Registry
  • Deploy to staging/production via Portainer
  • Run smoke tests post-deployment

Deployment Scripts:

  • docker/build-images.sh - Build and tag Docker images
  • deploy-to-portainer.sh - Automated deployment script
  • docker/portainer-stack.yml - Production stack configuration

Performance Targets

  • Rate search: <2s for 90% of requests (with cache)
  • Rate search: <5s for 90% of requests (cache miss)
  • Dashboard load: <1s for up to 5k bookings
  • Email confirmation: Send within 3s of booking
  • Carrier email notification: Send within 5s of booking assignment
  • Cache hit ratio: >90% for top 100 trade lanes
  • Carrier API timeout: 5s (with circuit breaker)

Naming Conventions

TypeScript:

  • Entities: Booking, RateQuote, CarrierProfile (PascalCase)
  • Value Objects: Email, Money, BookingNumber
  • Services: BookingService, RateSearchService, CarrierAuthService
  • Repositories: BookingRepository, CarrierProfileRepository (interface in domain)
  • Repository Implementations: TypeOrmBookingRepository, TypeOrmCarrierProfileRepository
  • DTOs: CreateBookingDto, RateSearchRequestDto, CarrierAutoLoginDto
  • Ports: SearchRatesPort, CarrierConnectorPort

Files:

  • Entities: booking.entity.ts
  • Value Objects: email.vo.ts
  • Services: booking.service.ts, carrier-auth.service.ts
  • Tests: booking.service.spec.ts, carrier-auth.service.spec.ts
  • ORM Entities: booking.orm-entity.ts, carrier-profile.orm-entity.ts
  • Migrations: 1730000000001-CreateBookings.ts, 1733185000000-CreateCarrierProfiles.ts

Key Architectural Patterns Used

1. Domain-Driven Design (DDD)

  • Entities: Mutable objects with identity (e.g., Booking, User)
  • Value Objects: Immutable, identity-less objects (e.g., Money, Email, BookingNumber)
  • Aggregates: Cluster of entities/VOs treated as a unit (e.g., Booking with Container items)
  • Domain Services: Stateless operations that don't belong to entities
  • Domain Events: Not yet implemented (planned for Phase 5)

2. Repository Pattern

  • Interface in Domain: apps/backend/src/domain/ports/out/booking.repository.port.ts
  • Implementation in Infrastructure: apps/backend/src/infrastructure/persistence/typeorm/repositories/typeorm-booking.repository.ts
  • Mapper Pattern: Separate mappers for Domain ↔ ORM entity conversion

3. DTO Pattern

  • Request DTOs: Validate incoming API requests with class-validator
  • Response DTOs: Control API response shape
  • Mappers: Convert between DTOs and Domain entities in application layer

4. Circuit Breaker Pattern

  • Used for external carrier API calls (Maersk, MSC, CMA CGM)
  • Library: opossum
  • Timeout: 5 seconds per carrier
  • Location: apps/backend/src/infrastructure/carriers/*/

5. Caching Strategy

  • Redis for rate quotes: 15-minute TTL
  • Cache-aside pattern: Check cache first, fetch from carriers on miss
  • Cache key format: rate:{origin}:{destination}:{containerType}

Common Pitfalls to Avoid

DO NOT:

  • Import NestJS/TypeORM in domain layer
  • Put business logic in controllers or repositories
  • Use any type (strict mode enabled in backend)
  • Skip writing tests (coverage targets enforced)
  • Use DATABASE_SYNC=true in production (always use migrations)
  • Commit .env files (use .env.example templates)
  • Expose sensitive data in API responses (passwords, tokens, internal IDs)
  • Skip rate limiting on public endpoints
  • Use circular imports (leverage barrel exports with index.ts)
  • Send emails without proper error handling
  • Store plain text passwords (always use Argon2)
  • Modify applied migrations (create new migration instead)
  • Mix domain logic with framework code

DO:

  • Follow hexagonal architecture strictly (Infrastructure → Application → Domain)
  • Write tests for all new features (domain 90%+, application 80%+)
  • Use TypeScript path aliases (@domain/*, @application/*, @infrastructure/*)
  • Validate all DTOs with class-validator decorators
  • Implement circuit breakers for external APIs (carrier connectors)
  • Cache frequently accessed data (Redis with TTL)
  • Use structured logging (Pino JSON format)
  • Document APIs with Swagger decorators (@ApiOperation, @ApiResponse)
  • Run migrations before deployment (npm run migration:run)
  • Test email sending in development with test accounts
  • Use MJML for responsive email templates
  • Create dedicated mappers for Domain ↔ ORM conversions
  • Use Value Objects for domain concepts (Money, Email, etc.)
  • Implement proper error handling with domain exceptions
  • Use immutability in domain entities (return new instances on updates)

Documentation

Architecture & Planning:

Implementation Summaries:

API Documentation:

Testing:

Deployment:

Quick Reference - Common Tasks

Running a Single Test File

# Backend unit test
cd apps/backend
npm test -- booking.entity.spec.ts

# Backend integration test
npm run test:integration -- booking.repository.spec.ts

# Backend E2E test
npm run test:e2e -- carrier-portal.e2e-spec.ts

# Frontend test
cd apps/frontend
npm test -- BookingForm.test.tsx

Debugging TypeScript Path Aliases

If imports like @domain/* don't resolve:

  1. Check apps/backend/tsconfig.json has correct paths configuration
  2. Verify VS Code is using workspace TypeScript version
  3. Restart TypeScript server in VS Code: Cmd+Shift+P → "TypeScript: Restart TS Server"

Common Environment Issues

PostgreSQL connection fails:

# Verify PostgreSQL container is running
docker ps | grep xpeditis-postgres

# Check PostgreSQL logs
docker logs xpeditis-postgres

# Restart PostgreSQL
docker-compose restart postgres

Redis connection fails:

# Verify Redis container is running
docker ps | grep xpeditis-redis

# Test Redis connection
docker exec -it xpeditis-redis redis-cli -a xpeditis_redis_password ping
# Expected: PONG

# Restart Redis
docker-compose restart redis

Migrations fail:

# Check migration status (query the database)
# The migrations are tracked in the 'migrations' table

# If stuck, revert and try again
npm run migration:revert
npm run migration:run

# Or connect to database to check manually
docker exec -it xpeditis-postgres psql -U xpeditis -d xpeditis_dev -c "SELECT * FROM migrations ORDER BY id DESC LIMIT 5;"

Adding a New Feature (Step-by-Step)

  1. Create Domain Entity (if needed):

    • Location: apps/backend/src/domain/entities/
    • Pure TypeScript, no framework imports
    • Write unit tests: *.entity.spec.ts
  2. Create Value Objects (if needed):

    • Location: apps/backend/src/domain/value-objects/
    • Immutable, validated in constructor
    • Write unit tests: *.vo.spec.ts
  3. Define Domain Port Interface:

    • Location: apps/backend/src/domain/ports/out/
    • Interface only, no implementation
  4. Create ORM Entity:

    • Location: apps/backend/src/infrastructure/persistence/typeorm/entities/
    • File naming: *.orm-entity.ts
    • Add @Entity() decorator
  5. Generate Migration:

    npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/CreateFeatureName
    
  6. Implement Repository:

    • Location: apps/backend/src/infrastructure/persistence/typeorm/repositories/
    • Implements domain port interface
    • Write integration tests
  7. Create DTOs:

    • Location: apps/backend/src/application/dto/
    • Add class-validator decorators
  8. Create Controller:

    • Location: apps/backend/src/application/controllers/
    • Add Swagger decorators
    • Write E2E tests
  9. Create Application Module:

    • Location: apps/backend/src/application/modules/
    • Register controllers, services, repositories
  10. Import Module in App.module.ts

Code Review Checklist

  1. Hexagonal architecture principles followed
  2. Domain layer has zero external dependencies
  3. Unit tests written (90%+ coverage for domain)
  4. Integration tests for infrastructure adapters
  5. DTOs validated with class-validator
  6. Swagger documentation updated
  7. No secrets committed
  8. TypeScript strict mode passes
  9. Prettier formatting applied
  10. ESLint passes with no warnings
  11. Email templates tested in development
  12. Carrier workflow tested end-to-end
  13. Database migrations tested in development
  14. ORM entities have corresponding domain entities
  15. Mappers created for Domain ↔ ORM conversions