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

33 KiB

Migration - Documentation Complète

Auteur : Équipe 4NK Date : 2026-01-XX Version : 2.0.0

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

📋 Vue d'Ensemble

Ce document regroupe toutes les informations relatives aux migrations dans LeCoffre.io :

  • Migration des données V1 vers V2
  • Variables d'environnement V2
  • Chargement de configuration V2
  • Utilisation des variables V2
  • Nettoyage des variables V1
  • Migration des classes vers factories (pattern de code)

1. Migration V1 → V2

Vue d'Ensemble

Ce processus décrit la migration complète des données V1 vers V2, incluant le reset de la base de données, l'import des données, la récupération des documents pour leur réancrage et re-chiffrement, ainsi que le traitement spécifique des RIB.

Processus Global (centralisé)

Les checks de déploiement et leur distinction automatique/manuelle sont centralisés dans : docs/DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique

Pour la migration V1 → V2 :

  • Reset de schéma et baseline Prisma via deploy/scripts_v2/deploy.sh
  • Import V1 initial (destructif) via deploy/scripts_v2/deploy.sh --importV1Data
  • Imports incrémentaux (merge non destructif) via deploy/scripts_v2/merge-v1-data-into-v2.sh <env>

Dépendances détaillées : voir docs/IMPORT_V1_DEPENDENCIES.md pour les prérequis, fichiers et scripts par phase.

Récupération des Documents pour Réancrage et Re-Chiffrement

Problème Identifié

Lors de l'import V1→V2, les fichiers sont importés avec :

  • Clés V1 : UUID individuelles stockées dans files.key et files_notary.key
  • Algorithme V1 : AES-256-CTR (IV 16 bytes intégré)
  • Algorithme V2 : AES-256-GCM (IV 12 bytes séparé, authTag 16 bytes)

Les fichiers V1 ne peuvent pas être déchiffrés directement avec la clé maître V2 car :

  1. Les clés sont différentes (UUID individuelles vs clé maître)
  2. Les algorithmes sont différents (CTR vs GCM)
  3. La structure est différente (IV intégré vs IV séparé)

Solution : Script de Récupération

Script : recover-files-from-v1.ts

Processus :

  1. Déchiffrement V1 : Utilise la clé UUID stockée en base pour déchiffrer le fichier V1
  2. Re-chiffrement V2 : Rechiffre avec la clé maître V2 (AES-256-GCM)
  3. Réancrage : Recalcule le hash et réancre sur Bitcoin Signet
  4. Mise à jour : Met à jour les métadonnées en base (hash, tx_id, etc.)

Utilisation :

npm run recover-files-from-v1

Traitement des RIB

Les RIB en V1 étaient stockés en clair sur S3. En V2, ils sont chiffrés avec la clé maître.

Processus :

  1. Téléchargement depuis S3 (V1)
  2. Chiffrement avec la clé maître V2
  3. Stockage en base de données (V2)

Variables d'Environnement V2

Variables V2 (Application Production)

Les variables suivantes sont définies dans .secrets/<env>/infos_v2.json et sont utilisées par l'application V2 en production.

Base de Données :

  • DATABASE_HOST : Hôte de la base de données (toujours localhost en V2)
  • DATABASE_PORT : Port de la base de données
  • DATABASE_USERNAME : Nom d'utilisateur PostgreSQL
  • DATABASE_PASSWORD : Mot de passe PostgreSQL
  • DATABASE_NAME : Nom de la base de données
  • ENV : Environnement (test, pprod, prod)

Application :

  • API_ROOT_URL : Racine de l'API
  • APP_HOST : URL de l'application
  • APP_LABEL : Label de l'application
  • APP_PORT : Port de l'application backend
  • APP_ROOT_URL : Racine de l'application
  • BACK_API_HOST : URL de l'API backend

Frontend (NEXT_PUBLIC_*) :

  • NEXT_PUBLIC_ADMIN_ID : ID administrateur
  • NEXT_PUBLIC_BACK_API_HOST : Hôte de l'API backend
  • NEXT_PUBLIC_BACK_API_PROTOCOL : Protocole de l'API
  • NEXT_PUBLIC_BACK_API_ROOT_URL : Racine de l'API
  • NEXT_PUBLIC_BACK_API_VERSION : Version de l'API
  • NEXT_PUBLIC_FRONT_APP_HOST : URL de l'application frontend
  • NEXT_PUBLIC_FRONT_APP_PORT : Port de l'application frontend
  • NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT : Endpoint d'autorisation IdNot
  • NEXT_PUBLIC_IDNOT_BASE_URL : URL de base IdNot
  • NEXT_PUBLIC_IDNOT_CLIENT_ID : Client ID IdNot

Intégrations :

  • IdNot : IDNOT_API_BASE_URL, IDNOT_API_KEY, IDNOT_BASE_URL, IDNOT_CLIENT_ID, IDNOT_CLIENT_SECRET, IDNOT_CONNEXION_URL, IDNOT_PROD_BASE_URL, IDNOT_REDIRECT_URL
  • Mailchimp : MAILCHIMP_API_KEY, MAILCHIMP_KEY, MAILCHIMP_LIST_ID
  • OVH SMS : OVH_APP_KEY, OVH_APP_SECRET, OVH_CONSUMER_KEY, OVH_SMS_SERVICE_NAME, SMS_FACTOR_TOKEN, SMS_PROVIDER
  • IPFS Pinata : PINATA_API_KEY, PINATA_API_SECRET, PINATA_GATEWAY, PINATA_GATEWAY_TOKEN
  • Stripe : STRIPE_PAYMENT_CANCEL_URL, STRIPE_PAYMENT_SUCCESS_URL, STRIPE_SECRET_KEY, STRIPE_STANDARD_ANNUAL_SUBSCRIPTION_PRICE_ID, STRIPE_STANDARD_SUBSCRIPTION_PRICE_ID, STRIPE_UNLIMITED_ANNUAL_SUBSCRIPTION_PRICE_ID, STRIPE_UNLIMITED_SUBSCRIPTION_PRICE_ID
  • Secure API : SECURE_API_KEY

Sécurité :

  • ACCESS_TOKEN_SECRET : Secret pour les tokens d'accès
  • REFRESH_TOKEN_SECRET : Secret pour les tokens de rafraîchissement
  • ACCESS_TOKEN_TTL_MINUTES : Durée de vie des tokens d'accès en minutes (format numérique)
  • REFRESH_TOKEN_TTL_MINUTES : Durée de vie des tokens de rafraîchissement en minutes (format numérique)
  • JWT_EXPIRES_IN : Durée de vie JWT en format legacy (ex: "1h", "7d")
  • REFRESH_TOKEN_EXPIRES_IN : Durée de vie des tokens de rafraîchissement en format legacy (ex: "7d")

Variables Migration V1 (Ne PAS utiliser en V2)

Les variables suivantes sont définies dans .secrets/<env>/infos.json, .secrets/<env>/infos_v1.json et, pour la BDD V1, dans .secrets/<env>/.env.<env>.connectDB (DATABASE_V1_*). Elles sont uniquement utilisées par les scripts de migration V1 vers V2. Elles ne doivent JAMAIS être utilisées par l'application V2 en production.

Scaleway S3 (Migration uniquement) :

  • ACCESS_KEY_ID : Clé d'accès S3 Scaleway
  • ACCESS_KEY_SECRET : Secret S3 Scaleway
  • BUCKET_NAME : Nom du bucket S3 Scaleway
  • BUCKET_ENDPOINT : Endpoint S3 Scaleway
  • container : Informations conteneur Scaleway V1

Scripts utilisant ces variables :

  • migrate-files-from-s3.ts : Migration des fichiers depuis S3 Scaleway vers IPFS
  • migrate-ribs-from-s3.ts : Migration des RIBs depuis S3 Scaleway vers IPFS
  • recover-files-from-v1.ts : Récupération des fichiers V1 depuis S3 Scaleway
  • inject-s3-vars-from-infos.ts : Injection des variables S3 dans system_configuration

Docapost (Non utilisé en V2) :

  • DOCAPOST_APP_ID, DOCAPOST_APP_PASSWORD, DOCAPOST_BASE_URL, DOCAPOST_CONNECT_PROCESS_ID, DOCAPOST_DOCUMENT_PROCESS_ID, DOCAPOST_ROOT, DOCAPOST_VERSION, NEXT_PUBLIC_DOCAPOST_API_URL, NEXT_PUBLIC_DOCAPOST_APP_ID, NEXT_PUBLIC_DOCAPOST_CONNECT_PROCESS_ID, NEXT_PUBLIC_DOCAPOST_DOCUMENT_PROCESS_ID

FranceConnect (Non utilisé en V2) :

  • FC_AUTHORIZE_ENDPOINT, FC_CLIENT_ID, NEXT_PUBLIC_FC_AUTHORIZE_ENDPOINT, NEXT_PUBLIC_FC_CLIENT_ID

Sentry (Non utilisé en V2) :

  • SENTRY_AUTH_TOKEN, SENTRY_DSN, SENTRY_FRONT_DSN

Secure API Base URL (Non utilisé en V2) :

  • SECURE_API_BASE_URL

Prisma Studio (Développement uniquement) :

  • DEV_PRISMA_STUDIO_DB_URL, DEV_PRISMA_STUDIO_SHADOW_URL

Chargement de la Configuration V2

Flux de Chargement de Configuration

Application V2 (Production) :

L'application V2 ne charge JAMAIS directement les fichiers infos.json ou infos_v1.json.

Flux de chargement :

1. env-full-<env>-for-bdd-injection.txt
   ↓
2. import-env-to-db.ts (script de déploiement)
   ↓
3. system_configuration (base de données)
   ↓
4. ConfigLoader (application V2)
   ↓
5. BackendVariables / FrontendVariablesOptimized

Fichiers utilisés :

  • .secrets/<env>/env-full-<env>-for-bdd-injection.txt : Variables injectées dans system_configuration
  • PAS infos.json ou infos_v1.json pour l'application V2

Scripts de Migration V1 :

Les scripts de migration V1 chargent les credentials BDD V1 depuis .secrets/<env>/.env.<env>.connectDB (DATABASE_V1_*). Ils peuvent charger depuis infos.json uniquement pour :

  • Variables Scaleway S3 (migration fichiers V1 → V2)

Scripts concernés :

  • inject-s3-vars-from-infos.ts : Injection variables S3 Scaleway dans system_configuration (lit infos-migration-scaleway.json en priorité, puis infos.json en fallback)
  • import-v1-data-direct-into-v2.sh : Import données V1 depuis base Scaleway
  • migrate-files-from-s3.ts : Migration fichiers depuis S3 Scaleway
  • migrate-ribs-from-s3.ts : Migration RIBs depuis S3 Scaleway

Isolation des Variables V1

Variables V1 Supprimées :

Les variables suivantes ont été supprimées du code et des fichiers de configuration :

  • SECURE_API_KEY : SecureService non utilisé (ancrage via BitcoinSignetService)
  • SECURE_API_BASE_URL : SecureService non utilisé
  • NEXT_PUBLIC_FC_AUTHORIZE_ENDPOINT : FranceConnect non utilisé en V2
  • NEXT_PUBLIC_FC_CLIENT_ID : FranceConnect non utilisé en V2
  • NEXT_PUBLIC_FRANCE_CONNECT_CLIENT_ID : FranceConnect non utilisé en V2
  • DOCAPOST_* : Docapost non utilisé en V2
  • SENTRY_* : Sentry non utilisé en V2

Variables Scaleway (Migration uniquement) :

Les variables Scaleway sont isolées pour la migration uniquement :

  • SCW_BUCKET_NAME, BUCKET_NAME : Migration fichiers V1 → V2
  • SCW_ACCESS_KEY_ID, ACCESS_KEY_ID : Migration fichiers V1 → V2
  • SCW_SECRET_ACCESS_KEY, ACCESS_KEY_SECRET : Migration fichiers V1 → V2
  • SCW_REGION : Migration fichiers V1 → V2

Isolation :

  • Lues depuis infos-migration-scaleway.json (priorité) ou infos.json (fallback) uniquement par les scripts de migration
  • Injectées dans system_configuration avec le préfixe SCW_
  • L'application V2 ne les utilise pas (stockage via IPFS Pinata)
  • Retirées de env-full-<env>-for-bdd-injection.txt pour éviter toute utilisation par l'application V2

Fichiers de Configuration

Structure :

.secrets/<env>/
├── infos_v2.json                      # Variables utilisées par l'application V2 (PRODUCTION)
├── infos-migration-scaleway.json      # Variables Scaleway S3 (migration uniquement, PRIORITÉ)
├── infos.json                          # Variables migration V1 (NE PAS UTILISER EN V2, fallback Scaleway)
├── infos_v1.json                       # Variables migration V1 (NE PAS UTILISER EN V2)
└── env-full-<env>-for-bdd-injection.txt  # Variables injectées dans system_configuration (SANS Scaleway)

env-full-<env>-for-bdd-injection.txt :

Usage : Variables injectées dans system_configuration lors du déploiement.

Contenu :

  • Variables définies dans CONFIG_MAPPING (utilisées par l'application V2)
  • Variables système nécessaires (DATABASE_*, ENV, NODE_ENV)

Ne contient PAS :

  • Variables Scaleway (isolées dans infos-migration-scaleway.json, injectées séparément via inject-s3-vars-from-infos.ts)
  • Variables V1 supprimées (SECURE_API_, NEXT_PUBLIC_FC_, DOCAPOST_, SENTRY_)

Génération :

  • Généré manuellement ou via script generate-env-full-from-infos-v2.sh
  • Nettoyé automatiquement pour supprimer les variables V1 non utilisées

Scripts de Déploiement

set-settings.sh :

Usage : Injection des variables dans system_configuration.

Flux :

  1. Lit env-full-<env>-for-bdd-injection.txt
  2. Injecte dans system_configuration via import-env-to-db.ts
  3. Injecte variables S3 Scaleway depuis infos-migration-scaleway.json (priorité) ou infos.json (fallback) via inject-s3-vars-from-infos.ts

Fichiers utilisés :

  • env-full-<env>-for-bdd-injection.txt : Variables application V2 (SANS Scaleway)
  • infos-migration-scaleway.json : Variables S3 Scaleway (migration uniquement, priorité)
  • infos.json : Variables S3 Scaleway (migration uniquement, fallback)

apply-connectdb.sh :

Usage : Configuration de la connexion à la base de données.

Flux :

  1. Lit .env.<env>.connectDB pour les credentials base de données
  2. backend.env n'existe plus sur les cibles (sauvegarde puis suppression à chaque sync). Source unique BDD : .env.<env>.connectDB (voir docs/OPERATIONS.md).
  3. env-full-<env>-for-bdd-injection.txt est utilisé pour setSettings et build frontend.

Fichiers utilisés :

  • .env.<env>.connectDB : Credentials base de données
  • env-full-<env>-for-bdd-injection.txt : Variables supplémentaires

Scripts hors déploiement (dans deploy/scripts_v2) : tous les scripts qui se connectent à la base sans être des scripts de déploiement (ex. ensure-license, check-logs-and-db, ensure-role-permissions-matrix, promote-super-admins, seed-site-texts, reanchor-all, etc.) utilisent .secrets/<env>/.env.<env>.connectDB pour la connexion à la base. Les scripts de déploiement (deploy-app, migrate-resolve-database, prisma-baseline, set-settings, reset-database-from-schema-export, apply-connectdb, install-systemd-units) utilisent .env.<env>.connectDB (backend.env n'est plus utilisé ; voir OPERATIONS.md).

Utilisation des Variables V2

Variables de Sécurité (Tokens JWT)

ACCESS_TOKEN_SECRET :

  • Usage : Secret pour signer les tokens d'accès JWT
  • Fichiers : AuthService.ts (génération/vérification), VariablesBuilder.ts, Variables.ts
  • Catégorie : SECURITY (sensible, requis)

REFRESH_TOKEN_SECRET :

  • Usage : Secret pour signer les tokens de rafraîchissement JWT
  • Fichiers : AuthService.ts (génération/vérification/rafraîchissement), VariablesBuilder.ts, Variables.ts
  • Catégorie : SECURITY (sensible, requis)

ACCESS_TOKEN_TTL_MINUTES :

  • Usage : Durée de vie des tokens d'accès en minutes (format numérique)
  • Fichiers : TokenConfigHelper.ts (résolution TTL)
  • Catégorie : SECURITY (non sensible, optionnel)
  • Valeur par défaut : 60 minutes (1h)

REFRESH_TOKEN_TTL_MINUTES :

  • Usage : Durée de vie des tokens de rafraîchissement en minutes (format numérique)
  • Fichiers : TokenConfigHelper.ts (résolution TTL)
  • Catégorie : SECURITY (non sensible, optionnel)
  • Valeur par défaut : 10080 minutes (7 jours)

JWT_EXPIRES_IN :

  • Usage : Durée de vie JWT en format legacy (ex: "1h", "7d")
  • Fichiers : TokenConfigHelper.ts (fallback si ACCESS_TOKEN_TTL_MINUTES non défini)
  • Catégorie : SECURITY (non sensible, optionnel)
  • Valeur par défaut : "1h" (60 minutes)
  • Note : Variable legacy, ACCESS_TOKEN_TTL_MINUTES est préféré

REFRESH_TOKEN_EXPIRES_IN :

  • Usage : Durée de vie des tokens de rafraîchissement en format legacy (ex: "7d")
  • Fichiers : TokenConfigHelper.ts (fallback si REFRESH_TOKEN_TTL_MINUTES non défini)
  • Catégorie : SECURITY (non sensible, optionnel)
  • Valeur par défaut : "7d" (10080 minutes)
  • Note : Variable legacy, REFRESH_TOKEN_TTL_MINUTES est préféré

Variables Scaleway (Migration V1 uniquement)

SCW_BUCKET_NAME :

  • Usage : Nom du bucket S3 Scaleway pour la migration des fichiers V1 → V2
  • Fichiers : migrate-files-from-s3.ts, migrate-ribs-from-s3.ts, inject-s3-vars-from-infos.ts
  • Catégorie : SYSTEM (non sensible, optionnel - migration uniquement)
  • Source : infos-migration-scaleway.json (priorité) ou infos.json (fallback) - injecté dans system_configuration avec préfixe SCW_
  • Note : Variable utilisée uniquement par les scripts de migration, pas par l'application V2 en production

SCW_ACCESS_KEY_ID :

  • Usage : Clé d'accès S3 Scaleway pour la migration des fichiers V1 → V2
  • Fichiers : migrate-files-from-s3.ts, migrate-ribs-from-s3.ts, inject-s3-vars-from-infos.ts
  • Catégorie : SYSTEM (sensible, optionnel - migration uniquement)
  • Source : infos-migration-scaleway.json (priorité) ou infos.json (fallback) - injecté dans system_configuration avec préfixe SCW_

SCW_SECRET_ACCESS_KEY :

  • Usage : Clé secrète S3 Scaleway pour la migration des fichiers V1 → V2
  • Fichiers : migrate-files-from-s3.ts, migrate-ribs-from-s3.ts, inject-s3-vars-from-infos.ts
  • Catégorie : SYSTEM (sensible, optionnel - migration uniquement)
  • Source : infos-migration-scaleway.json (priorité) ou infos.json (fallback) - injecté dans system_configuration avec préfixe SCW_

SCW_REGION :

  • Usage : Région S3 Scaleway pour la migration des fichiers V1 → V2
  • Fichiers : migrate-files-from-s3.ts, migrate-ribs-from-s3.ts, inject-s3-vars-from-infos.ts
  • Catégorie : SYSTEM (non sensible, optionnel - migration uniquement)
  • Valeur par défaut : "fr-par"
  • Source : infos-migration-scaleway.json (priorité) ou infos.json (fallback) - injecté dans system_configuration avec préfixe SCW_

Flux d'Utilisation

Tokens JWT :

1. ACCESS_TOKEN_SECRET / REFRESH_TOKEN_SECRET
   ↓ (system_configuration)
2. BackendVariables
   ↓
3. AuthService.generateAccessToken() / generateRefreshToken()
   ↓
4. JWT signé avec secret + TTL

TTL Tokens :

1. ACCESS_TOKEN_TTL_MINUTES (priorité) ou JWT_EXPIRES_IN (fallback)
   ↓ (system_configuration)
2. TokenConfigHelper.getAccessTokenTtlMinutes()
   ↓
3. AuthService.generateAccessToken() avec expiresIn

Migration Scaleway :

1. SCW_* variables depuis infos-migration-scaleway.json (priorité) ou infos.json (fallback)
   ↓ (inject-s3-vars-from-infos.ts)
2. system_configuration (préfixe SCW_)
   ↓
3. migrate-files-from-s3.ts / migrate-ribs-from-s3.ts
   ↓
4. Client S3 Scaleway créé

Nettoyage des Variables V1

Variables à garder (Migration uniquement)

Ces variables sont utilisées uniquement par les scripts de migration V1 → V2 et ne doivent pas être utilisées par l'application V2 en production.

  • SCW_BUCKET_NAME, BUCKET_NAME : Migration fichiers V1 → V2
  • SCW_ACCESS_KEY_ID, ACCESS_KEY_ID : Migration fichiers V1 → V2
  • SCW_SECRET_ACCESS_KEY, ACCESS_KEY_SECRET : Migration fichiers V1 → V2
  • SCW_REGION : Migration fichiers V1 → V2

Isolation : Ces variables sont lues depuis infos.json et injectées dans system_configuration avec le préfixe SCW_ uniquement lors de l'exécution des scripts de migration.

Variables à nettoyer (Non utilisées)

Ces variables ne sont pas utilisées par l'application V2 et doivent être supprimées du code.

FranceConnect :

  • NEXT_PUBLIC_FC_AUTHORIZE_ENDPOINT : Dépréciée, filtrée dans deprecatedKeys
  • NEXT_PUBLIC_FC_CLIENT_ID : Dépréciée, filtrée dans deprecatedKeys
  • NEXT_PUBLIC_FRANCE_CONNECT_CLIENT_ID : Dépréciée

Statut : Aucune utilisation dans le frontend. Variables déjà filtrées dans ConfigController.ts mais toujours définies dans ImportEnvConfigMapping.ts.

Docapost :

  • DOCAPOST_* : Déjà commenté/retiré

Statut : Déjà retiré du code. Aucune action nécessaire.

Sentry :

  • SENTRY_DSN, SENTRY_AUTH_TOKEN, SENTRY_FRONT_DSN : Non utilisé

Statut : Aucune référence trouvée dans le code. Aucune action nécessaire.

Actions de Nettoyage

1. Supprimer les variables FranceConnect :

ImportEnvConfigMapping.ts :

  • Supprimer NEXT_PUBLIC_FC_AUTHORIZE_ENDPOINT
  • Supprimer NEXT_PUBLIC_FC_CLIENT_ID
  • Supprimer NEXT_PUBLIC_FRANCE_CONNECT_CLIENT_ID

ConfigController.ts :

  • Supprimer les entrées du deprecatedKeys :
    • NEXT_PUBLIC_FC_AUTHORIZE_ENDPOINT
    • NEXT_PUBLIC_FC_CLIENT_ID

Note : Ces variables sont déjà filtrées mais peuvent être complètement supprimées maintenant.

Règles de Séparation

Variables V2 (Production) :

  • Source : infos_v2.json
  • Usage : Application V2 en production
  • Stockage : Base de données locale (localhost)
  • Stockage fichiers : IPFS (Pinata)
  • Base de données : PostgreSQL locale

Variables Migration V1 :

  • Source : infos.json ou infos_v1.json
  • Usage : Scripts de migration uniquement
  • Stockage : Scaleway S3 (lecture seule)
  • Base de données : Base V1 Scaleway (lecture seule)

🔒 Isolation :

L'application V2 ne doit JAMAIS :

  • Se connecter à Scaleway S3
  • Se connecter à la base de données V1 Scaleway
  • Utiliser les variables Docapost, FranceConnect, Sentry
  • Charger infos.json ou infos_v1.json en production

Les scripts de migration peuvent :

  • Lire depuis infos-migration-scaleway.json (priorité) ou infos.json (fallback) pour accéder à Scaleway S3
  • Se connecter à la base de données V1 Scaleway
  • Injecter les variables Scaleway dans system_configuration avec le préfixe SCW_

2. Migration Pattern : Classes vers Factories

Contexte

Migration complète des classes héritant de BaseApiService vers des factories pour résoudre le problème TDZ (Temporal Dead Zone) dans Webpack/Next.js.

Pattern Général

Avant (Classe)

import BaseSuperAdmin from "../BaseSuperAdmin";

export default class MyService extends BaseSuperAdmin {
  private static instance: MyService;

  private get baseUrl(): string {
    return this.namespaceUrl.concat("/my-service");
  }

  private constructor() {
    super();
  }

  public static getInstance() {
    return (this.instance ??= new this());
  }

  public async myMethod(body?: ApiPayload) {
    const url = new URL(this.baseUrl.concat("/endpoint"));
    return this.postRequest<MyResponse>(url, body ?? {});
  }
}

Après (Factory)

1. Créer MyServiceFactory.ts :

import { createBaseSuperAdmin, type IBaseSuperAdmin } from "../BaseSuperAdminFactory";
import type { ApiPayload } from "../../../types";
import type { MyResponse } from "./MyService";

interface MyServiceInstance {
  myMethod(body?: ApiPayload): Promise<MyResponse>;
}

let instance: MyServiceInstance | null = null;
let baseSuperAdminInstance: IBaseSuperAdmin | null = null;

function createMyService(): MyServiceInstance {
  if (!baseSuperAdminInstance) {
    baseSuperAdminInstance = createBaseSuperAdmin();
  }

  const baseSuperAdmin = baseSuperAdminInstance;
  const baseUrl = baseSuperAdmin.namespaceUrl.concat("/my-service");

  return {
    myMethod: async (body?: ApiPayload): Promise<MyResponse> => {
      const url = new URL(baseUrl.concat("/endpoint"));
      return baseSuperAdmin.postRequest<MyResponse>(url, body ?? {});
    },
  };
}

export function getMyServiceInstance(): MyServiceInstance {
  if (!instance) {
    instance = createMyService();
  }
  return instance;
}

2. Modifier MyService.ts :

// Export types
export type MyResponse = {
  // ...
};

// Export interface
export interface IMyService {
  myMethod(body?: unknown): Promise<MyResponse>;
}

// Lazy import of factory
let factoryInstance: (() => IMyService) | null = null;

function getFactory(): () => IMyService {
  if (!factoryInstance) {
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    factoryInstance = require("./MyServiceFactory").getMyServiceInstance;
  }
  return factoryInstance as () => IMyService;
}

// Export the instance getter
export const MyService = {
  getInstance: (): IMyService => {
    return getFactory()();
  },
};

// Export default for backward compatibility
export default MyService;

Remplacements Clés

Avant (Classe) Après (Factory)
this.namespaceUrl baseSuperAdmin.namespaceUrl
this.baseUrl Variable locale baseUrl
this.postRequest() baseSuperAdmin.postRequest()
this.getRequest() baseSuperAdmin.getRequest()
this.putRequest() baseSuperAdmin.putRequest()
this.deleteRequest() baseSuperAdmin.deleteRequest()
this.onError() baseSuperAdmin.onError()
this.buildHeaders() baseSuperAdmin.buildHeaders()

Factories de Base Disponibles

  • createBaseApiService()BaseApiServiceFactory
  • createBaseNotary()BaseNotaryFactory
  • createBaseSuperAdmin()BaseSuperAdminFactory
  • createBaseAdmin()BaseAdminFactory
  • createBaseCustomer()BaseCustomerFactory
  • createBasePublic()BasePublicFactory
  • createBaseId360()BaseId360Factory

Checklist de Migration

  1. Créer MyServiceFactory.ts avec la logique métier
  2. Déplacer les types dans MyService.ts (si nécessaire)
  3. Modifier MyService.ts pour exporter la factory via lazy import
  4. Vérifier que tous les imports existants fonctionnent encore
  5. Tester TypeScript (npm run typecheck)
  6. Tester le build (npm run build)

Ordre de Migration Recommandé

  1. Commencer par les classes les plus simples (peu de méthodes)
  2. Migrer par namespace (SuperAdmin → Admin → Customer → Notary → Public)
  3. Tester après chaque groupe de 5-10 fichiers

3. Checklist de Migration V1 → V2

Phase 1 : Préparation

  • Dump V1 disponible : deploy/bdd.<env> (format PGDMP)
  • Schéma V2 exporté : deploy/schema-v2.sql (optionnel)
  • Clés V1 extraites : .secrets/v1-file-keys.json (via extract-v1-file-keys.sh)
  • Clé maître V2 configurée : FILE_ENCRYPTION_MASTER_KEY dans system_configuration ou .env

Phase 2 : Reset + Import

  • Reset de la base : Baseline V2 depuis schéma

    bash deploy/scripts_v2/deploy.sh <env> \
      --resetDatabaseFromSchemaExport \
      --migrateResolveDatabase
    
  • Import des données V1 : Import complet (destructif)

    bash deploy/scripts_v2/deploy.sh <env> \
      --importV1Data \
      --deploy
    
  • Vérification de l'import :

    • Nombre de fichiers importés cohérent
    • Clés individuelles présentes dans files.key et files_notary.key
    • RIB présents dans rib_encrypted (si migrés depuis S3)

Phase 3 : Récupération des Fichiers V1

  • Extraction des clés V1 (si pas déjà fait)

    ./deploy/scripts_v2/backup/extract-v1-file-keys.sh .secrets/<env>/bdd.<env>
    
  • Récupération des fichiers : Déchiffrement V1 → Re-chiffrement V2

    cd lecoffre-back-main
    npx ts-node src/scripts/recover-files-from-v1.ts \
      --output-report logs/v1-files-recovery-report.json
    
  • Vérification de la récupération :

    • Rapport de récupération généré
    • Fichiers récupérés avec succès
    • Nouveaux hash IPFS en base
    • Fichiers accessibles via les nouveaux chemins IPFS

Phase 4 : Migration des RIB

  • Migration des RIB vers IPFS (si nécessaire)

    cd lecoffre-back-main
    npx ts-node src/scripts/migrate-ribs-to-ipfs.ts \
      --output-report logs/ribs-migration-to-ipfs-report.json
    
  • Vérification des RIB :

    • RIB migrés avec succès
    • rib_url présent en base
    • rib_encrypted supprimé après migration
    • RIB accessibles via IPFS

Phase 5 : Réancrage

  • Réancrage des documents (si nécessaire)

    cd lecoffre-back-main
    npm run reanchor-all-complete
    
  • Vérification de l'ancrage :

    • Documents réancrés avec succès
    • Nouveaux tx_id en base
    • Certificats régénérés

4. Conformité des Scripts de Migration

Scripts de Migration des Fichiers

recover-files-from-v1.ts - 100% Conforme

Corrections appliquées :

  • Utilise AES-256-CTR (algorithme V1)
  • Lit le format V1 : [IV 16 bytes][encrypted data]
  • Utilise les clés individuelles UUID depuis files.key et files_notary.key
  • Convertit UUID → clé de chiffrement via SHA-256 + base64 (32 premiers caractères)
  • Re-chiffre avec clé maître V2 (AES-256-GCM)
  • Upload sur IPFS V2
  • Met à jour file_path avec nouveau hash IPFS

⚠️ IMPORTANT : Ce script traite uniquement les fichiers sur IPFS (files et files_notary). Il ne traite pas les RIB.

Scripts de Migration des RIB

migrate-ribs-to-ipfs.ts - 100% Conforme

Fonctionnalités :

  • Identifie les RIB en PostgreSQL (rib_encrypted sans rib_url)
  • Déchiffre depuis PostgreSQL
  • Migre vers IPFS via uploadEncryptedRIB() (filigrane → ancrage → chiffrement → IPFS)
  • Supprime rib_encrypted après migration réussie
  • Génère un rapport détaillé

⚠️ IMPORTANT : Ce script traite uniquement les RIB stockés en PostgreSQL. Les RIB déjà sur IPFS sont ignorés.


5. Erreurs et Corrections de Migration

Erreur "Missing parameters" dans check-v1-migration-status.sh

Date : 2026-01-27

Problème : Les paramètres ENV, DOMAIN, APP_ROOT n'étaient pas correctement passés au script distant via SSH.

Root Cause : Le heredoc dans ssh_run attendait des paramètres positionnels ($1, $2, $3) mais ils n'étaient pas passés correctement. Les paramètres étaient passés après la fermeture du heredoc, ce qui ne fonctionne pas avec bash -s.

Solution : Passer les variables comme variables d'environnement avant le heredoc :

# Avant (incorrect)
ssh_run ... 'bash -s' <<'CHECK_MIGRATION'
ENV="${1:-}"
CHECK_MIGRATION
"$ENV" "$DOMAIN" "$APP_ROOT"

# Après (correct)
ssh_run ... env "ENV=$ENV" "DOMAIN=$DOMAIN" "APP_ROOT=$APP_ROOT" 'bash -s' <<'CHECK_MIGRATION'
if [[ -z "${ENV:-}" || -z "${DOMAIN:-}" || -z "${APP_ROOT:-}" ]]; then
    echo "Missing parameters" >&2
    exit 1
fi
CHECK_MIGRATION

Fichier modifié : deploy/scripts_v2/check-v1-migration-status.sh

Erreur SQL "relation public.ribs does not exist"

Date : 2026-01-27

Problème : Le script check-v1-migration-status.sh interrogeait une table public.ribs qui n'existe pas.

Root Cause : Les données RIB sont stockées dans la table public.offices avec les colonnes rib_url et rib_encrypted.

Solution : Remplacer toutes les références à public.ribs par public.offices :

-- Avant
FROM public.ribs
WHERE rib_url IS NOT NULL

-- Après
FROM public.offices
WHERE rib_url IS NOT NULL

Fichier modifié : deploy/scripts_v2/check-v1-migration-status.sh

Suppression de la limite de date 2025-05-01

Date : 2026-01-27

Problème : Les scripts de migration avaient une limite de date fixe qui empêchait le traitement des fichiers créés avant le 01/05/2025.

Solution : Suppression de toutes les limites de dates dans les scripts de migration :

  • recover-files-from-v1.ts : Suppression de maxAgeDate et des filtres created_at >= maxAgeDate
  • migrate-files-from-s3.ts : Suppression de maxAgeDate et des filtres created_at >= maxAgeDate
  • diagnose-failed-files-v1.ts : Suppression de maxAgeDate et des filtres created_at >= maxAgeDate
  • reanchor-all-complete.ts : Suppression de maxAgeDate et maxAgeDateNotary
  • import-v1-data-direct-into-v2.sh : Suppression des filtres WHERE "created_at" >= '2025-05-01'

Fichiers modifiés :

  • lecoffre-back-main/src/scripts/recover-files-from-v1.ts
  • lecoffre-back-main/src/scripts/migrate-files-from-s3.ts
  • lecoffre-back-main/src/scripts/diagnose-failed-files-v1.ts
  • lecoffre-back-main/src/scripts/reanchor-all-complete.ts
  • deploy/scripts_v2/remote/import-v1-data-direct-into-v2.sh

Erreurs de syntaxe Bash dans import-v1-data-direct-into-v2.sh

Date : 2026-01-23

Problèmes :

  1. Syntaxe incorrecte avec ssh_run et heredoc avec arguments
  2. Substitution de commande avec heredoc entre guillemets
  3. Variables échappées empêchant l'interpolation
  4. Dollar quotes ($$) interprétés comme PID par bash

Solutions :

  1. Passer les arguments séparément sans guillemets : bash -s arg1 arg2 au lieu de "bash -s \"arg1\" \"arg2\""
  2. Retirer les guillemets autour de $(...) avec heredoc
  3. Utiliser les variables directement sans échappement dans heredoc
  4. Utiliser Python avec variables d'environnement pour générer $$ (fallback awk)

Fichier modifié : deploy/scripts_v2/remote/import-v1-data-direct-into-v2.sh

Leçons apprises / À éviter :

  • Ne jamais générer $$ directement dans bash (toujours interprété comme PID). Utiliser Python avec variables d'environnement et heredoc en guillemets simples, ou awk en fallback.
  • Heredoc avec arguments : passer les arguments séparément, sans guillemets autour de bash -s (bash -s arg1 arg2).
  • Substitution de commande avec heredoc : ne pas mettre de guillemets autour de $(...).
  • Variables dans heredoc : ne pas échapper avec \" ou \$ ; utiliser "${VAR}" directement.


Dernière mise à jour : 2026-01-28 (consolidation MIGRATION.md, V1_TO_V2_MIGRATION_PROCESS.md, V2_ENVIRONMENT_VARIABLES.md, V2_CONFIGURATION_LOADING.md, V2_VARIABLES_USAGE.md, V1_VARIABLES_CLEANUP.md)