fix celan v2

This commit is contained in:
David 2026-05-14 21:11:54 +02:00
parent ad761372f5
commit 4baffe0b7a
87 changed files with 2533 additions and 511 deletions

393
INDEX.md
View File

@ -1,348 +1,81 @@
# 📑 Xpeditis Documentation Index # Index de documentation — Xpeditis
Complete guide to all documentation files in the Xpeditis project.
--- ---
## 🚀 Getting Started (Read First) ## Démarrage
Start here if you're new to the project: | Fichier | Description |
|---------|-------------|
1. **[README.md](README.md)** - Project overview and quick start | [README.md](README.md) | Vue d'ensemble du projet |
2. **[QUICK-START.md](QUICK-START.md)** ⚡ - Get running in 5 minutes | [QUICK-START.md](QUICK-START.md) | Démarrage en 5 minutes |
3. **[INSTALLATION-STEPS.md](INSTALLATION-STEPS.md)** - Detailed installation guide | [CLAUDE.md](CLAUDE.md) | Architecture hexagonale, conventions, règles |
4. **[NEXT-STEPS.md](NEXT-STEPS.md)** - What to do after setup | [docs/README.md](docs/README.md) | Index complet de la documentation |
--- ---
## 📊 Project Status & Planning ## Documentation complète
### Sprint 0 (Complete ✅) Toute la documentation est organisée dans [docs/](docs/) :
- **[SPRINT-0-FINAL.md](SPRINT-0-FINAL.md)** - Complete Sprint 0 report ```
- All deliverables docs/
- Architecture details ├── README.md # Index principal
- How to use ├── getting-started/ # Installation et démarrage
- Success criteria │ ├── quick-start.md # Guide rapide mis à jour
│ ├── installation.md # Installation détaillée
- **[SPRINT-0-SUMMARY.md](SPRINT-0-SUMMARY.md)** - Executive summary │ └── windows.md # Spécifique Windows
- Objectives achieved
- Metrics ├── architecture/ # Documentation technique
- Key features │ ├── overview.md # Vue d'ensemble système
- Next steps │ ├── database.md # Schéma BDD complet (21 tables)
│ ├── backend.md # NestJS hexagonal, patterns
- **[SPRINT-0-COMPLETE.md](SPRINT-0-COMPLETE.md)** - Technical completion checklist │ └── frontend.md # Next.js 14, App Router, i18n
- Week-by-week breakdown
- Files created ├── features/ # Documentation par fonctionnalité
- Remaining tasks │ ├── auth.md # Auth JWT/OAuth/API Keys + RBAC
│ ├── bookings.md # Réservations standard
### Project Roadmap │ ├── csv-bookings.md # CSV bookings + portail carrier
│ ├── rate-search.md # Recherche tarifs FCL + CSV
- **[TODO.md](TODO.md)** 📅 - 30-week MVP development roadmap │ ├── subscriptions.md # Stripe + abonnements
- Sprint-by-sprint breakdown │ ├── notifications.md # WebSocket + webhooks
- Detailed tasks with checkboxes │ └── api-access.md # Clés API
- Phase 1-4 planning
- Go-to-market strategy ├── deployment/ # Déploiement
│ ├── portainer.md # Portainer / Docker Swarm (consolidé)
- **[PRD.md](PRD.md)** 📋 - Product Requirements Document │ ├── hetzner/ # Kubernetes Hetzner (15 fichiers numérotés)
- Business context │ └── STRIPE_SETUP.md # Configuration Stripe
- Functional specifications
- Technical requirements ├── testing/ # Tests
- Success metrics ├── csv-system/ # Système CSV (format, calcul prix)
├── carrier-portal/ # Portail carrier (recherche API)
├── api-access/ # Documentation accès API
├── backend/ # Notes backend (cleanup, MinIO)
└── archive/ # Rapports de sprint archivés
├── phases/ # Historique phases 1-4
└── debug/ # Notes de debug résolues
```
--- ---
## 🏗️ Architecture & Development Guidelines ## Commandes essentielles
### Core Architecture ```bash
# Démarrer
docker-compose up -d
npm run install:all
cd apps/backend && npm run migration:run && cd ../..
npm run backend:dev # http://localhost:4000
npm run frontend:dev # http://localhost:3000
- **[CLAUDE.md](CLAUDE.md)** 🏗️ - **START HERE FOR ARCHITECTURE** # Tests
- Complete hexagonal architecture guide npm run backend:test
- Domain/Application/Infrastructure layers npm run frontend:test
- Ports & Adapters pattern
- Naming conventions
- Testing strategy
- Common pitfalls
- Complete examples (476 lines)
### Component-Specific Documentation # Qualité
npm run format
- **[apps/backend/README.md](apps/backend/README.md)** - Backend (NestJS + Hexagonal) npm run backend:lint && npm run frontend:lint
- Architecture details ```
- Available scripts
- API endpoints
- Testing guide
- Hexagonal architecture DOs and DON'Ts
- **[apps/frontend/README.md](apps/frontend/README.md)** - Frontend (Next.js 14)
- Tech stack
- Project structure
- API integration
- Forms & validation
- Testing guide
--- ---
## 🛠️ Technical Documentation *Dernière mise à jour : Mai 2026*
### Configuration Files
**Root Level**:
- `package.json` - Workspace configuration
- `.gitignore` - Git ignore rules
- `.prettierrc` - Code formatting
- `docker-compose.yml` - PostgreSQL + Redis
- `tsconfig.json` - TypeScript configuration (per app)
**Backend** (`apps/backend/`):
- `package.json` - Backend dependencies
- `tsconfig.json` - TypeScript strict mode + path aliases
- `nest-cli.json` - NestJS CLI configuration
- `.eslintrc.js` - ESLint rules
- `.env.example` - Environment variables template
**Frontend** (`apps/frontend/`):
- `package.json` - Frontend dependencies
- `tsconfig.json` - TypeScript configuration
- `next.config.js` - Next.js configuration
- `tailwind.config.ts` - Tailwind CSS theme
- `postcss.config.js` - PostCSS configuration
- `.env.example` - Environment variables template
### CI/CD
**GitHub Actions** (`.github/workflows/`):
- `ci.yml` - Continuous Integration
- Lint & format check
- Unit tests (backend + frontend)
- E2E tests
- Build verification
- `security.yml` - Security Audit
- npm audit
- Dependency review
**Templates**:
- `.github/pull_request_template.md` - PR template with hexagonal architecture checklist
---
## 📚 Documentation by Use Case
### I want to...
**...get started quickly**
1. [QUICK-START.md](QUICK-START.md) - 5-minute setup
2. [INSTALLATION-STEPS.md](INSTALLATION-STEPS.md) - Detailed steps
3. [NEXT-STEPS.md](NEXT-STEPS.md) - Begin development
**...understand the architecture**
1. [CLAUDE.md](CLAUDE.md) - Complete hexagonal architecture guide
2. [apps/backend/README.md](apps/backend/README.md) - Backend specifics
3. [SPRINT-0-FINAL.md](SPRINT-0-FINAL.md) - See what's implemented
**...know what to build next**
1. [TODO.md](TODO.md) - Full roadmap
2. [NEXT-STEPS.md](NEXT-STEPS.md) - Immediate next tasks
3. [PRD.md](PRD.md) - Business requirements
**...understand the business context**
1. [PRD.md](PRD.md) - Product requirements
2. [README.md](README.md) - Project overview
3. [SPRINT-0-SUMMARY.md](SPRINT-0-SUMMARY.md) - Executive summary
**...fix an installation issue**
1. [INSTALLATION-STEPS.md](INSTALLATION-STEPS.md) - Troubleshooting section
2. [QUICK-START.md](QUICK-START.md) - Common issues
3. [README.md](README.md) - Basic setup
**...write code following best practices**
1. [CLAUDE.md](CLAUDE.md) - Architecture guidelines (READ THIS FIRST)
2. [apps/backend/README.md](apps/backend/README.md) - Backend DOs and DON'Ts
3. [TODO.md](TODO.md) - Task specifications and acceptance criteria
**...run tests**
1. [apps/backend/README.md](apps/backend/README.md) - Testing section
2. [apps/frontend/README.md](apps/frontend/README.md) - Testing section
3. [CLAUDE.md](CLAUDE.md) - Testing strategy
**...deploy to production**
1. [SPRINT-0-FINAL.md](SPRINT-0-FINAL.md) - Security checklist
2. [apps/backend/.env.example](apps/backend/.env.example) - All required variables
3. `.github/workflows/ci.yml` - CI/CD pipeline
---
## 📖 Documentation by Role
### For Developers
**Must Read**:
1. [CLAUDE.md](CLAUDE.md) - Architecture principles
2. [apps/backend/README.md](apps/backend/README.md) OR [apps/frontend/README.md](apps/frontend/README.md)
3. [TODO.md](TODO.md) - Current sprint tasks
**Reference**:
- [INSTALLATION-STEPS.md](INSTALLATION-STEPS.md) - Setup issues
- [PRD.md](PRD.md) - Business context
### For Architects
**Must Read**:
1. [CLAUDE.md](CLAUDE.md) - Complete architecture
2. [SPRINT-0-FINAL.md](SPRINT-0-FINAL.md) - Implementation details
3. [PRD.md](PRD.md) - Technical requirements
**Reference**:
- [TODO.md](TODO.md) - Technical roadmap
- [apps/backend/README.md](apps/backend/README.md) - Backend architecture
### For Project Managers
**Must Read**:
1. [SPRINT-0-SUMMARY.md](SPRINT-0-SUMMARY.md) - Status overview
2. [TODO.md](TODO.md) - Complete roadmap
3. [PRD.md](PRD.md) - Requirements & KPIs
**Reference**:
- [SPRINT-0-FINAL.md](SPRINT-0-FINAL.md) - Detailed completion report
- [README.md](README.md) - Project overview
### For DevOps
**Must Read**:
1. [INSTALLATION-STEPS.md](INSTALLATION-STEPS.md) - Setup guide
2. [docker-compose.yml](docker-compose.yml) - Infrastructure
3. `.github/workflows/` - CI/CD pipelines
**Reference**:
- [apps/backend/.env.example](apps/backend/.env.example) - Environment variables
- [SPRINT-0-FINAL.md](SPRINT-0-FINAL.md) - Security checklist
---
## 🗂️ Complete File List
### Documentation (11 files)
| File | Purpose | Length |
|------|---------|--------|
| [README.md](README.md) | Project overview | Medium |
| [CLAUDE.md](CLAUDE.md) | Architecture guide | Long (476 lines) |
| [PRD.md](PRD.md) | Product requirements | Long (352 lines) |
| [TODO.md](TODO.md) | 30-week roadmap | Very Long (1000+ lines) |
| [QUICK-START.md](QUICK-START.md) | 5-minute setup | Short |
| [INSTALLATION-STEPS.md](INSTALLATION-STEPS.md) | Detailed setup | Medium |
| [NEXT-STEPS.md](NEXT-STEPS.md) | What's next | Medium |
| [SPRINT-0-FINAL.md](SPRINT-0-FINAL.md) | Sprint 0 report | Long |
| [SPRINT-0-SUMMARY.md](SPRINT-0-SUMMARY.md) | Executive summary | Medium |
| [SPRINT-0-COMPLETE.md](SPRINT-0-COMPLETE.md) | Technical checklist | Short |
| [INDEX.md](INDEX.md) | This file | Medium |
### App-Specific (2 files)
| File | Purpose |
|------|---------|
| [apps/backend/README.md](apps/backend/README.md) | Backend guide |
| [apps/frontend/README.md](apps/frontend/README.md) | Frontend guide |
### Configuration (10+ files)
Root, backend, and frontend configuration files (package.json, tsconfig.json, etc.)
---
## 📊 Documentation Statistics
- **Total Documentation Files**: 13
- **Total Lines**: ~4,000+
- **Coverage**: Setup, Architecture, Development, Testing, Deployment
- **Last Updated**: October 7, 2025
---
## 🎯 Recommended Reading Path
### For New Team Members (Day 1)
**Morning** (2 hours):
1. [README.md](README.md) - 10 min
2. [QUICK-START.md](QUICK-START.md) - 30 min (includes setup)
3. [CLAUDE.md](CLAUDE.md) - 60 min (comprehensive architecture)
4. [PRD.md](PRD.md) - 20 min (business context)
**Afternoon** (2 hours):
5. [apps/backend/README.md](apps/backend/README.md) OR [apps/frontend/README.md](apps/frontend/README.md) - 30 min
6. [TODO.md](TODO.md) - Current sprint section - 30 min
7. [NEXT-STEPS.md](NEXT-STEPS.md) - 30 min
8. Start coding! 🚀
### For Code Review (30 minutes)
1. [CLAUDE.md](CLAUDE.md) - Hexagonal architecture section
2. [apps/backend/README.md](apps/backend/README.md) - DOs and DON'Ts
3. [TODO.md](TODO.md) - Acceptance criteria for the feature
### For Sprint Planning (1 hour)
1. [TODO.md](TODO.md) - Next sprint tasks
2. [PRD.md](PRD.md) - Requirements for the module
3. [SPRINT-0-SUMMARY.md](SPRINT-0-SUMMARY.md) - Current status
---
## 🔍 Quick Reference
### Common Questions
**Q: How do I get started?**
A: [QUICK-START.md](QUICK-START.md)
**Q: What is hexagonal architecture?**
A: [CLAUDE.md](CLAUDE.md) - Complete guide with examples
**Q: What should I build next?**
A: [NEXT-STEPS.md](NEXT-STEPS.md) then [TODO.md](TODO.md)
**Q: How do I run tests?**
A: [apps/backend/README.md](apps/backend/README.md) or [apps/frontend/README.md](apps/frontend/README.md)
**Q: Where are the business requirements?**
A: [PRD.md](PRD.md)
**Q: What's the project status?**
A: [SPRINT-0-SUMMARY.md](SPRINT-0-SUMMARY.md)
**Q: Installation failed, what do I do?**
A: [INSTALLATION-STEPS.md](INSTALLATION-STEPS.md) - Troubleshooting section
**Q: Can I change the database/framework?**
A: Yes! That's the point of hexagonal architecture. See [CLAUDE.md](CLAUDE.md)
---
## 📞 Getting Help
If you can't find what you need:
1. **Check this index** - Use Ctrl+F to search
2. **Read CLAUDE.md** - Covers 90% of architecture questions
3. **Check TODO.md** - Has detailed task specifications
4. **Open an issue** - If documentation is unclear or missing
---
## 🎉 Happy Reading!
All documentation is up-to-date as of Sprint 0 completion.
**Quick Links**:
- 🚀 [Get Started](QUICK-START.md)
- 🏗️ [Architecture](CLAUDE.md)
- 📅 [Roadmap](TODO.md)
- 📋 [Requirements](PRD.md)
---
*Xpeditis MVP - Maritime Freight Booking Platform*
*Documentation Index - October 7, 2025*

307
README.md
View File

@ -1,206 +1,151 @@
# Xpeditis - Maritime Freight Booking Platform # Xpeditis Maritime Freight Booking Platform
**Xpeditis** is a B2B SaaS platform for freight forwarders to search, compare, and book maritime freight in real-time. Plateforme B2B SaaS permettant aux transitaires de rechercher, comparer et réserver du fret maritime en temps réel.
--- ---
## ⭐ **[START HERE](START-HERE.md)** ⭐ ## Démarrage rapide
**New to the project?** Read **[START-HERE.md](START-HERE.md)** - Get running in 10 minutes!
---
## 🚀 Quick Start
### Prerequisites
- Node.js >= 20.0.0
- npm >= 10.0.0
- Docker & Docker Compose
- PostgreSQL 15+
- Redis 7+
### Installation
```bash ```bash
# Install dependencies # 1. Installer les dépendances
npm install npm run install:all
# Start infrastructure (PostgreSQL + Redis) # 2. Démarrer l'infrastructure (PostgreSQL + Redis + MinIO)
docker-compose up -d docker-compose up -d
# Setup environment variables # 3. Configurer l'environnement
cp apps/backend/.env.example apps/backend/.env cp apps/backend/.env.example apps/backend/.env
cp apps/frontend/.env.example apps/frontend/.env cp apps/frontend/.env.example apps/frontend/.env.local
# Run database migrations # 4. Exécuter les migrations
npm run backend:migrate cd apps/backend && npm run migration:run && cd ../..
# Start backend (development) # 5. Démarrer les serveurs
npm run backend:dev npm run backend:dev # http://localhost:4000 · Swagger: /api/docs
npm run frontend:dev # http://localhost:3000
# Start frontend (development)
npm run frontend:dev
``` ```
### Access Points ---
- **Frontend**: http://localhost:3000 ## Structure du projet
- **Backend API**: http://localhost:4000
- **API Documentation**: http://localhost:4000/api/docs
## 📁 Project Structure
``` ```
xpeditis/ xpeditis/
├── apps/ ├── apps/
│ ├── backend/ # NestJS API (Hexagonal Architecture) │ ├── backend/ # NestJS 10 — Architecture hexagonale
│ │ └── src/ │ │ └── src/
│ │ ├── domain/ # Pure business logic │ │ ├── domain/ # Logique métier pure (TypeScript)
│ │ ├── application/ # Controllers & DTOs │ │ ├── application/ # Controllers, DTOs, Guards
│ │ └── infrastructure/ # External adapters │ │ └── infrastructure/ # TypeORM, Redis, S3, Email, Stripe
│ └── frontend/ # Next.js 14 App Router │ └── frontend/ # Next.js 14 App Router
├── packages/ │ ├── app/[locale]/ # Routing i18n (fr, en)
├── shared-types/ # Shared TypeScript types └── src/ # Components, hooks, lib/api
│ └── domain/ # Shared domain logic ├── docker-compose.yml # PostgreSQL 15 + Redis 7 + MinIO
└── infra/ # Infrastructure configs └── docs/ # Documentation complète
``` ```
## 🏗️ Architecture
This project follows **Hexagonal Architecture** (Ports & Adapters) principles:
- **Domain Layer**: Pure business logic, no external dependencies
- **Application Layer**: Use cases, controllers, DTOs
- **Infrastructure Layer**: Database, external APIs, cache, email, storage
See [CLAUDE.md](CLAUDE.md) for detailed architecture guidelines.
## 🛠️ Development
### Backend
```bash
npm run backend:dev # Start dev server
npm run backend:test # Run tests
npm run backend:test:watch # Run tests in watch mode
npm run backend:test:cov # Generate coverage report
npm run backend:lint # Lint code
npm run backend:build # Build for production
```
### Frontend
```bash
npm run frontend:dev # Start dev server
npm run frontend:build # Build for production
npm run frontend:test # Run tests
npm run frontend:lint # Lint code
```
## 📚 Documentation
### Getting Started
- **[QUICK-START.md](QUICK-START.md)** ⚡ - Get running in 5 minutes
- **[INSTALLATION-STEPS.md](INSTALLATION-STEPS.md)** 📦 - Detailed installation guide
- **[NEXT-STEPS.md](NEXT-STEPS.md)** 🚀 - What to do after setup
### Architecture & Guidelines
- **[CLAUDE.md](CLAUDE.md)** 🏗️ - Hexagonal architecture guidelines (complete)
- **[apps/backend/README.md](apps/backend/README.md)** - Backend documentation
- **[apps/frontend/README.md](apps/frontend/README.md)** - Frontend documentation
### Project Planning
- **[PRD.md](PRD.md)** 📋 - Product Requirements Document
- **[TODO.md](TODO.md)** 📅 - 30-week development roadmap
- **[SPRINT-0-FINAL.md](SPRINT-0-FINAL.md)** ✅ - Sprint 0 completion report
- **[SPRINT-0-SUMMARY.md](SPRINT-0-SUMMARY.md)** 📊 - Executive summary
### API Documentation
- **[API Docs](http://localhost:4000/api/docs)** 📖 - OpenAPI/Swagger (when running)
## 🧪 Testing
```bash
# Run all tests
npm run test:all
# Run backend tests
npm run backend:test
# Run frontend tests
npm run frontend:test
# E2E tests (after implementation)
npm run test:e2e
```
## 🔒 Security
- All passwords hashed with bcrypt (12 rounds minimum)
- JWT tokens (access: 15min, refresh: 7 days)
- HTTPS/TLS 1.2+ enforced
- OWASP Top 10 protection
- Rate limiting on all endpoints
- CSRF protection
## 📊 Tech Stack
### Backend
- **Framework**: NestJS 10+
- **Language**: TypeScript 5+
- **Database**: PostgreSQL 15+
- **Cache**: Redis 7+
- **ORM**: TypeORM
- **Testing**: Jest, Supertest
- **API Docs**: Swagger/OpenAPI
### Frontend
- **Framework**: Next.js 14+ (App Router)
- **Language**: TypeScript 5+
- **Styling**: Tailwind CSS
- **UI Components**: shadcn/ui
- **State**: React Query (TanStack Query)
- **Forms**: React Hook Form + Zod
- **Testing**: Jest, React Testing Library, Playwright
## 🚢 Carrier Integrations
MVP supports the following maritime carriers:
- ✅ Maersk
- ✅ MSC
- ✅ CMA CGM
- ✅ Hapag-Lloyd
- ✅ ONE (Ocean Network Express)
## 📈 Monitoring & Logging
- **Logging**: Winston / Pino
- **Error Tracking**: Sentry
- **APM**: Application Performance Monitoring
- **Metrics**: Prometheus (planned)
## 🔧 Environment Variables
See `.env.example` files in each app for required environment variables.
## 🤝 Contributing
1. Create a feature branch
2. Make your changes
3. Write tests
4. Run linting and formatting
5. Submit a pull request
## 📝 License
Proprietary - All rights reserved
## 👥 Team
Built with ❤️ by the Xpeditis team
--- ---
For detailed implementation guidelines, see [CLAUDE.md](CLAUDE.md). ## Documentation
| Sujet | Fichier |
|-------|---------|
| Index complet | [docs/README.md](docs/README.md) |
| Architecture hexagonale + conventions | [CLAUDE.md](CLAUDE.md) |
| Vue d'ensemble système | [docs/architecture/overview.md](docs/architecture/overview.md) |
| Schéma BDD (21 tables) | [docs/architecture/database.md](docs/architecture/database.md) |
| Démarrage rapide | [docs/getting-started/quick-start.md](docs/getting-started/quick-start.md) |
---
## Commandes de développement
```bash
# Backend
npm run backend:dev # Serveur avec hot-reload
npm run backend:test # Tests unitaires Jest
npm run backend:lint # ESLint
npm run backend:build # Build production
# Frontend
npm run frontend:dev # Serveur avec hot-reload
npm run frontend:test # Tests unitaires Jest
npm run frontend:lint # ESLint
cd apps/frontend && npm run test:e2e # Playwright E2E
# Qualité
npm run format # Prettier (tous les fichiers)
# Base de données
cd apps/backend
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/NomMigration
npm run migration:run
npm run migration:revert
```
---
## Stack technique
### Backend
| Composant | Technologie |
|-----------|-------------|
| Framework | NestJS 10 + TypeScript 5 (strict) |
| Base de données | PostgreSQL 15 + TypeORM |
| Cache | Redis 7 (ioredis) |
| Auth | JWT (15min) + Refresh + OAuth2 + API Keys (Argon2) |
| Temps réel | Socket.IO |
| Email | Nodemailer + MJML |
| Paiements | Stripe |
| Stockage | S3/MinIO |
| Logging | nestjs-pino |
| Monitoring | Sentry |
### Frontend
| Composant | Technologie |
|-----------|-------------|
| Framework | Next.js 14 App Router + TypeScript |
| Styling | Tailwind CSS + shadcn/ui (Radix UI) |
| State serveur | TanStack Query v5 |
| Tables | TanStack Table v8 + Virtual |
| Formulaires | react-hook-form + zod |
| Temps réel | Socket.IO client |
| i18n | next-intl (fr, en) |
| Graphiques | recharts |
---
## Carriers intégrés
| Carrier | Code | Statut |
|---------|------|--------|
| Maersk | MAEU | Connecteur API |
| MSC | MSCU | Connecteur API |
| CMA CGM | CMDU | Connecteur API |
| Hapag-Lloyd | HLCU | Connecteur API |
| ONE | ONEY | Connecteur API |
| SSC Consolidation | — | CSV |
| ECU Worldwide | — | CSV + API |
| TCC Logistics | — | CSV |
| NVO Consolidation | — | CSV |
---
## Fonctionnalités principales
- **Recherche tarifs** : FCL (carriers API + cache Redis 15min) + LCL CSV
- **Réservation standard** : workflow 4 étapes, numéro WCM-YYYY-XXXXXX
- **Réservation CSV + Portail Carrier** : magic link, accept/reject
- **Dashboard** : KPI, graphiques, table interactive virtuelle
- **Auth** : JWT, OAuth2 (Google/Microsoft), API Keys, RBAC (5 rôles)
- **Abonnements** : Stripe (FREE/BRONZE/SILVER/GOLD/PLATINIUM)
- **Notifications** : WebSocket temps réel + webhooks tiers
- **GDPR** : export/suppression des données utilisateur
- **Blog** : gestion de contenu bilingue (fr/en)
- **Audit** : journal d'audit de toutes les actions
---
*Architecture hexagonale — NestJS 10 + Next.js 14 — PostgreSQL 15 + Redis 7*

105
docs/README.md Normal file
View File

@ -0,0 +1,105 @@
# Xpeditis — Documentation
Documentation complète de la plateforme B2B SaaS de réservation de fret maritime.
---
## Démarrage rapide
| Objectif | Fichier |
|---|---|
| Démarrer en 5 minutes | [getting-started/quick-start.md](getting-started/quick-start.md) |
| Installation détaillée | [getting-started/installation.md](getting-started/installation.md) |
| Windows | [getting-started/windows.md](getting-started/windows.md) |
---
## Architecture
| Sujet | Fichier |
|---|---|
| Vue d'ensemble système | [architecture/overview.md](architecture/overview.md) |
| Schéma base de données | [architecture/database.md](architecture/database.md) |
| Backend (NestJS hexagonal) | [architecture/backend.md](architecture/backend.md) |
| Frontend (Next.js 14) | [architecture/frontend.md](architecture/frontend.md) |
---
## Fonctionnalités
| Fonctionnalité | Fichier |
|---|---|
| Recherche de tarifs (FCL + CSV) | [features/rate-search.md](features/rate-search.md) |
| Réservation standard | [features/bookings.md](features/bookings.md) |
| Réservation CSV + Portail Carrier | [features/csv-bookings.md](features/csv-bookings.md) |
| Authentification & RBAC | [features/auth.md](features/auth.md) |
| Abonnements Stripe | [features/subscriptions.md](features/subscriptions.md) |
| Notifications temps réel | [features/notifications.md](features/notifications.md) |
| Accès API (clés API) | [features/api-access.md](features/api-access.md) |
| Système CSV | [../csv-system/CSV_RATE_SYSTEM.md](../csv-system/CSV_RATE_SYSTEM.md) |
---
## Déploiement
| Sujet | Fichier |
|---|---|
| Portainer / Docker Swarm | [deployment/portainer.md](deployment/portainer.md) |
| Hetzner / Kubernetes | [deployment/hetzner/README.md](deployment/hetzner/README.md) |
| Stripe (paiements) | [deployment/STRIPE_SETUP.md](deployment/STRIPE_SETUP.md) |
---
## Tests
| Sujet | Fichier |
|---|---|
| Guide tests (unité, intégration, E2E) | [testing/TEST_EXECUTION_GUIDE.md](testing/TEST_EXECUTION_GUIDE.md) |
| Tests locaux | [testing/LOCAL_TESTING.md](testing/LOCAL_TESTING.md) |
| Tests manuels | [testing/MANUAL_TEST_INSTRUCTIONS.md](testing/MANUAL_TEST_INSTRUCTIONS.md) |
| Postman | [testing/GUIDE_TESTS_POSTMAN.md](testing/GUIDE_TESTS_POSTMAN.md) |
| Couverture | [testing/TEST_COVERAGE_REPORT.md](testing/TEST_COVERAGE_REPORT.md) |
---
## Portail Carrier
| Sujet | Fichier |
|---|---|
| Recherche API carriers | [carrier-portal/CARRIER_API_RESEARCH.md](carrier-portal/CARRIER_API_RESEARCH.md) |
| Plan d'implémentation | [carrier-portal/CARRIER_PORTAL_IMPLEMENTATION_PLAN.md](carrier-portal/CARRIER_PORTAL_IMPLEMENTATION_PLAN.md) |
---
## Archives
Les rapports de sprint et notes de debug sont archivés dans [archive/](archive/).
---
## Pour les développeurs
### Lire dans cet ordre
1. [getting-started/quick-start.md](getting-started/quick-start.md) — démarrer le projet
2. `CLAUDE.md` à la racine — **architecture hexagonale, règles et conventions**
3. [architecture/overview.md](architecture/overview.md) — vision système
4. [architecture/database.md](architecture/database.md) — schéma BDD complet
### Commandes essentielles
```bash
# Infrastructure
docker-compose up -d
# Démarrer
npm run backend:dev # http://localhost:4000 — Swagger: /api/docs
npm run frontend:dev # http://localhost:3000
# Tests
npm run backend:test
npm run frontend:test
# Migrations
cd apps/backend && npm run migration:run
```

View File

@ -0,0 +1,180 @@
# Architecture Backend — NestJS Hexagonale
---
## Structure des couches
```
apps/backend/src/
├── domain/ # Logique métier PURE — aucun import NestJS/TypeORM
│ ├── entities/ # 17 entités métier (private constructor + static create())
│ ├── value-objects/ # Objets valeur immuables (Email, Money, BookingNumber...)
│ ├── services/ # Services métier purs (csv-rate-price-calculator)
│ ├── exceptions/ # Exceptions domaine
│ └── ports/
│ ├── in/ # Interfaces use-case (execute())
│ └── out/ # Interfaces repository/SPI (token constants)
├── application/ # Couche API — dépend UNIQUEMENT du domain
│ ├── controllers/ # REST controllers (Swagger + class-validator)
│ ├── dto/ # Data Transfer Objects
│ ├── mappers/ # Domain ↔ DTO (méthodes statiques)
│ ├── guards/ # JwtAuthGuard, RolesGuard, ApiKeyOrJwtGuard
│ ├── decorators/ # @Public(), @Roles(), @CurrentUser()
│ ├── filters/ # DomainExceptionFilter
│ ├── interceptors/ # PerformanceMonitoringInterceptor
│ ├── gateways/ # WebSocket Socket.IO (notifications)
│ ├── services/ # Services applicatifs (audit, notification, export, webhooks)
│ └── [feature]/ # Modules par feature (auth, bookings, rates, etc.)
└── infrastructure/ # Adaptateurs externes — dépend UNIQUEMENT du domain
├── persistence/typeorm/
│ ├── entities/ # ORM entities (*.orm-entity.ts)
│ ├── repositories/# Implémentations TypeORM
│ ├── mappers/ # ORM ↔ Domain (static toOrm/toDomain/toDomainMany)
│ └── migrations/ # Migrations TypeORM
├── carriers/ # 5 connecteurs carriers + CSV loader
├── cache/ # Adaptateur Redis
├── email/ # MJML + Nodemailer
├── storage/ # S3/MinIO (+ csv-storage/)
├── stripe/ # Paiements et abonnements
├── external/ # Pappers (SIRET), ECU Worldwide
├── pdf/ # Génération PDF pdfkit
├── security/ # Utilitaires sécurité
└── monitoring/ # Sentry + Pino
```
---
## Entités domaine (17)
| Entité | Fichier |
|--------|---------|
| ApiKey | api-key.entity.ts |
| AuditLog | audit-log.entity.ts |
| BlogPost | blog-post.entity.ts |
| Booking | booking.entity.ts |
| Carrier | carrier.entity.ts |
| Container | container.entity.ts |
| CsvBooking | csv-booking.entity.ts |
| CsvRate | csv-rate.entity.ts |
| InvitationToken | invitation-token.entity.ts |
| License | license.entity.ts |
| Notification | notification.entity.ts |
| Organization | organization.entity.ts |
| Port | port.entity.ts |
| RateQuote | rate-quote.entity.ts |
| Subscription | subscription.entity.ts |
| User | user.entity.ts |
| Webhook | webhook.entity.ts |
---
## Pattern entité domaine
```typescript
// Private constructor + static create() factory
export class Booking {
private constructor(private readonly props: BookingProps) {}
static create(props: Omit<BookingProps, 'bookingNumber' | 'status'>): Booking {
return new Booking({
...props,
bookingNumber: BookingNumber.generate(),
status: BookingStatus.DRAFT,
});
}
// Les mutations retournent une nouvelle instance (immuabilité)
updateStatus(newStatus: BookingStatus): Booking {
return new Booking({ ...this.props, status: newStatus });
}
}
```
---
## Pattern repository
```typescript
// domain/ports/out/booking.repository.ts
export const BOOKING_REPOSITORY = 'BookingRepository';
export interface BookingRepository {
findById(id: string): Promise<Booking | null>;
save(booking: Booking): Promise<Booking>;
findByOrganization(orgId: string, filters: BookingFilters): Promise<Booking[]>;
}
// infrastructure/persistence/typeorm/repositories/typeorm-booking.repository.ts
@Injectable()
export class TypeOrmBookingRepository implements BookingRepository {
constructor(
@InjectRepository(BookingOrmEntity)
private readonly repo: Repository<BookingOrmEntity>,
) {}
// ...
}
```
---
## Conventions de nommage
| Couche | Suffix | Exemple |
|--------|--------|---------|
| Domain entity | .entity.ts | booking.entity.ts |
| Value object | .vo.ts | money.vo.ts |
| In port | .use-case.ts | create-booking.use-case.ts |
| Out port | .repository.ts | booking.repository.ts |
| ORM entity | .orm-entity.ts | booking.orm-entity.ts |
| ORM mapper | .mapper.ts | booking.mapper.ts |
| Controller | .controller.ts | bookings.controller.ts |
| DTO | .dto.ts | create-booking-request.dto.ts |
| App mapper | .mapper.ts | booking.mapper.ts |
---
## Règles critiques
- **Jamais** d'import NestJS/TypeORM dans `domain/`
- **Jamais** de type `any` dans le backend (strict mode)
- **Jamais** modifier une migration déjà appliquée
- **Toujours** valider les DTOs avec class-validator
- **Toujours** créer un mapper séparé pour ORM ↔ Domain
- `DATABASE_SYNC` est hard-codé à `false` — utiliser les migrations
---
## Modules NestJS (app.module.ts)
**Guards globaux** (toutes routes) :
- `JwtAuthGuard` — JWT obligatoire sauf routes `@Public()`
- `CustomThrottlerGuard` — rate limiting
**Feature modules** :
Auth · Rates · Ports · Bookings · CsvBookings · Organizations · Users · Dashboard · Audit · Notifications · Webhooks · GDPR · Admin · Subscriptions · ApiKeys · Blog · Logs
**Infrastructure modules** :
CacheModule · CarrierModule · SecurityModule · CsvRateModule · StripeModule · PdfModule · StorageModule · EmailModule
---
## Alias de chemins (tsconfig.json)
```json
{
"@domain/*": ["src/domain/*"],
"@application/*": ["src/application/*"],
"@infrastructure/*": ["src/infrastructure/*"]
}
```
---
## Configuration TypeScript
- `strict: true`
- `strictNullChecks: true`
- `strictPropertyInitialization: false` (exception pour ORM entities)
- `noImplicitAny: true`

View File

@ -0,0 +1,462 @@
# Schéma de base de données — Xpeditis
PostgreSQL 15 — 21 tables.
**Extensions requises** : `uuid-ossp`, `pg_trgm`
---
## Vue d'ensemble des tables
| Table | Description |
|-------|-------------|
| organizations | Organisations (transitaires, transporteurs) |
| users | Comptes utilisateurs |
| carriers | Transporteurs maritimes |
| ports | Base de données des ports (UN/LOCODE) |
| rate_quotes | Cotations de tarifs carriers |
| bookings | Réservations standard |
| containers | Conteneurs liés aux réservations |
| csv_bookings | Réservations créées via CSV |
| csv_rate_configs | Configuration des carriers CSV |
| carrier_profiles | Profils portail carrier |
| carrier_activities | Activités du portail carrier |
| audit_logs | Journal d'audit des actions |
| notifications | Notifications push (WebSocket) |
| webhooks | Configuration des webhooks tiers |
| subscriptions | Abonnements Stripe |
| licenses | Licences d'utilisation |
| api_keys | Clés API (auth alternative au JWT) |
| invitation_tokens | Tokens d'invitation utilisateur |
| password_reset_tokens | Tokens de réinitialisation mot de passe |
| cookie_consents | Consentements RGPD cookies |
| blog_posts | Articles de blog |
---
## Tables détaillées
### organizations
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| name | VARCHAR(255) | NOT NULL, UNIQUE | Nom de l'organisation |
| type | VARCHAR(50) | NOT NULL | FREIGHT_FORWARDER, CARRIER, SHIPPER |
| scac | CHAR(4) | UNIQUE, NULLABLE | Standard Carrier Alpha Code |
| address_street | VARCHAR(255) | NOT NULL | Adresse |
| address_city | VARCHAR(100) | NOT NULL | Ville |
| address_state | VARCHAR(100) | NULLABLE | État/Province |
| address_postal_code | VARCHAR(20) | NOT NULL | Code postal |
| address_country | CHAR(2) | NOT NULL | Code pays ISO 3166-1 |
| logo_url | TEXT | NULLABLE | URL du logo |
| documents | JSONB | DEFAULT '[]' | Documents compliance |
| siret | VARCHAR(20) | NULLABLE | SIRET (entreprises françaises) |
| status_badge | VARCHAR(50) | NULLABLE | Badge de statut Pappers |
| is_carrier | BOOLEAN | DEFAULT FALSE | Est un carrier (portail) |
| is_active | BOOLEAN | DEFAULT TRUE | Compte actif |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
---
### users
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations | Organisation |
| email | VARCHAR(255) | NOT NULL, UNIQUE | Email (minuscules) |
| password_hash | VARCHAR(255) | NOT NULL | Hash Argon2 |
| role | VARCHAR(50) | NOT NULL | ADMIN, MANAGER, USER, VIEWER, CARRIER |
| first_name | VARCHAR(100) | NOT NULL | Prénom |
| last_name | VARCHAR(100) | NOT NULL | Nom |
| phone_number | VARCHAR(20) | NULLABLE | Téléphone |
| is_email_verified | BOOLEAN | DEFAULT FALSE | Email vérifié |
| is_active | BOOLEAN | DEFAULT TRUE | Compte actif |
| preferred_language | VARCHAR(10) | DEFAULT 'fr' | Langue préférée (fr, en) |
| last_login_at | TIMESTAMP | NULLABLE | Dernière connexion |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
Index : `idx_users_email`, `idx_users_organization`, `idx_users_role`
---
### carriers
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| name | VARCHAR(255) | NOT NULL | Nom (ex: "Maersk") |
| code | VARCHAR(50) | NOT NULL, UNIQUE | Code (ex: "MAERSK") |
| scac | CHAR(4) | NOT NULL, UNIQUE | Standard Carrier Alpha Code |
| logo_url | TEXT | NULLABLE | URL du logo |
| website | TEXT | NULLABLE | Site web |
| api_config | JSONB | NULLABLE | Config API (credentials, timeout) |
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
| supports_api | BOOLEAN | DEFAULT FALSE | Intégration API disponible |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
Carriers seedés : Maersk (MAEU), MSC (MSCU), CMA CGM (CMDU), Hapag-Lloyd (HLCU), ONE (ONEY)
---
### ports
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| code | CHAR(5) | NOT NULL, UNIQUE | UN/LOCODE (ex: "NLRTM") |
| name | VARCHAR(255) | NOT NULL | Nom du port |
| city | VARCHAR(255) | NOT NULL | Ville |
| country | CHAR(2) | NOT NULL | Code pays |
| country_name | VARCHAR(100) | NOT NULL | Nom du pays |
| latitude | DECIMAL(9,6) | NOT NULL | Latitude |
| longitude | DECIMAL(9,6) | NOT NULL | Longitude |
| timezone | VARCHAR(50) | NULLABLE | Fuseau horaire IANA |
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
Index GIN pour recherche floue : `idx_ports_name_trgm`, `idx_ports_city_trgm`
---
### rate_quotes
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| carrier_id | UUID | FK carriers | Carrier |
| carrier_name | VARCHAR(255) | NOT NULL | Nom carrier (dénormalisé) |
| carrier_code | VARCHAR(50) | NOT NULL | Code carrier (dénormalisé) |
| origin_code | CHAR(5) | NOT NULL | Port d'origine |
| destination_code | CHAR(5) | NOT NULL | Port de destination |
| base_freight | DECIMAL(10,2) | NOT NULL | Fret de base |
| surcharges | JSONB | DEFAULT '[]' | Surcharges (BAF, CAF, etc.) |
| total_amount | DECIMAL(10,2) | NOT NULL | Prix total |
| currency | CHAR(3) | NOT NULL | Devise ISO 4217 |
| container_type | VARCHAR(20) | NOT NULL | Type conteneur (20GP, 40HC, etc.) |
| mode | VARCHAR(10) | NOT NULL | FCL ou LCL |
| etd | TIMESTAMP | NOT NULL | Départ estimé |
| eta | TIMESTAMP | NOT NULL | Arrivée estimée |
| transit_days | INTEGER | NOT NULL | Jours de transit |
| route | JSONB | NOT NULL | Escales |
| availability | INTEGER | NOT NULL | Disponibilité conteneurs |
| valid_until | TIMESTAMP | NOT NULL | Expiration (created_at + 15 min) |
---
### bookings
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| booking_number | VARCHAR(20) | NOT NULL, UNIQUE | Format WCM-YYYY-XXXXXX |
| user_id | UUID | FK users | Utilisateur créateur |
| organization_id | UUID | FK organizations | Organisation |
| rate_quote_id | UUID | FK rate_quotes, NULLABLE | Cotation source |
| carrier_id | UUID | FK carriers | Carrier |
| status | VARCHAR(50) | NOT NULL | draft, confirmed, shipped, delivered, cancelled |
| shipper | JSONB | NOT NULL | Infos expéditeur |
| consignee | JSONB | NOT NULL | Infos destinataire |
| cargo | JSONB | NULLABLE | Détails marchandise |
| notes | TEXT | NULLABLE | Notes internes |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
---
### containers
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| booking_id | UUID | FK bookings, NULLABLE | Réservation |
| type | VARCHAR(20) | NOT NULL | 20GP, 40HC, 40RF, etc. |
| category | VARCHAR(20) | NOT NULL | DRY, REEFER, OPEN_TOP, FLAT_RACK, TANK |
| container_number | VARCHAR(11) | NULLABLE, UNIQUE | ISO 6346 |
| seal_number | VARCHAR(50) | NULLABLE | Numéro de plomb |
| vgm | INTEGER | NULLABLE | Masse Brute Vérifiée (kg) |
| is_hazmat | BOOLEAN | DEFAULT FALSE | Marchandise dangereuse |
| imo_class | VARCHAR(10) | NULLABLE | Classe IMO |
| cargo_description | TEXT | NULLABLE | Description de la marchandise |
---
### csv_bookings
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations | Organisation |
| carrier_id | UUID | FK carriers, NULLABLE | Carrier assigné |
| booking_number | VARCHAR(50) | NOT NULL, UNIQUE | Numéro de réservation |
| shipper_name | VARCHAR(255) | NOT NULL | Expéditeur |
| consignee_name | VARCHAR(255) | NOT NULL | Destinataire |
| origin_port | CHAR(5) | NOT NULL | Port d'origine (UN/LOCODE) |
| destination_port | CHAR(5) | NOT NULL | Port de destination |
| container_type | VARCHAR(20) | NOT NULL | Type conteneur |
| commodity | TEXT | NULLABLE | Marchandise |
| weight_kg | DECIMAL(10,2) | NULLABLE | Poids |
| status | VARCHAR(50) | NOT NULL | pending, accepted, rejected, in_transit, delivered |
| carrier_magic_link_token | VARCHAR(255) | NULLABLE | Token lien magique carrier |
| carrier_magic_link_expires_at | TIMESTAMP | NULLABLE | Expiration du token |
| carrier_password_hash | VARCHAR(255) | NULLABLE | Hash mdp portail carrier |
| notes | TEXT | NULLABLE | Notes |
| documents | JSONB | DEFAULT '[]' | Documents joints |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
---
### csv_rate_configs
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| company_name | VARCHAR(255) | NOT NULL, UNIQUE | Nom du carrier CSV |
| csv_file_path | VARCHAR(500) | NOT NULL | Chemin fichier CSV |
| type | VARCHAR(50) | DEFAULT 'CSV_ONLY' | CSV_ONLY ou CSV_AND_API |
| has_api | BOOLEAN | DEFAULT FALSE | A une API |
| api_connector | VARCHAR(100) | NULLABLE | Identifiant du connecteur API |
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
| uploaded_at | TIMESTAMP | NOT NULL | Upload |
| uploaded_by | UUID | FK users, NULLABLE | Uploadé par |
| row_count | INTEGER | NULLABLE | Nombre de lignes |
---
### carrier_profiles
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations, UNIQUE | Organisation carrier |
| carrier_code | VARCHAR(50) | NOT NULL | Code carrier |
| contact_email | VARCHAR(255) | NOT NULL | Email de contact |
| contact_name | VARCHAR(255) | NULLABLE | Nom du contact |
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### carrier_activities
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| carrier_profile_id | UUID | FK carrier_profiles | Profil carrier |
| csv_booking_id | UUID | FK csv_bookings | Réservation CSV |
| action | VARCHAR(50) | NOT NULL | ACCEPTED, REJECTED, VIEWED, DOCUMENT_UPLOADED |
| notes | TEXT | NULLABLE | Notes de l'action |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### audit_logs
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| user_id | UUID | FK users, NULLABLE | Utilisateur |
| organization_id | UUID | FK organizations, NULLABLE | Organisation |
| action | VARCHAR(100) | NOT NULL | Type d'action (26 types) |
| resource_type | VARCHAR(50) | NULLABLE | Type de ressource |
| resource_id | VARCHAR(255) | NULLABLE | ID de la ressource |
| status | VARCHAR(20) | NOT NULL | SUCCESS, FAILURE, WARNING |
| metadata | JSONB | NULLABLE | Données supplémentaires |
| ip_address | VARCHAR(45) | NULLABLE | Adresse IP |
| user_agent | TEXT | NULLABLE | User agent |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
Index : `idx_audit_logs_user_id`, `idx_audit_logs_action`, `idx_audit_logs_created_at`
---
### notifications
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| user_id | UUID | FK users | Destinataire |
| type | VARCHAR(50) | NOT NULL | BOOKING_CREATED, DOCUMENT_UPLOADED, etc. (9 types) |
| title | VARCHAR(255) | NOT NULL | Titre |
| message | TEXT | NOT NULL | Message |
| data | JSONB | NULLABLE | Données associées |
| priority | VARCHAR(20) | NOT NULL | LOW, MEDIUM, HIGH, URGENT |
| read | BOOLEAN | DEFAULT FALSE | Lu |
| read_at | TIMESTAMP | NULLABLE | Date de lecture |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### webhooks
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations | Organisation |
| url | TEXT | NOT NULL | URL cible |
| secret | VARCHAR(255) | NOT NULL | Secret HMAC SHA-256 |
| events | JSONB | NOT NULL | Événements souscrits |
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
| last_triggered_at | TIMESTAMP | NULLABLE | Dernier déclenchement |
| failure_count | INTEGER | DEFAULT 0 | Compteur d'échecs |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### subscriptions
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations, UNIQUE | Organisation |
| stripe_customer_id | VARCHAR(255) | NULLABLE | ID client Stripe |
| stripe_subscription_id | VARCHAR(255) | NULLABLE | ID abonnement Stripe |
| plan | VARCHAR(50) | NOT NULL | FREE, BRONZE, SILVER, GOLD, PLATINIUM |
| status | VARCHAR(50) | NOT NULL | active, past_due, cancelled, trialing, pending_payment, pending_bank_transfer |
| current_period_start | TIMESTAMP | NULLABLE | Début de période |
| current_period_end | TIMESTAMP | NULLABLE | Fin de période |
| billing_interval | VARCHAR(20) | NULLABLE | monthly, yearly |
| commission_rate | DECIMAL(5,4) | DEFAULT 0 | Taux de commission Xpeditis |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
---
### licenses
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations | Organisation |
| feature | VARCHAR(100) | NOT NULL | Fonctionnalité activée |
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
| valid_until | TIMESTAMP | NULLABLE | Expiration |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### api_keys
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations | Organisation |
| user_id | UUID | FK users | Créateur |
| name | VARCHAR(255) | NOT NULL | Nom de la clé |
| key_hash | VARCHAR(255) | NOT NULL | Hash Argon2 de la clé |
| key_prefix | VARCHAR(10) | NOT NULL | Préfixe visible (ex: xped_) |
| last_used_at | TIMESTAMP | NULLABLE | Dernière utilisation |
| expires_at | TIMESTAMP | NULLABLE | Expiration |
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### invitation_tokens
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| organization_id | UUID | FK organizations | Organisation |
| email | VARCHAR(255) | NOT NULL | Email invité |
| token | VARCHAR(255) | NOT NULL, UNIQUE | Token d'invitation |
| role | VARCHAR(50) | NOT NULL | Rôle assigné |
| expires_at | TIMESTAMP | NOT NULL | Expiration (24h) |
| used_at | TIMESTAMP | NULLABLE | Utilisé le |
| created_by | UUID | FK users | Créateur |
---
### password_reset_tokens
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| user_id | UUID | FK users | Utilisateur |
| token | VARCHAR(255) | NOT NULL, UNIQUE | Token de réinitialisation |
| expires_at | TIMESTAMP | NOT NULL | Expiration (1h) |
| used_at | TIMESTAMP | NULLABLE | Utilisé le |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### cookie_consents
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| user_id | UUID | FK users, NULLABLE | Utilisateur (si connecté) |
| session_id | VARCHAR(255) | NULLABLE | Session anonyme |
| analytics | BOOLEAN | NOT NULL | Consentement analytics |
| marketing | BOOLEAN | NOT NULL | Consentement marketing |
| ip_address | VARCHAR(45) | NULLABLE | IP |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
---
### blog_posts
| Colonne | Type | Contraintes | Description |
|---------|------|-------------|-------------|
| id | UUID | PK | Identifiant |
| slug | VARCHAR(255) | NOT NULL, UNIQUE | Slug URL |
| title_fr | VARCHAR(500) | NOT NULL | Titre en français |
| title_en | VARCHAR(500) | NULLABLE | Titre en anglais |
| content_fr | TEXT | NOT NULL | Contenu en français |
| content_en | TEXT | NULLABLE | Contenu en anglais |
| excerpt_fr | TEXT | NULLABLE | Extrait français |
| excerpt_en | TEXT | NULLABLE | Extrait anglais |
| cover_image_url | TEXT | NULLABLE | Image de couverture |
| author_id | UUID | FK users | Auteur |
| is_published | BOOLEAN | DEFAULT FALSE | Publié |
| published_at | TIMESTAMP | NULLABLE | Date de publication |
| tags | JSONB | DEFAULT '[]' | Tags |
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
---
## Relations principales
```
organizations 1──* users
organizations 1──1 subscriptions
organizations 1──* licenses
organizations 1──* api_keys
organizations 1──* webhooks
organizations 1──* bookings
organizations 1──* csv_bookings
organizations 1──1 carrier_profiles
users 1──* bookings
users 1──* audit_logs
users 1──* notifications
users 1──* api_keys
bookings 1──* containers
bookings 1──1 rate_quotes (optionnel)
csv_bookings 1──* carrier_activities (via carrier_profiles)
carrier_profiles 1──* carrier_activities
```
---
## Stratégie de migrations
Les migrations sont dans `apps/backend/src/infrastructure/persistence/typeorm/migrations/`.
Ne jamais modifier une migration déjà appliquée — créer une nouvelle migration.
```bash
cd apps/backend
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/NomMigration
npm run migration:run
```
---
*Dernière mise à jour : Mai 2026 — 21 tables*

View File

@ -0,0 +1,157 @@
# Architecture Frontend — Next.js 14
---
## Structure
```
apps/frontend/
├── app/ # Next.js App Router
│ ├── [locale]/ # i18n wrapper (fr, en) — next-intl
│ │ ├── about/
│ │ ├── blog/
│ │ ├── booking/ # Flux de réservation
│ │ ├── careers/
│ │ ├── carrier/ # Portail carrier (magic link)
│ │ ├── compliance/
│ │ ├── contact/
│ │ ├── dashboard/ # Application protégée
│ │ │ ├── bookings/
│ │ │ ├── csv-bookings/
│ │ │ ├── search/
│ │ │ ├── settings/
│ │ │ ├── admin/
│ │ │ └── wiki/
│ │ ├── docs/
│ │ ├── forgot-password/
│ │ ├── login/
│ │ ├── pricing/
│ │ ├── register/
│ │ ├── reset-password/
│ │ └── verify-email/
│ └── api/v1/ # API routes Next.js (proxy)
├── src/
│ ├── components/ # Composants React
│ │ ├── admin/
│ │ ├── blog/
│ │ ├── bookings/
│ │ ├── docs/
│ │ ├── layout/
│ │ ├── organization/
│ │ ├── rate-search/
│ │ └── ui/ # Composants shadcn/ui (Radix UI)
│ ├── hooks/ # Custom hooks (TanStack Query)
│ ├── lib/
│ │ ├── api/ # Client fetch avec auto-refresh JWT
│ │ │ ├── client.ts # get/post/patch/del/upload/download
│ │ │ ├── auth.ts
│ │ │ ├── bookings.ts
│ │ │ ├── rates.ts
│ │ │ └── ...
│ │ ├── context/ # AuthContext, CookieContext
│ │ └── providers/ # QueryProvider (TanStack Query)
│ ├── types/ # Types TypeScript
│ └── utils/ # Export Excel, PDF
├── i18n/ # Config next-intl
├── messages/
│ ├── fr.json # Traductions français
│ └── en.json # Traductions anglais
└── middleware.ts # Auth + i18n routing
```
---
## i18n (Internationalisation)
Le frontend supporte **français** (par défaut) et **anglais** via `next-intl`.
Routes : `/fr/login`, `/en/login`, etc.
```typescript
// i18n/routing.ts
export const routing = defineRouting({
locales: ['fr', 'en'],
defaultLocale: 'fr',
});
```
Le middleware `middleware.ts` combine la protection d'auth **et** le routing i18n.
---
## Client API
`src/lib/api/client.ts` — wrapper fetch avec auto-refresh JWT :
```typescript
// Toutes les requêtes passent par ces fonctions
export const get = <T>(url: string): Promise<T>
export const post = <T>(url: string, body: unknown): Promise<T>
export const patch = <T>(url: string, body: unknown): Promise<T>
export const del = <T>(url: string): Promise<T>
export const upload = <T>(url: string, formData: FormData): Promise<T>
export const download = (url: string): Promise<Blob>
```
- Sur 401 : refresh automatique du token, retry de la requête
- Tokens : localStorage ET cookie `accessToken` (pour le middleware Next.js)
---
## State management
- **Données serveur** : TanStack Query v5 (`@tanstack/react-query`)
- **État global UI** : zustand (minimal)
- **Formulaires** : react-hook-form + zod
```typescript
// Pattern hook standard
export function useBookings(filters?: BookingFilters) {
return useQuery({
queryKey: ['bookings', filters],
queryFn: () => bookingsApi.list(filters),
});
}
```
---
## Protection des routes
`middleware.ts` vérifie le cookie `accessToken` avant chaque route.
**Routes publiques exactes** : `/fr`, `/en`, `/`
**Routes publiques par préfixe** :
`/login`, `/register`, `/forgot-password`, `/reset-password`, `/verify-email`,
`/about`, `/blog`, `/pricing`, `/contact`, `/careers`, `/press`, `/security`,
`/privacy`, `/terms`, `/cookies`, `/compliance`, `/carrier`
Toutes les autres routes → redirection `/login?redirect=<pathname>`
---
## Design system
| Élément | Valeur |
|---------|--------|
| Couleur primaire | Navy `#10183A` |
| Couleur accent | Turquoise `#34CCCD` |
| Succès | Green `#067224` |
| Fond neutre | Gray `#F2F2F2` |
| Font headings | Manrope |
| Font body | Montserrat |
| UI components | shadcn/ui (Radix UI) |
| Icônes | lucide-react |
---
## Conventions
- Pas de fetch direct — toujours via `src/lib/api/*.ts`
- Les hooks wrappent TanStack Query, pas de `useEffect` pour les données
- `strict: false` en frontend (contrairement au backend)
- Alias `@/*``./src/*`
- La landing page est en **français**

View File

@ -0,0 +1,215 @@
# Architecture — Xpeditis
**Xpeditis** est une plateforme B2B SaaS de réservation de fret maritime, construite en monorepo avec une architecture hexagonale stricte côté backend.
---
## Vue d'ensemble système
```
┌─────────────────────────────────────────────────────────────┐
│ Frontend (Next.js 14 + App Router) │
│ React 18 · TanStack Query · Socket.IO · next-intl (i18n) │
└──────────────────────────┬──────────────────────────────────┘
│ HTTPS / WSS
┌──────────────────────────▼──────────────────────────────────┐
│ Backend (NestJS 10) │
│ JWT Auth · Rate Limiting · Swagger OpenAPI │
└────┬──────────┬──────────┬──────────┬──────────┬────────────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
Rates Bookings Users Carriers CSV System
Service Service Service Service Service
│ │ │ │ │
└──────────┴──────────┴──────────┴──────────┘
┌──────────────────┼──────────────────┐
▼ ▼ ▼
PostgreSQL 15 Redis 7 MinIO (S3)
(données) (cache 15min) (documents)
```
---
## Architecture hexagonale (backend)
```
apps/backend/src/
├── domain/ # Logique métier pure — zéro dépendance framework
│ ├── entities/ # 17 entités métier
│ ├── value-objects/ # Objets valeur immuables
│ ├── services/ # Services métier purs
│ ├── ports/in/ # Interfaces use-case (execute())
│ └── ports/out/ # Interfaces repository/SPI
├── application/ # Controllers, DTOs, Guards
│ ├── controllers/ # REST controllers avec Swagger
│ ├── dto/ # DTOs class-validator
│ ├── mappers/ # Domain ↔ DTO
│ ├── guards/ # JwtAuthGuard, RolesGuard, ApiKeyGuard
│ ├── gateways/ # WebSocket (Socket.IO)
│ └── services/ # Services applicatifs (audit, notification)
└── infrastructure/ # Adaptateurs externes
├── persistence/ # TypeORM (entities, repositories, mappers, migrations)
├── carriers/ # Connecteurs carriers + CSV loader
├── cache/ # Adaptateur Redis
├── email/ # MJML + Nodemailer
├── storage/ # S3/MinIO + CSV storage
├── stripe/ # Abonnements et paiements
├── external/ # Pappers (SIRET)
├── pdf/ # Génération PDF (pdfkit)
└── monitoring/ # Sentry, logging Pino
```
**Règles de dépendance** :
- Domain : aucune dépendance externe (TypeScript pur)
- Application : dépend uniquement du domain
- Infrastructure : dépend uniquement du domain
- Le flux de dépendances pointe toujours vers le centre
---
## Stack technique
### Backend
| Composant | Technologie |
|-----------|-------------|
| Framework | NestJS 10.x |
| Langage | TypeScript 5.3+ strict |
| ORM | TypeORM 0.3.x |
| Base de données | PostgreSQL 15+ |
| Cache | Redis 7+ (ioredis) |
| Auth | JWT (15min) + Refresh tokens (7j) + OAuth2 |
| Auth alternative | API Keys (Argon2 hash) |
| WebSocket | Socket.IO |
| Email | Nodemailer + MJML templates |
| PDF | pdfkit |
| Paiements | Stripe |
| Stockage fichiers | S3 / MinIO |
| Validation | class-validator + class-transformer |
| Docs API | Swagger/OpenAPI |
| Logging | nestjs-pino (pino-pretty dev) |
| Monitoring | Sentry |
| i18n | nestjs-i18n |
| Circuit breaker | opossum (5s timeout carriers) |
### Frontend
| Composant | Technologie |
|-----------|-------------|
| Framework | Next.js 14 (App Router) |
| Langage | TypeScript |
| Styling | Tailwind CSS |
| State serveur | TanStack Query v5 |
| Tables | TanStack Table v8 + Virtual |
| Formulaires | react-hook-form + zod |
| Temps réel | Socket.IO client |
| Graphiques | recharts |
| Cartes | react-leaflet |
| i18n | next-intl (fr, en) |
| Éditeur riche | Tiptap |
| État global | zustand |
| Animations | framer-motion |
---
## Modules NestJS
**Guards globaux** : `JwtAuthGuard` (toutes les routes protégées par défaut), `CustomThrottlerGuard`
**Feature modules** :
- Auth, Rates, Ports, Bookings, CsvBookings, Organizations, Users
- Dashboard, Audit, Notifications, Webhooks, GDPR, Admin
- Subscriptions, ApiKeys, Blog, Logs
**Infrastructure modules** :
- CacheModule (Redis), CarrierModule, SecurityModule
- CsvRateModule, StripeModule, PdfModule, StorageModule, EmailModule
---
## Flux clés
### Recherche de tarifs (FCL)
```
POST /api/v1/rates/search
→ Vérification cache Redis (TTL 15min)
→ Si cache miss : appel parallel carriers API (5s timeout + circuit breaker)
→ Normalisation résultats → stockage Redis
→ Réponse JSON paginée
```
### Réservation standard
```
POST /api/v1/bookings
→ Validation DTO → Génération WCM-YYYY-XXXXXX
→ Persistance PostgreSQL
→ Audit log
→ Notification WebSocket
→ Déclenchement webhooks
→ Email confirmation (MJML)
→ PDF booking
```
### Portail Carrier (CSV Bookings)
```
Admin crée CSV booking → assigne carrier
→ Email magic link (1h expiry)
→ Carrier s'authentifie via token
→ Accept/Reject → Activité logguée
```
### Abonnements
```
Stripe webhook → /api/v1/subscriptions/webhook
→ Vérification signature HMAC
→ Mise à jour subscription + license
```
---
## Sécurité
| Mesure | Implémentation |
|--------|---------------|
| Rate limiting | 100 req/min global, 5/min auth, 30/min search |
| Password hashing | Argon2id |
| JWT | Access 15min + Refresh 7j avec rotation |
| API Keys | Argon2 hash, préfixe xped_ |
| Brute force | Exponential backoff après 3 échecs |
| Headers sécurité | Helmet.js (CSP, HSTS, XSS) |
| Validation | class-validator sur tous les DTOs |
| RBAC | 5 rôles : ADMIN, MANAGER, USER, VIEWER, CARRIER |
| CORS | Origines strictes |
| Upload fichiers | Validation MIME, max 10MB |
| GDPR | Export/suppression données utilisateur |
---
## Performances
- Recherche tarifs (avec cache) : < 2s (p90) ~500ms observé
- Création booking : < 3s ~1s observé
- Dashboard (5k bookings) : < 1s
- Cache hit ratio cible : > 90%
---
## Déploiement
L'application est containerisée (Dockerfile dans chaque app).
- **Développement** : docker-compose (PostgreSQL + Redis + MinIO)
- **Production** : Portainer / Docker Swarm ou Kubernetes (Hetzner)
- **CI/CD** : GitHub Actions (`.github/workflows/`)
Voir [../deployment/portainer.md](../deployment/portainer.md) et [../deployment/hetzner/README.md](../deployment/hetzner/README.md).
---
*Dernière mise à jour : Mai 2026*

16
docs/archive/README.md Normal file
View File

@ -0,0 +1,16 @@
# Archives
Ce dossier contient les documents historiques qui ne sont plus actifs mais conservés pour référence.
## Contenu
| Dossier | Description |
|---------|-------------|
| phases/ | Rapports de sprint (Sprint 0, Phase 1-4) — projet terminé |
| debug/ | Notes de debugging résolues |
| installation/ | Anciens guides d'installation (remplacés par docs/getting-started/) |
| portainer/ | 24 fichiers de debug/fix Portainer — consolidés dans docs/deployment/portainer.md |
## Note
La documentation active et à jour se trouve dans [../](../README.md).

View File

@ -0,0 +1,248 @@
# Déploiement Portainer / Docker Swarm
Guide de déploiement de Xpeditis sur Portainer avec Docker Swarm.
---
## Infrastructure
| Composant | Image | Registry |
|-----------|-------|----------|
| Backend NestJS | xpeditis-backend | rg.fr-par.scw.cloud/weworkstudio |
| Frontend Next.js | xpeditis-frontend | rg.fr-par.scw.cloud/weworkstudio |
| PostgreSQL 15 | postgres:15-alpine | Docker Hub |
| Redis 7 | redis:7-alpine | Docker Hub |
| MinIO | minio/minio | Docker Hub |
**Registry** : Scaleway Container Registry (fr-par)
**Portainer** : https://portainer.weworkstudio.com
---
## Prérequis
### 1. Configurer le registry Scaleway dans Portainer
**Portainer → Registries → Add registry** :
- Registry URL : `rg.fr-par.scw.cloud/weworkstudio`
- Username : `nologin`
- Password : token Scaleway (Console → Registry → Push/Pull credentials)
### 2. Créer le réseau Traefik
```bash
docker network create traefik_network
```
### 3. Vérifier que les images existent
```bash
docker manifest inspect rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod
docker manifest inspect rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod
```
---
## Build et push des images
### Script de déploiement complet
```bash
# Build et push backend (supporte AMD64 + ARM64)
cd apps/backend
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod \
--push .
# Build et push frontend
cd ../frontend
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod \
--push .
```
> Pour ARM64 seul (serveur Hetzner CAX) : `--platform linux/arm64`
---
## Déploiement dans Portainer
1. **Portainer → Stacks → Add stack**
2. **Name** : `xpeditis-preprod`
3. **Build method** : Web editor
4. Coller le contenu de `docker/portainer-stack.yml`
5. Définir les variables d'environnement (voir section suivante)
6. **Deploy the stack**
---
## Variables d'environnement production
### Backend
```bash
NODE_ENV=production
PORT=4000
API_PREFIX=api/v1
FRONTEND_URL=https://app.xpeditis.com
# Base de données
DATABASE_HOST=xpeditis-db
DATABASE_PORT=5432
DATABASE_USER=xpeditis
DATABASE_PASSWORD=CHANGER_EN_PROD
DATABASE_NAME=xpeditis_prod
DATABASE_SYNC=false
DATABASE_LOGGING=false
# Redis
REDIS_HOST=xpeditis-redis
REDIS_PORT=6379
REDIS_PASSWORD=CHANGER_EN_PROD
# JWT
JWT_SECRET=MINIMUM_32_CARACTERES_ALEATOIRES
JWT_ACCESS_EXPIRATION=15m
JWT_REFRESH_EXPIRATION=7d
# Email
SMTP_HOST=smtp-relay.brevo.com
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
SMTP_FROM=noreply@xpeditis.com
# Storage (MinIO en prod ou S3)
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
AWS_REGION=us-east-1
AWS_S3_ENDPOINT=http://xpeditis-minio:9000
# Swagger
SWAGGER_USERNAME=admin
SWAGGER_PASSWORD=CHANGER_EN_PROD
# Stripe
STRIPE_SECRET_KEY=sk_live_xxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxx
STRIPE_SILVER_MONTHLY_PRICE_ID=price_xxxx
# ... autres price IDs
# Monitoring
SENTRY_DSN=
```
### Frontend
```bash
NEXT_PUBLIC_API_URL=https://api.xpeditis.com
```
---
## Migrations automatiques
Le backend exécute les migrations automatiquement au démarrage via le script `docker-entrypoint.sh` :
```bash
# apps/backend/docker-entrypoint.sh attend PostgreSQL puis :
npm run migration:run
node dist/main.js
```
Les logs Portainer affichent :
```
✅ PostgreSQL is ready
✅ Successfully ran N migration(s)
🚀 Xpeditis API Server Running
```
---
## Vérifier le déploiement
```bash
# Depuis Portainer → Containers → xpeditis-backend → Logs
# Ou en SSH sur le serveur :
docker logs xpeditis-backend --tail 50 -f
# Tester les endpoints
curl https://api.xpeditis.com/api/v1/health
# → {"status":"ok"}
curl https://app.xpeditis.com
# → 200 OK
```
---
## Problèmes courants
### CSS manquant en production (Next.js)
Vérifier que la variable `NEXT_PUBLIC_API_URL` est définie **au moment du build** (pas au runtime).
Solution : passer la variable en ARG dans le Dockerfile frontend ou utiliser `--build-arg`.
### 404 sur routes Next.js
Le frontend Next.js est configuré en mode `standalone`. Vérifier que le serveur pointe bien sur `server.js` et non sur un fichier statique.
Si Traefik retourne 404 :
```yaml
# Dans portainer-stack.yml, vérifier le label Traefik :
traefik.http.routers.frontend.rule=Host(`app.xpeditis.com`)
traefik.http.services.frontend.loadbalancer.server.port=3000
```
### Migrations échouent
```bash
docker exec -it xpeditis-backend sh
cd /app && npm run migration:run
```
Si blocage : vérifier que PostgreSQL est accessible (`DATABASE_HOST` = nom du service Docker).
### Registry pull échoue (401)
1. Vérifier le token Scaleway (peut expirer)
2. Portainer → Registries → rafraîchir les credentials
3. `docker login rg.fr-par.scw.cloud/weworkstudio`
### ARM64 / multi-architecture
Les Dockerfiles sont compatibles AMD64 et ARM64. Si le build échoue sur ARM64 :
- Vérifier que `buildx` est installé et activé
- Utiliser le builder multi-platform : `docker buildx create --use`
---
## CI/CD GitHub Actions
Le workflow `.github/workflows/ci.yml` exécute en automatique :
1. Lint + type-check
2. Tests unitaires (backend + frontend)
3. Build des images Docker
4. Push vers registry Scaleway (sur merge vers `main` ou `preprod`)
Variables GitHub Actions requises (Settings → Secrets) :
```
SCALEWAY_REGISTRY_TOKEN
PORTAINER_URL
PORTAINER_API_KEY
PORTAINER_STACK_ID
```
---
## Coûts d'infrastructure estimés
| Option | Coût/mois | Notes |
|--------|-----------|-------|
| Hetzner CAX21 (ARM64) | ~8€ | Recommandé pour preprod |
| Hetzner CX31 (AMD64) | ~12€ | Production |
| Scaleway Registry | Gratuit | Jusqu'à 1GB |
Voir [../deployment/hetzner/README.md](hetzner/README.md) pour le déploiement Kubernetes sur Hetzner.

View File

@ -0,0 +1,71 @@
# Accès API via clés API
---
## Vue d'ensemble
En plus du JWT, Xpeditis supporte l'authentification par **clé API** pour les intégrations tierces.
---
## Format
```
Header: x-api-key: xped_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
Le préfixe `xped_` est toujours visible. Le reste est une chaîne aléatoire sécurisée.
La clé complète est hashée avec Argon2 — impossible de la retrouver après création.
---
## Gestion des clés
| Méthode | Route | Description |
|---------|-------|-------------|
| GET | /api/v1/api-keys | Liste les clés de l'organisation |
| POST | /api/v1/api-keys | Créer une nouvelle clé |
| PATCH | /api/v1/api-keys/:id | Renommer / désactiver |
| DELETE | /api/v1/api-keys/:id | Supprimer |
### Créer une clé
```
POST /api/v1/api-keys
Authorization: Bearer <jwt>
{ "name": "Integration ERP" }
```
Réponse (unique — la clé complète n'est retournée qu'une seule fois) :
```json
{
"id": "uuid",
"name": "Integration ERP",
"key": "xped_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"keyPrefix": "xped_xxxx",
"createdAt": "2026-05-13T10:00:00Z"
}
```
---
## Permissions
Les clés API héritent des permissions de l'organisation. Elles ne peuvent pas avoir plus de droits que le compte utilisateur qui les a créées.
---
## Sécurité
- Stockage : hash Argon2 uniquement (pas de récupération possible)
- Expiration : configurable (`expires_at`, null = pas d'expiration)
- Révocation immédiate : `DELETE /api/v1/api-keys/:id`
- Suivi : `last_used_at` mis à jour à chaque utilisation
---
## Endpoints supportant les clés API
Tous les endpoints protégés acceptent soit un JWT soit une clé API.
Voir `apps/backend/src/application/guards/api-key-or-jwt.guard.ts` pour l'implémentation.

140
docs/features/auth.md Normal file
View File

@ -0,0 +1,140 @@
# Authentification & Autorisation
---
## Mécanismes d'authentification
### 1. JWT (principal)
- **Access token** : 15 minutes, signé avec `JWT_SECRET`
- **Refresh token** : 7 jours, rotation automatique
- **Stockage frontend** : localStorage + cookie `accessToken` (pour le middleware Next.js)
#### Flow login
```
POST /api/v1/auth/login
{ email, password }
→ Vérification hash Argon2
→ Brute-force check (3 échecs → backoff exponentiel)
→ Retourne { accessToken, refreshToken, user }
```
#### Refresh
```
POST /api/v1/auth/refresh
{ refreshToken }
→ Nouveau accessToken + refreshToken (rotation)
```
### 2. OAuth2
- **Google** : `GET /api/v1/auth/google` → callback `GOOGLE_CALLBACK_URL`
- **Microsoft** : `GET /api/v1/auth/microsoft` → callback `MICROSOFT_CALLBACK_URL`
Configuration dans `.env` :
```bash
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
MICROSOFT_CLIENT_ID=...
MICROSOFT_CLIENT_SECRET=...
```
### 3. API Keys
Authentification alternative au JWT pour intégrations tierces.
```
Header: x-api-key: xped_xxxxxxxxxxxxxxxx
```
Gestion via `GET/POST /api/v1/api-keys`. Les clés sont hashées avec Argon2 — seul le préfixe est stocké en clair.
---
## RBAC — Rôles et permissions
| Rôle | Description | Accès |
|------|-------------|-------|
| ADMIN | Administrateur de l'organisation | Tout |
| MANAGER | Gestionnaire | Bookings, dashboard, utilisateurs (no admin) |
| USER | Utilisateur standard | Recherche, création bookings |
| VIEWER | Lecture seule | Dashboard, liste bookings |
| CARRIER | Portail carrier | Accepter/rejeter CSV bookings assignés |
### Décorateurs
```typescript
@Roles('ADMIN', 'MANAGER') // Restreindre à des rôles
@Public() // Route publique (pas de JWT requis)
@CurrentUser() // Injecter l'utilisateur courant
```
---
## Vérification email
```
POST /api/v1/auth/register
→ Email de vérification envoyé (token 24h)
POST /api/v1/auth/verify-email?token=xxx
→ Marque l'email comme vérifié
```
---
## Réinitialisation de mot de passe
```
POST /api/v1/auth/forgot-password { email }
→ Email avec token (1h, table password_reset_tokens)
POST /api/v1/auth/reset-password { token, newPassword }
→ Nouveau mot de passe hashé Argon2
```
---
## Invitations
Les admins peuvent inviter des utilisateurs dans leur organisation :
```
POST /api/v1/invitations { email, role }
→ Email d'invitation avec token (24h, table invitation_tokens)
GET /api/v1/invitations/accept?token=xxx
→ Crée l'utilisateur avec le rôle assigné
```
---
## Protection des routes (middleware Next.js)
`apps/frontend/middleware.ts` vérifie le cookie `accessToken` avant chaque requête.
**Routes publiques** (pas de redirection) :
- Exactes : `/`, pages légales
- Par préfixe : `/login`, `/register`, `/carrier`, `/about`, `/blog`, `/pricing`, etc.
Toutes les autres routes redirigent vers `/login?redirect=<pathname>`.
---
## Variables d'environnement
```bash
JWT_SECRET=your-super-secret-jwt-key
JWT_ACCESS_EXPIRATION=15m
JWT_REFRESH_EXPIRATION=7d
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_CALLBACK_URL=http://localhost:4000/api/v1/auth/google/callback
MICROSOFT_CLIENT_ID=
MICROSOFT_CLIENT_SECRET=
MICROSOFT_CALLBACK_URL=http://localhost:4000/api/v1/auth/microsoft/callback
BCRYPT_ROUNDS=12
SESSION_TIMEOUT_MS=7200000
```

109
docs/features/bookings.md Normal file
View File

@ -0,0 +1,109 @@
# Réservations standard
---
## Workflow de réservation (4 étapes max)
```
1. Sélection de l'offre (vérification dispo temps réel)
2. Informations expéditeur / destinataire
3. Détails conteneur
4. Confirmation + CGU → Génération booking number
```
---
## Numéro de réservation
Format : `WCM-YYYY-XXXXXX` (XXXXXX = 6 caractères alphanumériques uniques)
Exemple : `WCM-2026-A3F7K2`
---
## Statuts
| Statut | Description |
|--------|-------------|
| draft | Brouillon (en cours de création) |
| confirmed | Confirmé |
| shipped | En transit |
| delivered | Livré |
| cancelled | Annulé |
---
## API
| Méthode | Route | Description |
|---------|-------|-------------|
| GET | /api/v1/bookings | Liste (paginée, filtrable) |
| POST | /api/v1/bookings | Créer une réservation |
| GET | /api/v1/bookings/:id | Détail |
| PATCH | /api/v1/bookings/:id | Mettre à jour |
| DELETE | /api/v1/bookings/:id | Annuler |
| GET | /api/v1/bookings/:id/pdf | Générer PDF |
| POST | /api/v1/bookings/export | Export Excel/PDF |
### Exemple création
```
POST /api/v1/bookings
Authorization: Bearer <token>
{
"rateQuoteId": "uuid-de-la-cotation",
"shipper": {
"name": "Acme Corp",
"address": "123 Main St",
"country": "FR"
},
"consignee": {
"name": "Shanghai Trading",
"address": "456 Nanjing Rd",
"country": "CN"
},
"containers": [
{
"type": "40HC",
"cargoDescription": "Electronic components",
"isHazmat": false
}
],
"notes": "Fragile cargo"
}
```
---
## Post-booking automatique
Après création d'une réservation :
1. **Audit log** — action `BOOKING_CREATED`
2. **Notification WebSocket** — push en temps réel
3. **Webhooks** — événement `BOOKING_CREATED` envoyé aux abonnés
4. **Email confirmation** — template MJML
5. **PDF** — généré via pdfkit, stocké sur MinIO
---
## Filtres disponibles
```
GET /api/v1/bookings?status=confirmed&carrierId=xxx&page=1&limit=20
&startDate=2026-01-01&endDate=2026-12-31
&search=WCM-2026 (recherche floue sur numéro, expéditeur, destinataire)
```
---
## Dashboard
Le dashboard agrège :
- KPI cards : bookings/mois, TEUs, montant total
- Graphiques 6 mois (recharts)
- Alertes (retards, confirmations en attente)
- Table interactive avec TanStack Table (tri, filtres, pagination, virtual scroll)
Endpoint : `GET /api/v1/dashboard/stats`

View File

@ -0,0 +1,116 @@
# Réservations CSV & Portail Carrier
---
## Vue d'ensemble
Le système de réservation CSV permet aux admins de créer des réservations en important des fichiers CSV et d'envoyer automatiquement un **lien magique** aux transporteurs pour qu'ils acceptent ou rejettent via un portail dédié.
---
## Workflow complet
```
1. Admin upload CSV → création csv_bookings
2. Admin assigne un carrier à la réservation
3. Système envoie email avec magic link (expiry 1h)
4. Carrier clique → authentification automatique (token URL)
5. Carrier voit les détails → Accept ou Reject
6. Activité logguée dans carrier_activities
7. Admin voit le statut mis à jour en dashboard
```
---
## API — Réservations CSV (Admin)
| Méthode | Route | Description |
|---------|-------|-------------|
| GET | /api/v1/csv-bookings | Liste des réservations CSV |
| POST | /api/v1/csv-bookings | Créer une réservation CSV |
| GET | /api/v1/csv-bookings/:id | Détail d'une réservation |
| PATCH | /api/v1/csv-bookings/:id | Mettre à jour |
| DELETE | /api/v1/csv-bookings/:id | Supprimer |
| POST | /api/v1/csv-bookings/:id/assign-carrier | Assigner un carrier |
| POST | /api/v1/csv-bookings/:id/send-magic-link | Envoyer le lien magique |
---
## API — Portail Carrier
| Méthode | Route | Description |
|---------|-------|-------------|
| GET | /api/v1/carrier/auth | Auth via magic link token |
| GET | /api/v1/carrier/booking | Voir la réservation assignée |
| POST | /api/v1/carrier/booking/accept | Accepter |
| POST | /api/v1/carrier/booking/reject | Rejeter |
| POST | /api/v1/carrier/booking/documents | Uploader des documents |
### Authentification portail carrier
Le lien magique contient un token unique :
```
https://app.xpeditis.com/carrier/auth?token=xxxxxxxx
```
Le token est stocké dans `csv_bookings.carrier_magic_link_token` (hashé).
Expiry : 1 heure. Si expiré, l'admin doit renvoyer un nouveau lien.
---
## Statuts des réservations CSV
| Statut | Description |
|--------|-------------|
| pending | En attente d'assignation carrier |
| sent | Lien magique envoyé au carrier |
| accepted | Carrier a accepté |
| rejected | Carrier a refusé |
| in_transit | En cours de transport |
| delivered | Livré |
---
## Pages frontend
| Route | Description |
|-------|-------------|
| /dashboard/csv-bookings | Liste admin des réservations CSV |
| /carrier/auth | Page d'auth carrier (via magic link) |
| /carrier/booking | Dashboard carrier (accept/reject) |
| /carrier/documents | Upload documents carrier |
---
## Import CSV (upload admin)
Le fichier CSV peut être uploadé via `POST /api/v1/admin/csv-rates/upload`.
Format des colonnes requis : voir [../csv-system/CSV_RATE_SYSTEM.md](../csv-system/CSV_RATE_SYSTEM.md).
---
## Profils carrier
Les carriers qui utilisent le portail ont un `CarrierProfile` lié à leur `Organization`.
Chaque action (accept, reject, document upload) est tracée dans `carrier_activities`.
```sql
SELECT ca.action, ca.created_at, cb.booking_number
FROM carrier_activities ca
JOIN csv_bookings cb ON cb.id = ca.csv_booking_id
WHERE ca.carrier_profile_id = 'xxx'
ORDER BY ca.created_at DESC;
```
---
## Email magic link
Template MJML dans `apps/backend/src/infrastructure/email/templates/`.
Variables disponibles :
- `bookingNumber` — numéro de réservation
- `magicLink` — URL avec token
- `expiresIn` — durée de validité ("1 heure")
- `carrierName` — nom du carrier

View File

@ -0,0 +1,112 @@
# Notifications temps réel & Webhooks
---
## Notifications WebSocket
### Architecture
```
Événement serveur → NotificationService → Création en base (notifications)
NotificationsGateway (Socket.IO)
Émission vers la room userId
Client reçoit l'événement 'notification'
```
### Connexion depuis le frontend
Le hook `useNotifications` gère la connexion Socket.IO :
```typescript
// Connexion avec JWT dans le handshake
const socket = io(API_URL, {
auth: { token: accessToken }
});
socket.on('notification', (notification) => { /* ... */ });
```
### Types de notifications
| Type | Déclencheur |
|------|-------------|
| BOOKING_CREATED | Nouvelle réservation |
| BOOKING_STATUS_CHANGED | Changement de statut |
| DOCUMENT_UPLOADED | Document uploadé |
| CARRIER_ACCEPTED | Carrier a accepté une CSV booking |
| CARRIER_REJECTED | Carrier a refusé |
| PAYMENT_SUCCESS | Paiement Stripe réussi |
| PAYMENT_FAILED | Paiement Stripe échoué |
| SUBSCRIPTION_UPDATED | Abonnement modifié |
| SYSTEM | Notification système |
### Niveaux de priorité
`LOW` · `MEDIUM` · `HIGH` · `URGENT`
### API notifications
| Méthode | Route | Description |
|---------|-------|-------------|
| GET | /api/v1/notifications | Liste (paginée, filtrable) |
| PATCH | /api/v1/notifications/:id/read | Marquer comme lu |
| PATCH | /api/v1/notifications/read-all | Tout marquer comme lu |
| DELETE | /api/v1/notifications/:id | Supprimer |
---
## Webhooks
### Pour qui
Les webhooks permettent à des systèmes tiers de recevoir des événements Xpeditis en temps réel.
### Configuration
```
POST /api/v1/webhooks
{
"url": "https://your-system.com/webhook",
"events": ["BOOKING_CREATED", "BOOKING_UPDATED"],
"secret": "your-signing-secret"
}
```
### Sécurité
Chaque webhook est signé HMAC-SHA256 :
```
X-Webhook-Signature: sha256=xxxxxxxx
```
Vérification côté récepteur :
```typescript
const signature = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const isValid = `sha256=${signature}` === headers['x-webhook-signature'];
```
### Retry
- 3 tentatives avec backoff exponentiel
- Après 3 échecs → statut `FAILED`, webhook désactivé
- `failure_count` incrémenté à chaque échec
### Événements disponibles
`BOOKING_CREATED` · `BOOKING_UPDATED` · `BOOKING_CANCELLED` · `RATE_QUOTED` · `CARRIER_ACCEPTED` · `CARRIER_REJECTED` · `PAYMENT_SUCCESS` · `PAYMENT_FAILED`
### API webhooks
| Méthode | Route | Description |
|---------|-------|-------------|
| GET | /api/v1/webhooks | Liste des webhooks |
| POST | /api/v1/webhooks | Créer un webhook |
| PATCH | /api/v1/webhooks/:id | Modifier |
| DELETE | /api/v1/webhooks/:id | Supprimer |
| POST | /api/v1/webhooks/:id/test | Tester le webhook |

View File

@ -0,0 +1,143 @@
# Recherche de tarifs
---
## Deux types de recherche
| Type | Description | Endpoint |
|------|-------------|----------|
| FCL (Full Container Load) | Tarifs via connecteurs carriers (Maersk, MSC, etc.) | POST /api/v1/rates/search |
| CSV / LCL | Tarifs chargés depuis des fichiers CSV | POST /api/v1/rates/csv-search |
---
## Recherche FCL — Carriers API
### Endpoint
```
POST /api/v1/rates/search
Authorization: Bearer <token>
{
"origin": "NLRTM",
"destination": "CNSHA",
"containerType": "40HC",
"mode": "FCL",
"departureDate": "2026-06-01",
"hazmat": false
}
```
### Réponse
```json
{
"results": [
{
"id": "uuid",
"carrier": { "name": "Maersk", "code": "MAERSK", "logoUrl": "..." },
"origin": { "code": "NLRTM", "name": "Rotterdam" },
"destination": { "code": "CNSHA", "name": "Shanghai" },
"baseFreight": 1850.00,
"surcharges": [
{ "type": "BAF", "amount": 250.00, "currency": "USD" }
],
"totalAmount": 2100.00,
"currency": "USD",
"transitDays": 28,
"etd": "2026-06-01T00:00:00Z",
"eta": "2026-06-29T00:00:00Z",
"availability": 50,
"validUntil": "2026-05-13T10:15:00Z"
}
],
"total": 5,
"page": 1,
"pageSize": 20
}
```
### Cache Redis
- Clé : `rate:{origin}:{destination}:{containerType}`
- TTL : 15 minutes
- Les cotations expirent automatiquement après 15min (`valid_until`)
### Carriers intégrés
| Carrier | Code | SCAC |
|---------|------|------|
| Maersk | MAERSK | MAEU |
| MSC | MSC | MSCU |
| CMA CGM | CMACGM | CMDU |
| Hapag-Lloyd | HAPAG | HLCU |
| ONE | ONE | ONEY |
Chaque carrier a son connecteur dans `apps/backend/src/infrastructure/carriers/`.
Circuit breaker via `opossum` : timeout 5s, bascule sur fallback si indisponible.
---
## Recherche CSV
### Endpoint
```
POST /api/v1/rates/csv-search
Authorization: Bearer <token>
{
"origin": "NLRTM",
"destination": "USNYC",
"volumeCBM": 25.5,
"weightKG": 3500,
"palletCount": 10,
"filters": {
"companies": ["SSC Consolidation"],
"minPrice": 1000,
"maxPrice": 3000,
"currency": "USD"
}
}
```
### Carriers CSV disponibles
| Company | Type | API |
|---------|------|-----|
| SSC Consolidation | CSV_ONLY | Non |
| ECU Worldwide | CSV_AND_API | Oui |
| TCC Logistics | CSV_ONLY | Non |
| NVO Consolidation | CSV_ONLY | Non |
Les fichiers CSV sont dans `apps/backend/src/infrastructure/storage/csv-storage/rates/`.
### Calcul de prix CSV
```typescript
// Freight class : prendre le max de volume-based ou weight-based
const volumePrice = volumeCBM * pricePerCBM;
const weightPrice = weightKG * pricePerKG;
const freightPrice = Math.max(volumePrice, weightPrice);
const totalPrice = freightPrice + surchargeBAF + surchargeCAF;
```
---
## Recherche de ports
Autocomplete avec recherche floue (pg_trgm) :
```
GET /api/v1/ports/search?q=rotterdam&limit=10
```
~10 000 ports UN/LOCODE seedés en base.
---
## Export des résultats
Les résultats peuvent être exportés en PDF ou Excel depuis le frontend.
Voir `apps/frontend/src/utils/` pour les utilitaires d'export.

View File

@ -0,0 +1,110 @@
# Abonnements & Paiements (Stripe)
---
## Plans disponibles
| Plan | Description |
|------|-------------|
| FREE | Accès limité (après inscription) |
| BRONZE | Entrée de gamme |
| SILVER | Standard |
| GOLD | Avancé |
| PLATINIUM | Entreprise |
Les plans BRONZE/SILVER/GOLD/PLATINIUM sont disponibles en facturation **mensuelle** ou **annuelle**.
---
## Architecture
Le système utilise Stripe pour la gestion des paiements. Chaque organisation a exactement un enregistrement `subscriptions`.
```
Organization 1──1 Subscription
└── stripe_customer_id (Stripe Customer)
└── stripe_subscription_id (Stripe Subscription)
```
---
## API
| Méthode | Route | Description |
|---------|-------|-------------|
| GET | /api/v1/subscriptions/current | Abonnement courant de l'org |
| POST | /api/v1/subscriptions/create-checkout | Créer session Stripe Checkout |
| POST | /api/v1/subscriptions/cancel | Annuler l'abonnement |
| POST | /api/v1/subscriptions/webhook | Webhook Stripe (signature HMAC) |
| GET | /api/v1/subscriptions/plans | Liste des plans disponibles |
---
## Configuration
```bash
# .env backend
STRIPE_SECRET_KEY=sk_test_xxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxx
# Price IDs depuis le Dashboard Stripe
STRIPE_SILVER_MONTHLY_PRICE_ID=price_xxxx
STRIPE_SILVER_YEARLY_PRICE_ID=price_xxxx
STRIPE_GOLD_MONTHLY_PRICE_ID=price_xxxx
STRIPE_GOLD_YEARLY_PRICE_ID=price_xxxx
STRIPE_PLATINIUM_MONTHLY_PRICE_ID=price_xxxx
STRIPE_PLATINIUM_YEARLY_PRICE_ID=price_xxxx
```
---
## Webhook Stripe
Le endpoint `/api/v1/subscriptions/webhook` reçoit les événements Stripe.
**Événements gérés** :
- `checkout.session.completed` — activation abonnement
- `customer.subscription.updated` — changement de plan
- `customer.subscription.deleted` — annulation
- `invoice.payment_succeeded` — paiement réussi
- `invoice.payment_failed` — paiement échoué → statut `past_due`
Le secret `STRIPE_WEBHOOK_SECRET` est utilisé pour vérifier la signature de chaque événement.
### Configurer le webhook en local (test)
```bash
# Installer Stripe CLI
stripe listen --forward-to localhost:4000/api/v1/subscriptions/webhook
```
---
## Statuts d'abonnement
| Statut | Description |
|--------|-------------|
| active | Abonnement en cours, paiement OK |
| trialing | Période d'essai |
| past_due | Paiement en retard |
| cancelled | Annulé |
| pending_payment | En attente de paiement CB |
| pending_bank_transfer | En attente de virement bancaire |
---
## Licenses
Le système de licenses (`licenses` table) permet d'activer des fonctionnalités spécifiques par organisation, indépendamment du plan Stripe.
---
## Taux de commission
La colonne `subscriptions.commission_rate` (DECIMAL 5,4) permet de stocker un taux de commission Xpeditis par organisation (pour tracking interne).
---
## Guide de configuration initial
Voir [../deployment/STRIPE_SETUP.md](../deployment/STRIPE_SETUP.md) pour la configuration complète de Stripe (création des products/prices, webhooks, etc.).

View File

@ -0,0 +1,160 @@
# Démarrage rapide — Xpeditis
Guide de démarrage en 5 minutes.
---
## Prérequis
- **Node.js** ≥ 20.x
- **npm** ≥ 10.x
- **Docker** + Docker Compose (pour PostgreSQL, Redis, MinIO)
---
## 1. Installer les dépendances
```bash
npm run install:all
```
> Sur Windows si l'installation échoue, voir [windows.md](windows.md).
---
## 2. Démarrer l'infrastructure
```bash
docker-compose up -d
```
Vérifier que tout est actif :
```bash
docker-compose ps
# postgres Up (healthy)
# redis Up (healthy)
# minio Up (healthy)
```
---
## 3. Configurer l'environnement
```bash
cp apps/backend/.env.example apps/backend/.env
cp apps/frontend/.env.example apps/frontend/.env.local
```
Les valeurs par défaut fonctionnent pour le développement local — aucune modification nécessaire.
---
## 4. Exécuter les migrations
```bash
cd apps/backend && npm run migration:run && cd ../..
```
---
## 5. Démarrer les serveurs
```bash
# Terminal 1
npm run backend:dev
# → http://localhost:4000/api/v1
# → Swagger: http://localhost:4000/api/docs
# Terminal 2
npm run frontend:dev
# → http://localhost:3000
```
---
## Vérification
| URL | Attendu |
|-----|---------|
| http://localhost:4000/api/v1/health | `{"status":"ok"}` |
| http://localhost:4000/api/docs | Swagger UI |
| http://localhost:3000 | Page d'accueil Xpeditis |
---
## Commandes de référence
```bash
# Développement
npm run backend:dev # Backend avec hot-reload
npm run frontend:dev # Frontend avec hot-reload
# Tests
npm run backend:test # Tests unitaires backend
npm run frontend:test # Tests unitaires frontend
cd apps/backend && npm run test:integration # Tests d'intégration
cd apps/frontend && npm run test:e2e # Tests E2E Playwright
# Qualité de code
npm run backend:lint # ESLint backend
npm run frontend:lint # ESLint frontend
npm run format # Prettier (tous les fichiers)
npm run format:check # Vérifier le formatage
# Base de données
cd apps/backend
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/NomMigration
npm run migration:run
npm run migration:revert
# Build
npm run backend:build # Build NestJS
npm run frontend:build # Build Next.js
npm run clean # Supprimer node_modules, dist, .next
```
---
## Infrastructure locale (Docker)
| Service | URL / Port | Credentials |
|---------|-----------|-------------|
| PostgreSQL | localhost:5432 | xpeditis / xpeditis_dev_password |
| Redis | localhost:6379 | password: xpeditis_redis_password |
| MinIO API | http://localhost:9000 | minioadmin / minioadmin |
| MinIO Console | http://localhost:9001 | minioadmin / minioadmin |
---
## Comptes de test (après migration)
Les migrations seed créent automatiquement des comptes de test. Voir la migration `1730000000007-SeedTestUsers.ts` pour les credentials exacts.
---
## Résolution de problèmes courants
**Backend ne démarre pas :**
```bash
cd apps/backend && rm -rf node_modules && npm install && npm run dev
```
**Erreur de migration :**
```bash
cd apps/backend
npm run migration:revert # Annuler la dernière migration
npm run migration:run # Relancer
```
**Port déjà utilisé :**
```bash
# Modifier PORT dans apps/backend/.env
PORT=4001
```
**Docker ne démarre pas :**
```bash
docker-compose down
docker-compose up -d
```