Add production deployment guide and checklist
This commit is contained in:
@@ -15,6 +15,7 @@ PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
|
|||||||
ALLOWED_DOCS = {
|
ALLOWED_DOCS = {
|
||||||
"README.md": PROJECT_ROOT / "README.md",
|
"README.md": PROJECT_ROOT / "README.md",
|
||||||
"ROADMAP.md": PROJECT_ROOT / "docs" / "ROADMAP.md",
|
"ROADMAP.md": PROJECT_ROOT / "docs" / "ROADMAP.md",
|
||||||
|
"PRODUCTION_CHECKLIST.md": PROJECT_ROOT / "docs" / "PRODUCTION_CHECKLIST.md",
|
||||||
"USER_GUIDE.md": PROJECT_ROOT / "docs" / "USER_GUIDE.md",
|
"USER_GUIDE.md": PROJECT_ROOT / "docs" / "USER_GUIDE.md",
|
||||||
"ARCHITECTURE.md": PROJECT_ROOT / "docs" / "ARCHITECTURE.md",
|
"ARCHITECTURE.md": PROJECT_ROOT / "docs" / "ARCHITECTURE.md",
|
||||||
"API_GUIDE.md": PROJECT_ROOT / "docs" / "API_GUIDE.md",
|
"API_GUIDE.md": PROJECT_ROOT / "docs" / "API_GUIDE.md",
|
||||||
|
|||||||
@@ -0,0 +1,308 @@
|
|||||||
|
# Guide de déploiement — Imago sur serveur Docker
|
||||||
|
|
||||||
|
> Cible : serveur Docker distant (VM Proxmox, VPS, ou bare metal)
|
||||||
|
> Prérequis : Docker 24+, Docker Compose v2, accès SSH
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 1 — Préparer le registry d'images
|
||||||
|
|
||||||
|
Choisir UNE des options :
|
||||||
|
|
||||||
|
### Option A : Gitea Container Registry (recommandé si Gitea dispo)
|
||||||
|
```bash
|
||||||
|
# Builder et tagger l'image
|
||||||
|
cd C:\dev\git\python\imago
|
||||||
|
docker build -t gitea.dracodev.net/projets/imago-backend:latest .
|
||||||
|
docker build -t gitea.dracodev.net/projets/imago-admin:latest ./imago-admin
|
||||||
|
|
||||||
|
# Se connecter au registry Gitea
|
||||||
|
docker login gitea.dracodev.net -u bruno
|
||||||
|
|
||||||
|
# Pusher
|
||||||
|
docker push gitea.dracodev.net/projets/imago-backend:latest
|
||||||
|
docker push gitea.dracodev.net/projets/imago-admin:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option B : Docker Hub
|
||||||
|
```bash
|
||||||
|
docker build -t tonuser/imago-backend:latest .
|
||||||
|
docker build -t tonuser/imago-admin:latest ./imago-admin
|
||||||
|
docker push tonuser/imago-backend:latest
|
||||||
|
docker push tonuser/imago-admin:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option C : Registry local sur le serveur
|
||||||
|
```bash
|
||||||
|
# Sur le serveur cible
|
||||||
|
docker run -d -p 5000:5000 --name registry registry:2
|
||||||
|
|
||||||
|
# En local, builder et pusher
|
||||||
|
docker build -t localhost:5000/imago-backend:latest .
|
||||||
|
docker push localhost:5000/imago-backend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 2 — Préparer les secrets de production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Générer des secrets forts (à faire UNE SEULE fois)
|
||||||
|
openssl rand -hex 32 # SECRET_KEY
|
||||||
|
openssl rand -hex 32 # ADMIN_API_KEY → note-la, c'est ta clé d'accès admin
|
||||||
|
openssl rand -hex 32 # JWT_SECRET_KEY
|
||||||
|
openssl rand -hex 32 # SIGNED_URL_SECRET
|
||||||
|
openssl rand -hex 16 # S3_SECRET_KEY
|
||||||
|
openssl rand -hex 16 # MINIO_ROOT_PASSWORD
|
||||||
|
openssl rand -hex 16 # POSTGRES_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
Créer le fichier `.env.production` :
|
||||||
|
```bash
|
||||||
|
# ── Application ──
|
||||||
|
APP_NAME=Imago
|
||||||
|
APP_VERSION=2.0.0
|
||||||
|
DEBUG=false
|
||||||
|
SECRET_KEY=<valeur générée>
|
||||||
|
|
||||||
|
# ── Base de données ──
|
||||||
|
DATABASE_URL=postgresql+asyncpg://imago:<POSTGRES_PASSWORD>@db:5432/imago
|
||||||
|
|
||||||
|
# ── Stockage S3/MinIO ──
|
||||||
|
STORAGE_BACKEND=s3
|
||||||
|
S3_BUCKET=imago
|
||||||
|
S3_ENDPOINT_URL=http://minio:9000
|
||||||
|
S3_ACCESS_KEY=minioadmin
|
||||||
|
S3_SECRET_KEY=<S3_SECRET_KEY généré>
|
||||||
|
S3_REGION=us-east-1
|
||||||
|
SIGNED_URL_SECRET=<valeur générée>
|
||||||
|
|
||||||
|
# ── Redis ──
|
||||||
|
REDIS_URL=redis://redis:***@ADMIN_API_KEY=<valeur générée>
|
||||||
|
JWT_SECRET_KEY=<valeur générée>
|
||||||
|
JWT_ALGORITHM=HS256
|
||||||
|
|
||||||
|
# ── AI ──
|
||||||
|
AI_ENABLED=true
|
||||||
|
AI_PROVIDER=openrouter
|
||||||
|
OPENROUTER_API_KEY=<ta clé OpenRouter>
|
||||||
|
OPENROUTER_MODEL=qwen/qwen2.5-vl-72b-instruct
|
||||||
|
AI_TAGS_MIN=5
|
||||||
|
AI_TAGS_MAX=10
|
||||||
|
AI_DESCRIPTION_LANGUAGE=francais
|
||||||
|
AI_REQUEST_TIMEOUT=60
|
||||||
|
AI_MAX_RETRIES=2
|
||||||
|
|
||||||
|
# ── OCR ──
|
||||||
|
OCR_ENABLED=true
|
||||||
|
OCR_LANGUAGES=fra+eng
|
||||||
|
|
||||||
|
# ── CORS ──
|
||||||
|
CORS_ORIGINS=["https://admin.ton-domaine.com"]
|
||||||
|
|
||||||
|
# ── Pipeline ──
|
||||||
|
PIPELINE_TIMEOUT=300
|
||||||
|
PIPELINE_MAX_RETRIES=3
|
||||||
|
|
||||||
|
# ── Rate Limiting (Redis persistence) ──
|
||||||
|
RATE_LIMIT_STORAGE_URL=redis://redis:6379/1
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 3 — Préparer le docker-compose.production.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: traefik:v3.0
|
||||||
|
command:
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
- "--entrypoints.websecure.address=:443"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.email=bruno.charest@gmail.com"
|
||||||
|
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- traefik_certs:/letsencrypt
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: gitea.dracodev.net/projets/imago-backend:latest
|
||||||
|
env_file: .env.production
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.imago-api.rule=Host(`api.ton-domaine.com`)"
|
||||||
|
- "traefik.http.routers.imago-api.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.imago-api.tls.certresolver=letsencrypt"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1G
|
||||||
|
cpus: '2'
|
||||||
|
|
||||||
|
worker:
|
||||||
|
image: gitea.dracodev.net/projets/imago-backend:latest
|
||||||
|
command: python worker.py
|
||||||
|
env_file: .env.production
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
cpus: '1'
|
||||||
|
|
||||||
|
admin:
|
||||||
|
image: nginx:alpine
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:3000:80"
|
||||||
|
volumes:
|
||||||
|
- ./admin-dist:/usr/share/nginx/html:ro
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.imago-admin.rule=Host(`admin.ton-domaine.com`)"
|
||||||
|
- "traefik.http.routers.imago-admin.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.imago-admin.tls.certresolver=letsencrypt"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
env_file: .env.production
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: imago
|
||||||
|
POSTGRES_DB: imago
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/data
|
||||||
|
- ./backups:/backups
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U imago -d imago"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
restart: unless-stopped
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
|
||||||
|
volumes:
|
||||||
|
- redisdata:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256M
|
||||||
|
|
||||||
|
minio:
|
||||||
|
image: minio/minio
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
env_file: .env.production
|
||||||
|
volumes:
|
||||||
|
- miniodata:/data
|
||||||
|
restart: unless-stopped
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pgdata:
|
||||||
|
redisdata:
|
||||||
|
miniodata:
|
||||||
|
traefik_certs:
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 4 — Déployer sur le serveur
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Se connecter au serveur
|
||||||
|
ssh ton-serveur
|
||||||
|
|
||||||
|
# 2. Créer le répertoire de l'application
|
||||||
|
mkdir -p /opt/imago && cd /opt/imago
|
||||||
|
|
||||||
|
# 3. Copier les fichiers de configuration
|
||||||
|
# (depuis ton poste local)
|
||||||
|
scp docker-compose.production.yml ton-serveur:/opt/imago/
|
||||||
|
scp .env.production ton-serveur:/opt/imago/
|
||||||
|
|
||||||
|
# 4. S'assurer que les volumes de backup existent
|
||||||
|
mkdir -p backups
|
||||||
|
|
||||||
|
# 5. Démarrer la stack
|
||||||
|
docker compose -f docker-compose.production.yml up -d
|
||||||
|
|
||||||
|
# 6. Vérifier les logs
|
||||||
|
docker compose -f docker-compose.production.yml logs -f backend
|
||||||
|
|
||||||
|
# 7. Vérifier la santé
|
||||||
|
curl https://api.ton-domaine.com/health
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 5 — Backup automatique (cron)
|
||||||
|
|
||||||
|
Ajouter au crontab du serveur :
|
||||||
|
```cron
|
||||||
|
# Backup PostgreSQL — tous les jours à 2h
|
||||||
|
0 2 * * * docker exec imago-db-1 pg_dump -U imago imago > /opt/imago/backups/imago_$(date +\%Y\%m\%d).sql
|
||||||
|
|
||||||
|
# Nettoyer les backups de plus de 30 jours
|
||||||
|
0 3 * * * find /opt/imago/backups -name "*.sql" -mtime +30 -delete
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Étape 6 — Vérifications post-déploiement
|
||||||
|
|
||||||
|
- [ ] `https://api.ton-domaine.com/health` → `{"status":"healthy"}`
|
||||||
|
- [ ] `https://api.ton-domaine.com/health/detailed` → tous les checks OK
|
||||||
|
- [ ] `https://admin.ton-domaine.com` → page de login accessible
|
||||||
|
- [ ] Connexion admin avec `ADMIN_API_KEY`
|
||||||
|
- [ ] Upload d'une image test → pipeline OK
|
||||||
|
- [ ] WebSocket `/ws/pipeline/{id}` → événements reçus
|
||||||
|
- [ ] Métriques Prometheus `/metrics` → données présentes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Résumé des commandes rapides
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Builder les images (local)
|
||||||
|
docker build -t gitea.dracodev.net/projets/imago-backend:latest .
|
||||||
|
docker login gitea.dracodev.net
|
||||||
|
docker push gitea.dracodev.net/projets/imago-backend:latest
|
||||||
|
|
||||||
|
# Déployer (serveur)
|
||||||
|
ssh serveur "cd /opt/imago && docker compose pull && docker compose up -d"
|
||||||
|
|
||||||
|
# Vérifier
|
||||||
|
curl https://api.ton-domaine.com/health
|
||||||
|
```
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# Imago — Checklist Production
|
||||||
|
|
||||||
|
> Dernière mise à jour : 2026-06-22
|
||||||
|
> 46 items à compléter avant la mise en production publique
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 Critique — Doit être fait avant la mise en ligne
|
||||||
|
|
||||||
|
### 🔐 Sécurité
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Changer `SECRET_KEY` (encore `changez-moi`) | Tous les tokens JWT et URLs signées sont compromis |
|
||||||
|
| 2 | Changer `ADMIN_API_KEY` (`imago-admin-key`) | Accès admin trivial |
|
||||||
|
| 3 | Changer `JWT_SECRET_KEY` | Tokens JWT falsifiables |
|
||||||
|
| 4 | Changer `SIGNED_URL_SECRET` | URLs sécurisées contournables |
|
||||||
|
| 5 | Changer `S3_SECRET_KEY` / `MINIO_ROOT_PASSWORD` (minioadmin) | Accès complet au stockage |
|
||||||
|
| 6 | Changer `POSTGRES_PASSWORD` (imago) | Accès complet à la BDD |
|
||||||
|
| 7 | Passer `DEBUG=false` | Logs SQL en clair, stack traces exposées |
|
||||||
|
| 8 | Configurer CORS_ORIGINS pour le domaine de production | Sinon toute origine peut appeler l'API |
|
||||||
|
| 9 | Générer une `ADMIN_API_KEY` forte : `openssl rand -hex 32` | Clé admin actuelle trop simple |
|
||||||
|
| 10 | Restreindre `S3_ENDPOINT_PUBLIC` au domaine public réel | Éviter l'exposition de l'endpoint interne |
|
||||||
|
|
||||||
|
### 🌐 Réseau & TLS
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 11 | Mettre un reverse proxy devant l'API (nginx/Caddy/Traefik) | SSL termination, rate limiting, buffering |
|
||||||
|
| 12 | Configurer HTTPS (Let's Encrypt) | Données en clair sur le réseau |
|
||||||
|
| 13 | Supprimer les ports Docker exposés sur 0.0.0.0 (6379, 5432, 9000) | Redis et PostgreSQL exposés au monde |
|
||||||
|
| 14 | Mettre l'API derrière un domaine (ex: api.imago.example.com) | URLs signées, CORS,WebSocket dépendent du domaine |
|
||||||
|
|
||||||
|
### 📦 Sauvegarde
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 15 | Backup automatique PostgreSQL (pg_dump cron daily) | Perte de toutes les métadonnées |
|
||||||
|
| 16 | Backup MinIO/S3 (rclone ou S3 replication) | Perte de toutes les images |
|
||||||
|
| 17 | Tester une restauration complète (backup + restore) | Un backup non testé n'existe pas |
|
||||||
|
|
||||||
|
### 🔄 Migrations BDD
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 18 | Initialiser Alembic (`alembic init migrations`) | `create_all()` en production = pas de rollback |
|
||||||
|
| 19 | Générer la migration initiale (`alembic revision --autogenerate`) | Versionner le schéma actuel |
|
||||||
|
| 20 | Ajouter `alembic upgrade head` au démarrage du conteneur | Appliquer les migrations automatiquement |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟡 Important — Bloque la scalabilité
|
||||||
|
|
||||||
|
### 📊 Observabilité
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 21 | Déployer Grafana + Prometheus avec le dashboard fourni (`docs/grafana-dashboard.json`) | Aucune visibilité en prod |
|
||||||
|
| 22 | Configurer Alertmanager (alertes sur : API down, pipeline errors > seuil, disque > 80%) | Être réveillé avant les utilisateurs |
|
||||||
|
| 23 | Centraliser les logs (Loki, ELK, ou Datadog) | `docker logs` ne suffit pas à 3h du matin |
|
||||||
|
| 24 | Configurer Uptime Kuma ou similaire pour health check externe | Savoir si l'API est down depuis l'extérieur |
|
||||||
|
|
||||||
|
### 🚦 Résilience
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 25 | Ajouter `restart: unless-stopped` à TOUS les services Docker Compose | Le worker ne doit pas mourir silencieusement |
|
||||||
|
| 26 | Configurer des resource limits Docker (CPU/memory) par conteneur | Un conteneur qui leak ne tue pas le host |
|
||||||
|
| 27 | Mettre en place un health check au niveau du load balancer (`GET /health`) | Le load balancer doit savoir si le backend est vivant |
|
||||||
|
| 28 | Configurer Redis avec `maxmemory-policy` et une limite | Redis ne doit pas saturer la RAM |
|
||||||
|
|
||||||
|
### 🔑 Gestion des clés
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 29 | Utiliser Docker secrets ou un vault (Infisical, HashiCorp Vault) pour les secrets | `.env` en clair dans le repo = faille |
|
||||||
|
| 30 | Rotation automatique des clés API (politique : 90 jours) | Conformité sécurité |
|
||||||
|
| 31 | Journaliser les échecs d'authentification avec rate limiting | Détecter les attaques brute-force |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟢 Recommandé — Qualité de service
|
||||||
|
|
||||||
|
### 🧪 Qualité
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 32 | Exécuter la suite complète de tests dans la CI (GitHub Actions / Gitea Actions) | Tests qui ne tournent pas = tests inutiles |
|
||||||
|
| 33 | Ajouter des tests d'intégration avec Redis + MinIO + PostgreSQL réels | Les mocks ne trouvent pas les vrais bugs |
|
||||||
|
| 34 | Faire un audit de sécurité (bandit, trivy sur l'image Docker) | Vulnérabilités dans les dépendances |
|
||||||
|
| 35 | Scanner l'image Docker avec Trivy/Grype | CVE dans les packages système |
|
||||||
|
|
||||||
|
### 📖 Documentation
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 36 | Écrire un guide de déploiement production (`docs/DEPLOYMENT.md`) | Le nouveau dev ne devrait pas deviner |
|
||||||
|
| 37 | Écrire un runbook d'opérations (procédures : restart, backup restore, scale up) | Pas de panique à 3h du matin |
|
||||||
|
| 38 | Documenter l'architecture de sécurité (où sont les secrets, comment ils tournent) | Audit de sécurité |
|
||||||
|
|
||||||
|
### ⚖️ Conformité
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 39 | Ajouter une politique de rétention des données (combien de temps garder les images supprimées) | RGPD : droit à l'oubli |
|
||||||
|
| 40 | Ajouter un endpoint `DELETE /api/v1/auth/me` (suppression de compte + données) | RGPD : portabilité/effacement |
|
||||||
|
| 41 | Ajouter un endpoint `GET /api/v1/auth/me/export` (export des données) | RGPD : portabilité |
|
||||||
|
| 42 | Mettre une page de statut publique (status.imago.example.com) | Transparence utilisateurs |
|
||||||
|
| 43 | Ajouter un rate limit global par IP (en plus du limit par client) | Protection DDoS basique |
|
||||||
|
|
||||||
|
### 🚀 CI/CD
|
||||||
|
| # | Tâche | Pourquoi |
|
||||||
|
|---|---|---|
|
||||||
|
| 44 | Pipeline CI : lint → test → build image → push registry | Déploiement manuel = erreur humaine |
|
||||||
|
| 45 | Pipeline CD : pull image → migrate DB → restart conteneurs (rolling update) | Zéro downtime |
|
||||||
|
| 46 | Configurer un environnement de staging séparé | Tester en conditions réelles avant la prod |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Résumé
|
||||||
|
|
||||||
|
| Priorité | Items | Effort estimé |
|
||||||
|
|---|---|---|
|
||||||
|
| 🔴 Critique | 20 | 2-3 jours |
|
||||||
|
| 🟡 Important | 11 | 2 jours |
|
||||||
|
| 🟢 Recommandé | 15 | 3-4 jours |
|
||||||
|
| **Total** | **46** | **~8 jours** |
|
||||||
|
|
||||||
|
### Quick Start (top 5 à faire aujourd'hui)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Générer des secrets forts
|
||||||
|
openssl rand -hex 32 # pour SECRET_KEY
|
||||||
|
openssl rand -hex 32 # pour ADMIN_API_KEY
|
||||||
|
openssl rand -hex 32 # pour JWT_SECRET_KEY
|
||||||
|
openssl rand -hex 16 # pour MINIO_ROOT_PASSWORD
|
||||||
|
|
||||||
|
# 2. Mettre à jour .env avec ces valeurs
|
||||||
|
# 3. DEBUG=false
|
||||||
|
# 4. CORS_ORIGINS=["https://ton-domaine.com"]
|
||||||
|
# 5. docker compose up -d
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user