5.5 KiB
1quinquies. La bascule elle-même — Mongo → Postgres en prod (ajouté le 2026-08-09)
← Section §1quinquies du tableau de bord : STATUS.md
Trou identifié le 2026-08-09 : le §1ter dit ce qui doit entrer dans le schéma avant que la base se remplisse. Il ne dit nulle part comment on remplit la base. L'opération de bascule n'était écrite ni ici, ni dans le kanban, ni dans aucun plan de
v2/.Rappel : la prod tourne encore sur MongoDB. Le transfert se fait par
MigrationController(POST /api/migration/run, paramètresdryRunetinstanceId), qui rejoue Instances → Resources → Users → Configurations → ApplicationInstances → Sections → Devices, puis relie les menus et enrichit les ressources PDF.
⚠️ MigrationController a pris du retard sur le modèle
Écrit avant l'essentiel des chantiers de 2026 (SectionEvent, SectionParcours, abonnements, onboarding, guide IA, colonnes médias). Relevé le 2026-08-09 sur ManagerService/Controllers/MigrationController.cs :
| # | Écart | Où | Conséquence si on bascule tel quel |
|---|---|---|---|
| a | BuildSection ne couvre que 11 types (Map, Slider, Video, Web, Menu, Quiz, Article, PDF, Game, Agenda, Weather) |
:458-613 |
SectionEvent et SectionParcours tombent dans le default → ligne d'erreur dans le rapport, section non migrée, silencieusement |
| b | Les collections filles ne sont jamais remplies : QuizQuestions = new(), EventAgendas = new(), aucun GuidedPath/GuidedStep |
:526, :591 |
Un quiz arrive sans ses questions, un agenda sans ses événements |
| c | Instance : 4 champs migrés sur ~35 |
:106-112 |
SubscriptionPlanId null → instance sans plan (quotas à 0, HasStats false) ; PublicApiKey null → les apps visiteur ne s'authentifient plus (X-Api-Key) ; WebSlug null → visitapp-web injoignable ; IsMobile/IsTablet/IsWeb/IsAssistant à false |
| d | Role = UserRole.ContentEditor en dur |
:225 |
Plus aucun administrateur après la bascule |
| e | Resource : StoragePath, FileName, IncludeInAiKnowledge, AiIndexStatus non renseignés ; SizeBytes déduit d'un HEAD sur l'URL Firebase, échec avalé → 0 |
:172-181 |
C'est le point 5 du §1ter (backfill) : à faire dans la migration, pas après |
| f | IsQRCode / IsSearchText / IsSearchNumber forcés à false |
:276-278 |
Réglages de configuration perdus |
| g | MapResourceId = dto?.iconResourceId |
:469 |
À répercuter le jour où la colonne est renommée en IconResourceId (§6bis) |
| h | Pas de transaction globale : 9 étapes, un SaveChangesAsync chacune, catch qui renvoie 200 OK avec FatalError dans le corps |
:68-86 |
Un échec au milieu laisse la base à moitié remplie. La reprise ne tient qu'aux tests AnyAsync d'idempotence — qui existent, eux, et sont corrects |
Le point c est le plus dangereux : il ne produit aucune erreur. La migration se déclare réussie et le lieu est inaccessible aux visiteurs.
La bascule, dans l'ordre
Numérotation continue avec le §1ter (1-13).
| # | Quoi | Note |
|---|---|---|
| 14 | Remettre MigrationController à niveau — les 8 écarts a→h ci-dessus |
Le plus gros morceau. À faire avant tout le reste |
| 15 | Dry run sur un export Mongo de prod, puis comparer les comptages par entité aux comptages Mongo | dryRun=true n'écrit rien. Un export existe déjà dans manager-service/migration-data/ |
| 16 | Créer l'environnement prod Postgres : Deployment/Dockerfile.postgres (épinglé par digest), compose prod, Traefik, port 5432 fermé |
Dépend de la rotation des secrets (§3) — ne pas créer la prod avec les clés committées |
| 17 | dotnet ef database update sur la base vide, puis vérifier postgis et vector présents |
Le §1quater rappelle qu'une base en retard d'une migration fait planter l'API dès le login |
| 18 | pg_dump avant et après, puis cron quotidien |
Déjà noté en §4 comme non fait. Ici il devient bloquant : c'est le seul filet du jour J |
| 19 | Rejouer pour de vrai, instance par instance (instanceId=…), en commençant par la plus petite |
Le paramètre existe précisément pour ça |
| 20 | Vérifications post-bascule : login manager-app, une app visiteur avec sa clé API, un parcours, une carte, un PDF, un quiz avec ses questions | Les points b et c ne se voient qu'ici |
| 21 | Bascule DNS / API, Mongo gardé en lecture seule quelques jours | |
| 22 | Plan de retour arrière écrit avant le jour J | Un rollback qu'on improvise à 23 h n'est pas un rollback |
Après la bascule — relationnel, pas technique
| Quoi | Note |
|---|---|
| Reprendre contact avec Louise Smets — Musée d'Ixelles | À faire une fois la prod stabilisée, pas avant : on n'ouvre pas une conversation en montrant un produit en cours de bascule. Objectif d'abord d'écoute — comprendre ce qu'est réellement son travail au quotidien et sur quoi elle bute — avant de parler de MyInfoMate. L'entraide se décide après, pas dans le premier message. Rien n'est su de son rôle exact à ce stade : à ne pas supposer. |
Rappel de la porte : rien de tout ça ne démarre avant que le reste du backlog soit terminé (§1quater). La base Postgres vide est une fenêtre — chaque chantier de schéma passé maintenant est un chantier qui n'exigera pas de fenêtre de maintenance plus tard.