DOCS/status/bascule-prod.md
2026-09-03 14:00:51 +02:00

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ètres dryRun et instanceId), 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 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.