171 lines
5.8 KiB
Markdown
171 lines
5.8 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
cd apps/backend
|
|
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/MigrationName
|
|
npm run migration:run
|
|
npm run migration:revert
|
|
```
|
|
|
|
### Build
|
|
|
|
```bash
|
|
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)
|
|
```typescript
|
|
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 Entity** → `domain/entities/*.entity.ts` (pure TS, unit tests)
|
|
2. **Value Objects** → `domain/value-objects/*.vo.ts` (immutable)
|
|
3. **Port Interface** → `domain/ports/out/*.repository.ts`
|
|
4. **ORM Entity** → `infrastructure/persistence/typeorm/entities/*.orm-entity.ts`
|
|
5. **Generate Migration** → `npm run migration:generate -- ...`
|
|
6. **Repository Impl** → `infrastructure/persistence/typeorm/repositories/`
|
|
7. **DTOs** → `application/dto/` (with class-validator decorators)
|
|
8. **Controller** → `application/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`
|