**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
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.keyetfiles_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 :
- Les clés sont différentes (UUID individuelles vs clé maître)
- Les algorithmes sont différents (CTR vs GCM)
- 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 :
- Déchiffrement V1 : Utilise la clé UUID stockée en base pour déchiffrer le fichier V1
- Re-chiffrement V2 : Rechiffre avec la clé maître V2 (AES-256-GCM)
- Réancrage : Recalcule le hash et réancre sur Bitcoin Signet
- 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 :
- Téléchargement depuis S3 (V1)
- Chiffrement avec la clé maître V2
- 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 (toujourslocalhosten V2)DATABASE_PORT: Port de la base de donnéesDATABASE_USERNAME: Nom d'utilisateur PostgreSQLDATABASE_PASSWORD: Mot de passe PostgreSQLDATABASE_NAME: Nom de la base de donnéesENV: Environnement (test, pprod, prod)
Application :
API_ROOT_URL: Racine de l'APIAPP_HOST: URL de l'applicationAPP_LABEL: Label de l'applicationAPP_PORT: Port de l'application backendAPP_ROOT_URL: Racine de l'applicationBACK_API_HOST: URL de l'API backend
Frontend (NEXT_PUBLIC_*) :
NEXT_PUBLIC_ADMIN_ID: ID administrateurNEXT_PUBLIC_BACK_API_HOST: Hôte de l'API backendNEXT_PUBLIC_BACK_API_PROTOCOL: Protocole de l'APINEXT_PUBLIC_BACK_API_ROOT_URL: Racine de l'APINEXT_PUBLIC_BACK_API_VERSION: Version de l'APINEXT_PUBLIC_FRONT_APP_HOST: URL de l'application frontendNEXT_PUBLIC_FRONT_APP_PORT: Port de l'application frontendNEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT: Endpoint d'autorisation IdNotNEXT_PUBLIC_IDNOT_BASE_URL: URL de base IdNotNEXT_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èsREFRESH_TOKEN_SECRET: Secret pour les tokens de rafraîchissementACCESS_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 ScalewayACCESS_KEY_SECRET: Secret S3 ScalewayBUCKET_NAME: Nom du bucket S3 ScalewayBUCKET_ENDPOINT: Endpoint S3 Scalewaycontainer: Informations conteneur Scaleway V1
Scripts utilisant ces variables :
migrate-files-from-s3.ts: Migration des fichiers depuis S3 Scaleway vers IPFSmigrate-ribs-from-s3.ts: Migration des RIBs depuis S3 Scaleway vers IPFSrecover-files-from-v1.ts: Récupération des fichiers V1 depuis S3 Scalewayinject-s3-vars-from-infos.ts: Injection des variables S3 danssystem_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 danssystem_configuration- PAS
infos.jsonouinfos_v1.jsonpour 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 danssystem_configuration(litinfos-migration-scaleway.jsonen priorité, puisinfos.jsonen fallback)import-v1-data-direct-into-v2.sh: Import données V1 depuis base Scalewaymigrate-files-from-s3.ts: Migration fichiers depuis S3 Scalewaymigrate-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 V2NEXT_PUBLIC_FC_CLIENT_ID: FranceConnect non utilisé en V2NEXT_PUBLIC_FRANCE_CONNECT_CLIENT_ID: FranceConnect non utilisé en V2DOCAPOST_*: Docapost non utilisé en V2SENTRY_*: 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 → V2SCW_ACCESS_KEY_ID,ACCESS_KEY_ID: Migration fichiers V1 → V2SCW_SECRET_ACCESS_KEY,ACCESS_KEY_SECRET: Migration fichiers V1 → V2SCW_REGION: Migration fichiers V1 → V2
Isolation :
- ✅ Lues depuis
infos-migration-scaleway.json(priorité) ouinfos.json(fallback) uniquement par les scripts de migration - ✅ Injectées dans
system_configurationavec le préfixeSCW_ - ✅ L'application V2 ne les utilise pas (stockage via IPFS Pinata)
- ✅ Retirées de
env-full-<env>-for-bdd-injection.txtpour é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 viainject-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 :
- Lit
env-full-<env>-for-bdd-injection.txt - Injecte dans
system_configurationviaimport-env-to-db.ts - Injecte variables S3 Scaleway depuis
infos-migration-scaleway.json(priorité) ouinfos.json(fallback) viainject-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 :
- Lit
.env.<env>.connectDBpour les credentials base de données backend.envn'existe plus sur les cibles (sauvegarde puis suppression à chaque sync). Source unique BDD :.env.<env>.connectDB(voir docs/OPERATIONS.md).env-full-<env>-for-bdd-injection.txtest utilisé pour setSettings et build frontend.
Fichiers utilisés :
.env.<env>.connectDB: Credentials base de donnéesenv-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 siACCESS_TOKEN_TTL_MINUTESnon défini) - Catégorie :
SECURITY(non sensible, optionnel) - Valeur par défaut : "1h" (60 minutes)
- Note : Variable legacy,
ACCESS_TOKEN_TTL_MINUTESest 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 siREFRESH_TOKEN_TTL_MINUTESnon défini) - Catégorie :
SECURITY(non sensible, optionnel) - Valeur par défaut : "7d" (10080 minutes)
- Note : Variable legacy,
REFRESH_TOKEN_TTL_MINUTESest 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é) ouinfos.json(fallback) - injecté danssystem_configurationavec préfixeSCW_ - 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é) ouinfos.json(fallback) - injecté danssystem_configurationavec préfixeSCW_
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é) ouinfos.json(fallback) - injecté danssystem_configurationavec préfixeSCW_
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é) ouinfos.json(fallback) - injecté danssystem_configurationavec préfixeSCW_
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 → V2SCW_ACCESS_KEY_ID,ACCESS_KEY_ID: Migration fichiers V1 → V2SCW_SECRET_ACCESS_KEY,ACCESS_KEY_SECRET: Migration fichiers V1 → V2SCW_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 dansdeprecatedKeysNEXT_PUBLIC_FC_CLIENT_ID: Dépréciée, filtrée dansdeprecatedKeysNEXT_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_ENDPOINTNEXT_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.jsonouinfos_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.jsonouinfos_v1.jsonen production
Les scripts de migration peuvent :
- Lire depuis
infos-migration-scaleway.json(priorité) ouinfos.json(fallback) pour accéder à Scaleway S3 - Se connecter à la base de données V1 Scaleway
- Injecter les variables Scaleway dans
system_configurationavec le préfixeSCW_
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()→BaseApiServiceFactorycreateBaseNotary()→BaseNotaryFactorycreateBaseSuperAdmin()→BaseSuperAdminFactorycreateBaseAdmin()→BaseAdminFactorycreateBaseCustomer()→BaseCustomerFactorycreateBasePublic()→BasePublicFactorycreateBaseId360()→BaseId360Factory
Checklist de Migration
- ✅ Créer
MyServiceFactory.tsavec la logique métier - ✅ Déplacer les types dans
MyService.ts(si nécessaire) - ✅ Modifier
MyService.tspour exporter la factory via lazy import - ✅ Vérifier que tous les imports existants fonctionnent encore
- ✅ Tester TypeScript (
npm run typecheck) - ✅ Tester le build (
npm run build)
Ordre de Migration Recommandé
- Commencer par les classes les plus simples (peu de méthodes)
- Migrer par namespace (SuperAdmin → Admin → Customer → Notary → Public)
- 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(viaextract-v1-file-keys.sh) - Clé maître V2 configurée :
FILE_ENCRYPTION_MASTER_KEYdanssystem_configurationou.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.keyetfiles_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_urlprésent en baserib_encryptedsupprimé 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_iden 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.keyetfiles_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_pathavec 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_encryptedsansrib_url) - ✅ Déchiffre depuis PostgreSQL
- ✅ Migre vers IPFS via
uploadEncryptedRIB()(filigrane → ancrage → chiffrement → IPFS) - ✅ Supprime
rib_encryptedaprè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 demaxAgeDateet des filtrescreated_at >= maxAgeDatemigrate-files-from-s3.ts: Suppression demaxAgeDateet des filtrescreated_at >= maxAgeDatediagnose-failed-files-v1.ts: Suppression demaxAgeDateet des filtrescreated_at >= maxAgeDatereanchor-all-complete.ts: Suppression demaxAgeDateetmaxAgeDateNotaryimport-v1-data-direct-into-v2.sh: Suppression des filtresWHERE "created_at" >= '2025-05-01'
Fichiers modifiés :
lecoffre-back-main/src/scripts/recover-files-from-v1.tslecoffre-back-main/src/scripts/migrate-files-from-s3.tslecoffre-back-main/src/scripts/diagnose-failed-files-v1.tslecoffre-back-main/src/scripts/reanchor-all-complete.tsdeploy/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 :
- Syntaxe incorrecte avec
ssh_runet heredoc avec arguments - Substitution de commande avec heredoc entre guillemets
- Variables échappées empêchant l'interpolation
- Dollar quotes (
$$) interprétés comme PID par bash
Solutions :
- Passer les arguments séparément sans guillemets :
bash -s arg1 arg2au lieu de"bash -s \"arg1\" \"arg2\"" - Retirer les guillemets autour de
$(...)avec heredoc - Utiliser les variables directement sans échappement dans heredoc
- 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)