Nicolas Cantu 61cec6f430 Sync ia_dev: token resolution via .secrets/<env>/ia_token, doc updates
**Motivations:**
- Align master with current codebase (token from projects/<id>/.secrets/<env>/ia_token)
- Id resolution by mail To or by API token; no slug

**Root causes:**
- Token moved from conf.json to .secrets/<env>/ia_token; env from directory name

**Correctifs:**
- Server and scripts resolve project+env by scanning all projects and envs

**Evolutions:**
- tickets-fetch-inbox routes by To address; notary-ai agents and API doc updated

**Pages affectées:**
- ai_working_help/server.js, docs, project_config.py, lib/project_config.sh
- projects/README.md, lecoffreio/docs/API.md, gitea-issues/tickets-fetch-inbox.py
2026-03-16 15:00:23 +01:00

80 KiB
Raw Permalink Blame History

Déploiement LeCoffre.io - Guide Complet

Dernière mise à jour : 2026-03-10 Version : 2.0.1

Ce document consolide toute la documentation relative au déploiement (scripts, variables, logging, Nginx, SSL).


📋 Table des Matières

  1. Vue d'ensemble
  2. Prérequis
  3. Configuration
  4. Variables d'environnement
  5. Déploiement principal
  6. Cartographie des checks de déploiement (source unique)
  7. Logs de déploiement
  8. Scripts et commandes
  9. Maintenance et troubleshooting
  10. API d'ancrage Bitcoin séparée
  11. Sécurité
  12. Monitoring
  13. Disaster Recovery

Vue d'ensemble

LeCoffre.io utilise un système de déploiement automatisé via SSH orchestré depuis le proxy (point dentrée unique).

Le mode de déploiement recommandé est deploy/scripts_v2/ (services systemd sur les serveurs denvironnements) :

  • Synchronisation Git
  • Installation des dépendances système sur lhôte (PostgreSQL, ClamAV, Chromium, LibreOffice, Java…)
  • Build backend/frontend
  • Services systemd (backend/cron/frontend/router)
  • Migrations Prisma, injection de configuration (system_configuration), scripts métier (Stripe, ré-ancrage…)

Environnements disponibles :

  • test : Environnement de test
  • pprod : Pré-production
  • prod : Production
  • demo : Démonstration

Prérequis

Sur la machine locale (déploiement)

  • Git : Pour le versioning et la synchronisation
  • Node.js 25+ : Pour la compilation TypeScript
  • npm : Gestionnaire de paquets
  • rsync : Synchronisation des fichiers
  • SSH avec clé configurée : Accès au serveur distant

Sur la machine distante (cible)

  • Accès SSH avec clé
  • PostgreSQL (service système, port 5432)
  • ClamAV (service système, port 3310)
  • Chromium (binaire /usr/bin/chromium)
  • LibreOffice + Java
  • Node.js 25+ et npm (pour build et exécution). Mise à jour si inférieur : bash deploy/scripts_v2/run-update-node-25-on-servers.sh (test, pprod, prod).

Configuration SSH

# Configurer la clé SSH
ssh-copy-id -i ~/.ssh/id_ed25519 ncantu@4nk.myftp.biz

# Tester la connexion
ssh ncantu@4nk.myftp.biz "echo OK"

Configuration

1. Fichier .env.<env>

Créer .secrets/test/.env.test, .secrets/pprod/.env.pprod, ou .secrets/prod/.env.prod avec :

# Database
# Variables construites dynamiquement depuis ENV :
#   DATABASE_HOST=127.0.0.1
#   DATABASE_PORT=5432
#   DATABASE_USERNAME=lecoffre-user-${ENV}
#   DATABASE_NAME=bdd-${ENV}
# Seule variable requise :
DATABASE_PASSWORD=***

# Deployment (scripts_v2)
# Les déploiements sont exécutés sur le proxy (4nk.myftp.biz / 192.168.1.100).
# Les environnements sont sur le réseau privé :
# - test  : 192.168.1.101 → test.lecoffreio.4nkweb.com
# - pprod : 192.168.1.102 → pprod.lecoffreio.4nkweb.com
# - prod  : 192.168.1.103 → prod.lecoffreio.4nkweb.com
DEPLOY_SSH_USER=ncantu
DEPLOY_SSH_KEY=~/.ssh/id_ed25519

# Frontend (sera injecté en base lors du premier déploiement)
NEXT_PUBLIC_SPLASH_MESSAGE=Environnement de test

# Grafana (monitoring)
GRAFANA_ADMIN_USER=grafana-admin
GRAFANA_ADMIN_PASSWORD=change_me

1bis. Git (scripts_v2)

deploy/scripts_v2/deploy.sh effectue automatiquement, en local, avant toute synchronisation côté cible :

  • npm run lint:fix sur lecoffre-ressources-dev, lecoffre-back-main, lecoffre-front-main (non bloquant) (le déploiement échoue si lint:fix retourne une erreur non corrigeable)
  • git add -A
  • git commit (message au format imposé par le dépôt)
  • git push origin $DEPLOY_GIT_BRANCH

Le script est strict :

  • il exige DEPLOY_GIT_BRANCH (dans .secrets/<env>/.env.<env> ou exporté)
  • la branche locale courante doit être exactement $DEPLOY_GIT_BRANCH
  • la cible est synchronisée uniquement sur origin/$DEPLOY_GIT_BRANCH (pas dautre ref)

1ter. Migrations requises (scripts_v2)

En mode scripts_v2, certaines actions exigent que les migrations Prisma soient exécutées dans la même commande (mode strict) :

  • --resetDatabasedoit être accompagné de --migrateResolveDatabase
  • --resetDatabaseFromSchemaExportdoit être accompagné de --migrateResolveDatabase (voir ci-dessous)
  • --setSettings, --seedSiteTexts, --importStripe, --reanchorAll, --promoteSuperAdmins, --activateSubscriptionsdoivent être accompagnés de --migrateResolveDatabase

Variables d'automatisation (stockées en BDD via system_configuration) :

  • SUPERADMIN_EMAILS : Liste d'emails (séparés par des virgules) promus automatiquement en super-admin lors du déploiement avec --promoteSuperAdmins
  • AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS : Liste d'emails (séparés par des virgules) dont tous les abonnements seront activés/créés automatiquement lors du déploiement avec --activateSubscriptions

Baseline DB v2 depuis un export de schéma (sans rejouer l'historique des migrations)

Quand les dumps disponibles sont uniquement en v1 (et/ou que l'historique des migrations pose problème), scripts_v2 permet de reconstruire une base v2 vide directement depuis un export SQL schema-only :

  • Le script applique un export SQL schema-only sur une base vide :
    • deploy/schema-v2.sql si présent (prioritaire)
    • sinon deploy/scripts_v2/schema-v2-initial.sql (export de référence v2 fourni dans le repo)
  • Puis exécute prisma migrate resolve --applied sur toutes les migrations présentes dans le repo (sans les exécuter) pour que Prisma considère la base comme "à jour"
  • Ensuite, --migrateResolveDatabase peut s'exécuter (il ne doit appliquer que des migrations futures, au-delà de la baseline)

Fichier requis :

  • deploy/schema-v2.sql (optionnel) : export du schéma cible (schema-only) compatible psql -f
    • il peut contenir des directives psql (ex: \restrict / \unrestrict) : scripts_v2 les filtre lors de l'application
    • si besoin, utiliser deploy/schema-v2.sql.example comme guide

Commande type :

bash deploy/scripts_v2/deploy.sh test \
  --resetDatabaseFromSchemaExport \
  --migrateResolveDatabase \
  --deploy \
  --skipCheckLint

Import v1 → v2 : Premier import (full) vs Imports incrémentaux (merge)

Premier import (full, destructif) :

Le flag --importV1Data effectue un import complet depuis un dump v1 :

  • Applique la compatibilité layer v1→v2 (enums + colonnes manquantes)
  • TRUNCATE toutes les tables (sauf _prisma_migrations et system_configuration)
  • Restaure les TABLE DATA du dump v1 via pg_restore --data-only
bash deploy/scripts_v2/deploy.sh test \
  --resetDatabaseFromSchemaExport \
  --migrateResolveDatabase \
  --importV1Data \
  --deploy \
  --skipCheckLint

Imports incrémentaux (merge, non-destructif) :

Le flag --importV1DataMerge effectue un merge des données v1 dans la v2 existante :

  • Applique la compatibilité layer v1→v2 (enums + colonnes manquantes)
  • Restaure le dump v1 dans une DB temporaire
  • Effectue des INSERT ... ON CONFLICT DO UPDATE par table (upsert)
  • Préserve les données v2 existantes
  • Intègre les nouvelles données v1
# Script wrapper (recommandé)
bash deploy/scripts_v2/merge-v1-data-into-v2.sh test

# Ou directement
bash deploy/scripts_v2/deploy.sh test \
  --importV1DataMerge \
  --skipCheckLint

Workflow recommandé :

  1. Premier import : install-or-reset-env-from-schema-export.sh <env> (baseline + import full)
  2. Imports suivants : merge-v1-data-into-v2.sh <env> (merge incrémental)

Prérequis pour les imports :

  • Le dump v1 doit être présent localement : .secrets/<env>/bdd.<env>
  • Format attendu : custom-format pg_dump (PGDMP)

Détails techniques (merge) :

  • Les tables sans PK/UK sont ignorées (risque de doublons)
  • Les colonnes communes entre v1 et v2 sont synchronisées
  • Les colonnes v1 absentes en v2 sont ignorées (après compat layer)
  • Les colonnes v2 absentes en v1 sont préservées (non modifiées)

2. Base de données

La base PostgreSQL doit être créée et accessible. Le script :

  • Applique les migrations Prisma automatiquement
  • Synchronise les données (IdNot, Annuaire, Stripe)
  • Valide les identifiants PostgreSQL avant déploiement
  • Ne crée PAS la base (à faire manuellement)

Validation des identifiants PostgreSQL : Le script valide automatiquement les identifiants (DATABASE_USERNAME / DATABASE_PASSWORD) avant de démarrer le déploiement. En cas d'échec de connexion, le script affiche un message d'erreur explicite et s'arrête.

Gestion des migrations Prisma :

  • Le schéma Prisma est dans lecoffre-back-main/prisma/schema.prisma
  • Les migrations sont dans prisma/migrations/
  • Le script crée automatiquement un lien symbolique src/common/databases/migrationsprisma/migrations pour que Prisma trouve les migrations
  • Les migrations sont appliquées via npm run migrate (qui utilise prisma migrate deploy)
  • Détection automatique des migrations baselinées (marquées comme appliquées sans être exécutées) et réinitialisation si nécessaire

3. Configuration ClamAV (system_configuration via import-env-to-db)

Les variables suivantes ne vont pas dans .env.<env> mais dans .secrets/<env>/env-full-<env>-for-bdd-injection.txt (puis importées via config:import-env) :

CLAMAV_HOST=127.0.0.1
CLAMAV_PORT=3310
CLAMAV_SCAN_ENABLED=true
CLAMAV_CONNECTION_TIMEOUT_MS=8000
CLAMAV_READ_TIMEOUT_MS=150000
CLAMAV_MAX_FILE_SIZE_MB=120

Sans ces clés, le backend refuse désormais les uploads (aucun fallback).


Variables d'environnement

Vue d'ensemble

Le script build-and-deploy.sh lit ses configurations de déploiement depuis les fichiers .env.<env> au lieu d'avoir des valeurs hardcodées.

Variables requises

Chaque fichier .env.test, .env.pprod, .env.prod doit contenir :

Variables de déploiement SSH

# Host SSH de la machine cible
DEPLOY_SSH_HOST=<IP_SERVEUR>

# Utilisateur SSH (optionnel, défaut: debian)
DEPLOY_SSH_USER=debian

# Clé SSH (optionnel, défaut: ~/.ssh/id_rsa)
DEPLOY_SSH_KEY=~/.ssh/id_rsa

# Répertoire de déploiement sur la machine distante
DEPLOY_REMOTE_PATH=/home/debian/sites/test-lecoffreio.4nkweb.com

# Domaine pour Nginx et SSL
DEPLOY_DOMAIN=test-lecoffreio.4nkweb.com

Configuration par environnement

Test

DEPLOY_SSH_HOST=<IP_SERVEUR_TEST>
DEPLOY_SSH_USER=debian
DEPLOY_REMOTE_PATH=/home/debian/sites/test-lecoffreio.4nkweb.com
DEPLOY_DOMAIN=test-lecoffreio.4nkweb.com

Pré-production

DEPLOY_SSH_HOST=<IP_SERVEUR_PPROD>
DEPLOY_SSH_USER=debian
DEPLOY_REMOTE_PATH=/home/debian/sites/pprod-lecoffreio.4nkweb.com
DEPLOY_DOMAIN=pprod-lecoffreio.4nkweb.com

Production

DEPLOY_SSH_HOST=<IP_SERVEUR_PROD>
DEPLOY_SSH_USER=debian
DEPLOY_REMOTE_PATH=/home/debian/sites/prod-lecoffreio.4nkweb.com
DEPLOY_DOMAIN=prod-lecoffreio.4nkweb.com

Fonctionnement

  1. Le script build-and-deploy.sh vérifie que .env.<env> existe
  2. Il source le fichier avec source .env.<env>
  3. Il mappe les variables DEPLOY_* vers les variables internes du script
  4. Il valide que toutes les variables requises sont définies
  5. Il bloque si DEPLOY_SSH_HOST=TBD (environnement non configuré)

Avantages

  • Pas de valeurs hardcodées dans le script
  • Configuration centralisée dans les fichiers .env
  • Cohérence avec le reste de l'architecture (config en BDD)
  • Facilité de maintenance : modifier .env.* au lieu du script
  • Sécurité : les .env.* sont en .gitignore
  • Validation : le script vérifie que toutes les variables sont présentes

Déploiement principal

Commande simple

./deploy/scripts/build-and-deploy.sh test    # Environnement test
./deploy/scripts/build-and-deploy.sh pprod   # Environnement pprod
./deploy/scripts/build-and-deploy.sh prod    # Environnement prod

Options de déploiement

# Déploiement complet avec toutes les étapes
./deploy/scripts/build-and-deploy.sh test --deploy --cert --resetDatabase --setSettings --syncIdNot --syncDirectory

# Opérations post-déploiement (conteneurs déjà actifs)
./deploy/scripts/build-and-deploy.sh pprod --syncIdNot --syncDirectory --reanchorAll

# Import Stripe et réancrage
./deploy/scripts/build-and-deploy.sh test --importStripe --reanchorAll

# Promotion super-admins depuis liste config
./deploy/scripts/build-and-deploy.sh pprod --promoteSuperAdmins

# Activation abonnements depuis liste config
./deploy/scripts/build-and-deploy.sh pprod --activateSubscriptions

Flags disponibles :

  • --deploy : Build et déploiement complet (redémarre les services systemd)

  • --resetDatabase : ⚠️ DESTRUCTIF : Recréer la base et importer depuis .secrets/<ENV>/bdd.<ENV>Important : relancer ensuite npm run config:import-env -- --env <env> sur le serveur cible puis reseeder role_permissions_matrix (cf. DATABASE_RESET_GUIDE)

  • --migrateResolveDatabase : Appliquer les migrations Prisma manquantes (prisma migrate deploy)

    • Vérifications systématisées : Vérifie et ajoute automatiquement les colonnes manquantes (proof_data, confirmations, anchor_job_id) dans les tables d'ancrage (document_anchors, document_notary_anchors)
    • 8 points de vérification : Les colonnes sont vérifiées à 8 endroits différents pour garantir leur présence
    • Gestion des erreurs : Retry automatique et messages d'erreur explicites si l'ajout de colonnes échoue
    • 📖 Voir ANCRAGE_COMPLETE.md pour les corrections détaillées sur les colonnes d'ancrage
  • --setSettings : Injection configurations depuis fichier env-full-*

  • --seedSiteTexts : Exécuter le seed des textes du site (node dist/scripts/seed-site-texts.js)

  • --syncIdNot : Synchronisation utilisateurs IdNot OAuth

  • --syncDirectory : Synchronisation API Annuaire

  • --cert : ⚠️ DESTRUCTIF : Ecrase les certificats existant, activer la gestion des certificats Let's Encrypt (sinon aucune action certificat)

  • --reanchorAll : ⚠️ DESTRUCTIF : Supprimer toutes les ancres et réancré tous les documents (tous statuts), documents notaires et RIB

    • Vérification préalable : Vérifie l'existence des tables avant d'ajouter les colonnes manquantes
    • Vérification finale : Bloque le réancrage si les colonnes indispensables (proof_data, confirmations) manquent
    • Ordre garanti : S'exécute toujours après --migrateResolveDatabase pour garantir la présence des colonnes
    • 📖 Voir ANCRAGE_COMPLETE.md pour les corrections détaillées sur les colonnes d'ancrage
  • --promoteSuperAdmins : Promotion automatique des super-admins configurés en BDD (clé SUPERADMIN_EMAILS)

  • --activateSubscriptions : Activation automatique des abonnements pour les emails configurés en BDD (clé AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS)

  • --importStripe : Synchronisation plans et abonnements Stripe

  • --getToken : Génère un couple access/refresh token pour le premier super-admin disponible (promotion automatique de laurence@notaires.fr si aucun super-admin actif)

  • --checkLint : Exécuter les lints/TypeScript/compilation checks avant le build (activé par défaut)

  • --skipCheckLint : Désactiver les vérifications pré-build (lint, TypeScript, compilation)

  • --skipBuildChecks : Désactiver uniquement les build checks (lint et typecheck toujours exécutés)

  • --skipDiskCleanup : Ignorer le nettoyage de l'espace disque (peut accélérer le déploiement)

  • --skipBackupsRecovery : Ignorer la récupération des sauvegardes sur la machine locale

  • --aggressiveCleanup : ⚠️ Nettoyage agressif de l'espace disque

  • --showLogs : Afficher les logs des services (backend/frontend) après le déploiement

  • --showLogsService <name> : Service spécifique pour --showLogs (backend, frontend, ou all, défaut: backend)

  • --showLogsTail <lines> : Nombre de lignes de logs à afficher (défaut: 200)

  • --showLogsSince <duration> : Filtrer les logs depuis (ex: 1h, 10m, 2024-12-02T10:00:00)

Mise à jour des secrets site texts (pprod / prod)

Les fichiers .secrets/<env>/seed-site-texts-<env>.ts et .secrets/<env>/env-full-<env>-for-bdd-injection.txt ne doivent pas être versionnés dans le dépôt applicatif cible. La source de vérité est le dépôt utilisé pour déclencher le déploiement.

  • Seed : copier le contenu du seed de test vers le seed de lenvironnement cible, puis adapter uniquement les mentions denvironnement (ex. retirer [ENVIRONNEMENT DE TEST] en prod).
  • Env-full : aligner la ligne SITE_TEXTS_KEYS_INDEX=... avec celle de test (même liste et même ordre) pour garantir que les clés seedées sont bien indexées.

Après mise à jour des secrets, un déploiement standard (deploy/scripts_v2/deploy.sh) synchronise les fichiers .secrets/<env>/ vers la cible et exécute le seed si --seedSiteTexts est actif.

Exemples d'usage :

# Déploiement complet environnement from scratch
./deploy/scripts/build-and-deploy.sh test --deploy --cert --resetDatabase --setSettings --syncIdNot --syncDirectory --importStripe --reanchorAll

# Synchronisation quotidienne sans interruption
./deploy/scripts/build-and-deploy.sh pprod --syncIdNot --syncDirectory --importStripe

# Réancrage tous dossiers existants (maintenance - DESTRUCTIF)
./deploy/scripts/build-and-deploy.sh test --reanchorAll

# Mise à jour code avec redéploiement
./deploy/scripts/build-and-deploy.sh pprod --deploy

# Génération d'un token super-admin sans redéployer
./deploy/scripts/build-and-deploy.sh pprod --getToken

# Déploiement avec affichage des logs backend
./deploy/scripts/build-and-deploy.sh pprod --deploy --showLogs --showLogsService backend --showLogsTail 500 --showLogsSince 1h

Pour les tests manuels, il est possible de récupérer un jeton en local via npm run token:get -- --json.

Processus complet

Le script exécute automatiquement :

Phase 1 : Build local

  1. Compilation TypeScript de lecoffre-ressources-dev
  2. Vérification du build (87 fichiers .js)

Phase 2 : Synchronisation

  1. Test connexion SSH
  2. Création répertoire distant si nécessaire
  3. Rsync de tous les fichiers (excluant node_modules, .git, logs...)
  4. Transfert des fichiers .env.<env>

Phase 3 : Build distant

  1. Backup base de données (pg_dump)
  2. Build backend/frontend
  3. Chargement variables .env.<env>

Phase 4 : Certificats SSL

  1. Vérification si certificats existent
  2. Génération certificat auto-signé temporaire si absent
  3. Démarrage services (systemd)
  4. Obtention certificat Let's Encrypt réel
  5. Rechargement Nginx avec certificat

Phase 5 : Déploiement

  1. Arrêt services existants (systemd)
  2. Démarrage services (systemd)
  3. Attente démarrage (10s)
  4. Vérification statut (systemctl)
  5. Cleanup builds obsolètes

Phase 6 : Synchronisation données (si flags activés)

  1. --setSettings : Injection configurations depuis env-full-<env>-for-bdd-injection.txt
    • Commande utilisée côté serveur : npm run config:import-env -- --env <env> (dans le répertoire backend)
    • Doit être rejouée manuellement après --resetDatabase
    • Depuis 2025-12-02, le transfert des fichiers sensibles sous Windows passe par un répertoire de staging pour Compress-Archive, ce qui garantit que les chemins relatifs (deploy/...) sont bien conservés lors de l'extraction distante.
  2. --syncIdNot : Synchronisation utilisateurs IdNot OAuth
  3. --syncDirectory : Synchronisation offices/personnes API Annuaire
  4. --importStripe : Synchronisation plans et abonnements Stripe
  5. --reanchorAll : ⚠️ DESTRUCTIF : Supprimer toutes les ancres et réancrer tous les documents et dossiers
  6. --promoteSuperAdmins : Promotion super-admins depuis liste emails
  7. --getToken : Génération d'un access/refresh token super-admin (trace logs/token-superadmin-*.log)
  8. Logs sauvegardés dans logs/

Phase 7 : Scripts de fix (automatique)

  1. Exécution automatique : Tous les scripts .sh dans deploy/fix/ sont exécutés automatiquement après le déploiement
  2. Ordre alphabétique : Les scripts sont exécutés dans l'ordre alphabétique
  3. Déplacement automatique : Après exécution réussie, chaque script est déplacé dans deploy/fixDone/
  4. Arrêt en cas d'erreur : Si un script échoue, le processus s'arrête et le script reste dans deploy/fix/
  5. Contexte complet : Chaque script reçoit ENV et DOMAIN comme paramètres et a accès à toutes les variables d'environnement nécessaires

Phase 8 : Vérifications finales

  1. Statut services systemd
  2. Health check backend (/api/v1/public/health)
  3. Logs accessibles

Première fois (from scratch)

Option 1 : Script automatique

# Déployer de A à Z (inclut SSL, migrations, sync)
./deploy/scripts/build-and-deploy.sh test

Le script détecte automatiquement que c'est un premier déploiement et :

  • Génère les certificats SSL
  • Applique toutes les migrations Prisma
  • Synchronise les données

Option 2 : Script init (legacy)

# Alternative : script init manuel (moins maintenu)
./deploy/scripts/init-environment.sh test admin@4nkweb.com

Cartographie des checks de déploiement (source unique)

Cette section fait foi pour distinguer ce qui est exécuté automatiquement pendant un déploiement standard (deploy/scripts_v2/deploy.sh) et ce qui reste manuel.

Snippet de renvoi standard (gabarit interne)

Position attendue dans chaque document concerné : en tête du fichier, juste après le titre et les métadonnées éventuelles.

Règle unique : aucun bloc local de checks de déploiement dans les autres documents. Conserver uniquement le snippet de renvoi, avec éventuellement une phrase de contexte métier non-check.

Depuis un document situé dans docs/ :

**Référence unique (checks de déploiement)** : [`docs/DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique`](./DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique)

Depuis un document situé hors docs/ :

**Référence unique (checks de déploiement)** : [`docs/DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique`](../docs/DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique)

Checks automatiques (pipeline de déploiement)

Check Déclenchement Script source Statut
Vérification API d'ancrage (health + test d'ancrage) Systématique dans deploy.sh deploy/scripts_v2/deploy.sh (test_anchor_api_blocking) Automatique
Migrations Prisma (prisma generate + prisma migrate deploy) Systématique dans deploy.sh deploy/scripts_v2/remote/migrate-resolve-database.sh Automatique
Build backend/frontend sur cible Systématique en déploiement normal/import deploy/scripts_v2/remote/deploy-app.sh Automatique
Vérification post-déploiement (health + systemd + logs récents) Systématique après déploiement/import deploy/scripts_v2/_lib/git-flow.sh (verify_deployment_success) Automatique
Lint/typecheck/build locaux Option --checkLint deploy/scripts_v2/deploy.sh Optionnel

Scripts manuels (hors pipeline automatique)

Script Usage Statut
deploy/scripts_v2/run-verify-db-connection.sh Vérification ciblée connectivité DB Manuel
deploy/scripts_v2/run-verify-invited-received-documents.sh Vérification SQL ciblée documents invités Manuel
deploy/scripts_v2/run-check-role-permissions-matrix.sh Vérification droits/rôles Manuel
deploy/scripts_v2/run-check-logs-and-db-invite-notaire-587.sh Diagnostic ciblé logs + DB Manuel
deploy/scripts_v2/run-check-user-offices-logs.sh Diagnostic ciblé logs UserOffices (offices vides / sync IdNot) Manuel
deploy/scripts_v2/run-copy-connectdb-if-missing.sh Remédiation ciblée fichier connectDB Manuel
deploy/scripts_v2/run-set-settings.sh Exécution manuelle set-settings Manuel

Scripts orphelins nettoyés

  • Supprimés car non appelés par le pipeline et non référencés comme étapes obligatoires :
    • lecoffre-back-main/test-audit.js
    • lecoffre-back-main/test-audit.js.map
    • lecoffre-back-main/scripts/test-guest-folders-query.ts
    • lecoffre-back-main/scripts/test-guest-folders-complete.ts

Architecture (scripts_v2 - host-native)

Vue d'ensemble

Dans linfrastructure proxy 192.168.1.100, le SSL et le routage sont gérés uniquement sur le proxy. Les serveurs denvironnements (192.168.1.101/102/103) exposent uniquement des ports applicatifs HTTP.

Le déploiement est orchestré par deploy/scripts_v2/deploy.sh.

En fin d'exécution, deploy/scripts_v2/deploy.sh affiche l'heure de fin au format HH:MM pour faciliter la lecture chronologique des logs de déploiement.

Structure des fichiers sur un serveur denvironnement

/srv/4NK/test.lecoffreio.4nkweb.com/
├── deploy/                     # Scripts + fichiers de déploiement versionnés
├── deploy/scripts_v2/           # Scripts v2 (host-native)
├── lecoffre-back-main/          # Backend
├── lecoffre-front-main/         # Frontend
└── lecoffre-ressources-dev/     # Ressources partagées

Services système (systemd)

  • lecoffreio-backend@<domain>
  • lecoffreio-cron@<domain>
  • lecoffreio-frontend@<domain>
  • lecoffreio-router@<domain> (port service, ex: 3009)

Logs de déploiement

Script principal build-and-deploy.sh

Le script principal ne produit pas automatiquement de logs. Il faut rediriger la sortie manuellement :

# Exemple recommandé
./deploy/scripts/build-and-deploy.sh pprod --deploy > logs/build-and-deploy-pprod.log 2>&1

Format recommandé : logs/build-and-deploy-<env>.log

Avantages de la redirection manuelle :

  • Contrôle total sur le nom du fichier
  • Peut inclure des informations supplémentaires (date, numéro de déploiement)
  • Permet de gérer plusieurs logs simultanés

Exemples d'utilisation :

# Log simple
./deploy/scripts/build-and-deploy.sh pprod --deploy > logs/build-and-deploy-pprod.log 2>&1

# Log avec timestamp
./deploy/scripts/build-and-deploy.sh pprod --deploy > logs/build-and-deploy-pprod-$(date +%Y%m%d_%H%M%S).log 2>&1

# Log avec affichage en temps réel (tee)
./deploy/scripts/build-and-deploy.sh pprod --deploy 2>&1 | tee logs/build-and-deploy-pprod.log

Copie automatique vers serveur distant

Le script build-and-deploy.sh copie automatiquement les logs de déploiement vers le serveur distant après l'exécution (succès ou échec) pour que Promtail puisse les collecter.

Fonctionnement :

  • Vérifie si le fichier de log local existe
  • Crée le répertoire logs/ sur le serveur distant s'il n'existe pas
  • Copie le log avec un nom horodaté (build-and-deploy-<env>-YYYYMMDD-HHMMSS.log)
  • Le nom correspond au pattern Promtail : build-and-deploy-*.log
  • La copie est non-bloquante (ne fait pas échouer le déploiement si elle échoue)

Voir README.md pour la consolidation et ANCRAGE_COMPLETE.md pour le dépannage ancrage.

Répertoire des logs

Structure

logs/
├── build-and-deploy-pprod.log              # Log principal (manuel)
├── build-and-deploy-pprod-20250102_143022.log  # Log horodaté (copié automatiquement)
├── sync-idnot-20251124_143022.log          # Sync IdNot (automatique)
├── sync-directory-20251124_143100.log       # Sync Directory (automatique)
├── import-stripe-20251124_144000.log        # Import Stripe (automatique)
├── reanchor-all-20251124_150000.log         # Réancrage complet (automatique)
├── token-superadmin-20251124_151000.log     # Token super-admin (automatique)
└── activate-subscriptions-20251124_152000.log  # Activation abonnements (automatique)

Création automatique

Le répertoire logs/ est créé automatiquement par :

  • build-and-deploy.sh (ligne 451)
  • run_sync_idnot() (ligne 853)
  • run_sync_directory() (ligne 887)

Gestion des logs volumineux

Compression automatique

Les logs de synchronisation sont automatiquement compressés si >5MB :

  • Réduction à 2000 dernières lignes
  • Compression en .gz
  • Affichage des 20 dernières lignes après compression

Nettoyage

Les logs ne sont pas nettoyés automatiquement. Il est recommandé de :

  • Archiver les anciens logs
  • Supprimer les logs >30 jours
  • Surveiller l'espace disque

Script de nettoyage recommandé :

# Supprimer les logs >30 jours
find logs/ -name "*.log" -mtime +30 -delete
find logs/ -name "*.log.gz" -mtime +90 -delete

Scripts et commandes

Mise à jour Node.js 25 sur test, pprod, prod

Si la version de Node sur les serveurs est inférieure à 25, exécuter (depuis la machine locale, les scripts font le SSH via le proxy) :

bash deploy/scripts_v2/run-update-node-25-on-servers.sh

Ce script copie et exécute deploy/scripts_v2/remote/update-node-25.sh sur chaque hôte (test, pprod, prod). Idempotent : ne modifie rien si Node >= 25. Utilise NodeSource setup_25.x avec repli sur setup_current.x si 25 nest pas disponible.

Scripts de déploiement

deploy/scripts_v2/install-or-reset-env.sh (scripts_v2)

Bootstrap / reset complet en 1 commande (DESTRUCTIF) pour test et pprod.

Ce wrapper exécute un cycle complet :

  • setup host (--setupHost)
  • reset DB depuis .secrets/<env>/bdd.<env> (--resetDatabase)
  • migrations Prisma (--migrateResolveDatabase)
  • build+restart (--deploy)
  • import settings en BDD (--setSettings)
  • scripts métier (--seedSiteTexts, --importStripe, --reanchorAll, --promoteSuperAdmins, --activateSubscriptions)
# Usage
bash deploy/scripts_v2/install-or-reset-env.sh test

deploy/scripts_v2/install-or-reset-env-from-schema-export.sh (scripts_v2)

Bootstrap / reset complet en 1 commande (DESTRUCTIF) pour test et pprod, basé sur une baseline schema-only (utile quand les dumps disponibles sont uniquement en v1).

Ce script enchaîne :

  • --resetDatabaseFromSchemaExport (création DB v2 vide depuis export SQL schema-only)
  • --importV1Data (import des TABLE DATA v1 dans la DB v2)
    • scripts_v2 prépare automatiquement une compat layer v1→v2 (types/colonnes manquants) en restaurant le schéma v1 dans une DB temporaire puis en appliquant le diff sur la DB v2
    • scripts_v2 n'importe pas _prisma_migrations (baseline Prisma gérée à part) ni system_configuration (géré via --setSettings)
  • --migrateResolveDatabase (baseline Prisma via migrate resolve --applied + migrations futures)
  • --deploy + scripts post-déploiement (--setSettings, --seedSiteTexts, --importStripe, --reanchorAll, --promoteSuperAdmins, --activateSubscriptions)
# Usage
bash deploy/scripts_v2/install-or-reset-env-from-schema-export.sh test

⚠️ Pour prod, ce wrapper refuse d'exécuter (risque de reset DB). Utiliser deploy/scripts_v2/deploy.sh et valider les flags explicitement.

deploy/scripts_v2/merge-v1-data-into-v2.sh (scripts_v2)

Merge incrémental v1 → v2 (NON-DESTRUCTIF) pour test, pprod et prod.

Ce script effectue un merge des données v1 dans la v2 existante, puis exécute les scripts post-déploiement :

Étapes du merge :

  1. Applique la compatibilité layer v1→v2 (enums + colonnes manquantes)
  2. Restaure le dump v1 dans une DB temporaire
  3. Effectue des upserts (INSERT ... ON CONFLICT DO UPDATE) par table
  4. Préserve les données v2 existantes
  5. Intègre les nouvelles données v1

Scripts post-déploiement systématisés :

Après le merge, le script exécute automatiquement :

  • --migrateResolveDatabase : Applique les migrations Prisma (requis, ajouté automatiquement)
  • --setSettings : Import des configurations depuis env-full-<env>-for-bdd-injection.txt
  • --seedSiteTexts : Initialise les textes du site
  • --importStripe : Importe les abonnements Stripe
  • --reanchorAll : Réancrage complet des documents (DESTRUCTIF pour les ancres existantes)
  • --promoteSuperAdmins : Promotion des super-admins (via SUPERADMIN_EMAILS en DB)
  • --activateSubscriptions : Activation des abonnements (via AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS en DB)

Note : Ces scripts sont systématisés pour garantir la cohérence des environnements après chaque merge v1→v2.

# Usage
bash deploy/scripts_v2/merge-v1-data-into-v2.sh test

Workflow recommandé :

  1. Premier import : install-or-reset-env-from-schema-export.sh <env> (baseline + import full + scripts post-déploiement)
  2. Imports suivants : merge-v1-data-into-v2.sh <env> (merge incrémental + scripts post-déploiement)

Prérequis :

  • Le dump v1 doit être présent localement : .secrets/<env>/bdd.<env>
  • Format attendu : custom-format pg_dump (PGDMP)

Détails techniques (merge) :

  • Les tables sans PK/UK sont ignorées (risque de doublons)
  • Les colonnes communes entre v1 et v2 sont synchronisées
  • Les colonnes v1 absentes en v2 sont ignorées (après compat layer)
  • Les colonnes v2 absentes en v1 sont préservées (non modifiées)
  • Les lignes avec NULL dans des colonnes NOT NULL sont automatiquement filtrées

build-and-deploy.sh

Script principal de déploiement complet

Déploie l'application de A à Z sur un environnement distant via SSH.

# Usage
./deploy/scripts/build-and-deploy.sh <ENV> [options]

# Exemples
./deploy/scripts/build-and-deploy.sh test --deploy --cert --resetDatabase --setSettings
./deploy/scripts/build-and-deploy.sh pprod --syncIdNot --syncDirectory
./deploy/scripts/build-and-deploy.sh prod --deploy --importStripe --reanchorAll

init-environment.sh (legacy)

Initialisation d'un nouvel environnement

Alternative pour la première fois (moins maintenu que build-and-deploy.sh).

# Usage
./deploy/scripts/init-environment.sh <ENV> <EMAIL>

# Exemple
./deploy/scripts/init-environment.sh pprod nicolas.cantu@pm.me

Note : build-and-deploy.sh est maintenant autonome et recommandé pour tous les cas.

bump-version.sh

Mise à jour de version

# Usage
./deploy/scripts/bump-version.sh <VERSION> "<MESSAGE>"

# Exemple
./deploy/scripts/bump-version.sh 2.1.0 "Nouveaux exports"

Scripts de maintenance

cleanup-remote-disk-aggressive.sh

Nettoyage agressif de l'espace disque

# Usage
bash deploy/scripts/cleanup-remote-disk-aggressive.sh <ENV>

Actions effectuées :

  1. Arrêt des services systemd (backend, frontend, cron, router)
  2. Nettoyage agressif (builds, caches, journaux)
  3. Nettoyage des anciens builds
  4. Nettoyage des caches système (apt, journaux, logs)
  5. Nettoyage des caches npm et node_modules
  6. Nettoyage des fichiers temporaires (/tmp, /var/tmp, builds, logs)
  7. Nettoyage Git agressif (reflog, packs volumineux)
  8. Affichage de l'état du disque avant et après

Précautions :

  • La base de données PostgreSQL n'est pas modifiée
  • Les node_modules nécessaires pour le build sont préservés
  • Le script affiche l'état du disque avant et après le nettoyage

repair-remote-git.sh

Réparation du repository Git corrompu

# Usage
bash deploy/scripts/repair-remote-git.sh <ENV>

Cas d'utilisation :

  • Erreur BUG: diff-lib.c:633: run_diff_index must be passed exactly one tree
  • Erreur fatal: unresolved deltas left after unpacking
  • Erreur fatal: unpack-objects failed
  • Erreur invalid sha1 pointer

Actions effectuées :

  1. Sauvegarde des fichiers sensibles (.env, nginx)
  2. Nettoyage des fichiers Git verrouillés
  3. Tentative de réparation avec git fsck et git gc
  4. Si le repository est trop corrompu : recréation complète
  5. Restauration des fichiers sensibles
  6. Vérification de l'état final

Scripts de fix automatiques

Vue d'ensemble

Les scripts de fix sont des scripts bash optionnels placés dans deploy/fix/ qui sont exécutés automatiquement après chaque déploiement. Ils permettent d'appliquer des correctifs ponctuels ou des mises à jour de configuration sans modifier le code principal.

Méthode de déploiement

  1. Placement : Créer un script .sh dans deploy/fix/
  2. Exécution automatique : Le script build-and-deploy-local-fix.sh est appelé automatiquement par build-and-deploy-local.sh après le déploiement
  3. Ordre : Les scripts sont exécutés dans l'ordre alphabétique
  4. Déplacement : Après exécution réussie, le script est automatiquement déplacé dans deploy/fixDone/

Structure obligatoire

#!/bin/bash

# Description du script
# Usage: Ce script est exécuté automatiquement par build-and-deploy-local-fix.sh

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
DEPLOY_SCRIPTS_DIR="$(cd "$SCRIPT_DIR/../scripts" && pwd)"
source "$DEPLOY_SCRIPTS_DIR/build-and-deploy-local-common.sh"

ENV="$1"
DOMAIN="$2"

if [ -z "$ENV" ]; then
    error "ENV manquant"
    exit 1
fi

if [ -z "$DOMAIN" ]; then
    error "DOMAIN manquant"
    exit 1
fi

init_deploy_context "$ENV" "$DOMAIN"
validate_database_credentials

# Votre code ici

Règles importantes

  1. Paramètres : Le script doit accepter ENV et DOMAIN comme paramètres
  2. Initialisation : Utiliser init_deploy_context pour charger les variables d'environnement
  3. Vérifications : Vérifier l'état des services systemd et les credentials BDD avant d'exécuter
  4. Code de retour : Retourner 0 en cas de succès, 1 en cas d'échec
  5. Logging : Utiliser les fonctions info, success, error, warning du script commun

Scripts utilitaires backend

Promotion des super-administrateurs

La promotion/dé-promotion se fait via les scripts npm du backend, exécutés sur le serveur cible :

# Sur le serveur, dans le répertoire backend
npm run promote:superadmin -- --email user@notaires.fr
npm run promote:superadmin -- --uid 123e4567-e89b-12d3-a456-426614174000
  • Le script applique automatiquement les contraintes (rechargement configuration, connexion BDD via Prisma).
  • L'utilisateur doit se reconnecter pour régénérer ses jetons après promotion.

Générer un token super-admin

npm run token:get -- --json

Ce script promeut automatiquement un super-admin si aucun n'est présent, puis génère un couple access/refresh token.

Activation des abonnements utilisateur

L'activation automatique passe par npm run activate:subscriptions (backend) :

npm run activate:subscriptions -- user@notaires.fr
  • Recherche par email, UID ou IdNot.
  • Crée un abonnement UNLIMITED si nécessaire et active ceux existants.
  • Fournit un résumé pour chaque office.

Dans les pipelines de déploiement (--activateSubscriptions), cette commande est appelée automatiquement pour chaque email configuré dans AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS.


Maintenance et troubleshooting

Vérifications post-déploiement

Logs

# Depuis la machine distante
ssh debian@<IP_SERVEUR>
cd /home/debian/sites/test-lecoffreio.4nkweb.com

# Logs temps réel
journalctl -u lecoffreio-backend@<domain> -f
journalctl -u lecoffreio-frontend@<domain> -f
journalctl -u lecoffreio-cron@<domain> -f

# Logs synchronisation
tail -100 logs/sync-all-*.log | grep -E "ok|error|✅|❌"

Tests

# Health check
curl https://test-lecoffreio.4nkweb.com/api/v1/public/health | jq

# Page d'accueil
curl -I https://test-lecoffreio.4nkweb.com/

# Config publique
curl https://test-lecoffreio.4nkweb.com/api/v1/public/config | jq
  • Interface Super Admin https://test-lecoffreio.4nkweb.com/super-admin/health
    • Permet de lancer des tests live (ancrage Signet, SMS OVH, e-mail Mailchimp, upload Pinata, lectures ID.NOT).
    • Chaque carte affiche le résultat détaillé : lien mempool, URL IPFS, modales JSON IdNot, confirmation "Message envoyé".
    • La section "Résumé base de données" reprend les volumes principaux (ex: offices).

Base de données

# Compter les enregistrements
psql -h $DATABASE_HOST -p $DATABASE_PORT -U $DATABASE_USERNAME -d $DATABASE_NAME \
  -c "SELECT 'offices' as table, COUNT(*) FROM offices UNION SELECT 'users', COUNT(*) FROM users;"

Maintenance

Re-déploiement

# Simple
./deploy/scripts/build-and-deploy.sh test

# Le script :
# - Détecte que SSL existe déjà → ne régénère pas
# - Applique nouvelles migrations uniquement
# - Re-synchronise les données

Renouvellement SSL

Les certificats sont renouvelés automatiquement par Certbot (toutes les 12h).

Pour forcer le renouvellement :

ssh debian@<IP_SERVEUR>
cd /home/debian/sites/test-lecoffreio.4nkweb.com
# Renouvellement certificats (sur le proxy ou serveur où Certbot est installé)
certbot renew
# Rechargement Nginx (sur le proxy)
nginx -s reload

Rollback

# Restaurer backup BDD
ssh debian@<IP_SERVEUR>
cd /home/debian/sites/test-lecoffreio.4nkweb.com
psql -h ... -U ... -d bdd.test < backups/bdd-test_YYYYMMDD_HHMMSS.sql

# Re-déployer version précédente
git checkout <commit-hash>
./deploy/scripts/build-and-deploy.sh test

Troubleshooting

Erreur : Variable DEPLOY_SSH_HOST manquante

→ Vérifier que .env.<env> contient toutes les variables DEPLOY_*

Erreur : Impossible de se connecter

→ Vérifier clé SSH : ssh debian@<IP_SERVEUR>

Erreur : Certificat Let's Encrypt échoue

→ Vérifier DNS : host test-lecoffreio.4nkweb.com → Vérifier ports : nc -zv <IP_SERVEUR> 80 443

Backend en crash loop

→ Vérifier logs : ssh ... 'journalctl -u lecoffreio-backend@<domain> -n 200' → Vérifier BDD accessible : tester avec psql → Vérifier migrations Prisma : marquer comme appliquées si nécessaire

Erreur : Connexion PostgreSQL impossible

→ Vérifier que DATABASE_USERNAME et DATABASE_PASSWORD dans deploy/.env.<env> sont corrects → Vérifier que l'utilisateur PostgreSQL existe : psql -U postgres -c "\du" → Vérifier que l'utilisateur a les permissions sur la base : psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE bdd-test TO lecoffre-user-test;"

Erreur : No migration found in prisma/migrations

→ Vérifier que le répertoire prisma/migrations existe dans le conteneur → Vérifier que le lien symbolique src/common/databases/migrationsprisma/migrations est créé → Le script crée automatiquement ce lien lors du déploiement avec --migrateResolveDatabase

Erreur : Disque plein (Out of diskspace)

→ Utiliser le script de nettoyage : bash deploy/scripts/cleanup-remote-disk-aggressive.sh <env> → Vérifier l'espace disque : ssh ... 'df -h' → Le script libère généralement 15-20GB d'espace

Erreur : Repository Git corrompu

→ Utiliser le script de réparation : bash deploy/scripts/repair-remote-git.sh <env> → Erreurs courantes : unresolved deltas, invalid sha1 pointer, unpack-objects failed → Le script sauvegarde les fichiers sensibles avant réparation

Synchronisation échoue

→ Vérifier credentials IdNot dans system_configuration → Vérifier les logs applicatifs (API IdNot / Annuaire) côté backend

Erreur : curl_error variable sans liaison (deploy.sh)

Symptômes : ./deploy/scripts_v2/deploy.sh: ligne 281: curl_error : variable sans liaison lorsque l'API d'ancrage échoue et que le fichier d'erreur curl est vide.

Root cause : Avec set -u, toute référence à une variable non définie provoque une erreur. curl_error n'est défini que si le fichier d'erreur curl contient des données ; sinon la variable est utilisée sans exister.

Correctif : Initialiser local curl_error="" avant usage. Fichier : deploy/scripts_v2/deploy.sh.

Vérifications et debugging

Vérifier les certificats sur le host

# Sur le serveur distant
ssh debian@<IP_SERVEUR>

cd /home/debian/sites/test-lecoffreio.4nkweb.com

# Lister certificats
sudo ls -la deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/

# Vérifier validité
sudo openssl x509 -in deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/fullchain.pem -noout -dates

Vérifier la configuration Nginx

# Tester configuration (sur le host)
cat deploy/nginx/nginx-test.conf

# Tester configuration Nginx
nginx -t

# Recharger Nginx
nginx -s reload

Vérifier les montages et la configuration Nginx

# Voir les volumes montés
# Vérifier la configuration Nginx sur le proxy
nginx -T

# Exemple de sortie :
# /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/nginx-test.conf -> /etc/nginx/nginx.conf
# /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/certbot/conf-test -> /etc/letsencrypt
# /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/certbot/www-test -> /var/www/certbot

Vérifier les logs

# Logs Nginx (sur le proxy)
journalctl -u nginx -n 50

# Logs backend (sur le serveur env)
journalctl -u lecoffreio-backend@<domain> -n 50

# Certbot : selon l'installation (cron ou service systemd)

API d'ancrage Bitcoin séparée

L'API d'ancrage Bitcoin est déployée sur un serveur séparé.

Production : anchorage.certificator.4nkweb.com (HTTPS)

Configuration

cp env.bitcoin.api.deploy.example .env.bitcoin.api.deploy
nano .env.bitcoin.api.deploy  # Configurer serveur Bitcoin

Variables requises :

REMOTE_HOST=<USER>@<IP_SERVEUR_BITCOIN>
REMOTE_DIR=~/dev/lecoffre-anchor-api
LOCAL_DIR=~/dev/lecoffre-anchor-api
PM2_APP_NAME=lecoffre-anchor-api
SSH_KEY=$HOME/.ssh/id_ed25519_4nk

# Production
ANCHORE_API_URL=https://anchorage.certificator.4nkweb.com
ANCHORE_API_KEY=<CLE_API>

Déploiement

./deploy-anchor-api.sh

Infrastructure

  • Serveur Production : anchorage.certificator.4nkweb.com (HTTPS)
  • Répertoire : /home/<USER>/dev/lecoffre-anchor-api
  • Health : https://anchorage.certificator.4nkweb.com/health

Sécurité

Certificats SSL

  • Certificats SSL Let's Encrypt valides (renouvellement auto toutes les 12h)
  • Certificats en lecture seule pour Nginx
  • Permissions strictes sur les clés privées (600)

Configuration

  • Fichiers .env.* en .gitignore
  • Certificats SSL Let's Encrypt valides
  • Configurations sensibles en BDD (masquées)
  • CORS strictement configuré
  • Rate limiting actif
  • Pas de ports exposés (sauf 80/443 via Nginx)

Permissions des certificats

# Les certificats doivent appartenir à root (générés par Certbot en root)
sudo chown -R root:root deploy/nginx/certbot/conf-test/

# Permissions recommandées
sudo chmod 755 deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/
sudo chmod 644 deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/fullchain.pem
sudo chmod 600 deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/privkey.pem

Lecture seule

Les certificats et configurations Nginx sont configurés en lecture seule sur le système de fichiers.

Avantages :

  • Nginx ne peut pas modifier les certificats
  • Séparation des privilèges

Architecture récapitulative

┌─────────────────────────────────────────────────────────────┐
│                    HOST (Serveur distant)                    │
│  /home/debian/sites/test-lecoffreio.4nkweb.com/            │
│                                                              │
│  ┌─────────────────┐  ┌──────────────────┐                 │
│  │ deploy/nginx/   │  │ deploy/nginx/    │                 │
│  │ nginx-test.conf │  │ certbot/         │                 │
│  │                 │  │ ├─ conf-test/    │                 │
│  │ (Bind mount)    │  │ │  └─ live/...   │                 │
│  └────────┬────────┘  │ └─ www-test/     │                 │
│           │           │  (Bind mounts)   │                 │
│           │           └────────┬──────────┘                 │
│           │                    │                             │
│  ┌────────▼────────────────────▼──────────────────────┐    │
│  │            Services (systemd / Nginx)                 │    │
│  │                                                      │    │
│  │  ┌──────────────┐  ┌──────────────┐               │    │
│  │  │   Nginx      │  │  Certbot     │               │    │
│  │  │ (nginx:alpine│  │(certbot/      │               │    │
│  │  │  ports 80,443│  │ certbot)      │               │    │
│  │  └──────┬───────┘  └──────────────┘               │    │
│  │         │                                           │    │
│  │  ┌──────▼───────┐  ┌──────────────┐               │    │
│  │  │  Frontend    │  │   Backend     │               │    │
│  │  │ (Next.js)    │  │  (Express)    │               │    │
│  │  │  port 3000   │  │   port 3001   │               │    │
│  │  └──────────────┘  └──────────────┘               │    │
│  │                                                      │    │
│  │  ┌──────────────┐                                   │    │
│  │  │     Cron     │                                   │    │
│  │  │ (Tâches)     │                                   │    │
│  │  └──────────────┘                                   │    │
│  │                                                      │    │
│  │  ┌──────────────┐  ┌──────────────┐               │    │
│  │  │    Loki      │  │   Promtail    │               │    │
│  │  │ (port 3100)  │  │ (collecte)   │               │    │
│  │  └──────┬───────┘  └──────┬───────┘               │    │
│  │         │                  │                         │    │
│  │  ┌──────▼──────────────────▼───────┐             │    │
│  │  │         Grafana                  │             │    │
│  │  │    (port 3000 loopback)          │             │    │
│  │  └──────────────────────────────────┘             │    │
│  └──────────────────────────────────────────────────────┘    │
│                                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  PostgreSQL (Base de données externe)               │   │
│  │  <IP_POSTGRESQL>:<PORT_POSTGRESQL>                  │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Commandes utiles

Déploiement complet avec certificats

# Depuis la machine de développement
cd /home/debian/legacy/lecoffreio
./deploy/scripts/build-and-deploy.sh test --deploy --cert

Renouveler les certificats manuellement

# Sur le serveur distant
cd /home/debian/sites/test-lecoffreio.4nkweb.com

# Forcer renouvellement (sur le proxy ou serveur où Certbot est installé)
certbot renew --force-renewal

# Recharger Nginx (sur le proxy)
nginx -s reload

Vérifier l'état des services

# Statut des services (sur le serveur env)
systemctl status 'lecoffreio-*@*'

# Logs en temps réel
journalctl -u lecoffreio-backend@<domain> -f

# Health check backend
curl https://test-lecoffreio.4nkweb.com/health

Logs après déploiement (depuis machine distante)

ssh ncantu@<IP_SERVEUR> 'journalctl -u lecoffreio-backend@<domain> -f'

# Statut services
ssh ncantu@<IP_SERVEUR> 'systemctl status "lecoffreio-*@*"'

# Logs synchronisation
ssh debian@<IP_SERVEUR> 'cd /home/debian/sites/test-lecoffreio.4nkweb.com && tail -100 logs/sync-all-*.log'

# Health check
curl https://test-lecoffreio.4nkweb.com/api/v1/public/health | jq

Monitoring

Architecture

Objectif

  • Centraliser les logs applicatifs (logs/*.log) via Promtail → Loki
  • Offrir aux équipes support un Grafana local accounts (pas de SSO)
  • Faciliter l'analyse racine via requêtes Loki (filtre job, level, message)

Services déployés

Service Instance Port Volume de données
Loki lecoffre_loki_${ENV} 3100 (interne) /var/lib/lecoffre/loki-${ENV}
Promtail lecoffre_promtail_${ENV} - /var/lib/lecoffre/promtail-${ENV}
Grafana lecoffre_grafana_${ENV} 3000 (loopback) /var/lib/lecoffre/grafana-${ENV}

Réseau

Les services de monitoring communiquent sur l'hôte (localhost ou réseau interne).

Flux de données

Backend/Cron → Fichiers logs → Promtail → Loki → Grafana

Infrastructure

  • Promtail : surveille logs/ (bind ../logs) via jobs application-logs et sync-logs
  • Loki : stocke les logs sur /var/lib/lecoffre/loki-<env> (retention 14 jours par défaut)
  • Grafana : interface UI, accessible via /monitor (reverse proxy) ou tunnel SSH (127.0.0.1:3000)

Configuration Grafana

Accès

Via HTTPS (recommandé) :

  1. URL : https://<DEPLOY_DOMAIN>/monitor/
  2. Authentification : Identifiants configurés dans .env.<env>
    • User : GRAFANA_ADMIN_USER
    • Password : GRAFANA_ADMIN_PASSWORD

Via tunnel SSH (fallback) :

ssh -L 3000:127.0.0.1:3000 debian@<DEPLOY_SSH_HOST>

Puis ouvrir http://localhost:3000 dans le navigateur.

Variables d'environnement

GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-grafana}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-grafana-pass}
GF_SECURITY_ALLOW_EMBEDDING: "false"
GF_SECURITY_DISABLE_GRAVATAR: "true"
GF_USERS_ALLOW_SIGN_UP: "false"
GF_SERVER_DOMAIN: ${DEPLOY_DOMAIN}
GF_SERVER_ROOT_URL: "https://${DEPLOY_DOMAIN}/monitor/"
GF_SERVER_SERVE_FROM_SUB_PATH: "true"

Provisioning automatique

Datasources :

Emplacement : deploy/monitoring/grafana/provisioning/datasources/loki.yml

La datasource Loki est automatiquement configurée avec :

  • URL : http://loki:3100
  • Type : loki
  • Accès : proxy
  • Par défaut : Oui
  • Max lines : 1000
  • Derived fields : Support pour les traceID

Dashboards :

Emplacement : deploy/monitoring/grafana/provisioning/dashboards/dashboards.yml

Le provisioning des dashboards est configuré pour :

  • Charger automatiquement les dashboards depuis /etc/grafana/provisioning/dashboards
  • Mettre à jour toutes les 10 secondes
  • Permettre les mises à jour via l'UI
  • Organiser les dashboards par structure de dossiers

Reverse Proxy Nginx

Fichier : deploy/nginx/includes/monitor.conf

Nginx configure un reverse proxy pour Grafana :

  • Path : /monitor/
  • Backend : http://grafana:3000
  • Headers : Préservation des headers X-Forwarded-* pour HTTPS
  • Timeout : 300s pour les requêtes longues

Configuration Loki

Fichier de configuration

Emplacement : deploy/monitoring/loki-config.yml

Paramètres clés

  • Port HTTP : 3100 (interne uniquement)
  • Stockage : Filesystem (/var/lib/loki)
  • Rétention : 336h (14 jours)
  • Schéma : v12 avec boltdb-shipper
  • Compression : Activée pour les réponses

Rétention des données

table_manager:
  retention_deletes_enabled: true
  retention_period: 336h  # 14 jours
  poll_interval: 5m

Les données sont automatiquement supprimées après 14 jours.

Configuration Promtail

Fichier de configuration

Emplacement : deploy/monitoring/promtail-config.yml

Jobs de collecte

Promtail collecte les logs depuis /var/log/lecoffre (monté depuis ../logs sur l'hôte) :

  1. application-logs : Tous les fichiers *.log à la racine
  2. sync-logs : Fichiers sync-*.log
  3. winston-logs : Fichiers Winston avec pattern de date :
    • error-YYYY-MM-DD.log
    • combined-YYYY-MM-DD.log
    • login-YYYY-MM-DD.log
  4. deployment-logs : Fichiers build-and-deploy-*.log

Labels

  • job : Type de log (application-logs, sync-logs, deployment-logs)
  • env : Environnement (test, pprod, prod, demo) - ajouté via -client.external-labels

Positions

Les positions de lecture sont stockées dans /var/promtail/positions.yaml pour éviter de relire les fichiers depuis le début.

Dashboards

Dashboard Vue d'ensemble

Fichier : deploy/monitoring/grafana/provisioning/dashboards/lecoffre-overview.json

Panneaux :

  • Logs applicatifs récents + Erreurs récentes
  • Statistiques (1h) : Erreurs, Warnings, Connexions, Requêtes lentes
  • Graphiques timeseries : Erreurs/heure, Warnings/heure
  • Logs spécialisés : Connexion [LOGIN_MARKER], Requêtes Prisma lentes, Erreurs Prisma
  • Logs de synchronisation + Logs de déploiement

Dashboards spécialisés

Les dashboards suivants sont disponibles :

  1. LeCoffre.io - Backend : Logs backend, erreurs, connexions, requêtes Prisma lentes
  2. LeCoffre.io - Frontend : Logs frontend Next.js, erreurs, builds
  3. LeCoffre.io - Base de données : Requêtes Prisma lentes, erreurs Prisma, erreurs connexion PostgreSQL
  4. LeCoffre.io - ClamAV Antivirus : Scans antivirus, malwares détectés
  5. LeCoffre.io - IdNot : Logs de connexion, synchronisation des offices
  6. LeCoffre.io - OVH/SMS : Logs SMS, codes 2FA
  7. LeCoffre.io - Stripe : Webhooks Stripe, abonnements
  8. LeCoffre.io - Mailchimp : Emails envoyés, erreurs d'envoi
  9. LeCoffre.io - Bitcoin Signet : Ancrages réussis/échoués, vérifications blockchain
  10. LeCoffre.io - Espace Tiers : Ajouts de tiers, documents consultés
  11. LeCoffre.io - Espace Client : Documents consultés, fichiers uploadés
  12. LeCoffre.io - Dossiers Invités : Partages de dossiers, accès notaires invités
  13. LeCoffre.io - Espace Notaire : Créations de dossiers, documents, ancrages

Requêtes LogQL

Requêtes courantes

  • {job="application-logs"} |= "ERROR" : Toutes les erreurs applicatives
  • {job="sync-logs"} |= "sync-directory" : Logs de synchronisation
  • {job="application-logs"} |= "[Antivirus]" : Tous les scans ClamAV
  • {job="application-logs"} |= "[Antivirus] Malware detected" : Malwares détectés

Logs applicatifs généraux

{job="application-logs"}

Erreurs uniquement

{job="application-logs"} |~ "(ERROR|❌|error)"

Warnings

{job="application-logs"} |~ "(WARN|⚠️|warn)"

Logs ClamAV

{job="application-logs"} |= "[Antivirus]"

Malwares détectés

{job="application-logs"} |= "[Antivirus] Malware detected"

Logs de synchronisation

{job="sync-logs"}

Logs de déploiement

{job="deployment-logs"}

Métriques temporelles

Nombre d'erreurs par heure :

count_over_time({job="application-logs"} |= "ERROR" [1h])

Nombre de scans ClamAV par heure :

count_over_time({job="application-logs"} |= "[Antivirus] Scan started" [1h])

Patterns de logs utilisés

  • [LOGIN_MARKER] : Logs de connexion utilisateur
  • [Prisma Slow Query] : Requêtes Prisma lentes (> 1 seconde)
  • [Prisma Error] : Erreurs Prisma
  • [Antivirus] : Tous les logs ClamAV
  • ERROR, , error : Erreurs générales
  • WARN, ⚠️, warn : Warnings
  • : Succès

Troubleshooting Monitoring

Problème "No Data" dans Grafana

1. Vérifier que les fichiers de logs existent :

# Sur le serveur distant
ls -la /home/debian/sites/<env>-lecoffreio.4nkweb.com/logs/

Résultat attendu :

  • backend-YYYY-MM-DD.log (logs backend)
  • cron-YYYY-MM-DD.log (logs cron)
  • Autres fichiers de logs (Winston, déploiement, etc.)

2. Vérifier que Promtail peut lire les fichiers :

# Vérifier les logs Promtail (selon déploiement : systemd ou service)
journalctl -u promtail -n 100

# Vérifier les positions (chemin selon installation)
cat /var/lib/lecoffre/promtail-<env>/positions.yaml

# Vérifier que les fichiers de logs existent
ls -la logs/

3. Vérifier la connexion Promtail → Loki :

# Vérifier que Loki est accessible (selon déploiement)
curl -s http://127.0.0.1:3100/ready

# Vérifier les logs Promtail pour les erreurs de connexion
journalctl -u promtail -n 100 | grep -i error

4. Vérifier que Loki reçoit les logs :

# Vérifier les logs Loki (selon déploiement)
journalctl -u loki -n 100

# Tester l'API Loki (labels disponibles)
curl -s http://127.0.0.1:3100/loki/api/v1/labels

# Tester une requête LogQL
curl -s "http://127.0.0.1:3100/loki/api/v1/query_range?query={job=\"application-logs\"}&limit=10"

5. Vérifier les labels dans Grafana :

Dans Grafana, aller dans Explore (icône boussole) :

  1. Sélectionner la datasource Loki
  2. Tester la requête : {job="application-logs"}
  3. Vérifier que des logs apparaissent

6. Vérifier la plage de temps :

Les logs doivent avoir des timestamps récents. Si les logs sont trop anciens, ils peuvent ne pas apparaître dans la plage de temps sélectionnée dans Grafana.

Solution : Ajuster la plage de temps dans Grafana (par défaut : now-6h à now)

Causes courantes et solutions

Cause 1 : Fichiers de logs non créés :

Symptômes :

  • ls -la logs/ ne montre pas de fichiers backend-*.log ou cron-*.log
  • Les conteneurs backend/cron démarrent mais n'écrivent pas de logs

Solutions :

  1. Vérifier que les scripts wrapper sont exécutables
  2. Vérifier les logs backend : journalctl -u lecoffreio-backend@<domain> -n 100
  3. Vérifier le répertoire des logs : ls -la logs/

Cause 2 : Promtail ne peut pas lire les fichiers :

Symptômes :

  • Les fichiers existent mais Promtail ne les lit pas
  • Erreurs permission denied dans les logs Promtail

Solutions :

  1. Vérifier les permissions des fichiers : ls -la logs/
  2. Vérifier que Promtail a accès au répertoire des logs (configuration Promtail)
  3. Vérifier les permissions du répertoire logs/

Cause 3 : Promtail ne peut pas se connecter à Loki :

Symptômes :

  • Erreurs connection refused dans les logs Promtail
  • Loki ne reçoit pas de logs

Solutions :

  1. Vérifier que Loki est démarré : systemctl status loki ou selon déploiement
  2. Vérifier que Promtail et Loki communiquent (même hôte ou URL configurée)
  3. Vérifier l'URL dans promtail-config.yml : http://127.0.0.1:3100/loki/api/v1/push

Cause 4 : Labels incorrects :

Symptômes :

  • Loki reçoit des logs mais les dashboards affichent "No data"
  • Les requêtes LogQL ne retournent rien

Solutions :

  1. Vérifier les labels disponibles : curl http://localhost:3100/loki/api/v1/labels
  2. Vérifier que les labels dans promtail-config.yml correspondent aux requêtes dans les dashboards
  3. Vérifier que le label job est bien défini dans tous les scrape_configs

Cause 5 : Configuration Promtail obsolète :

Symptôme : Pattern trop large (*.log) créant des doublons

Solution : Supprimer le scrape_config avec pattern trop large et conserver uniquement les configurations spécifiques (backend-.log, cron-.log, etc.)

Voir README.md et logs backend pour le dépannage Grafana/Loki.

Persistance des données Monitoring

Persistance des données

Toutes les données sont persistées sur l'hôte dans /var/lib/lecoffre/ :

  • Loki : /var/lib/lecoffre/loki-${ENV}/ - Index et chunks de logs
  • Promtail : /var/lib/lecoffre/promtail-${ENV}/ - Positions de lecture
  • Grafana : /var/lib/lecoffre/grafana-${ENV}/ - Dashboards, datasources, utilisateurs

Survie aux redéploiements

Les répertoires de données sont créés avant le démarrage des services et survivent aux redéploiements.

Sécurité Monitoring

Authentification Grafana

  • Authentification locale uniquement
  • Pas d'inscription publique (GF_USERS_ALLOW_SIGN_UP: "false")
  • Pas d'embedding externe (GF_SECURITY_ALLOW_EMBEDDING: "false")

Accès réseau

  • Loki : Accessible sur le réseau local (port 3100)
  • Promtail : Pas de port exposé (collecte uniquement)
  • Grafana : Port 3000 exposé uniquement en loopback (127.0.0.1:3000)

Accès externe

L'accès externe se fait uniquement via HTTPS via Nginx reverse proxy sur /monitor/.

Vérification de l'état Monitoring

Vérifier que les services sont en cours d'exécution

systemctl status loki promtail grafana-server

Vérifier les logs des services

# Loki
journalctl -u loki -n 100

# Promtail
journalctl -u promtail -n 100

# Grafana
journalctl -u grafana-server -n 100

Vérifier la connectivité Loki

curl -s http://127.0.0.1:3100/ready

Vérifier les fichiers de logs collectés

ls -la logs/

Vérifier les positions Promtail

cat /var/lib/lecoffre/promtail-<env>/positions.yaml

Disaster Recovery

Vue d'Ensemble

Le système de disaster recovery permet de :

  • Sauvegarder quotidiennement l'état complet de la production
  • Conserver 7 versions de sauvegardes sur une VM Gandi
  • Récupérer automatiquement en cas d'incident : installation complète, bascule DNS, certificats SSL, relance des services

RTO (Recovery Time Objective) : 3 heures RPO (Recovery Point Objective) : 24 heures (sauvegarde quotidienne)

Architecture

Infrastructure

Serveur Prod (192.168.1.103)
    │
    │ [backup-daily.sh - quotidien 2h00]
    │
    ▼
VM Gandi (92.243.24.12)
    │
    │ /var/lecoffreio/prod/
    │   ├── backup-20250109-020000.tar.gz
    │   ├── backup-20250108-020000.tar.gz
    │   ├── ... (7 versions)
    │   └── latest -> backup-20250109-020000.tar.gz
    │
    ▼
[En cas d'incident]
    │
    │ [disaster-recovery.sh]
    │
    ▼
Serveur de Récupération (RECOVERY_TARGET_HOST)
    │
    │ [Bascule DNS via API Gandi]
    │
    ▼
prod.lecoffreio.4nkweb.com → Nouvelle IP

Composants

  1. backup-daily.sh : Script de sauvegarde quotidienne automatique
  2. disaster-recovery.sh : Script de récupération automatisée complète
  3. gandi-dns-api.sh : Script d'interaction avec l'API Gandi pour la bascule DNS

Configuration Initiale

1. Créer le fichier de configuration

cp .secrets/.env.backup.example .secrets/.env.backup

2. Configurer les variables

Éditez .secrets/.env.backup :

# VM Gandi (Sauvegarde)
BACKUP_GANDI_HOST=92.243.24.12
BACKUP_GANDI_USER=debian
BACKUP_GANDI_SSH_KEY=~/.ssh/id_ed25519
BACKUP_GANDI_PATH=/var/lecoffreio

# API Gandi (Bascule DNS)
GANDI_API_KEY=your-gandi-api-key-here
GANDI_DOMAIN=prod.lecoffreio.4nkweb.com

# Configuration de sauvegarde
BACKUP_RETENTION_DAYS=7
BACKUP_SCHEDULE_HOUR=2
BACKUP_SCHEDULE_MINUTE=0
BACKUP_ENV=prod

# Récupération (optionnel - pour disaster-recovery.sh)
RECOVERY_TARGET_HOST=92.243.24.12
RECOVERY_TARGET_USER=debian
RECOVERY_TARGET_SSH_KEY=~/.ssh/id_ed25519

3. Configurer l'accès SSH

Assurez-vous que les clés SSH sont configurées :

# Test connexion VM Gandi
ssh -i ~/.ssh/id_ed25519 debian@92.243.24.12 "echo 'OK'"

# Test connexion serveur de récupération (si différent)
ssh -i ~/.ssh/id_ed25519 debian@$RECOVERY_TARGET_HOST "echo 'OK'"

4. Préparer la VM Gandi

Sur la VM Gandi, créer la structure de répertoires :

ssh debian@92.243.24.12
sudo mkdir -p /var/lecoffreio/prod
sudo chown debian:debian /var/lecoffreio/prod

5. Vérifier l'API Gandi

Tester l'accès à l'API Gandi :

curl -H "Authorization: Apikey $GANDI_API_KEY" \
     https://id.gandi.net/tokeninfo

Sauvegarde Quotidienne

Exécution Manuelle

./deploy/scripts/backup/backup-daily.sh

Configuration Cron (Automatique)

Sur le serveur prod, ajouter dans le crontab :

# Sauvegarde quotidienne à 2h00
0 2 * * * /path/to/lecoffreio/deploy/scripts/backup/backup-daily.sh >> /path/to/logs/backup-daily.log 2>&1

Contenu des Sauvegardes

Chaque sauvegarde contient :

  • database.dump : Dump PostgreSQL au format custom (pg_dump -Fc)
  • .env.prod : Fichier de configuration de l'environnement
  • nginx-prod.conf : Configuration Nginx
  • certbot-conf-prod/ : Certificats SSL (live, archive, accounts, renewal)
  • backup-metadata.json : Métadonnées (timestamp, Git commit, environnement)

Structure sur VM Gandi

/var/lecoffreio/prod/
├── backup-20250109-020000.tar.gz
├── backup-20250108-020000.tar.gz
├── backup-20250107-020000.tar.gz
├── backup-20250106-020000.tar.gz
├── backup-20250105-020000.tar.gz
├── backup-20250104-020000.tar.gz
├── backup-20250103-020000.tar.gz
└── latest -> backup-20250109-020000.tar.gz

Rotation Automatique

Le script conserve automatiquement les 7 dernières sauvegardes. Les sauvegardes plus anciennes sont supprimées automatiquement.

Récupération d'Urgence

Exécution

# Utiliser la dernière sauvegarde (latest)
./deploy/scripts/backup/disaster-recovery.sh

# Utiliser une sauvegarde spécifique
./deploy/scripts/backup/disaster-recovery.sh backup-20250108-020000.tar.gz

Processus Automatisé

Le script disaster-recovery.sh effectue automatiquement :

  1. Récupération de la sauvegarde depuis la VM Gandi
  2. Extraction de l'archive et vérification du contenu
  3. Préparation du serveur de récupération (vérification prérequis)
  4. Clone/update du repository Git sur le serveur de récupération
  5. Restauration des fichiers de configuration (.env, nginx, certificats)
  6. Upload du dump de base de données
  7. Bascule DNS via API Gandi (prod.lecoffreio.4nkweb.com → IP serveur de récupération)
  8. Attente de la propagation DNS (vérification toutes les 30 secondes)
  9. Restauration de la base de données sur le serveur de récupération
  10. Mise à jour des certificats SSL (renouvellement si nécessaire)
  11. Build et déploiement (build, démarrage services systemd)
  12. Vérification de la santé des services (backend, nginx)
  13. Tests de connectivité HTTP/HTTPS

Durée Estimée

  • Récupération sauvegarde : ~5-10 minutes
  • Bascule DNS : ~5-10 minutes (propagation)
  • Restauration BDD : ~10-30 minutes (selon taille)
  • Build : ~15-30 minutes
  • Total : ~45-80 minutes (objectif RTO : 3 heures)

Gestion DNS via API Gandi

Script Gandi DNS API

Le script gandi-dns-api.sh permet de gérer les enregistrements DNS :

# Récupérer l'enregistrement actuel
./deploy/scripts/backup/gandi-dns-api.sh get prod.lecoffreio.4nkweb.com

# Mettre à jour vers une nouvelle IP
./deploy/scripts/backup/gandi-dns-api.sh update prod.lecoffreio.4nkweb.com 92.243.24.12

# Supprimer un enregistrement (rarement nécessaire)
./deploy/scripts/backup/gandi-dns-api.sh delete prod.lecoffreio.4nkweb.com

Format de l'API

L'API Gandi utilise le format :

  • URL : https://api.gandi.net/api/v5/domains/{domain}/records/{name}/{type}
  • Authorization : Apikey ${GANDI_API_KEY}
  • Domain : lecoffreio.4nkweb.com (domaine de base)
  • Name : prod (sous-domaine)
  • Type : A (enregistrement IPv4)

Monitoring et Maintenance Disaster Recovery

Vérification Quotidienne des Sauvegardes

# Lister les sauvegardes sur VM Gandi
ssh debian@92.243.24.12 "ls -lh /var/lecoffreio/prod/"

# Vérifier la dernière sauvegarde
ssh debian@92.243.24.12 "ls -lh /var/lecoffreio/prod/latest"

Logs

Les scripts génèrent des logs dans logs/ :

# Logs de sauvegarde
ls -lh logs/backup-daily-*.log

# Logs de récupération
ls -lh logs/disaster-recovery-*.log

Vérification de l'Espace Disque

Sur la VM Gandi :

# Espace disque utilisé
ssh debian@92.243.24.12 "df -h /var/lecoffreio"

# Taille des sauvegardes
ssh debian@92.243.24.12 "du -sh /var/lecoffreio/prod/*"

Tests de Récupération

Il est recommandé de tester la récupération trimestriellement :

  1. Utiliser un serveur de test (ou VM temporaire)
  2. Exécuter disaster-recovery.sh avec une sauvegarde récente
  3. Vérifier que tous les services fonctionnent
  4. Documenter les problèmes rencontrés

Dépannage Disaster Recovery

Problème : Sauvegarde échoue

Symptômes :

  • Le script backup-daily.sh échoue
  • Pas de nouvelle sauvegarde dans /var/lecoffreio/prod/

Diagnostic :

# Vérifier les logs
tail -100 logs/backup-daily-*.log

# Vérifier la connexion SSH au serveur prod
ssh -i ~/.ssh/id_ed25519 debian@<PROD_SERVER> "echo 'OK'"

# Vérifier la connexion SSH à la VM Gandi
ssh -i ~/.ssh/id_ed25519 debian@92.243.24.12 "echo 'OK'"

# Vérifier l'espace disque sur VM Gandi
ssh debian@92.243.24.12 "df -h /var"

Solutions :

  • Vérifier les clés SSH
  • Vérifier l'espace disque disponible
  • Vérifier que PostgreSQL est accessible

Problème : Récupération échoue

Symptômes :

  • Le script disaster-recovery.sh échoue à une étape
  • Services non démarrés après récupération

Diagnostic :

# Vérifier les logs
tail -100 logs/disaster-recovery-*.log

# Vérifier l'état des services sur le serveur de récupération
ssh ncantu@$RECOVERY_TARGET_HOST "systemctl status 'lecoffreio-*@*'"

# Vérifier les logs
ssh ncantu@$RECOVERY_TARGET_HOST "journalctl -u lecoffreio-backend@<domain> -n 100"

Solutions :

  • Vérifier les prérequis (Git, Node, services systemd) sur le serveur de récupération
  • Vérifier l'espace disque disponible
  • Vérifier que le dump de base de données est valide
  • Vérifier la configuration DNS

Problème : DNS non propagé

Symptômes :

  • Le script indique que le DNS n'est pas propagé
  • Le site n'est pas accessible via HTTPS

Diagnostic :

# Vérifier l'enregistrement DNS actuel
./deploy/scripts/backup/gandi-dns-api.sh get prod.lecoffreio.4nkweb.com

# Vérifier la résolution DNS
dig prod.lecoffreio.4nkweb.com @8.8.8.8

# Vérifier depuis différents serveurs DNS
nslookup prod.lecoffreio.4nkweb.com 8.8.8.8
nslookup prod.lecoffreio.4nkweb.com 1.1.1.1

Solutions :

  • Attendre la propagation DNS (TTL peut être jusqu'à 600 secondes)
  • Vérifier que l'enregistrement DNS a bien été mis à jour via l'API
  • Vérifier les permissions de l'API Gandi

Problème : Certificats SSL invalides

Symptômes :

  • Erreur de certificat SSL lors de l'accès HTTPS
  • Certificats expirés

Solutions :

# Sur le serveur de récupération, régénérer les certificats
ssh debian@$RECOVERY_TARGET_HOST
cd /home/debian/sites/lecoffreio.4nkweb.com
bash deploy/scripts/build-and-deploy-local-cert.sh prod lecoffreio.4nkweb.com

Procédures Avancées Disaster Recovery

Restaurer une Sauvegarde Spécifique

# Lister les sauvegardes disponibles
ssh debian@92.243.24.12 "ls -lh /var/lecoffreio/prod/backup-*.tar.gz"

# Restaurer une sauvegarde spécifique
./deploy/scripts/backup/disaster-recovery.sh backup-20250108-020000.tar.gz

Restaurer uniquement la Base de Données

Si vous voulez restaurer uniquement la base de données (sans tout le reste) :

# Télécharger le backup
scp debian@92.243.24.12:/var/lecoffreio/prod/backup-XXXXXX.tar.gz /tmp/

# Extraire le dump
tar xzf /tmp/backup-XXXXXX.tar.gz -C /tmp/extracted

# Utiliser le script de reset avec le dump
./deploy/scripts/reset-and-import-database.sh prod /tmp/extracted/database.dump

Vérifier l'Intégrité d'une Sauvegarde

# Télécharger le backup
scp debian@92.243.24.12:/var/lecoffreio/prod/backup-XXXXXX.tar.gz /tmp/

# Extraire et vérifier
tar xzf /tmp/backup-XXXXXX.tar.gz -C /tmp/extracted
ls -lh /tmp/extracted/

# Vérifier le dump PostgreSQL
file /tmp/extracted/database.dump

# Vérifier les métadonnées
cat /tmp/extracted/backup-metadata.json

Sécurité Disaster Recovery

Protection des Clés API

  • Les clés API Gandi sont stockées dans .env.backup (fichier non versionné)
  • Ne jamais commiter .env.backup dans Git
  • Limiter les permissions : chmod 600 .secrets/.env.backup

Chiffrement (Optionnel)

Si vous souhaitez chiffrer les sauvegardes :

# Chiffrer avant transfert
gpg --symmetric --cipher-algo AES256 backup.tar.gz

# Déchiffrer lors de la récupération
gpg --decrypt backup.tar.gz.gpg > backup.tar.gz

Bonnes Pratiques Disaster Recovery

  1. Tests Réguliers : Tester la récupération trimestriellement
  2. Monitoring : Surveiller les logs de sauvegarde quotidienne
  3. Espace Disque : Surveiller l'espace disque sur la VM Gandi
  4. Documentation : Documenter toute modification du processus
  5. Validation : Valider manuellement après chaque récupération

Informations Validées

  1. Infrastructure VM Gandi :

  2. Stratégie de sauvegarde :

    • Environnement : prod uniquement
    • Conservation : 7 versions
  3. API Gandi :

    • Clé API : Fournie (stockée dans .env.backup)
    • Permissions : Admin DNS
    • Domaine : prod.lecoffreio.4nkweb.com
  4. Récupération :

    • RTO (Recovery Time Objective) : 3 heures
    • RPO (Recovery Point Objective) : 24 heures (sauvegarde quotidienne)
  5. Sécurité :

    • Gestion des clés : Fichiers .env.backup
    • Chiffrement : Non requis (infrastructure privée)

Références

Documentation

  • Architecture : ARCHITECTURE.md
  • Reset base de données : docs/DATABASE_RESET_GUIDE.md
  • Scripts backend : SCRIPTS.md
  • Monitoring : Voir section "Monitoring" ci-dessus
  • Disaster Recovery : Voir section "Disaster Recovery" ci-dessus

Fichiers de configuration

  • Configuration systemd : deploy/scripts_v2/systemd/*.service
  • Configuration Nginx : deploy/nginx/nginx-*.conf
  • Script de déploiement : deploy/scripts/build-and-deploy.sh
  • Fichiers d'injection BDD : .secrets/<env>/env-full-<env>-for-bdd-injection.txt

Documentation externe


Git Workflow et Versioning

Voir deploy/README.md pour les scripts. Format des commits : Motivations, Root causes, Correctifs, Evolutions, Pages affectées. Hooks : .git/hooks/commit-msg, .git/hooks/pre-push. Template : .gitmessage. Bump version : ./deploy/scripts/bump-version.sh <version> "<description>" ; met à jour VERSION, package.json (backend + frontend), génère le template splash.

Auteur des commits : L'auteur doit être 4NK ou Nicolas Cantu uniquement. Ne jamais ajouter de ligne Co-authored-by: Cursor ni aucune ligne Co-authored-by qui ferait apparaître un auteur autre que 4NK ou Nicolas Cantu.


Dernière mise à jour : 2026-01-29 (consolidation DEPLOYMENT, MONITORING, DISASTER_RECOVERY, GIT_WORKFLOW, VERSIONING)