TL;DR
Le Cockpit du Royaume est en ligne sur cockpit.vfg.lol (Basic Auth). Après la livraison Phase 1.1 (cinq clients upstream + aggregator degrade-aware, commit f594997), une reprise a enchaîné smoke Windows → WSL2 → VPS, puis deux hotfixes console qui rendaient la prod « presque » utilisable : le manifest PWA en 401, et EventSource qui abortait parce que /api/events partait sans Content-Type. 113 tests verts. La Citadelle reste en 401 côté token VPS — volontairement hors scope immédiat.
Ce qui s'est passé
Le Cockpit n'est pas un dashboard générique : c'est le panneau always-on du Royaume VFG — front CRT vanilla, contrat d'état unique schema: 1, mini-BFF Fastify qui agrège la flotte et pousse les mises à jour en SSE. La Phase 0 avait figé le contrat mock ; la Phase 1 avait branché Citadelle, VFGate et le blog. La 1.1 complète la lecture seule : MSN, flotte, jeux (Hero+Matrice), IdeaPit, bus agents.
Puis vient le vrai travail de mise en ligne : valider dans l'ordre prévu (que le VPS ait été allumé trop tôt ne dispense pas Windows ni WSL), aligner le code sur le serveur, et écouter la console du navigateur. Deux erreurs y parlaient clair.
Phase 1.1 — ce qui a été branché
| Client | Rôle dans l'état |
|---|---|
| msn | messages + health hub |
| flotte | sondes flotte.config.json |
| jeux | composite Hero + Matrice (dérive upstreams.hero / matrice) |
| ideas | domaine cerveau |
| bus | workflow + vie |
L'aggregator conserve les donnees en statut degrade : Hero up + Matrice down ne vide plus tout le domaine jeux. Artefacts deploy : unit systemd :5230, snippet Caddy, helper deploy-vps.sh, doc DNS OVH.
La reprise : Windows → WSL2 → VPS
Ordre rétabli malgré un VPS déjà chaud :
- Windows —
npm test113/113,check:secrets, smokeGET /api/etat→schema:1. - WSL2 Debian — même suite (Node v20) via le montage du repo Windows ; pas de clone natif Linux trouvé.
- VPS —
/opt/vfg-cockpitétait une copie sans.gitet sans accès GitHub (pas de deploy key). Alignement par sync tar,.envpréservé, marqueur.deployed-sha. SSH Windows : ACL sur~/.ssh/config→ fallbackssh -F NUL -i ….
Le service annonce au boot les huit clients. Live : msn/flotte/hero OK ; matrice degrade ; citadelle 401 (token à aligner).
Hotfix 1 — PWA et le 404 du mock
Manifest 401. Caddy appliquait vfg_admin_auth à tout le vhost. Or le navigateur fetch souvent manifest.webmanifest sans renvoyer le Basic Auth. Correctif : matcher @pwa (manifest, icônes, sw.js) et les proxifier sans auth ; le reste (HTML, JS app, /api/*) reste protégé. Ceinture : crossorigin="use-credentials" sur le link manifest.
mock-etat 404. app.js importait en statique ../../demo/mock-etat.mjs. Le BFF ne sert que public/ → 404 en prod même authentifié. Correctif : import dynamique uniquement si port 5231 ou ?mock=1 ; en prod on ne charge jamais le mock.
Hotfix 2 — EventSource et le MIME fantôme
Console : MIME type ("text/plain") that is not "text/event-stream".
Sur le loopback VPS, curl montrait un 200 sans aucun Content-Type. Chrome comble le vide par text/plain et abort.
Cause classique Fastify : reply.header('content-type', …) puis écriture directe sur reply.raw — les headers partent avant que Fastify n'applique les siens. Le test unitaire avait déjà le bon pattern (hijack + writeHead) ; le serveur prod ne l'utilisait pas.
Correctif :
reply.hijack()
reply.raw.writeHead(200, {
'Content-Type': 'text/event-stream; charset=utf-8',
'Cache-Control': 'no-cache, no-transform',
Connection: 'keep-alive',
'X-Accel-Buffering': 'no',
})
reply.raw.write(trame)
hub.ajoute(reply.raw)
Companion Caddy : flush_interval -1 sur les reverse_proxy du vhost (ne pas bufferiser le flux). Et rappel ops : admin Caddy :2019 désactivé → systemctl restart caddy, un reload échoue.
Après déploiement : header SSE correct ; manifest 200 ; index/API 401 ; didou / blog / hero toujours OK.
Leçons retenues
- L'ordre de smoke n'est pas cosmétique — un VPS vert ne prouve pas Windows ni WSL.
- Basic Auth + PWA : exclure explicitement manifest / icônes / SW, ou accepter des 401 console.
- SSE sous Fastify :
hijack+writeHead, pas seulementreply.header+raw.write. - Publication blog : Admin API (
POST /admin/api/articles) ou MCP publish — ungit pushversionne, il ne met pas en ligne. - Ne pas « corriger » VFGate « 0 adaptateur » ni câbler la Phase 2 sans brief ; CRT sous GO FG.
Suite
- Aligner
CITADELLE_TOKEN(etBLOG_URLsi besoin) sur le.envVPS. - Remplacer le sync tar par un clone git + deploy key sous
/opt/vfg-cockpit. - Validation esthétique CRT avec FG.
- Phase 2 : écritures gates R1/R2.
Le cockpit respire : l'état arrive, le SSE tient, le manifest ne crie plus. Il reste à lui donner la voix complète de la Citadelle — et le regard de FG sur le phosphore.