xpeditis2.0/CLAUDE.md
2026-01-27 19:33:51 +01:00

5.8 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 platform. Freight forwarders search and compare real-time shipping rates, book containers, and manage shipments. Built as a monorepo with NestJS backend (Hexagonal Architecture) and Next.js 14 frontend.

Development Commands

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

# Install dependencies
npm install && cd apps/backend && npm install && cd ../frontend && npm install

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

# Start development servers
npm run backend:dev    # http://localhost:4000, Swagger: /api/docs
npm run frontend:dev   # http://localhost:3000

Testing

# Backend (from apps/backend/)
npm test                              # Unit tests
npm test -- booking.entity.spec.ts    # Single file
npm run test:cov                      # With coverage
npm run test:integration              # Integration tests (needs DB/Redis)
npm run test:e2e                      # E2E tests

# Frontend (from apps/frontend/)
npm test
npx playwright test                   # E2E tests

Database Migrations

cd apps/backend
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/MigrationName
npm run migration:run
npm run migration:revert

Build

npm run backend:build    # Compiles TS with path alias resolution (tsc-alias)
npm run frontend:build   # Next.js production build

Architecture

Hexagonal Architecture (Backend)

apps/backend/src/
├── domain/           # CORE - Pure TypeScript, NO framework imports
│   ├── entities/     # Booking, RateQuote, User (with private props, static create())
│   ├── value-objects/# Money, Email, BookingNumber (immutable, validated)
│   ├── services/     # Domain services
│   ├── ports/
│   │   ├── in/      # Use case interfaces
│   │   └── out/     # Repository interfaces (SPIs)
│   └── exceptions/   # Domain exceptions
├── application/      # Controllers, DTOs, Guards (depends ONLY on domain)
└── infrastructure/   # TypeORM, Redis, Carrier APIs (depends ONLY on domain)

Critical Rules:

  • Domain layer: Zero imports from NestJS, TypeORM, Redis
  • Dependencies flow inward: Infrastructure → Application → Domain
  • Use path aliases: @domain/*, @application/*, @infrastructure/*
  • Domain tests run without NestJS TestingModule

Frontend (Next.js 14 App Router)

apps/frontend/
├── app/              # App Router pages
│   ├── dashboard/    # Protected routes
│   │   ├── bookings/ # Booking management
│   │   ├── admin/    # Admin features (ADMIN role)
│   │   └── settings/ # User/org settings
│   └── carrier/      # Carrier portal (magic link auth)
└── src/
    ├── components/   # React components (shadcn/ui in ui/)
    ├── hooks/        # useBookings, useNotifications
    ├── lib/api/      # API client modules
    └── types/        # TypeScript definitions

Path aliases: @/*./src/*, @/components/*, @/lib/*, @/hooks/*

Key Patterns

Entity Pattern (Domain)

export class Booking {
  private readonly props: BookingProps;
  static create(props: Omit<BookingProps, 'bookingNumber'>): Booking { ... }
  updateStatus(newStatus: BookingStatus): Booking { // Returns new instance
    return new Booking({ ...this.props, status: newStatus });
  }
}

Repository Pattern

  • Interface in domain/ports/out/booking.repository.ts
  • Implementation in infrastructure/persistence/typeorm/repositories/typeorm-booking.repository.ts
  • Separate mappers for Domain ↔ ORM entity conversions

Circuit Breaker (External APIs)

  • Library: opossum, Timeout: 5s
  • Used for carrier API calls (Maersk, MSC, CMA CGM)

Caching

  • Redis with 15-min TTL for rate quotes
  • Cache key format: rate:{origin}:{destination}:{containerType}

Business Rules

  • Booking number format: WCM-YYYY-XXXXXX
  • Rate quotes expire after 15 minutes
  • Multi-currency: USD, EUR
  • RBAC Roles: ADMIN, MANAGER, USER, VIEWER, CARRIER

Carrier Portal Workflow

  1. Admin creates CSV booking → assigns carrier
  2. Email with magic link sent (1-hour expiry)
  3. Carrier auto-login → accept/reject booking
  4. Activity logged in carrier_activities table

Tech Stack

Backend: NestJS 10, TypeORM 0.3, PostgreSQL 15, Redis 7, Argon2, Pino, Sentry Frontend: Next.js 14, React 18, TanStack Query/Table, React Hook Form + Zod, Tailwind + shadcn/ui, Socket.IO

Common Pitfalls

  • Never import NestJS/TypeORM in domain layer
  • Never use any type (strict mode enabled)
  • Never use DATABASE_SYNC=true in production
  • Never modify applied migrations - create new ones
  • Always validate DTOs with class-validator
  • Always create mappers for Domain ↔ ORM conversions

Adding a New Feature

  1. Domain Entitydomain/entities/*.entity.ts (pure TS, unit tests)
  2. Value Objectsdomain/value-objects/*.vo.ts (immutable)
  3. Port Interfacedomain/ports/out/*.repository.ts
  4. ORM Entityinfrastructure/persistence/typeorm/entities/*.orm-entity.ts
  5. Generate Migrationnpm run migration:generate -- ...
  6. Repository Implinfrastructure/persistence/typeorm/repositories/
  7. DTOsapplication/dto/ (with class-validator decorators)
  8. Controllerapplication/controllers/ (with Swagger decorators)
  9. Module → Register and import in app.module.ts

Documentation

  • API Docs: http://localhost:4000/api/docs (Swagger)
  • Architecture: docs/architecture.md
  • Carrier Portal API: apps/backend/docs/CARRIER_PORTAL_API.md
  • Full docs index: docs/README.md