# 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
