5 Commits

Author SHA1 Message Date
Thomas Fransolet
149ebc0cf1 Dry run de la bascule, et les 20 sections qui disparaissaient en silence
Le dry run est automatisé en test (MigrationDryRunTests) : il appelle le
contrôleur directement, ce qui évite la chaîne login + JWT SuperAdmin, et se
saute si aucun Mongo n'écoute sur MIGRATION_TEST_MONGO — la suite reste donc
verte sans dépendance. Les tailles de fichier sont court-circuitées : un HEAD
sur 2374 ressources prendrait des minutes pour une information que ce test ne
vérifie pas.

Il a trouvé du premier coup ce qu'aucune lecture de code n'avait vu : 327
sections dans Mongo, 307 migrées, et Erreurs : 0.

Les 20 manquantes référencent deux configurations supprimées dans Mongo — 19
articles et un slider, du contenu MDLF. La migration a raison de ne pas les
reprendre : les sections sont collectées configuration par configuration,
donc les orphelines ne sont jamais énumérées, et la FK ConfigurationId les
refuserait. Le défaut était le silence — elles partent désormais dans
Skipped, avec le détail de la configuration introuvable.

L'invariant affirmé par le test n'est donc pas « tout est migré » mais
« rien ne disparaît sans être signalé » : migrées + signalées = Mongo.

dotnet test 144/144.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:40:11 +02:00
Thomas Fransolet
934d71c2ee Lot G : les 8 écarts de MigrationController
Trois n'existaient pas — vérifié dans l'export Mongo plutôt que dans la doc :
- (a) « BuildSection ne couvre que 11 types sur 13 » : les 327 sections de
  l'export ne contiennent que les types 0 à 10. SectionEvent et
  SectionParcours sont nés avec Postgres v3, le default est un filet.
- (f) IsQRCode/IsSearchText/IsSearchNumber n'existent pas dans Mongo, false
  est le bon défaut. Contrôle inverse fait : les cinq réglages qui existent
  vraiment sont bien mappés sur AppConfigurationLink.
- (g) était tombé avec le rename du lot B.

Les cinq réels :
- (b) QuizQuestions = new() jetait les questions. Mesuré : 5 sections quiz
  en portent 41, réponses comprises. Migrées en MultipleChoice, le type de
  validation n'existant pas dans l'ancien modèle. EventAgendas et l'absence
  de GuidedPath sont corrects : Mongo n'a ni événement ni parcours.
- (c) la source ne contient que 4 champs, il n'y avait rien à mapper de
  plus. PublicApiKey générée (même schéma que l'onboarding), WebSlug via
  SlugHelper, drapeaux de plateforme dérivés des configurations, plan
  affecté par nom avec repli sur Pro, IsAssistant allumé seulement si le
  plan donne des jetons.
- (d) Mongo n'a pas de champ Role : le ContentEditor en dur dégradait les
  10 utilisateurs en silence, plus personne n'aurait pu gérer les
  utilisateurs de son instance. Passé à InstanceAdmin.
- (e) StoragePath n'était pas écrit du tout. Passe par ResourceStorage, le
  calculateur commun à la création et au backfill. L'échec du HEAD, jusqu'ici
  avalé, remonte dans le rapport.
- (h) transaction unique sur les neuf étapes, et 500 au lieu de 200 OK sur
  échec fatal — un script de bascule testant le code HTTP concluait au
  succès alors que l'erreur n'était que dans le corps.

ApplyPlanQuotas est dupliqué depuis InstanceController plutôt qu'appelé : la
migration ne doit pas casser si ce contrôleur change de forme.

dotnet build vert, dotnet test 143/143. Reste le dry run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:26:01 +02:00
Thomas Fransolet
7625487806 Lot B : geler le schéma, plus sécurité rapide et calculateur de stockage
LOT B — une seule migration EF (LotB_FreezeSchema) :
- SectionMap.MapResourceId → IconResourceId. L'écart (g) de la bascule tombe
  avec. Il fallait renommer aussi la propriété de navigation MapResource :
  la convention EF l'appariait au FK, la laisser aurait fabriqué un FK
  fantôme. Elle n'était utilisée nulle part ailleurs.
- SectionEvent.ParcoursIds supprimé (champ, DTO, SectionFactory, et une
  initialisation dans un montage de test).
- Instance.IsImageWatermark remplace le `instanceId == "633ee379…"` en dur
  de ResourceController.

EF a généré un RenameColumn, pas un drop+add : les icônes déjà configurées
survivent. L'avertissement de perte de données ne porte que sur le DropColumn
de ParcoursIds, ce qui est l'intention.

Non fait, et c'était une erreur de doc : « supprimer SectionEvent.IconResourceId ».
Ce champ n'existe pas — la ligne visée appartient à la classe imbriquée
MapAnnotation, partagée par SectionEvent, SectionAgenda et SectionMap, lue par
cinq contrôleurs et par GetReferencedResourceIds. La supprimer aurait cassé
les icônes d'annotation des trois types et la collecte offline.

SÉCURITÉ (lot A, même repo) :
- AuthenticationController.Authenticate : un bloc #if DEBUG écrasait l'email
  et le mot de passe reçus par un compte de test, donc toute compilation en
  Debug authentifiait n'importe quelle saisie. Retiré.
- EnableSensitiveDataLogging (qui écrit les valeurs des paramètres dans les
  logs) passe sous #if DEBUG, l'idiome déjà employé dans Startup.cs pour le
  CORS et Hangfire. Le Dockerfile publiant en -c Release, c'est un verrou réel.

LOT C1 :
- Calculateur StoragePath/SizeBytes extrait dans Helpers/ResourceStorage.cs,
  avec 13 tests fixant l'invariant des types URL. Il ferme le lien L5 : le
  backfill (C2) et l'écart (e) de la migration appelleront le même code.
- L'extraction a révélé la divergence qu'elle devait empêcher : des deux
  chemins de création de ResourceController, le chemin multipart écrivait
  SizeBytes mais laissait StoragePath nul.

dotnet build Debug et Release verts, dotnet test 143/143 (130 + 13).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 15:32:19 +02:00
Thomas Fransolet
e0ff0eeba6 Quota update in controller, audit log (serilog) + ai translator + Unit tests ! (to be tested) + migration update 2026-04-10 16:28:33 +02:00
Thomas Fransolet
eff4f7ba5c Add seed subscriptionplan + wip migration controller 2026-04-01 17:26:27 +02:00