05 août 2025·8 min de lecture

Reconstruire une appli sans changer la base de données : plan de cutover efficace

Apprenez à reconstruire une appli sans changer la base de données grâce à un plan de cutover sûr qui préserve comptes et historique, avec déploiement progressif et rollback.

Reconstruire une appli sans changer la base de données : plan de cutover efficace

Ce qui peut mal tourner quand vous reconstruisez tout en gardant la même base de données

Garder votre base de données actuelle peut sembler plus sûr que de migrer tout. Mais une reconstruction peut quand même échouer d'une manière qui ressemble à une « donnée manquante » pour les utilisateurs. La plupart des problèmes viennent de petits écarts entre ce que l'ancienne appli supposait et ce que fait réellement la nouvelle.

Les pires échecs se traduisent par une perte de comptes ou des historiques « vides ». Les lignes peuvent être toujours présentes, mais la nouvelle appli les lit différemment. Les causes courantes incluent un changement du hachage des mots de passe, une normalisation différente des emails (sensibilité à la casse, suppression d'espaces), de nouveaux formats d'identifiants utilisateur, ou un nouveau fournisseur d'authentification qui ne se mappe pas proprement aux identités existantes.

Une reconstruction sans changement de base de données risque aussi une corruption subtile lors du basculement. Si l'ancienne et la nouvelle appli écrivent en même temps, vous pouvez créer une réalité bifurquée : enregistrements dupliqués, mises à jour écrasées, ou événements enregistrés dans un système mais pas dans l'autre.

Un plan de cutover doit surtout protéger quelques éléments : les connexions et le mapping des identités, l'ordre des écritures (pas de doublons ni de mises à jour perdues), les traces d'audit et l'historique (horodatages, changements d'état, factures, messages), et les jobs en arrière-plan (emails, webhooks, traitements de facturation) qui pourraient retraiter d'anciennes données.

Parfois, garder la base de données est la mauvaise décision. Si le schéma est dangereux (secrets exposés, traces d'injections SQL, contraintes manquantes) ou si le modèle de données est tellement incohérent que chaque écran nécessite une logique ad hoc, vous passerez plus de temps à patcher qu'à reconstruire.

Un exemple simple : votre refonte change les règles d'« appartenance à une organisation ». Les anciennes données autorisent plusieurs rôles par utilisateur, mais la nouvelle appli n'en attend qu'un. Les utilisateurs « perdent » soudainement l'accès parce que le nouveau code choisit le mauvais rôle. Détecter ça tôt est l'objectif des vérifications de compatibilité.

Fixez les objectifs et choisissez une approche de cutover

Commencez par écrire les promesses que vous refusez de casser. Cela empêche la reconstruction de devenir une réécriture risquée où des gens perdent l'accès, l'historique ou la confiance.

La plupart des équipes arrivent à des promesses comme : les comptes existants fonctionnent toujours, les données historiques restent intactes, et le temps d'arrêt est soit quasi nul soit planifié et court. Si une promesse peut être flexible (par exemple une fenêtre de maintenance de 10 minutes est acceptable), décidez-le maintenant, pas la nuit du lancement.

Transformez le « succès » en contrôles simples sur lesquels toute l'équipe s'accorde. Par exemple : les utilisateurs peuvent se connecter et voient le même rôle et les mêmes permissions ; les pages clés affichent les mêmes totaux (commandes, factures, messages) ; les nouvelles actions créent exactement une écriture dans la base ; les jobs critiques s'exécutent toujours ; et le support dispose d'un script clair pour les problèmes les plus probables.

Deux styles courants de cutover

Un basculement programmé (big-bang) redirige tout le trafic vers la nouvelle appli à un moment planifié. C'est plus simple à raisonner, mais les enjeux sont plus élevés si quelque chose casse.

Un basculement progressif déplace le trafic par étapes (pourcentage, groupes d'utilisateurs, ou fonctionnalités). C'est plus lent, mais réduit le risque car vous pouvez apprendre de l'usage réel avant d'aller jusqu'au bout.

Définissez le rollback comme quelque chose que vous pouvez décider rapidement et exécuter sans hésitation. Soyez explicite sur ce que vivront les utilisateurs (période en lecture seule vs retour complet à l'ancienne appli) et ce qu'il advient des données créées pendant la tentative.

Cartographiez les données actuelles et les parcours utilisateurs liés

Ayez une image claire de ce qui est réellement en production aujourd'hui, pas seulement ce que dit l'ERD. Les reconstructions cassent souvent parce qu'une table « petite » ou un job en arrière-plan faisait discrètement beaucoup de travail.

Commencez par inventorier les données derrière vos flux les plus utilisés. Concentrez-vous sur les tables qui définissent qui est un utilisateur, ce à quoi il peut accéder, et ce pour quoi vous êtes payé. En pratique, cela signifie en général les tables d'identité et d'accès, de facturation/abonnement, vos enregistrements domaine principaux et paramètres, ainsi que les logs et tables d'intégration qui expliquent ce qui s'est passé (et pourquoi).

Ensuite, cartographiez les relations que vous ne pouvez pas casser. Cherchez les clés étrangères (ou les liens « mous » appliqués seulement dans le code), les contraintes d'unicité, et les enregistrements « qui doivent exister » (par exemple une organisation par défaut ou un rôle propriétaire). Notez ce qui doit rester vrai après le cutover, par exemple : chaque abonnement correspond exactement à un compte actif.

Enfin, documentez où les données sont créées ou modifiées. Restez simple : formulaires UI, outils admin, jobs en arrière-plan, imports, et webhooks. Capturez les bizarreries dont la production dépend, même si elles sont sales.

Exemple : si votre appli actuelle écrit org_id de deux manières différentes (inscription web vs onboarding assisté par les ventes), la nouvelle appli doit gérer les deux.

Rendre l'authentification et l'identité utilisateur compatibles

L'authentification est souvent le premier point de rupture en production. De petits écarts dans les IDs utilisateurs, l'appartenance à une org ou les rôles peuvent verrouiller des personnes hors du système ou, pire, les connecter au mauvais compte.

Confirmez ce que votre système considère comme l'identité « principale ». Est-ce un user_id numérique, un UUID, un email, ou un ID fournisseur externe (Google, GitHub) ? Choisissez la clé stable et utilisez-la de la même façon partout : appartenance org, permissions, propriété de facturation, et logs d'audit.

Effectuez une vérification de compatibilité qui attrape la plupart des problèmes :

  • Le même user ID correspond au même email et à la même org dans les deux applis.
  • Les tables d'orgs et de rôles signifient la même chose (pas seulement les mêmes noms).
  • Les règles d'unicité reflètent la réalité (surtout l'unicité des emails).
  • Les utilisateurs supprimés ou désactivés se comportent de la même manière.
  • Les champs d'audit comme created_at et last_login sont préservés.

Le traitement des mots de passe nécessite une attention particulière. Ne re-hachez pas les mots de passe sauf si c'est strictement nécessaire. Si l'ancienne appli utilise bcrypt et la nouvelle attend argon2, continuez à vérifier avec l'ancien hachage et migrez au prochain login (stocker le nouveau hachage après une connexion réussie). Cela évite des réinitialisations forcées, des tickets au support et du churn.

Les sessions et tokens sont un autre piège. Pendant un déploiement progressif, des anciennes sessions peuvent subsister. Décidez si vous les autorisez, les expirez, ou faites tourner deux validateurs de tokens pendant une courte fenêtre. Si vous changez les clés de signature, planifiez-le comme une release et non comme une surprise.

Les cas limites apparaissent toujours : emails dupliqués issus d'imports anciens, utilisateurs dans plusieurs orgs, et anciens noms de rôles comme owner vs admin. Corrigez ces cas avec une couche de mapping, pas avec des modifications ad hoc de la base.

Concevez vos changements de schéma et d'API pour la compatibilité arrière

La compatibilité arrière est ce qui garde le cutover calme. Commencez par vous mettre d'accord sur ce qui ne doit pas changer parce que l'ancienne appli en dépend encore.

Traitez la base de données comme un contrat : noms de tables, colonnes clés, clés primaires, et le sens des valeurs existantes. Si l'ancien code attend users.id comme UUID et users.email comme unique, conservez cela stable pendant la transition.

Séparez ensuite les changements sûrs des changements risqués.

Les changements en ajout seulement sont généralement sûrs : nouvelles colonnes nullables, nouvelles tables, nouveaux index.

Les changements cassants (renommer des colonnes, changer les types, resserrer des contraintes) doivent attendre que la nouvelle appli serve tout le trafic.

Un schéma pratique : expand first, switch second, contract last. Exemple : ajoutez users.timezone en nullable, déployez la nouvelle appli pour qu'elle l'écrive, backfill les lignes anciennes, puis envisagez de le rendre NOT NULL.

Checklist pratique de compatibilité

Avant d'appliquer une migration, assurez-vous :

  • Les nouvelles colonnes commencent comme nullable ou avec une valeur par défaut.
  • Les nouveaux enums acceptent les anciennes valeurs (ou vous les mappez en sécurité).
  • Les contraintes se resserrent progressivement (valider d'abord, appliquer plus tard).
  • Les anciennes API fonctionnent toujours même si la nouvelle appli ajoute des champs.
  • Vous avez un plan pour backfiller et vérifier les lignes existantes.

Les anciennes lignes sont le piège. Si de nouvelles règles de validation rejettent des données héritées (téléphone manquant, états invalides, noms vides), ne « corrigez » pas en bloquant les connexions. Utilisez des lectures tolérantes, des scripts de migration, et des invites ciblées (demandez aux utilisateurs de compléter les champs manquants après leur connexion).

Plan de déploiement progressif étape par étape (lecture seule à trafic complet)

Deployment Ready Build
We prepare the build for production deploy and smoother releases.

Considérez le cutover comme une série de petits paris. Chaque étape doit être réversible, et chacune doit avoir un test clair prouvant que la nouvelle appli se comporte comme l'ancienne.

Étapes (de la plus sûre à la plus risquée)

Commencez par pointer la nouvelle appli sur les données de production, mais limitez ce qu'elle peut faire :

  • Exécutez la nouvelle appli en mode lecture seule. Laissez les utilisateurs parcourir, rechercher et consulter l'historique, mais bloquez les actions qui écrivent.
  • Ajoutez du shadow traffic pour quelques endpoints clés. L'ancienne appli sert les réponses, tandis que la nouvelle exécute en arrière-plan les mêmes requêtes et vous comparez les sorties.
  • Activez un petit ensemble d'actions d'écriture pour un groupe réduit via des feature flags (utilisateurs internes, puis un petit pourcentage).
  • Augmentez le trafic graduellement (10 %, 25 %, 50 %, puis 100 %), avec des paliers de monitoring à chaque étape.

Entre les étapes, faites une pause et examinez ce que vous avez appris. Si quelque chose cloche, arrêtez la montée en charge et corrigez avant d'augmenter le risque.

Critères pour avancer

Écrivez des checks « go/no-go » à l'avance pour que les décisions ne se prennent pas sous pression :

  • Le taux d'erreur et la latence restent dans un petit écart par rapport à l'ancienne appli.
  • Les réponses shadow correspondent sur les champs clés (permissions, totaux, prix, statuts).
  • Aucune écriture inattendue ne se produit en mode lecture seule (confirmez via les logs DB).
  • Les tickets de support et les plaintes utilisateurs ne montent pas après chaque palier.
  • Un runbook de rollback est testé et peut restaurer l'ancienne appli en quelques minutes.

Planifiez les écritures durant la transition (éviter les forks de données)

La manière la plus rapide de casser un cutover est de laisser les deux versions écrire sur les mêmes enregistrements de façons différentes. Vous devez avoir une règle claire : à chaque étape, qui peut écrire quoi.

Choisissez une source de vérité pour les écritures. Souvent, l'ancienne appli continue d'écrire pendant que la nouvelle fonctionne en lecture seule. Puis vous inversez : la nouvelle devient écrivaine et l'ancienne devient lecture seule ou voit ses endpoints d'écriture bloqués. Cela évite un « split brain » silencieux.

Les écritures doubles (dual writes) semblent sûres, mais elles créent souvent des forks que vous ne remarquez que des jours plus tard, comme des statuts d'abonnement incohérents ou des factures dupliquées. N'effectuez des écritures doubles que si vous pouvez prouver que c'est sans risque.

Si vous devez tolérer des écritures doubles pour une courte fenêtre, rendez les conflits prévisibles :

  • Rendre chaque écriture idempotente en utilisant un request ID stable.
  • Définir les règles de conflit à l'avance (last-write-wins pour les champs profil, mais jamais pour les paiements).
  • Ajouter une petite table de log d'écriture (request ID, user ID, timestamp, entité principale touchée).
  • Rejeter les champs inconnus ou les mappings « au mieux ».
  • Mettre des feature flags stricts autour des nouveaux chemins d'écriture pour pouvoir les couper rapidement.

Une approche pratique : pendant la migration des inscriptions, laissez la nouvelle appli créer des comptes, mais routez les réinitialisations de mot de passe et les changements de facturation via l'ancienne appli jusqu'à ce que vous ayez vérifié chaque chemin d'écriture.

Monitoring et validation des données pendant le cutover

Le cutover n'est pas juste un déploiement. C'est une expérience en direct, surtout quand vous déplacez le trafic par paliers.

Commencez par un ensemble restreint de signaux qui indiquent si les utilisateurs peuvent toujours se connecter, naviguer et enregistrer des modifications :

  • Taux de succès des connexions et des réinitialisations de mot de passe
  • Taux d'erreur par endpoint (5xx, timeouts, erreurs d'auth)
  • Échecs d'écriture et retries (créations, mises à jour, paiements, invitations)
  • Latence au p95/p99
  • Santé des queues et des jobs en arrière-plan (emails, webhooks, synchronisations de facturation)

Les chiffres ne suffisent pas. Validez aussi les données elles-mêmes à chaque palier de trafic (5 % puis 25 % puis 100 %) : comparez les comptes de lignes et les totaux pour les entités touchées, vérifiez la cohérence des activités récentes (clés étrangères, horodatages, statuts), et contrôlez manuellement les dernières écritures pour détecter des anomalies évidentes.

Ajoutez les signaux utilisateurs. Un pic de tickets support, une chute après connexion, ou des captures d'écran répétées « quelque chose s'est mal passé » montrent souvent les problèmes avant les dashboards.

Définissez des seuils de décision avant de commencer. Exemple : si la réussite des connexions baisse de 2 % pendant 10 minutes, ou si les échecs d'écriture dépassent 0,5 %, mettez en pause le déploiement et investiguez. Si la cause n'est pas évidente rapidement, rollbackez.

Plan de rollback exécutable en quelques minutes

Rollback Plan You Can Run
We help you write and test a rollback that protects accounts.

Le rollback n'est pas un échec. C'est la soupape de sécurité qui vous permet de protéger les comptes et l'historique utilisateur.

Définir des déclencheurs clairs de rollback

Choisissez un petit ensemble d'alarmes qui forcent l'action, pas le débat :

  • Échecs de connexion ou d'inscription au-dessus d'un seuil (par ex. 2 % pendant 5 minutes)
  • Écritures suspectes (champs requis manquants, nulls inattendus, enregistrements dupliqués)
  • Régression de performance majeure (timeouts, CPU DB saturé, backlog de queues)
  • Signaux de sécurité (contournement d'auth, vérifications de permission non exécutées)

Quand un déclencheur sonne, une personne doit avoir l'autorité pour l'appeler. Tout le monde exécute ensuite.

Les étapes de rollback en « minutes, pas heures »

Rédigez cela comme une checklist d'urgence et répétez-la une fois :

  • Rediriger le trafic vers l'ancienne appli (load balancer, feature flag, ou toggle de déploiement).
  • Geler les nouvelles écritures dans la nouvelle appli (retourner un message de maintenance clair).
  • Préserver les preuves : logs de requêtes, traces d'erreur, et un snapshot des tables affectées.
  • Drain ou pause des jobs en arrière-plan pour qu'ils n'écrivent pas davantage de données erronées.
  • Vérifier : une personne contrôle les connexions et workflows clés, une autre inspecte la santé des données.

Pour les écritures partielles, gardez une règle de récupération simple. Soit marquez les nouvelles écritures par source (old vs new) pour pouvoir les isoler, soit mettez les écritures en file et rejouez uniquement après validation.

Erreurs et pièges fréquents (et comment les éviter)

La plupart des cutovers échouent pour des raisons banales : un petit décalage qui n'apparaît qu'avec de vrais utilisateurs et un vrai historique. Considérez la compatibilité comme une fonctionnalité produit, pas comme une tâche de dernière minute.

Une erreur classique est de casser l'identité utilisateur. Si vous changez les clés primaires, renumérotez les utilisateurs, ou changez le format des UUID en cours de route, vous pouvez déconnecter silencieusement les comptes des abonnements, permissions et historiques. Conservez les mêmes user IDs de bout en bout, ou ajoutez une couche de mapping stable et testez-la sur un snapshot complet de production.

Les mots de passe sont un autre piège fréquent. Des équipes « migrent » l'auth et réinitialisent accidentellement tout le monde parce que le nouveau service ne peut pas vérifier l'ancien schéma de hachage (ou oublie le salt/pepper par utilisateur). Conservez l'ancienne vérification, re-hachez au login réussi, et ne loggez jamais ni n'exposez de secrets pendant le débogage.

Les données de production vous surprendront. Les données de test n'incluent pas souvent les utilisateurs supprimés, les emails dupliqués d'anciens imports, les particularités de fuseau horaire, les enregistrements partiels, ou des flags hérités cachés par l'UI depuis des années. Planifiez des tests autour des cas limites, pas seulement des parcours heureux.

Cinq contrôles évitent la plupart des incidents :

  • Geler le format des user IDs et des clés primaires pendant le cutover.
  • Confirmer que le hachage des mots de passe et les règles de session/token correspondent à l'ancien comportement.
  • Répéter avec un snapshot proche de la production et des scripts de migration réels.
  • Inventorier les writers en arrière-plan (jobs, webhooks, cron) et les verrouiller pendant le rollout.
  • Différer les changements de schéma cassants jusqu'à ce que la nouvelle appli gère 100 % du trafic en lecture et écriture.

Liste de contrôle rapide avant, pendant et après le cutover

Protect History and Totals
We check invoices, timestamps, and audit trails so users don't see empty pages.

Traitez le cutover comme une répétition, pas comme un simple interrupteur.

Avant le cutover (répétez comme si c'était réel)

Vérifiez les backups en les restaurant dans un environnement de test et en ouvrant l'appli contre la copie restaurée. Répétez les migrations de bout en bout (appliquer, vérifier, rollback) en utilisant un volume proche de la production. Confirmez que le monitoring et les alertes couvrent erreurs, latence et verrous/queries lentes en base. Exécutez les flux d'auth (login, signup, réinitialisation, refresh de session, accès basé sur rôles) pour quelques rôles réels. Échantillonnez les tables clés (users, subscriptions/commandes, audit/historique) et cherchez des nulls inattendus, des index manquants, et des enregistrements récents incohérents.

Faites une répétition chronométrée avec un petit groupe interne. Si quelque chose n'est pas clair, transformez-le en étape de runbook.

Pendant et après le cutover (faire confiance, mais vérifier)

Commencez avec un pourcentage minime et augmentez par paliers. Confirmez que l'interrupteur de rollback fonctionne sans déploiement de code (pratiquez avant le jour J). Validez les écritures pour les flux qui comptent le plus (profils, paiements, permissions). Vérifiez que le travail en arrière-plan (queues, cron jobs, emails, webhooks) ne s'exécute qu'une fois et pas deux. Préparez le support avec une note de statut courte, une liste de problèmes connus, et un moyen rapide de retrouver les utilisateurs affectés.

Scénario d'exemple : reconstruire une appli SaaS en conservant tout l'historique

Une petite équipe SaaS décide de reconstruire son web app parce que l'actuelle est lente et fragile, mais elle ne peut rien perdre dans la base : comptes utilisateurs, projets, factures, et statut d'abonnement. L'objectif est de reconstruire sans changer la base, puis de basculer le trafic en sécurité.

D'abord, ils livrent la nouvelle appli en mode lecture seule. Les utilisateurs continuent d'éditer via l'ancienne appli, mais la nouvelle peut se connecter, charger les projets, afficher les factures passées, et montrer le plan actuel. En interne, l'équipe compare les comptes et totaux (projets par utilisateur, montant de la dernière facture, date du prochain renouvellement) entre les écrans anciens et nouveaux. Les clients ne voient pas de changement, mais l'équipe trouve rapidement où les hypothèses diffèrent.

Ensuite, ils déploient pour une petite cohorte : 5 % d'utilisateurs à faible risque de support et mix de plans. Ils surveillent le succès des connexions, le temps de chargement des projets, les totaux de factures correspondant à l'ancienne appli, et les nouveaux tickets support mentionnant des données manquantes.

Le deuxième jour, ils repèrent un écart de facturation pour les plans annuels. La nouvelle appli affiche “payé” correctement, mais écrit une mauvaise next_billing_date quand un utilisateur met à jour le profil de sa société. C'est un moment de rollback. Ils basculent le trafic vers l'ancienne appli, désactivent les écritures dans la nouvelle, et rejouent le petit ensemble de mises à jour affectées à l'aide d'un script et des logs d'audit. Personne ne perd l'historique, et la correction est retestée en lecture seule avant de rouvrir la cohorte.

Étapes suivantes et quand faire appel à FixMyMess

Traitez le plan de cutover comme un projet à part entière. Commencez par écrire ce qui ne doit pas casser : l'authentification, la facturation, les rapports clés, et toutes les intégrations qui écrivent en base.

Faites appel à de l'aide tôt si vous observez des schémas comme des problèmes intermittents de login/session à travers les environnements, un schéma qui « a grandi organiquement » sans propriétaire clair, ou des lacunes de sécurité comme des secrets exposés et des requêtes SQL suspectes.

Si vous avez hérité d'un prototype généré par IA qui échoue sous de vrais comportements de production, FixMyMess (fixmymess.ai) se concentre sur le diagnostic et la réparation de ces écarts — en particulier les problèmes d'auth, les schémas dangereux et la logique fragile — pour que votre plan de rollout et de rollback corresponde à ce que le code fait réellement. Un point de départ courant est un audit de code gratuit pour faire remonter les vrais points de défaillance avant de basculer le trafic.