Skip to content

feat(status): add status page with uptime collection (unlisted, noindex)#156

Merged
remigit55 merged 1 commit into
masterfrom
claude/gifted-keller-81qkn3
Jun 17, 2026
Merged

feat(status): add status page with uptime collection (unlisted, noindex)#156
remigit55 merged 1 commit into
masterfrom
claude/gifted-keller-81qkn3

Conversation

@remigit55

Copy link
Copy Markdown
Collaborator

Objectif

Page de statut côté Modular (status.blueprint-modular.com), transposée du modèle Maker (status.blueprint-maker.com), qui collecte un historique de disponibilité 90 jours dès le déploiement — pour disposer d'un historique réel le jour où il y aura des utilisateurs.

Étape 0 — Cartographie du modèle Maker (rapport)

Aspect Constat Maker Décision Modular
Stockage historique Aucun. L'uptime 90 j est recalculé à chaque requête depuis la table GeneratedApp (createdAt + validationResult.passed). ❌ Non transposable (Modular n'a pas d'activité « génération »). On stocke de vrais points de mesure en Postgres.
Infra uptime Dérivée de « ≥ 1 app créée ce jour = up ». Le code admet ne pas pouvoir marquer down sans journal réseau. ✅ Corrigé : statut dérivé de la vraie joignabilité publique.
Sonde Interne (/api/internal/health sur bpm-prod : DB, mémoire, disque…). Tombe avec le service → angle mort. ✅ Corrigé : la sonde appelle les URLs publiques (DNS + nginx + SSL + app).

Conclusion : le modèle Maker est interne + dérivé + sans stockage. On ne le réplique pas tel quel ; on implémente une sonde réelle qui persiste ses mesures.

Ce qui est livré

  • Sonde lib/status/probe.ts : GET vitrine (200–399 = up) ; POST JSON-RPC tools/list sur le MCP (200/SSE = up, jamais de GET).
  • Stockage : table status_check (migration Prisma) — 1 ligne/service/passage. Appliquée automatiquement par deploy-from-git.sh (prisma migrate deploy).
  • Agrégation lib/status/data.ts : fenêtre 90 j + incidents (séquences d'échecs).
  • Routes : POST /api/status/probe (jeton, fail-closed) pour le cron ; GET /api/status/public (JSON, monitoring externe).
  • Page app/status/ (serveur, i18n fr/en, tokens var(--bpm-*)), noindex, non listée : URL directe + lien discret en pied de page.
  • Ops (dans la PR, à activer par Rémi) : deploy/nginx-status-blueprint-modular.conf, deploy/status-probe.crontab, doc deploy/STATUS_PAGE.md, vars .env.

⚠️ Point à arbitrer — noindex vs « indexer »

Le message de commit demandé dit « unlisted, noindex » et l'objectif (collecter avant qu'il y ait des utilisateurs) va dans ce sens → j'ai implémenté noindex + non listée + lien footer discret. La consigne « Indexer la page status » du brief contredit cela. Facile à inverser (retirer robots du layout + ajouter au sitemap) si l'intention est l'indexation immédiate.

Angle mort résiduel (assumé, documenté)

La sonde tourne sur bpm-prod (cron → route POST). Si l'app Next.js est elle-même à terre, aucune mesure n'est écrite → la journée apparaît en no_data (pas outage). Fidèle pour toute panne en aval (DNS, certificat, nginx, MCP). Un monitoring externe pourra plus tard appeler GET /api/status/public pour lever cet angle mort.

Validation

  • npx tsc --noEmit : 0 erreur (parité i18n fr/en garantie par le typage).
  • npm run build : vert/status, /api/status/probe, /api/status/public rendus dynamiques (ƒ).
  • Preuve runtime (collecte + sonde MCP en POST + non-100 %-par-défaut) : à constater par Rémi après merge + deploy-from-git.sh + ops DNS/SSL/nginx/cron.

Ops hors-code (action humaine)

DNS status.blueprint-modular.com → bpm-prod · nginx vhost · certbot SSL · jeton STATUS_PROBE_TOKEN + cron 5 min. Détails dans deploy/STATUS_PAGE.md.

🤖 Generated with Claude Code


Generated by Claude Code

Transpose the Maker status page to Modular, correcting its two main
defects: the Maker model derived "uptime" from app-generation activity
plus an internal /health (which falls with the service and stores no
measurements). Here, a real probe measures public availability and
persists measurement points to Postgres, so the 90-day window fills from
deployment.

- Probe (lib/status/probe.ts): GET vitrine (200-399 = up), POST JSON-RPC
  tools/list to the MCP endpoint (200/SSE = up, never GET).
- Storage: status_check table (Prisma migration) — one row per service
  per run; aggregated into a 90-day window in lib/status/data.ts.
- POST /api/status/probe (token-protected, fail-closed) for the cron;
  GET /api/status/public for external monitoring.
- Page app/status (server, i18n fr/en, var(--bpm-*) tokens), noindex,
  unlisted: direct URL + discreet footer link.
- Ops (in-PR, human-activated): nginx vhost, certbot, DNS, 5-min cron.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3uxfWJ26LF6Dj7p7fbWod
@remigit55
remigit55 merged commit 6d579d8 into master Jun 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants