From 73955b43ab782a5830d4f49e98b76e83513d0c51 Mon Sep 17 00:00:00 2001 From: Ronan Lenouvel Date: Fri, 2 Oct 2026 12:14:25 +0200 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9C=85=20test(SchemaInSync):=20le=20sch?= =?UTF-8?q?=C3=A9ma=20des=20migrations=20doit=20=C3=A9galer=20celui=20des?= =?UTF-8?q?=20entit=C3=A9s,=20d=C3=A9fauts=20des=20*=5Fcount=20align=C3=A9?= =?UTF-8?q?s=20(#571)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Entity/TakeoutImport.php | 4 +-- tests/Integration/SchemaInSyncTest.php | 48 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 tests/Integration/SchemaInSyncTest.php diff --git a/src/Entity/TakeoutImport.php b/src/Entity/TakeoutImport.php index 6597de30..cab0c6b6 100644 --- a/src/Entity/TakeoutImport.php +++ b/src/Entity/TakeoutImport.php @@ -74,7 +74,7 @@ class TakeoutImport * (contrairement aux compteurs finaux qui restent null tant que * l'import n'est pas terminé). */ - #[ORM\Column] + #[ORM\Column(options: ['default' => 0])] private int $processedCount = 0; /** @@ -89,7 +89,7 @@ class TakeoutImport * Progress bar pendant l'extraction (#515) : nombre de ZIP déjà extraits * — incrémenté au fil du Handler, même pattern que processedCount. */ - #[ORM\Column] + #[ORM\Column(options: ['default' => 0])] private int $extractedZipCount = 0; #[ORM\Column] diff --git a/tests/Integration/SchemaInSyncTest.php b/tests/Integration/SchemaInSyncTest.php new file mode 100644 index 00000000..98f8a81c --- /dev/null +++ b/tests/Integration/SchemaInSyncTest.php @@ -0,0 +1,48 @@ +get(EntityManagerInterface::class); + + $statements = (new SchemaTool($em))->getUpdateSchemaSql($em->getMetadataFactory()->getAllMetadata()); + // La table de suivi des migrations n'appartient à aucune entité : la + // commande doctrine:schema:update l'ignore, SchemaTool non. + $statements = array_values(array_filter( + $statements, + static fn (string $sql): bool => !str_contains($sql, 'doctrine_migration_versions'), + )); + + $this->assertSame( + [], + $statements, + "Le schéma issu des migrations diverge des entités. Ajouter la migration manquante (ou corriger le mapping) :\n" . implode("\n", $statements), + ); + } +} From 8d47be45c221196288d1b79ff29a958ed15cc3a8 Mon Sep 17 00:00:00 2001 From: Ronan Lenouvel Date: Fri, 2 Oct 2026 12:14:25 +0200 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=93=9D=20docs(migrations):=20commenta?= =?UTF-8?q?ires=20de=20d=C3=A9rive=20obsol=C3=A8tes=20et=20consigne=20make?= =?UTF-8?q?:migration=20(#571)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/architecture.md | 2 +- migrations/Version20260926172610.php | 8 ++++---- migrations/Version20260926183234.php | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.claude/architecture.md b/.claude/architecture.md index d072d221..b1fc8e9b 100644 --- a/.claude/architecture.md +++ b/.claude/architecture.md @@ -46,7 +46,7 @@ public function __construct(...) | Fichier | Méthode | |--------------------------------|--------------------------------------------------------------------| -| Migration | `make:migration` **obligatoire** (diff schema/entités automatique) | +| Migration | `make:migration` **obligatoire** (diff schema/entités automatique) — **relire et ne garder que l'évolution voulue** (DROP parasites possibles venant de la base de dev, cf. #571) ; `SchemaInSyncTest` échoue si une entité diverge des migrations | | Entité/Controller/Service/Test | Claude génère directement (maker interactif incompatible) | ## Pipeline média diff --git a/migrations/Version20260926172610.php b/migrations/Version20260926172610.php index df01d728..6e2d1789 100644 --- a/migrations/Version20260926172610.php +++ b/migrations/Version20260926172610.php @@ -19,10 +19,10 @@ public function getDescription(): string public function up(Schema $schema): void { - // Note : make:migration détecte aussi un drift préexistant sans - // rapport avec ce ticket (broadcast_messages / last_broadcast_seen_at, - // entité déjà retirée du code mais jamais migrée en base) — non repris - // ici volontairement, à traiter séparément. + // Note : make:migration détectait aussi des DROP sans rapport avec ce + // ticket (broadcast_messages / last_broadcast_seen_at). Audit #571 : ils + // viennent uniquement de la base de dev locale — aucune migration ni + // entité ne les a jamais créés, et ils n'existent pas en prod. Non repris. $this->addSql('CREATE TABLE content_fingerprints (id BINARY(16) NOT NULL, content_hash VARCHAR(64) NOT NULL, first_seen_at DATETIME NOT NULL, owner_id BINARY(16) NOT NULL, INDEX IDX_8973604F7E3C61F9 (owner_id), INDEX idx_content_fingerprints_hash (content_hash), UNIQUE INDEX uniq_owner_content_hash (owner_id, content_hash), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4'); $this->addSql('ALTER TABLE content_fingerprints ADD CONSTRAINT FK_8973604F7E3C61F9 FOREIGN KEY (owner_id) REFERENCES users (id)'); } diff --git a/migrations/Version20260926183234.php b/migrations/Version20260926183234.php index 117f839c..18f846ea 100644 --- a/migrations/Version20260926183234.php +++ b/migrations/Version20260926183234.php @@ -19,10 +19,10 @@ public function getDescription(): string public function up(Schema $schema): void { - // Note : make:migration détecte ici aussi content_fingerprints (déjà - // migré sur main via #449) et le même drift preexistant sans rapport - // (broadcast_messages / last_broadcast_seen_at) — non repris, cf. - // Version20260926172610. + // Note : make:migration détectait ici aussi content_fingerprints (déjà + // migré sur main via #449) et des DROP sans rapport (broadcast_messages / + // last_broadcast_seen_at) venant de la base de dev locale, jamais créés + // par aucune migration ni en prod — non repris, cf. #571. $this->addSql('CREATE TABLE takeout_imports (id BINARY(16) NOT NULL, status VARCHAR(16) NOT NULL, media_imported_count INT DEFAULT NULL, duplicates_skipped_count INT DEFAULT NULL, unrecognized_files_count INT DEFAULT NULL, created_at DATETIME NOT NULL, completed_at DATETIME DEFAULT NULL, error_message LONGTEXT DEFAULT NULL, owner_id BINARY(16) NOT NULL, INDEX IDX_416C1617E3C61F9 (owner_id), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4'); $this->addSql('ALTER TABLE takeout_imports ADD CONSTRAINT FK_416C1617E3C61F9 FOREIGN KEY (owner_id) REFERENCES users (id)'); } From 16024a27375726198f43c7197ac25b67bd2e1961 Mon Sep 17 00:00:00 2001 From: Ronan Lenouvel Date: Fri, 2 Oct 2026 12:14:34 +0200 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=93=9D=20docs(avancement):=20suivi=20?= =?UTF-8?q?#571=20d=C3=A9rive=20sch=C3=A9ma/migrations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/avancement.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/avancement.md b/.github/avancement.md index 212e99ac..221729f0 100644 --- a/.github/avancement.md +++ b/.github/avancement.md @@ -6,6 +6,16 @@ --- +## 🚧 Dérive schéma/migrations (2026-10-02, #571, branche `chore/571-schema-drift`) + +- Audit : base vierge construite depuis les 25 migrations = **un seul écart** avec les entités (défauts `0` de `takeout_imports.processed_count` / `extracted_zip_count`, cosmétique). Les `DROP broadcast_messages` / `DROP users.last_broadcast_seen_at` venaient uniquement de la base de dev locale (jamais créés par aucune migration ni entité, absents de la prod ronan). +- `options: ['default' => 0]` sur les deux propriétés : l'entité s'aligne sur la base, **aucune migration** (rien à exécuter sur les instances). +- `SchemaInSyncTest` : échoue si le schéma issu des migrations diverge des entités (vérifié par mutation : rouge avec un champ non migré). La CI construit sa base de test par `migrations:migrate`, donc le test y est fiable. +- Base de dev nettoyée (table et colonne orphelines, vides) ; commentaires obsolètes « non repris, à traiter séparément » mis à jour dans deux migrations ; consigne `make:migration` ajoutée à `.claude/architecture.md`. +- Reste : revue, `gh pr create` (label + `Closes #571` + assignee + board), CI verte, merge ; relancer l'audit `schema:update --dump-sql` sur les 6 autres instances une fois réparées (#569). + +--- + ## ✅ Déploiement : composer en CLI, vérification de vendor/, rollback (2026-10-02, #570, PR #602 mergée) - Cause de l'incident #569 (6 instances en 500) : composer lancé en PHP CGI par le cron affichait son aide et sortait en 0 ; code déjà mis à jour par `git checkout`, `vendor/` ancien, aucun rollback. From ba9c138d7095ef8de7404953d8f88e0068290eab Mon Sep 17 00:00:00 2001 From: Ronan Lenouvel Date: Fri, 2 Oct 2026 12:17:07 +0200 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=93=9D=20docs(avancement):=20cl=C3=B4?= =?UTF-8?q?t=20l'entr=C3=A9e=20#528=20(PR=20#603=20merg=C3=A9e)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/avancement.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/avancement.md b/.github/avancement.md index 221729f0..8eefce5b 100644 --- a/.github/avancement.md +++ b/.github/avancement.md @@ -28,7 +28,7 @@ --- -## 🚧 Admin : charge serveur et imports Takeout différés (2026-10-02, #528, branche `feat/528-admin-charge-takeout`) +## ✅ Admin : charge serveur et imports Takeout différés (2026-10-02, #528, PR #603 mergée) - `ServerLoadChecker` expose `getLoadAverage()`, `getThreshold()` et `isCalm(?array)` (décision sur une mesure déjà prise : la commande mesure une fois, l'issue loguée reste cohérente avec la charge loguée). - Nouvelle table `takeout_dispatch_log` (entité `TakeoutDispatchLog`) : `app:takeout:nightly-dispatch` y écrit une ligne par cycle de 15 min (`dispatched` / `deferred` / `idle`, load 1/5/15, seuil, nb en attente / dispatchés), puis purge au-delà de 30 jours (un seul `DELETE` indexé, pas de nouveau cron). Les cycles `idle` sont tracés exprès : ils servent d'échantillonnage de charge pour #547. Écriture et purge n'interrompent jamais le dispatch (erreur journalisée seulement). @@ -36,7 +36,7 @@ - Page `/admin/takeout-load` (whitelist AdminVoter, lien « Charge Takeout » dans le layout admin) : load courant vs seuil, imports `scheduled` (propriétaire, depuis quand), historique des 50 derniers cycles et part de cycles calmes sur 24 h. Dates affichées en `Europe/Paris`. - Migrations : deux, additives (CREATE TABLE + ADD COLUMN nullable). `make:migration` avait généré de la dérive de la base de dev locale (DROP `broadcast_messages`, DROP `users.last_broadcast_seen_at`, CHANGE sur `takeout_imports`) : retirée à la main, à garder en tête pour les prochaines migrations. - Suite complète : 1410/1410 verts. -- Reste : revue, `gh pr create` (label + `Closes #528` + assignee + board), CI verte, merge ; l'échantillonnage ne démarre qu'au déploiement. +- PR #603 mergée, CI verte. L'échantillonnage de charge ne démarre qu'au déploiement (déploiement exceptionnel prévu, cf. #569). ---