# Migration Automatique des Migrations - DĂ©ploiement Portainer ## 📋 RĂ©sumĂ© Ce document dĂ©crit les modifications apportĂ©es pour que les migrations de base de donnĂ©es s'exĂ©cutent **automatiquement au dĂ©marrage du container backend**, aussi bien en local (Docker Compose) qu'en production (Portainer). --- ## ✅ ProblĂšme RĂ©solu **Avant** : Les migrations devaient ĂȘtre exĂ©cutĂ©es manuellement avec `npm run migration:run`, ce qui n'Ă©tait pas possible dans un environnement de production Portainer. **AprĂšs** : Les migrations s'exĂ©cutent automatiquement au dĂ©marrage du container backend, avant le lancement de l'application NestJS. --- ## 🔧 Modifications Techniques ### 1. Nouveau Script de DĂ©marrage (`apps/backend/startup.js`) Créé un script Node.js qui : 1. **Attend que PostgreSQL soit prĂȘt** (retry avec timeout) 2. **ExĂ©cute automatiquement les migrations** via TypeORM 3. **DĂ©marre l'application NestJS** **Fichier** : `apps/backend/startup.js` ```javascript // Attend PostgreSQL (30 tentatives max) async function waitForPostgres() { ... } // ExĂ©cute les migrations TypeORM async function runMigrations() { const AppDataSource = new DataSource({ type: 'postgres', host: process.env.DATABASE_HOST, port: parseInt(process.env.DATABASE_PORT, 10), username: process.env.DATABASE_USER, password: process.env.DATABASE_PASSWORD, database: process.env.DATABASE_NAME, entities: [...], migrations: [...], }); await AppDataSource.initialize(); await AppDataSource.runMigrations(); } // DĂ©marre NestJS function startApplication() { spawn('node', ['dist/main'], { stdio: 'inherit' }); } ``` ### 2. Modification du Dockerfile **Fichier** : `apps/backend/Dockerfile` **Avant** : ```dockerfile CMD ["node", "dist/main"] ``` **AprĂšs** : ```dockerfile # Copy startup script (includes migrations) COPY --chown=nestjs:nodejs startup.js ./startup.js CMD ["node", "startup.js"] ``` ### 3. Variables d'environnement ajoutĂ©es **Fichier** : `docker/portainer-stack.yml` Ajout des variables manquantes pour le backend : ```yaml environment: # API API_PREFIX: api/v1 # Database DATABASE_SYNC: false DATABASE_LOGGING: false # Redis REDIS_DB: 0 # JWT JWT_ACCESS_EXPIRATION: 15m JWT_REFRESH_EXPIRATION: 7d # CORS - Ajout de l'API backend dans les origines CORS_ORIGIN: https://app.preprod.xpeditis.com,https://www.preprod.xpeditis.com,https://api.preprod.xpeditis.com # Security BCRYPT_ROUNDS: 10 SESSION_TIMEOUT_MS: 7200000 # Rate Limiting RATE_LIMIT_TTL: 60 RATE_LIMIT_MAX: 100 ``` --- ## 🚀 DĂ©ploiement sur Portainer ### Étape 1 : Rebuild des Images Docker Les images Docker doivent ĂȘtre reconstruites avec le nouveau `startup.js` : ```bash # Backend cd apps/backend docker build -t rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod . docker push rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod # Frontend (si nĂ©cessaire) cd ../frontend docker build -t rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod . docker push rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod ``` ### Étape 2 : Mise Ă  Jour du Stack Portainer 1. Aller sur **Portainer** → **Stacks** → **xpeditis-preprod** 2. Cliquer sur **Editor** 3. Copier le contenu de `docker/portainer-stack.yml` 4. Cliquer sur **Update the stack** 5. Cocher **Re-pull image and redeploy** 6. Cliquer sur **Update** ### Étape 3 : VĂ©rification des Logs ```bash # Voir les logs du backend docker logs xpeditis-backend -f # VĂ©rifier que les migrations sont exĂ©cutĂ©es # Vous devriez voir : # ✅ PostgreSQL is ready # ✅ DataSource initialized # ✅ Successfully ran X migration(s): # - CreateAuditLogsTable1700000001000 # - CreateNotificationsTable1700000002000 # - CreateWebhooksTable1700000003000 # - ... # ✅ Database migrations completed # 🚀 Starting NestJS application... ``` --- ## 📊 Migrations ExĂ©cutĂ©es Automatiquement Lors du premier dĂ©marrage, les migrations suivantes seront exĂ©cutĂ©es : 1. **CreateAuditLogsTable** - Table des logs d'audit 2. **CreateNotificationsTable** - Table des notifications 3. **CreateWebhooksTable** - Table des webhooks 4. **CreateInitialSchema** - SchĂ©ma initial (users, organizations, carriers, ports, etc.) 5. **SeedOrganizations** - DonnĂ©es de test (organisations) 6. **SeedCarriers** - DonnĂ©es de test (transporteurs maritimes) 7. **SeedTestUsers** - Utilisateurs de test : - `admin@xpeditis.com` (ADMIN) - Mot de passe : `AdminPassword123!` - `manager@xpeditis.com` (MANAGER) - Mot de passe : `AdminPassword123!` - `user@xpeditis.com` (USER) - Mot de passe : `AdminPassword123!` 8. **CreateCsvBookingsTable** - Table des rĂ©servations CSV 9. **CreateCsvRatesTable** - Table des tarifs CSV 10. **SeedPorts** - 10 000+ ports mondiaux (UN LOCODE) **Total** : ~10 migrations + seed data --- ## ⚠ Points d'Attention ### 1. Base de DonnĂ©es Vide vs Existante - **Base vide** : Toutes les migrations s'exĂ©cutent (premiĂšre fois) - **Base existante** : Seules les nouvelles migrations sont exĂ©cutĂ©es - **Idempotence** : Les migrations peuvent ĂȘtre relancĂ©es sans problĂšme ### 2. Temps de DĂ©marrage Le premier dĂ©marrage prend **~30-60 secondes** : - Attente PostgreSQL : ~10s - ExĂ©cution migrations : ~20-40s (avec seed de 10k ports) - DĂ©marrage NestJS : ~5-10s Les dĂ©marrages suivants sont plus rapides (~15-20s) car aucune migration n'est Ă  exĂ©cuter. ### 3. Rollback de Migration Si une migration Ă©choue : ```bash # Se connecter au container docker exec -it xpeditis-backend sh # VĂ©rifier les migrations appliquĂ©es node -e " const { DataSource } = require('typeorm'); const ds = new DataSource({ type: 'postgres', host: process.env.DATABASE_HOST, port: process.env.DATABASE_PORT, username: process.env.DATABASE_USER, password: process.env.DATABASE_PASSWORD, database: process.env.DATABASE_NAME, }); ds.initialize().then(async () => { const migrations = await ds.query('SELECT * FROM migrations ORDER BY timestamp DESC LIMIT 5'); console.log(migrations); await ds.destroy(); }); " # Rollback derniĂšre migration (si nĂ©cessaire) # Attention : ceci doit ĂȘtre fait manuellement depuis le serveur ``` --- ## 🔐 SĂ©curitĂ© ### Variables d'Environnement Sensibles Assurez-vous que les variables suivantes sont dĂ©finies correctement dans Portainer : ```yaml # Base de donnĂ©es DATABASE_PASSWORD: 9Lc3M9qoPBeHLKHDXGUf1 # CHANGER EN PRODUCTION # Redis REDIS_PASSWORD: hXiy5GMPswMtxMZujjS2O # CHANGER EN PRODUCTION # JWT JWT_SECRET: 4C4tQC8qym/evv4zI5DaUE1yy3kilEnm6lApOGD0GgNBLA0BLm2tVyUr1Lr0mTnV # CHANGER EN PRODUCTION # MinIO AWS_ACCESS_KEY_ID: minioadmin_preprod_CHANGE_ME # CHANGER EN PRODUCTION AWS_SECRET_ACCESS_KEY: RBJfD0QVXC5JDfAHCwdUW # CHANGER EN PRODUCTION ``` **Recommandation** : Utiliser Portainer Secrets pour les mots de passe en production. --- ## đŸ§Ș Test en Local Pour tester avant dĂ©ploiement Portainer : ```bash # 1. Reconstruire l'image backend cd apps/backend docker build -t xpeditis20-backend . # 2. Lancer le stack complet cd ../.. docker-compose -f docker-compose.dev.yml up -d # 3. VĂ©rifier les logs docker logs xpeditis-backend-dev -f # 4. VĂ©rifier que les tables existent docker exec -it xpeditis-postgres-dev psql -U xpeditis -d xpeditis_dev -c "\dt" # 5. Tester l'API curl http://localhost:4001/api/v1/auth/login -X POST \ -H "Content-Type: application/json" \ -d '{"email":"admin@xpeditis.com","password":"AdminPassword123!"}' ``` --- ## 📁 Fichiers ModifiĂ©s ``` apps/backend/ ├── startup.js # ✹ NOUVEAU - Script de dĂ©marrage avec migrations ├── Dockerfile # ✏ MODIFIÉ - CMD utilise startup.js ├── docker-entrypoint.sh # đŸ—‘ïž NON UTILISÉ (script shell alternatif) └── run-migrations.js # đŸ—‘ïž NON UTILISÉ (script migrations standalone) docker/ └── portainer-stack.yml # ✏ MODIFIÉ - Ajout variables d'environnement docker-compose.dev.yml # ✅ DÉJÀ CORRECT - Toutes les variables prĂ©sentes ``` --- ## ✅ Checklist de DĂ©ploiement - [ ] Rebuild de l'image backend avec `startup.js` - [ ] Push de l'image vers le registry Scaleway - [ ] Mise Ă  jour du `portainer-stack.yml` avec toutes les variables - [ ] Update du stack Portainer avec re-pull de l'image - [ ] VĂ©rification des logs backend (migrations exĂ©cutĂ©es) - [ ] Test de connexion avec `admin@xpeditis.com` / `AdminPassword123!` - [ ] VĂ©rification que toutes les routes du dashboard fonctionnent - [ ] Test de crĂ©ation d'une rĂ©servation - [ ] Test de recherche de tarifs - [ ] VĂ©rification des notifications en temps rĂ©el (WebSocket) --- ## 🆘 Troubleshooting ### ProblĂšme : Backend crash au dĂ©marrage **SymptĂŽme** : Container redĂ©marre en boucle **VĂ©rification** : ```bash docker logs xpeditis-backend --tail 100 ``` **Causes possibles** : 1. PostgreSQL pas prĂȘt → Attendre 30s de plus 2. Variables d'environnement manquantes → VĂ©rifier le stack 3. Migration Ă©chouĂ©e → VĂ©rifier les logs de migration ### ProblĂšme : Table "notifications" does not exist **SymptĂŽme** : Erreur 500 sur `/api/v1/notifications` **Cause** : Migrations non exĂ©cutĂ©es **Solution** : ```bash # RedĂ©marrer le backend pour forcer les migrations docker restart xpeditis-backend ``` ### ProblĂšme : "Failed to connect to PostgreSQL" **SymptĂŽme** : Backend ne dĂ©marre pas aprĂšs 30 tentatives **Cause** : PostgreSQL pas accessible **Solution** : ```bash # VĂ©rifier que PostgreSQL est healthy docker ps | grep postgres # VĂ©rifier les logs PostgreSQL docker logs xpeditis-db # Tester la connexion docker exec xpeditis-db psql -U xpeditis -d xpeditis_preprod -c "SELECT version();" ``` --- ## 📚 RĂ©fĂ©rences - [Documentation TypeORM Migrations](https://typeorm.io/migrations) - [Docker Multi-stage Builds](https://docs.docker.com/build/building/multi-stage/) - [Portainer Stack Documentation](https://docs.portainer.io/user/docker/stacks) - [NestJS Database](https://docs.nestjs.com/techniques/database) --- ## 🎯 RĂ©sultat Final ✅ **Migrations automatiques** au dĂ©marrage du container ✅ **Aucune action manuelle** requise ✅ **Idempotence** garantie (peut ĂȘtre relancĂ©) ✅ **Compatible** Docker Compose et Portainer ✅ **Production-ready** avec logs dĂ©taillĂ©s **Date de mise Ă  jour** : 2025-11-19 **Version** : 1.0