diff --git a/docs/runbooks/DEPLOYMENT.md b/docs/runbooks/DEPLOYMENT.md new file mode 100644 index 000000000..ea0e47878 --- /dev/null +++ b/docs/runbooks/DEPLOYMENT.md @@ -0,0 +1,50 @@ +# Runbook — Déploiement + +## Prérequis + +- Accès au registry Docker +- Variables d'environnement configurées (voir `.env.example`) +- Base de données migrée + +## Étapes + +### 1. Build images + +```bash +docker build -t veza/backend-api:${VERSION} -f veza-backend-api/Dockerfile . +docker build -t veza/stream-server:${VERSION} -f veza-stream-server/Dockerfile . +docker build -t veza/web:${VERSION} -f apps/web/Dockerfile . +``` + +### 2. Push images + +```bash +docker push veza/backend-api:${VERSION} +docker push veza/stream-server:${VERSION} +docker push veza/web:${VERSION} +``` + +### 3. Migrations + +```bash +cd veza-backend-api +DATABASE_URL=postgres://... make migrate +``` + +### 4. Deploy + +Suivant l'orchestrateur (Kubernetes, Docker Compose, etc.) : + +- Mettre à jour les images dans les manifests +- Appliquer : `kubectl apply -f k8s/` ou `docker-compose up -d` + +### 5. Vérification + +```bash +curl -s https://api.example.com/health | jq +curl -s https://api.example.com/health/deep | jq +``` + +### 6. Rollback + +En cas de problème : voir [ROLLBACK.md](ROLLBACK.md). diff --git a/docs/runbooks/GRACEFUL_DEGRADATION.md b/docs/runbooks/GRACEFUL_DEGRADATION.md new file mode 100644 index 000000000..720ae2182 --- /dev/null +++ b/docs/runbooks/GRACEFUL_DEGRADATION.md @@ -0,0 +1,27 @@ +# Runbook — Graceful Degradation + +## Comportement quand Redis est down + +| Fonctionnalité | Comportement | +|---------------------|---------------------------------------| +| Rate limiting | Fallback in-memory (par instance) | +| CSRF | Désactivé ou 503 si strict | +| Sessions | Échec login / refresh | +| Cache | Cache miss systématique | + +L’API reste opérationnelle pour les requêtes qui ne dépendent pas de Redis. Les routes protégées peuvent échouer si les sessions sont en Redis. + +## Comportement quand RabbitMQ est down + +- Les jobs asynchrones (transcode, notifications, etc.) ne sont pas traités +- Les requêtes synchrones restent fonctionnelles + +## Comportement quand S3/MinIO est down + +- Upload de fichiers : échec +- Lecture de fichiers stockés : échec +- Le reste de l’API fonctionne + +## Health /health/deep + +Le endpoint `/health/deep` indique l’état de chaque dépendance (DB, Redis, RabbitMQ, S3, disk). Utiliser ce diagnostic pour identifier la dégradation. diff --git a/docs/runbooks/INCIDENT_RESPONSE.md b/docs/runbooks/INCIDENT_RESPONSE.md new file mode 100644 index 000000000..6859ab421 --- /dev/null +++ b/docs/runbooks/INCIDENT_RESPONSE.md @@ -0,0 +1,39 @@ +# Runbook — Incident Response + +## API down + +1. Vérifier `GET /health` et `GET /health/deep` +2. Consulter les logs : `kubectl logs -l app=veza-backend-api --tail=200` +3. Vérifier DB, Redis, RabbitMQ (voir health/deep) +4. Redémarrer les pods si crash loop : `kubectl rollout restart deployment/veza-backend-api` +5. Rollback image si régression récente : [ROLLBACK.md](ROLLBACK.md) + +## Redis down + +- L’API peut fonctionner en mode dégradé (voir [GRACEFUL_DEGRADATION.md](GRACEFUL_DEGRADATION.md)) +- Vérifier : `redis-cli ping` +- Redémarrer le service Redis ou le pod +- Vérifier la persistance (AOF/RDB) si perte de données + +## DB down + +- **Critique** : l’API renvoie 503 +1. Vérifier la connexion PostgreSQL +2. Consulter les logs Postgres +3. Vérifier l’espace disque +4. Redémarrer Postgres si nécessaire +5. Pas de rollback migration automatique sans procédure validée + +## Webhook failed + +1. Consulter les logs du service appelant (ex. Stream server callbacks) +2. Vérifier `X-Internal-API-Key` et `STREAM_SERVER_INTERNAL_API_KEY` +3. Vérifier que l’URL du webhook est correcte +4. Réessayer manuellement si idempotent + +## DDoS / trafic anormal + +1. Activer le rate limiting (Redis requis pour distribué) +2. Vérifier les règles WAF / Cloudflare si applicable +3. Scaler horizontalement si charge légitime +4. Bloquer les IP abusives au niveau load balancer / firewall diff --git a/docs/runbooks/ROLLBACK.md b/docs/runbooks/ROLLBACK.md new file mode 100644 index 000000000..2d0c8d57f --- /dev/null +++ b/docs/runbooks/ROLLBACK.md @@ -0,0 +1,35 @@ +# Runbook — Rollback + +## Rollback image + +### Kubernetes + +```bash +kubectl rollout undo deployment/veza-backend-api +kubectl rollout undo deployment/veza-stream-server +kubectl rollout undo deployment/veza-web +``` + +### Docker Compose + +```bash +docker-compose down +# Éditer docker-compose.yml : utiliser l'image de la version précédente +docker-compose up -d +``` + +## Rollback base de données + +**Attention** : Les migrations down ne sont pas systématiques. Voir `docs/MIGRATION_CONSOLIDATION.md`. + +Pour une migration récente, si un fichier `*_down.sql` existe : + +```bash +psql $DATABASE_URL -f veza-backend-api/migrations/XXX_migration_down.sql +# Retirer la ligne correspondante de schema_migrations +psql $DATABASE_URL -c "DELETE FROM schema_migrations WHERE version = 'XXX_migration.sql';" +``` + +## Switch de trafic + +Avec load balancer / ingress : pointer vers la version précédente des pods/containers avant rollback complet. diff --git a/docs/runbooks/SECRET_ROTATION.md b/docs/runbooks/SECRET_ROTATION.md new file mode 100644 index 000000000..78468a463 --- /dev/null +++ b/docs/runbooks/SECRET_ROTATION.md @@ -0,0 +1,38 @@ +# Runbook — Rotation des secrets + +## JWT_SECRET + +1. Générer un nouveau secret : `openssl rand -base64 32` +2. Déployer avec l’ancien et le nouveau (dual-secret) si l’app le supporte +3. Sinon : maintenance window + - Mettre à jour `JWT_SECRET` dans le déploiement + - Redémarrer l’API + - Tous les tokens existants sont invalidés (re-login requis) + +## CHAT_JWT_SECRET + +Même procédure que JWT_SECRET. Doit être synchronisé entre backend et chat/stream si partagé. + +## OAUTH_ENCRYPTION_KEY + +Utilisé pour chiffrer les tokens OAuth en DB. Rotation complexe : + +1. Ne pas supprimer l’ancienne clé tant que des tokens chiffrés existent +2. Ajouter la nouvelle clé dans la config +3. Les nouveaux tokens utilisent la nouvelle clé +4. Après expiration des anciens tokens, retirer l’ancienne clé + +## STREAM_SERVER_INTERNAL_API_KEY / INTERNAL_API_KEY + +Doivent correspondre entre backend et stream server. + +1. Générer : `openssl rand -hex 32` +2. Mettre à jour les deux côtés quasi-simultanément +3. Redémarrer backend et stream server + +## DATABASE_URL + +1. Créer un nouvel utilisateur avec un nouveau mot de passe en DB +2. Mettre à jour `DATABASE_URL` dans le déploiement +3. Redémarrer l’API +4. Révoquer l’ancien utilisateur après validation