Runbooks d'exploitation — incidents type & procédures
Un runbook est une procédure éprouvée — pas un brainstorming. Il décrit comment réagir à un incident connu, étape par étape, dans l'ordre, sans avoir à réfléchir à 3 h du matin. La règle d'or : tenir cette page à jour APRÈS chaque incident (post-mortem), et tester chaque procédure en staging avant de la laisser ici. Un runbook obsolète est pire que pas de runbook.
Cette page est marquée noindex,nofollow et ne doit pas être publiée sur l'Internet
ouvert. Elle décrit des procédures qui touchent à la base financière. À héberger sur le
wiki interne ou le réseau privé de l'association.
Index des runbooks
| ID | Sévérité | Titre | Dernière révision |
|---|---|---|---|
| RB-01 | medium | Webhook HelloAsso non traité | 2026-05-19 |
| RB-02 | high | Solde adhérent incohérent | 2026-05-19 |
| RB-03 | high | SEPA en double prélèvement | 2026-05-19 |
| RB-04 | high | SSA redistribution échouée mid-flight | 2026-05-19 |
| RB-05 | high | Mandat SEPA annulé mais prélèvement parti | 2026-05-19 |
| RB-06 | critical | Server down (nginx / php-fpm / mariadb) | 2026-05-19 |
| RB-07 | critical | DB corruption / crash | 2026-05-19 |
| RB-08 | medium-high | Cron qui ne tourne plus | 2026-05-19 |
| RB-09 | high | Disque plein | 2026-05-19 |
| RB-10 | critical | Compromission soupçonnée | 2026-05-19 |
| RB-11 | high | Migration Doctrine échouée en prod | 2026-05-19 |
| RB-12 | high | IBAN chiffré illisible | 2026-05-19 |
JAMAIS toucher la BDD financière en SQL direct sans backup vérifié et test
reproduisant l'incident. Un UPDATE hâtif sur operation_*,
account_*, flux ou sepa_* peut créer ou détruire
silencieusement de la monnaie locale. C'est la priorité n°1 du projet (cf.
../dev/invariants.html).
RB-01 — Webhook HelloAsso non traité
Sévérité : medium · Domaine : HelloAsso / adhésion / Flux
Symptômes
- L'adhésion est validée côté HelloAsso (paiement encaissé, mail HelloAsso reçu).
- Aucun
FluxKohinos n'est créé pour l'adhérent. - L'adhérent n'a pas reçu son mail de bienvenue / activation.
Vérifications
# 1. Le webhook est-il arrivé jusqu'à nous ?
grep "helloasso" var/log/prod.log | tail -50
# ou via MCP : monolog-search term="helloasso" channel="webhook"
# 2. L'enregistrement existe-t-il en table helloasso ?
mysql kohinos -e "SELECT id, helloassoid, type, montant, created_at \
FROM helloasso ORDER BY id DESC LIMIT 10;"
# 3. Y a-t-il un Flux pour ce helloassoid ?
mysql kohinos -e "SELECT f.id, f.reference, f.created_at \
FROM flux f WHERE f.reference LIKE '%HELLOASSO%' ORDER BY f.id DESC LIMIT 10;"
# 4. La signature HMAC du webhook est-elle vérifiée ?
grep -E "(signature|HMAC|webhook)" var/log/prod.log | tail -20
Procédure
- Identifier la cause : signature invalide, secret rotatif désync, endpoint 4xx, code applicatif qui rejette.
- Rejouer le webhook manuellement :
# Récupérer le payload depuis HelloAsso (back-office HA → onglet notifications) curl -X POST https://kohinos.example.org/webhook/helloasso \ -H "Content-Type: application/json" \ -H "X-HelloAsso-Signature: <sig>" \ --data @payload.json - Vérifier l'idempotence : un seul
Fluxparhelloassoid. Cf.../dev/webhooks.htmlpour les invariants. - Si le retry échoue, contacter le support HelloAsso (ils peuvent rejouer côté serveur).
Prévention
- Monitoring du delta :
count(helloasso) − count(flux helloasso)doit être nul. - Alerter si > 0 pendant plus d'1 h (cf. monitoring).
RB-02 — Solde adhérent incohérent
Sévérité : HIGH — toute incohérence BDD financière est priorité absolue.
Symptômes
- L'adhérent voit un solde qui ne correspond pas à ses opérations.
account_*.balance≠ Σoperation_*.montant(entrées − sorties).- Alerte
kohinos:accounts:check.
Vérifications
# 1. Détection automatique
php bin/console kohinos:accounts:check
# 2. Recalcul manuel pour un compte donné
mysql kohinos -e "
SELECT a.id, a.balance,
SUM(CASE WHEN o.account_to_id = a.id THEN o.montant ELSE 0 END) AS in_sum,
SUM(CASE WHEN o.account_from_id = a.id THEN o.montant ELSE 0 END) AS out_sum
FROM account_user a
LEFT JOIN operation_user o ON o.account_to_id = a.id OR o.account_from_id = a.id
WHERE a.id = <ID>
GROUP BY a.id, a.balance;"
# 3. Tracer les modifs récentes via audit_log
mysql kohinos -e "SELECT * FROM audit_log \
WHERE object_class LIKE 'App\\\\Entity\\\\Account%' \
AND object_id = <ID> ORDER BY logged_at DESC LIMIT 20;"
Procédure
- ⛔ NE PAS toucher la BDD à la main. Un
UPDATE balancecache la cause sans la corriger. - Identifier la transaction divergente via
audit_log+flux(la divergence apparaît à un timestamp précis). - Geler l'écriture sur ce compte si possible (mode lecture seule applicatif).
- Re-jouer le calcul agrégé : la somme des opérations donne la vérité.
- Si correction nécessaire : écrire une commande Symfony dédiée
(idempotente, audit log, validation trésorier) ou une migration.
Jamais d'
UPDATEdirect. - Écrire un test reproduisant la divergence avant le fix.
Prévention
kohinos:accounts:checken cron quotidien (cf. cron).- Invariant
balance = Σ opérationstesté en intégration.
RB-03 — SEPA en double prélèvement
Sévérité : HIGH — impact direct sur le compte bancaire de l'adhérent.
Symptômes
- Deux
RecurringPurchaseRequestgénérés pour un même adhérent / même mois. - L'adhérent signale un débit double sur son relevé.
- Le fichier SEPA pain.008 contient deux lignes pour le même UMR / même période.
Vérifications
# 1. État de l'idempotence
mysql kohinos -e "SELECT id, mandate_reference, last_processed_month \
FROM sepa_mandate WHERE id = <ID>;"
# last_processed_month doit avoir été mis à jour AVANT la génération
# 2. Doublons sur le mois courant
mysql kohinos -e "
SELECT sepa_mandate_id, DATE_FORMAT(created_at, '%Y%m') AS month, COUNT(*)
FROM recurring_purchase_request
GROUP BY sepa_mandate_id, month
HAVING COUNT(*) > 1;"
# 3. Audit log de la commande sepa
grep "kohinos:sepa:process-monthly" var/log/prod.log | tail -50
Procédure
- Geler la commande SEPA (
kohinos:sepa:process-monthly) jusqu'à fix. - Identifier les doublons via la requête ci-dessus.
- Si le fichier SEPA n'est pas encore envoyé à la banque : régénérer après suppression du doublon, valider en double avec le trésorier.
- Si le débit est déjà parti :
- Rembourser manuellement l'adhérent (virement SEPA out).
- Annuler les opérations Kohinos correspondantes via une commande dédiée
(cf. règle RB-02 — pas d'
UPDATEdirect).
- Corriger l'idempotence : vérifier que
lastProcessedMonthest mis à jour dans la même transaction Doctrine que la création duRecurringPurchaseRequest. - Écrire un test reproduisant le scénario (commande lancée 2× sur le même mois → 1 seule requête générée).
Communication
Mail explicatif à l'adhérent dans les 24 h + notification du trésorier de l'association. Si l'incident touche plus de 10 adhérents, prévenir la fédération.
Prévention
- Contrainte unique applicative
(sepa_mandate_id, year_month)surrecurring_purchase_request. - Verrou applicatif (lockfile) sur la commande SEPA — cf. cron.
RB-04 — SSA redistribution échouée mid-flight
Sévérité : HIGH — partial state = conservation rompue.
Symptômes
- La commande
kohinos:ssa:executes'est interrompue (timeout, OOM, exception). - Certains adhérents ont été prélevés, d'autres pas.
- Certains prestataires ont été crédités, d'autres pas.
- Σ prélevé ≠ Σ redistribué.
Vérifications
# 1. État des items SSA
mysql kohinos -e "SELECT id, solidoume_parameter_id, last_month_payed \
FROM solidoume_item WHERE solidoume_parameter_id = <ID> \
ORDER BY id;"
# 2. Conservation : somme avant / après
mysql kohinos -e "
SELECT SUM(montant) FROM operation_user
WHERE reference LIKE 'Solidoume prélèvement %' AND DATE(created_at) = CURDATE();
SELECT SUM(montant) FROM operation_prestataire
WHERE reference LIKE 'Solidoume %' AND DATE(created_at) = CURDATE();"
# Les deux sommes doivent être EXACTEMENT égales
# 3. Logs d'exécution
grep "kohinos:ssa:execute" var/log/prod.log | tail -100
Procédure
- Geler immédiatement (ne pas relancer la commande).
- Évaluer l'état : la commande doit être atomique (transaction Doctrine). Si elle ne l'est pas, c'est le bug à corriger en priorité.
- Cas A — rollback possible : les modifications sont annulées par la
transaction. Vérifier
solidoume_item.last_month_payednon incrémenté → relancer en--testpuis en réel. - Cas B — commit partiel : situation à éviter à tout prix.
- Identifier les écritures déjà passées.
- Écrire une commande de compensation (annulation des opérations partielles).
- NE PAS faire d'
UPDATEdirect sur les balances. - Re-jouer avec
--force-date=YYYY-MM-DDaprès fix.
- Vérifier conservation Σ entrées = Σ sorties.
- Post-mortem obligatoire + test d'intégration reproduisant l'échec mid-flight.
Prévention
- Toute la commande SSA doit tenir dans une seule transaction Doctrine.
- Test d'intégration : lever une exception au milieu et vérifier rollback complet.
RB-05 — Mandat SEPA annulé mais prélèvement parti
Sévérité : HIGH — débit non autorisé = R-transaction garantie + plainte.
Symptômes
- L'adhérent a annulé son mandat dans l'admin.
- Pourtant, un débit SEPA part le mois suivant (ou pire, le jour même).
- R-transaction probable côté banque (MD01 — mandat invalide).
Vérifications
# 1. Statut du mandat au moment du process
mysql kohinos -e "SELECT id, mandate_reference, status, cancelled_at, last_processed_month \
FROM sepa_mandate WHERE id = <ID>;"
# status doit être 'active' au moment du process. Si 'cancelled', bug.
# 2. Requêtes récurrentes restées actives
mysql kohinos -e "SELECT * FROM recurring_purchase_request \
WHERE sepa_mandate_id = <ID> AND status != 'cancelled';"
Procédure
- Geler la commande SEPA si elle tourne encore.
- Si le débit n'est pas parti → retirer la ligne du fichier pain.008, re-signer, ré-envoyer.
- Si le débit est parti → remboursement immédiat (virement out), annuler les opérations Kohinos via commande dédiée.
- Corriger le code : l'annulation d'un mandat doit, dans la même transaction, annuler
atomiquement toutes les
RecurringPurchaseRequestet tous lesRecurringSubscriptionliés (cf. règle métier dansCLAUDE.md). - Test d'intégration : annulation mandat → assertions sur l'absence de débit suivant.
- Communication adhérent + trésorier obligatoire.
Prévention
SepaMandate::cancel()doit déclencher la propagation via event listener.- Vérification au début de la commande SEPA :
WHERE m.status = 'active'— pas de cache stale.
RB-06 — Server down (nginx / php-fpm / mariadb)
Sévérité : critical — indisponibilité totale.
Vérifications
# 1. État des services
sudo systemctl status nginx php8.4-fpm mariadb
# 2. Logs récents
sudo journalctl -xeu nginx --since "10 min ago"
sudo journalctl -xeu php8.4-fpm --since "10 min ago"
sudo journalctl -xeu mariadb --since "10 min ago"
# 3. Erreurs nginx applicatives
sudo tail -100 /var/log/nginx/error.log
sudo tail -100 /var/log/nginx/kohinos_error.log
# 4. OOM killer ?
sudo dmesg | grep -i -E "(killed|out of memory)" | tail -20
Procédure
- Restart séquentiel (du bas vers le haut) :
sudo systemctl restart mariadb sleep 5 sudo systemctl restart php8.4-fpm sudo systemctl restart nginx - Vérifier la santé en HTTP :
curl -sS -o /dev/null -w "%{http_code}\n" https://kohinos.example.org/ - Si OOM sur php-fpm : vérifier les batches Doctrine
(
$em->clear()manquant ?), réduirepm.max_childrentemporairement. - Si mariadb refuse de redémarrer → voir RB-07.
- Si nginx refuse de redémarrer :
sudo nginx -tpour vérifier la conf.
Prévention
- Monitoring uptime externe (UptimeRobot self-host, ping toutes les minutes).
- Alertes sur l'usage RAM (cf. monitoring).
- Limiter
pm.max_childrensur Raspberry Pi.
RB-07 — DB corruption / crash
Sévérité : critical — risque de perte de données financières.
Symptômes
- MariaDB refuse de démarrer.
- Erreurs
Table is marked as crashed,InnoDB: Database page corruption. - Requêtes qui retournent des données aberrantes.
Vérifications
# 1. Diagnostic
sudo mariadb-check --all-databases
sudo tail -200 /var/log/mysql/error.log
# 2. Espace disque (cause fréquente)
df -h
ls -lh /var/lib/mysql/
# 3. État des binlogs (CRITIQUE — ne pas les perdre)
ls -lh /var/lib/mysql/*-bin.*
Procédure
- Stopper l'application immédiatement (mode maintenance nginx).
- NE PAS PERDRE LES BINLOGS : ils permettent le point-in-time recovery.
sudo cp -a /var/lib/mysql/*-bin.* /var/backups/binlogs-$(date +%F)/ - Dump avant tout fix :
Sisudo mariadb-dump --all-databases --single-transaction --routines --triggers \ --master-data=2 > /var/backups/pre-fix-$(date +%F-%H%M).sqlmariadb-dumpéchoue, copier/var/lib/mysqlà froid (DB stoppée). - Tentative de réparation :
sudo mariadb-check --auto-repair --all-databases # ou en cas d'InnoDB corruption, mode recovery : # innodb_force_recovery=1 dans /etc/mysql/mariadb.conf.d/50-server.cnf # puis remonter par paliers (1 → 6), dump, restore propre - Si réparation impossible : restauration depuis backup (cf. backup-restore) + replay binlogs.
- Vérification post-restore :
php bin/console kohinos:accounts:check php bin/console doctrine:schema:validate # Comparer les soldes globaux avant/après - Si écart financier : bloquer toute opération, communiquer trésorier, audit complet.
Prévention
- Backups quotidiens vérifiés (restore test mensuel) — cf. backup-restore.
- Binlogs activés en permanence (
log_bin=ON). - Monitoring de l'espace disque (RB-09).
RB-08 — Cron qui ne tourne plus
Sévérité : medium à high selon le job (SEPA/SSA = high, nettoyage cache = low).
Symptômes
- Les notifications quotidiennes ne partent plus.
- La table
cron_reportn'a plus d'entrée récente. - SSA mensuel pas déclenché le 1er.
Vérifications
# 1. Crontab effectif
sudo crontab -l -u kohinos
sudo crontab -l -u www-data
cat /etc/cron.d/kohinos 2>/dev/null
# 2. Service cron actif
sudo systemctl status cron
# 3. Historique d'exécution
mysql kohinos -e "SELECT command, started_at, finished_at, status \
FROM cron_report ORDER BY started_at DESC LIMIT 30;"
# 4. Lockfile resté en place ?
ls -la var/lock/ /var/lock/kohinos-*
Procédure
- Identifier le job concerné — voir cron.html pour la liste.
- Si lockfile résiduel (crash précédent qui ne l'a pas relâché) :
sudo rm /var/lock/kohinos-sepa-process-monthly.lock # puis replay manuel sudo -u www-data php bin/console kohinos:sepa:process-monthly --test # si OK, sans --test - Si cron daemon down :
sudo systemctl restart cron. - Si permissions : vérifier que l'utilisateur cron peut écrire dans
var/logetvar/cache. - Replay manuel du job manqué avec
--force-date=YYYY-MM-DDsi applicable.
Prévention
- Monitoring heartbeat par job (cf. monitoring) —
alerte si pas d'entrée
cron_reportdans la fenêtre attendue. - Lockfile avec
flock+ suppression automatique entrap EXIT.
RB-09 — Disque plein
Sévérité : high — provoque crash MariaDB, échec d'écritures Symfony.
Vérifications
# 1. Vue d'ensemble
df -h
df -i # inodes (cause souvent oubliée)
# 2. Coupables habituels
sudo du -sh /var/www/kohinos/var/log
sudo du -sh /var/www/kohinos/var/cache
sudo du -sh /var/lib/mysql
sudo du -sh /var/log/nginx /var/log/mysql
sudo du -sh /var/backups
Procédure
- Faire de la place sans rien casser :
# Logs applicatifs > 30 jours (garder les logs financiers : sepa/, ssa/, audit/) sudo find /var/www/kohinos/var/log -name "*.log" -mtime +30 \ -not -path "*/sepa/*" -not -path "*/ssa/*" -not -path "*/audit/*" -delete # Cache Symfony prod (à régénérer ensuite) sudo -u www-data rm -rf /var/www/kohinos/var/cache/prod/* sudo -u www-data php /var/www/kohinos/bin/console cache:warmup --env=prod # Sessions expirées sudo find /var/www/kohinos/var/sessions -mtime +7 -delete # Logs nginx sudo logrotate -f /etc/logrotate.d/nginx - Backups anciens : NE PAS supprimer aveuglément. Conserver au moins : dernier daily × 7, dernier weekly × 4, dernier monthly × 12.
- Vérifier que la rotation de logs (
logrotate) fait son travail :cat /etc/logrotate.d/kohinos. - Si MariaDB binlogs prennent tout :
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 14 DAY;(seulement après backup vérifié).
Prévention
- Alerte à 75 % d'occupation, critique à 90 %.
logrotateconfiguré pour tous les logs applicatifs.- Politique de rétention backups documentée.
RB-10 — Compromission soupçonnée
Sévérité : critical — RGPD, fonds, réputation.
Symptômes
- Connexions admin depuis IP inconnues / pays improbables.
- Modifications de données non-traçables dans
audit_log. - Comptes utilisateur créés en lot, élévation de privilège.
- Fichiers inattendus dans
public/(webshell). - Alerte CrowdSec / fail2ban / WAF.
Procédure (dans cet ordre, sans hésiter)
- Isoler immédiatement :
# Bloquer tout sauf l'IP admin sudo ufw default deny incoming sudo ufw allow from <IP_ADMIN> to any port 22 sudo ufw allow from <IP_ADMIN> to any port 443 sudo ufw enable # Couper l'app au public (maintenance mode) sudo systemctl stop nginx - Rotation IMMÉDIATE de tous les secrets :
APP_SECRET(Symfony) → déconnecte toutes les sessions.- Password MariaDB (
SET PASSWORD FOR kohinos@localhost = PASSWORD('...');) +DATABASE_URL. - Clé de chiffrement IBAN (
KOHINOS_IBAN_SECRET) — déclenche RB-12. - Clés Ed25519 SEPA (libsodium).
- Tokens HelloAsso / PayZen (révocation côté provider + nouveaux).
- Mots de passe SMTP (
MAILER_DSN). - Clés SSH du serveur.
- Dump volume forensic AVANT toute remédiation :
sudo dd if=/dev/sda of=/mnt/forensic/disk-$(date +%F).img bs=4M status=progress # ou snapshot LVM / hyperviseur - Audit logs :
mysql kohinos -e "SELECT * FROM audit_log WHERE logged_at > NOW() - INTERVAL 30 DAY \ ORDER BY logged_at DESC LIMIT 500;" sudo last -50 sudo grep "Accepted" /var/log/auth.log | tail -100 - Identifier le vecteur d'entrée (CVE non patché ? credentials volés ? injection ?).
- Restauration depuis un backup antérieur à la compromission (cf. backup-restore) sur une nouvelle machine.
- Communication obligatoire :
- Trésorier + bureau de l'association.
- Si données personnelles touchées : notification CNIL sous 72 h (article 33 RGPD).
- Information des adhérents si risque pour leurs droits et libertés.
- Post-mortem détaillé + plan d'action sécurité (durcissement, MFA, patch policy).
Prévention
- MFA admin obligatoire, fail2ban, CrowdSec.
- Patch policy < 7 j pour CVE high/critical Symfony/PHP/MariaDB.
- Audit log immuable (append-only, signature chaînée Ed25519).
RB-11 — Migration Doctrine échouée en prod
Sévérité : HIGH — état schéma incohérent = app KO.
Symptômes
doctrine:migrations:migratea planté au milieu (timeout, erreur SQL, signal).- Table
doctrine_migration_versionsmarque la migration comme « executed » mais le schéma est incomplet. - L'application lève des erreurs Column X not found ou Table Y already exists.
Vérifications
# 1. État des migrations
php bin/console doctrine:migrations:status --env=prod
php bin/console doctrine:migrations:list --env=prod
# 2. Diff schéma réel vs entités
php bin/console doctrine:schema:validate --env=prod
# 3. Quelle migration ?
mysql kohinos -e "SELECT * FROM doctrine_migration_versions ORDER BY executed_at DESC LIMIT 5;"
Procédure
- Stopper le trafic (maintenance mode nginx).
- Backup immédiat avant toute manipulation (le DB est dans un état précis, on veut pouvoir y revenir).
- Tentative de rollback :
# Reculer d'une version php bin/console doctrine:migrations:migrate prev --env=prod --no-interaction # Ou viser une version précise php bin/console doctrine:migrations:migrate <version> --env=prod --no-interaction - Si le rollback échoue (down() non implémenté correctement) : restore depuis backup pre-deploy (cf. backup-restore).
- Corriger la migration en dev : tester sur copie de prod (
mysqldump→ copie locale) avant de relancer. - Écrire un test d'intégration sur la migration corrigée.
- Redéployer.
Prévention
- Toute migration testée sur copie de prod avant déploiement.
down()implémenté et testé pour chaque migration.- Backup automatique pre-deploy dans le pipeline CI/CD (cf. ci-cd).
RB-12 — IBAN chiffré illisible
Sévérité : high — empêche tout prélèvement SEPA.
Symptômes
- Erreurs
sodium_crypto_secretbox_openrenvoyantfalse. - Champs IBAN affichés en mojibake ou vides dans l'admin.
- Génération du fichier SEPA pain.008 échoue.
- Survenu typiquement après rotation de la clé de chiffrement.
Vérifications
# 1. La clé courante est-elle bien chargée ?
php bin/console debug:dotenv | grep -i iban
php bin/console secrets:list | grep -i iban
# 2. Tester le déchiffrement sur un compte connu
php bin/console app:migrate-iban-encryption --dry-run | head -20
# 3. Comparer les IBAN chiffrés (longueur, prefix) avant/après
mysql kohinos -e "SELECT id, LENGTH(iban_encrypted), \
LEFT(iban_encrypted, 16) FROM sepa_mandate LIMIT 5;"
Procédure
- Récupérer l'ancienne clé (gestionnaire de secrets, backup chiffré). Si perdue, restauration depuis backup pre-rotation obligatoire.
- Configurer une double-validation temporaire : l'app essaye la nouvelle
clé, en cas d'échec retombe sur l'ancienne (variable
KOHINOS_IBAN_SECRET_PREVIOUS). - Lancer la re-chiffrement de tous les IBAN avec la nouvelle clé :
php bin/console app:migrate-iban-encryption --dry-run # Vérifier la sortie, puis : php bin/console app:migrate-iban-encryption - Une fois 100 % migré et vérifié → retirer
KOHINOS_IBAN_SECRET_PREVIOUSet révoquer définitivement l'ancienne clé. - Test SEPA en mode
--testavant de relancer un cycle réel.
Prévention
- Toute rotation de clé suit la procédure : ajouter nouvelle clé en PREVIOUS, re-chiffrer, retirer l'ancienne — jamais en une étape.
- Backup chiffré de la clé hors-bande (coffre-fort papier chez le trésorier).
- Procédure de rotation documentée et testée en staging chaque trimestre.
Conventions de rédaction d'un runbook
Tout nouveau runbook doit suivre la même structure :
- Titre :
RB-XX — <phrase courte décrivant l'incident>. - Sévérité : low / medium / high / critical. Indique la priorité d'intervention et l'obligation de communication.
- Symptômes : ce que l'on voit (utilisateur, logs, monitoring). Permet l'identification rapide.
- Vérifications : commandes copy/paste-friendly, sans risque (lecture seule). Confirment le diagnostic.
- Procédure : liste numérotée d'actions, dans l'ordre. Chaque étape doit être atomique et idempotente quand possible.
- Prévention : ce qu'on met en place pour que l'incident ne revienne pas (monitoring, test, invariant).
- Post-mortem : lien (à créer après l'incident).
Post-mortem — exigence
Format : blameless (le but est d'améliorer le process, pas de désigner un
responsable). Stocké dans docs/postmortems/YYYY-MM-DD-titre.md.
Structure type d'un post-mortem :
- Résumé : 3 lignes — quoi, quand, impact.
- Timeline : minute par minute, faits objectifs, sans interprétation.
- Cause racine : le « pourquoi » (5 whys jusqu'à la cause structurelle).
- Ce qui a bien marché : monitoring, runbook utilisé, communication.
- Ce qui a mal marché : latence détection, étapes manquantes, etc.
- Actions correctives : tickets ou commits avec responsable et deadline.
- Mise à jour du runbook : référence au commit qui modifie cette page.
Voir aussi
- Backup & restore — procédures de restauration référencées par RB-07, RB-10, RB-11.
- Cron & jobs planifiés — détails de RB-08.
- Monitoring — alertes qui déclenchent ces runbooks.
- Webhooks (dev) — invariant d'idempotence (RB-01).
- Invariants financiers — règles que les runbooks protègent (RB-02, RB-03, RB-04).