37 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, comprehensive testing infrastructure, and active administration features development.
Active Branch: administration - Currently working on admin features, notifications system, and dashboard enhancements. Check git status for current feature branch.
Recent Development: Notifications system, dashboard improvements, pagination fixes, and admin user management features.
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.jsoncontains monorepo-level scripts - Each app has its own
package.jsonwith 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:
- Frontend: http://localhost:3000
- Backend API: http://localhost:4000
- API Docs (Swagger): http://localhost:4000/api/docs
- MinIO Console (local S3): http://localhost:9001 (minioadmin/minioadmin)
- Admin Dashboard: http://localhost:3000/dashboard/admin (ADMIN role required)
- Admin CSV Rates: http://localhost:3000/dashboard/admin/csv-rates
- Admin User Management: http://localhost:3000/dashboard/settings/users
- Notifications: http://localhost:3000/dashboard/notifications
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
│ ├── controllers/ # REST endpoints
│ │ ├── health.controller.ts
│ │ ├── gdpr.controller.ts
│ │ └── index.ts
│ ├── dto/ # Data transfer objects with validation
│ │ ├── booking-*.dto.ts
│ │ ├── rate-*.dto.ts
│ │ └── csv-*.dto.ts
│ ├── services/ # Application services
│ │ ├── fuzzy-search.service.ts
│ │ ├── brute-force-protection.service.ts
│ │ ├── file-validation.service.ts
│ │ └── gdpr.service.ts
│ ├── guards/ # Auth guards, rate limiting, RBAC
│ │ ├── jwt-auth.guard.ts
│ │ └── throttle.guard.ts
│ ├── decorators/ # Custom decorators
│ │ ├── current-user.decorator.ts
│ │ ├── public.decorator.ts
│ │ └── roles.decorator.ts
│ ├── interceptors/ # Request/response interceptors
│ │ └── performance-monitoring.interceptor.ts
│ └── gdpr/ # GDPR compliance module
│ └── gdpr.module.ts
│
└── infrastructure/ # 🏗️ External integrations (depends ONLY on domain)
├── persistence/typeorm/ # PostgreSQL repositories
│ ├── entities/
│ │ ├── booking.orm-entity.ts
│ │ ├── carrier.orm-entity.ts
│ │ ├── csv-rate-config.orm-entity.ts
│ │ ├── notification.orm-entity.ts
│ │ ├── port.orm-entity.ts
│ │ ├── rate-quote.orm-entity.ts
│ │ └── audit-log.orm-entity.ts
│ ├── repositories/
│ ├── mappers/ # Domain ↔ ORM entity mappers
│ └── migrations/
├── cache/ # Redis adapter
├── carriers/ # Maersk, MSC, CMA CGM connectors
│ ├── carrier.module.ts
│ ├── csv-loader/ # CSV-based rate connector
│ │ └── csv-converter.service.ts
│ └── maersk/
│ └── maersk.types.ts
├── email/ # MJML email service (carrier notifications)
├── storage/ # S3 storage adapter
│ └── csv-storage/ # CSV rate files storage
│ └── rates/
├── monitoring/ # Monitoring and observability
│ └── sentry.config.ts
├── websocket/ # Real-time carrier updates
└── security/ # Helmet.js, rate limiting, CORS
Critical Rules:
- Domain layer: No imports of NestJS, TypeORM, Redis, or any framework - pure TypeScript only
- Dependencies flow inward: Infrastructure → Application → Domain (never the reverse)
- TypeScript path aliases: Use
@domain/*,@application/*,@infrastructure/* - Testing: Domain tests must run without NestJS TestingModule
- 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/
│ ├── forgot-password/
│ ├── reset-password/
│ ├── verify-email/
│ ├── dashboard/ # Protected dashboard routes
│ │ ├── page.tsx # Main dashboard
│ │ ├── layout.tsx # Dashboard layout with navigation
│ │ ├── search/ # Rate search
│ │ ├── search-advanced/ # Advanced search with results
│ │ ├── bookings/ # Booking management
│ │ │ ├── page.tsx # Bookings list
│ │ │ ├── [id]/page.tsx # Booking details
│ │ │ └── new/page.tsx # Create booking
│ │ ├── profile/ # User profile
│ │ ├── notifications/ # Notifications page
│ │ ├── settings/ # Settings pages
│ │ │ ├── users/page.tsx # User management (admin)
│ │ │ └── organization/page.tsx # Organization settings
│ │ └── admin/ # Admin features (ADMIN role only)
│ │ └── csv-rates/page.tsx # CSV rate management
│ ├── booking/ # Booking actions (public with token)
│ │ ├── confirm/[token]/page.tsx
│ │ └── reject/[token]/page.tsx
│ ├── carrier/ # Carrier portal routes
│ │ ├── accept/[token]/page.tsx
│ │ └── reject/[token]/page.tsx
│ ├── demo-carte/ # Map demo page
│ └── test-image/ # Image testing page
├── 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)
- Leaflet + React Leaflet (maps)
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/
│ │ ├── brute-force-protection.service.spec.ts
│ │ ├── file-validation.service.spec.ts
│ │ ├── fuzzy-search.service.spec.ts
│ │ └── gdpr.service.spec.ts
│ └── domain/
│ ├── entities/
│ │ ├── rate-quote.entity.spec.ts
│ │ ├── notification.entity.spec.ts
│ │ └── webhook.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
│ ├── 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 (hasis_carrierflag)users- User accounts with RBAC roles (Argon2 password hashing)carriers- Shipping line integrations (Maersk, MSC, CMA CGM, etc.)carrier_profiles- Carrier profile metadata and settingscarrier_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 trackingaudit_logs- Compliance audit trailcsv_rates- CSV-based rate data for offline/bulk rate loadingcsv_bookings- CSV-based booking imports (hascarrier_idforeign 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 authenticationPOST /api/v1/auth/register- User registrationPOST /api/v1/rates/search- Search shipping rates (cached 15min)POST /api/v1/rates/csv-search- Search rates from CSV dataPOST /api/v1/bookings- Create bookingGET /api/v1/bookings- List bookings (paginated)GET /api/v1/bookings/:id- Get booking detailsPOST /api/v1/bookings/csv-import- Bulk import bookings from CSV
Admin Features
GET /api/v1/admin/users- List users (ADMIN role)POST /api/v1/admin/users- Create user (ADMIN role)PATCH /api/v1/admin/users/:id- Update user (ADMIN role)DELETE /api/v1/admin/users/:id- Delete user (ADMIN role)GET /api/v1/admin/csv-rates- List CSV rate configs (ADMIN role)POST /api/v1/admin/csv-rates/upload- Upload CSV rates (ADMIN role)
Notifications
GET /api/v1/notifications- Get user notificationsPATCH /api/v1/notifications/:id/read- Mark notification as readDELETE /api/v1/notifications/:id- Delete notificationWS /notifications- WebSocket for real-time notifications
GDPR Compliance
GET /api/v1/gdpr/export- Export user data (GDPR compliance)DELETE /api/v1/gdpr/delete- Delete user data (GDPR right to be forgotten)
Health Checks
GET /api/v1/health- Health check endpoint
Carrier Portal
POST /api/v1/carrier/auth/auto-login- Auto-login via magic link tokenPOST /api/v1/carrier/auth/login- Standard carrier loginGET /api/v1/carrier/dashboard/stats- Carrier dashboard statisticsGET /api/v1/carrier/bookings- List bookings assigned to carrierGET /api/v1/carrier/bookings/:id- Get booking detailsPATCH /api/v1/carrier/bookings/:id/accept- Accept booking requestPATCH /api/v1/carrier/bookings/:id/reject- Reject booking requestGET /api/v1/carrier/profile- Get carrier profilePATCH /api/v1/carrier/profile- Update carrier profile
Common
GET /api/v1/carriers/:id/status- Real-time carrier statusWS /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, user management, CSV rate uploadsMANAGER- Manage organization bookings + usersUSER- Create and view own bookingsVIEWER- Read-only accessCARRIER- Carrier portal access (view assigned bookings, accept/reject)
Carrier Portal Workflow:
- Admin creates CSV booking and assigns carrier
- Email sent to carrier with magic link (auto-login token, valid 1 hour)
- Carrier clicks link → auto-login → redirected to dashboard
- Carrier can accept/reject booking, download documents
- Activity logged in
carrier_activitiestable - 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_ratestable - Accessible via admin dashboard at
/dashboard/admin/csv-rates - CSV files stored in
apps/backend/src/infrastructure/storage/csv-storage/rates/ - Supported carriers: MSC, ECU Worldwide, NVO Consolidation, SSC Consolidation, TCC Logistics, Test Maritime Express
CSV Booking Import:
- Bulk import bookings from CSV files
- Validation and mapping to domain entities
- Stored in
csv_bookingstable - CSV parsing with
csv-parselibrary - Automatic carrier assignment and email notification
Export Features:
- Export bookings to Excel (
.xlsx) usingexceljs - Export to CSV format
- Export to PDF documents using
pdfkit - File downloads using
file-saveron frontend
Admin User Management
The platform includes a dedicated admin interface for user management:
Admin Features (Active on administration branch):
- User CRUD operations (Create, Read, Update, Delete)
- Organization management
- Role assignment and permissions
- Argon2 password hash generation for new users
- Accessible at
/dashboard/settings/users(ADMIN role required) - CSV rate management at
/dashboard/admin/csv-rates - Real-time notifications management
Password Hashing Utility:
- Use
apps/backend/generate-hash.jsto 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 imagesdeploy-to-portainer.sh- Automated deployment scriptdocker/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.,
BookingwithContaineritems) - 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.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
anytype (strict mode enabled in backend) - Skip writing tests (coverage targets enforced)
- Use
DATABASE_SYNC=truein production (always use migrations) - Commit
.envfiles (use.env.exampletemplates) - 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-validatordecorators - 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:
- ARCHITECTURE.md - System architecture (5,800 words)
- DEPLOYMENT.md - Deployment guide (4,500 words)
- PRD.md - Product requirements
- TODO.md - 30-week development roadmap
- CARRIER_PORTAL_IMPLEMENTATION_PLAN.md - Carrier portal implementation plan
Implementation Summaries:
- PHASE4_SUMMARY.md - Security, monitoring, testing
- PHASE3_COMPLETE.md - Booking workflow, exports
- PHASE2_COMPLETE.md - Authentication, RBAC
- PHASE-1-WEEK5-COMPLETE.md - Rate search, cache
API Documentation:
- apps/backend/docs/CARRIER_PORTAL_API.md - Carrier portal API reference
Testing:
- TEST_EXECUTION_GUIDE.md - How to run all tests
- TEST_COVERAGE_REPORT.md - Coverage metrics
- GUIDE_TESTS_POSTMAN.md - Postman API tests
Deployment:
- docker/PORTAINER_DEPLOYMENT_GUIDE.md - Portainer setup
- docker/DOCKER_BUILD_GUIDE.md - Docker build instructions
- DEPLOYMENT_CHECKLIST.md - Pre-deployment checklist
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:
- Check
apps/backend/tsconfig.jsonhas correctpathsconfiguration - Verify VS Code is using workspace TypeScript version
- 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)
-
Create Domain Entity (if needed):
- Location:
apps/backend/src/domain/entities/ - Pure TypeScript, no framework imports
- Write unit tests:
*.entity.spec.ts
- Location:
-
Create Value Objects (if needed):
- Location:
apps/backend/src/domain/value-objects/ - Immutable, validated in constructor
- Write unit tests:
*.vo.spec.ts
- Location:
-
Define Domain Port Interface:
- Location:
apps/backend/src/domain/ports/out/ - Interface only, no implementation
- Location:
-
Create ORM Entity:
- Location:
apps/backend/src/infrastructure/persistence/typeorm/entities/ - File naming:
*.orm-entity.ts - Add
@Entity()decorator
- Location:
-
Generate Migration:
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/CreateFeatureName -
Implement Repository:
- Location:
apps/backend/src/infrastructure/persistence/typeorm/repositories/ - Implements domain port interface
- Write integration tests
- Location:
-
Create DTOs:
- Location:
apps/backend/src/application/dto/ - Add
class-validatordecorators
- Location:
-
Create Controller:
- Location:
apps/backend/src/application/controllers/ - Add Swagger decorators
- Write E2E tests
- Location:
-
Create Application Module:
- Location:
apps/backend/src/application/modules/ - Register controllers, services, repositories
- Location:
-
Import Module in App.module.ts
Code Review Checklist
- Hexagonal architecture principles followed
- Domain layer has zero external dependencies
- Unit tests written (90%+ coverage for domain)
- Integration tests for infrastructure adapters
- DTOs validated with class-validator
- Swagger documentation updated
- No secrets committed
- TypeScript strict mode passes
- Prettier formatting applied
- ESLint passes with no warnings
- Email templates tested in development
- Carrier workflow tested end-to-end
- Database migrations tested in development
- ORM entities have corresponding domain entities
- Mappers created for Domain ↔ ORM conversions