Le 30 avril 2026, avant de toucher une ligne, j'ai écrit un état des lieux de 471 lignes sur un site de vente en ligne en production depuis 2019. Pas par goût de la paperasse : parce que presque tout ce qui pouvait tuer ce projet était en dehors du dépôt. Voici ce que je lis, dans quel ordre, et ce que j'ai refusé de chiffrer tant que je ne l'avais pas.
Reprendre le code de quelqu'un d'autre : ce qu'on lit avant de dire oui
1. Le journal git, avant le code
C'est gratuit, ça prend dix minutes, et c'est ce qui cadre tout le reste.
Sur ce projet : 645 commits, du 28 août 2019 au 24 avril 2026. Près de sept ans. Ce chiffre ne dit pas si le code est bon, il dit autre chose de plus utile : ce n'est pas un prototype abandonné, c'est un outil qui a servi tous les jours.
Le détail des auteurs est plus parlant que le total. 524 commits sont signés d'un
compte de développeur, 121 sont signés root@<nom-du-serveur>. Des modifications
faites directement sur des serveurs, pas depuis un poste de travail. Et les commits
signés du développeur s'arrêtent en janvier 2025, alors que ceux signés root
continuent jusqu'en avril 2026.
⚠️ Ce que ça veut dire et ce que ça ne veut pas dire. Ça ne dit pas que le code est mauvais. Ça dit qu'il faut vérifier une chose avant tout le reste : le dépôt que vous clonez est-il ce qui tourne ? Quand une partie de l'histoire a été écrite sur la machine de production, la réponse n'est plus automatique, et c'est la première chose à lever. Sur ce projet, la question s'est réglée en comparant le code au serveur ; sur d'autres, j'ai trouvé des fichiers modifiés en production et jamais recommittés.
Le dernier commit, lui, s'appelait « désactivation temporaire de la route /proposition ». Une fonctionnalité éteinte plutôt que réparée. Une seule ligne de journal ne fait pas un diagnostic, mais elle indique où regarder.
2. Ce qui n'est PAS dans le dépôt, et c'est là qu'est le risque
C'est la section que personne ne fait, et c'est celle qui rapporte. Un dépôt vous dit ce que quelqu'un a écrit. Il ne vous dit jamais ce qui tourne.
Sur ce projet, l'inventaire de ce qui vivait ailleurs a donné :
- Une tâche planifiée toutes les heures sur l'ancien serveur, qui importait des
clients depuis un logiciel tiers. Elle n'était mentionnée nulle part dans le code ni
dans la documentation. Je l'ai trouvée en lisant la crontab de
root, pas le dépôt. Oublier celle-là, c'est arrêter un flux de données le jour de la bascule et s'en apercevoir trois semaines plus tard. - Un script de sauvegarde de la base, quotidien, posé hors du projet, avec sa copie hors serveur.
- Les redirections SEO héritées d'un ancien site WordPress, implémentées dans un contrôleur PHP et pas dans la configuration Apache. L'inverse aurait été tout aussi probable, et invisible depuis le code.
- Les identifiants du prestataire de paiement, qui n'étaient pas dans un fichier d'environnement mais dans la base de données, une ligne par établissement.
- 1 037 fichiers d'images sur le disque, pour 72 lignes dans la table correspondante. Le rapport entre les deux se règle avant la migration, jamais après.
- Un abonnement à un fournisseur de polices, dont personne ne savait quel compte le portait.
⇒ La règle que j'en tire, et je l'applique depuis à toutes mes reprises : on inventorie ce qui tourne, pas ce qui est écrit. Les crontabs de tous les utilisateurs, les timers du système, les vhosts, les enregistrements DNS, la boîte mail qui expédie réellement, et les comptes qui paient quelque chose.
3. La base de données contre le code
Le code décrit un modèle. La base contient la vérité. Les deux divergent toujours un peu, et l'écart est une mesure.
Ici : 16 entités déclarées côté PHP, 23 tables en base. Sept d'entre elles sont des tables de liaison créées automatiquement, donc l'écart s'expliquait. Le fait d'avoir posé la question est ce qui compte.
Le vrai signal était ailleurs, et il a changé toute la stratégie : la table de suivi des migrations était absente de la base de production. L'historique du schéma n'y avait jamais été activé. Conséquence directe : on ne peut pas rejouer l'histoire du schéma, donc le dump de production devient la source de vérité, pas le code. C'est la décision qui a été prise le 4 mai, et elle inverse la façon dont on reconstruit : on part de la base réelle et on écrit le modèle qui la décrit, pas l'inverse.
Et les volumes, parce qu'ils gouvernent tout : 74 418 comptes, 35 627 commandes, 347 277 séances enregistrées. Une reprise qui ignore ces trois nombres est un fantasme. C'est aussi ce qui rend une bascule mesurable : on sait exactement ce qui doit se retrouver de l'autre côté.
4. Les URLs, parce que c'est ce qui rapporte
109 URLs canoniques dans le plan de site, dans deux langues, plus des redirections d'anciennes URLs vers les URLs actuelles. Des redirections de redirections, héritées d'une vie antérieure du site.
Casser ça ne se voit pas le jour de la bascule. Ça se voit trois mois plus tard, sur une courbe de trafic, quand plus personne ne fait le lien. C'est le risque le plus cher d'une reprise et le plus facile à éliminer : la liste des URLs est devenue un fichier de 110 lignes et un script qui les interroge toutes, exécuté contre le nouveau site avant la bascule, puis contre le domaine réel le jour même.
5. Ce qui se garde, ce qui se jette, et le critère qui tranche
La conclusion de cet état des lieux a été de reconstruire la couche de présentation plutôt que de la faire monter de version. Mais « reconstruire » est un mot qui cache ce qui s'est réellement passé, et le détail est plus intéressant que le mot.
Ce qui a été gardé, chaque fois contre une alternative écartée par écrit :
- Les données. Près de sept ans de commandes, de comptes et de cartes cadeaux, reprises telles quelles, y compris les noms de tables historiques plutôt que de les renommer pour faire propre.
- Les 109 URLs, à l'identique.
- Le prestataire de paiement. Passer à un acteur plus moderne était tentant et a été écarté : il n'y avait aucune raison de changer un encaissement qui fonctionne et une relation bancaire établie. C'est un arbitrage commercial, pas technique.
- La palette et le logo. La marque est reconnaissable par ses couleurs. La refonte visuelle s'est faite autour d'elles, pas contre elles.
Ce qui a été jeté : le framework en fin de vie, la chaîne d'assets, la couche jQuery, et les formulaires construits à la main dans les contrôleurs.
⇒ Le critère, en une phrase : on garde ce qui porte une valeur qui n'est pas dans le code (les données, les URLs, la marque, un contrat qui marche), et on jette ce qui ne porte que la façon dont c'était écrit. Dit comme ça c'est évident ; ce qui ne l'est pas, c'est que la liste se fait avant le devis, ligne par ligne, et qu'elle est le devis.
6. Ce qu'un état des lieux ne vous dira jamais
C'est la partie honnête, et c'est celle qui a le plus de valeur pour vous.
À la fin de ces 471 lignes, huit éléments étaient nécessaires pour aller plus loin, et quatre ne se trouvaient nulle part dans le code : les identifiants de production du prestataire de paiement, le compte qui portait l'abonnement aux polices, le logo en version vectorielle, et surtout la réponse à cette question : y a-t-il des intégrations externes silencieuses ? Le HTML de production portait une balise de vérification Facebook sans une ligne de code derrière. Un outil de mesure, un formulaire relié à un CRM, un pixel publicitaire : ces choses-là ne laissent aucune trace dans un dépôt, et leur disparition se paie chez le client, pas chez le prestataire.
Un chiffrage donné avant ces réponses est une devinette. C'est le seul moment d'une reprise où « je ne sais pas encore » est la phrase la plus utile qu'on puisse vous dire, et vous devriez vous méfier de ceux qui ne la prononcent jamais.
7. Une reprise n'est pas finie quand le code marche
Dernier point, et il vaut pour toute reprise : le jour de la bascule est un jour à risque, et ce risque se prépare.
Ici, l'environnement de production complet a été monté sur un domaine parallèle et la bascule a été répétée en entier avant d'être faite pour de vrai : mise en service, import des données, certificats, vérification de parité. Une procédure de retour arrière a été écrite avant la bascule, pas pendant. La bascule réelle a eu lieu le 1er juillet 2026 à 00h02, et le script de parité a été rejoué contre le domaine réel dans la foulée.
⚠️ Et il faut dire ce qui manquait, parce qu'un article qui ne dit que ce qui a bien marché n'apprend rien : ce projet n'avait aucun test automatisé, ni avant ni après. Le dossier de tests contenait un unique fichier d'amorçage. Ce qui a servi de filet, c'est le script de parité sur 110 URLs et la répétition générale. C'est moins bien qu'une suite de tests, c'est bien mieux que rien, et surtout c'est ce qu'on peut construire en deux heures sur un code qu'on vient de recevoir. Quand on reprend un projet, on n'a pas de tests : on a besoin d'un moyen de savoir qu'on n'a rien cassé, et il faut le fabriquer le premier jour.
Tout ce qui précède est un état des lieux, et il se facture à part : il n'engage à rien pour la suite, et il arrive qu'il conclue qu'il ne faut surtout rien refaire. C'est précisément ce qui le rend utile. Si vous avez un projet à l'arrêt, un développeur parti ou une agence qui ne répond plus, c'est par là que commence une reprise de projet web existant : on regarde pour de bon, puis on décide.
Dites-moi dans quel état est votre projet
Décrivez la situation en quelques lignes : ce que fait l'application, depuis quand elle est à l'arrêt, et ce à quoi vous avez encore accès. Je réponds sous 24 h, avec un avis franc, y compris quand la réponse est qu'il ne faut pas reprendre.