xpeditis2.0/PORTAINER_MIGRATION_AUTO.md
David 7dadd951bb
All checks were successful
CI/CD Pipeline / Backend - Build, Test & Push (push) Successful in 16m18s
CI/CD Pipeline / Frontend - Build, Test & Push (push) Successful in 30m58s
CI/CD Pipeline / Integration Tests (push) Has been skipped
CI/CD Pipeline / Deployment Summary (push) Successful in 2s
CI/CD Pipeline / Discord Notification (Failure) (push) Has been skipped
CI/CD Pipeline / Discord Notification (Success) (push) Successful in 1s
fix portainer deploy
2025-11-19 15:17:53 +01:00

378 lines
11 KiB
Markdown

# 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