Exploitation
Commandes
Section intitulée « Commandes »Toutes s’exécutent avec docker compose run --rm app <commande>.
| Commande | Ce qu’elle fait |
|---|---|
serve | démarre le serveur (c’est la commande par défaut du conteneur) |
provisionner-brasserie | crée une brasserie, son premier administrateur et ses emplacements de base |
creer-editeur | crée un compte du back-office éditeur |
semer-demonstration | injecte un parc de démonstration avec un an d’historique |
reconstruire-projections | rejoue le flux d’événements et recalcule l’état courant |
exporter-locataire | exporte l’intégralité des données d’une brasserie en JSON |
supprimer-locataire | supprime définitivement une brasserie |
Sauvegardes
Section intitulée « Sauvegardes »Le service sauvegarde produit une archive pg_dump --format=custom au
démarrage puis chaque nuit à 03h15, avec rotation : 7 quotidiennes,
4 hebdomadaires, 6 mensuelles (configurable par RETENTION_*).
Deux garde-fous, parce que les deux pannes silencieuses classiques sont d’archiver une base pas encore migrée et d’archiver une base vide sans s’en apercevoir :
- la première sauvegarde attend que le schéma existe ;
- chaque archive est relue (
pg_restore --list) et rejetée si elle ne contient pas les données deevenement_fut.
docker compose exec sauvegarde ls -lh /sauvegardes/quotidiendocker compose logs sauvegarde --tail 20Restauration — la procédure, testée
Section intitulée « Restauration — la procédure, testée »Une sauvegarde jamais restaurée n’est pas une sauvegarde. Celle-ci est rejouée par l’intégration continue à chaque modification, et voici la version manuelle.
Répétition sans risque, dans une base jetable :
DUMP=$(docker compose exec -T sauvegarde sh -c 'ls -1t /sauvegardes/quotidien/*.dump | head -1' | tr -d '\r')
docker compose exec -T postgres psql -U postgres -d postgres \ -c "drop database if exists webqr_restaure with (force);" \ -c "create database webqr_restaure;"
docker compose exec -T sauvegarde \ pg_restore -h postgres -U postgres --dbname=webqr_restaure \ --no-owner --no-privileges "$DUMP"
docker compose exec -T postgres psql -U postgres -d webqr_restaure -tAc \ "select (select count(*) from fut) || ' fûts, ' || (select count(*) from evenement_fut) || ' événements'"Comparez avec la base vivante. Puis drop database webqr_restaure.
Restauration réelle, après incident :
docker compose stop app caddydocker compose exec -T postgres psql -U postgres -d postgres \ -c "drop database webqr with (force);" -c "create database webqr owner webqr_owner;"docker compose exec -T sauvegarde pg_restore -h postgres -U postgres --dbname=webqr "$DUMP"docker compose start app caddydocker compose run --rm app reconstruire-projections --verifierLa dernière ligne n’est pas décorative : elle prouve que la base restaurée est cohérente, en rejouant tout le flux d’événements et en le comparant à l’état courant.
Cohérence des projections
Section intitulée « Cohérence des projections »L’état d’un fût affiché dans les listes est un cache. La vérité est la suite de ses événements, en ajout seul.
# Vérifie sans rien écrire ; sort en erreur s'il existe un écart.docker compose run --rm app reconstruire-projections --verifier
# Recalcule et corrige.docker compose run --rm app reconstruire-projections --locataire phareÀ lancer après une restauration, après une correction de bug de projection, ou simplement par acquit de conscience. Le rejeu est idempotent.
Sortie et suppression des données
Section intitulée « Sortie et suppression des données »docker compose run --rm app exporter-locataire --locataire phare --sortie phare.jsondocker compose run --rm app supprimer-locataire --locataire phare --confirmerL’export contient toutes les tables du locataire au format JSON ouvert. La suppression est définitive et emporte tout par cascade ; elle est journalisée dans le journal éditeur.
Rotation du secret applicatif
Section intitulée « Rotation du secret applicatif »SECRET_APP poivre Argon2id. Le changer invalide tous les mots de passe
et tous les codes PIN. Si vous devez le faire :
- prévenez les utilisateurs ;
- changez la variable et redémarrez ;
- réinitialisez chaque mot de passe depuis
Administration → Utilisateurs → Réinitialiser.
Il n’y a pas de migration en douceur : c’est le prix du poivre, et il est volontaire.
Journalisation et supervision
Section intitulée « Journalisation et supervision »Journalisation structurée sur la sortie standard, niveau réglé par
RUST_LOG (par exemple info,web=debug,sqlx=warn).
| Point | Usage |
|---|---|
GET /sante | vivacité : le processus répond |
GET /pret | disponibilité : la base répond aussi (utilisé par le healthcheck) |
Deux journaux d’audit en base :
journal_audit— par brasserie : connexions, changements de rôle, archivages, imports, validations de documents, modifications de paramètres. Consultable dansAdministration → Journal d'audit.journal_audit_editeur— hors brasserie : créations, suspensions, et chaque ouverture et fermeture d’assistance.
Assistance (usurpation de support)
Section intitulée « Assistance (usurpation de support) »Depuis /editeur, le bouton Assistance ouvre une session dans la
brasserie choisie, sur son premier administrateur actif. Cette session :
- dure une heure au maximum ;
- porte une marque en base (
session.usurpee_par) ; - affiche un bandeau rouge permanent dans toute l’application ;
- est journalisée à l’ouverture et à la fermeture.
C’est un pouvoir réel : ne l’utilisez que sur demande du client, et fermez la session dès que le diagnostic est fait.
Limitation de débit
Section intitulée « Limitation de débit »Deux niveaux, complémentaires :
- par adresse IP, en mémoire : 12 tentatives de connexion par minute, 8 pour le code PIN et le back-office éditeur, 240 scans par minute et par utilisateur. Remis à zéro au redémarrage, ce qui est acceptable pour ce qu’il protège.
- par compte, en base : au-delà de 5 échecs, verrouillage exponentiel (1, 2, 4, 8… minutes, plafonné à 30). Celui-là survit à un redémarrage — c’est lui qui protège réellement contre le bourrage.
Cinq codes PIN erronés révoquent la session : on repasse obligatoirement par le mot de passe.
Mise à l’échelle
Section intitulée « Mise à l’échelle »Le déploiement v1 est mono-instance. Pour passer à plusieurs instances d’application derrière le même proxy, deux points à traiter :
- la limitation de débit par IP est en mémoire : la déporter en base ou dans un cache partagé ;
- rien d’autre. Les sessions, les brouillons de capture et les compteurs de référence vivent déjà en base.
PostgreSQL reste l’unique point d’état. Les index et la pagination côté serveur sont dimensionnés pour un parc de plusieurs milliers de fûts et plusieurs centaines de milliers d’événements.