Granit Golem - Plateforme de monitoring qualité continu

Uptime Robot dit que tout est vert. Trois semaines plus tard, le client appelle : le site est lent, les headers de sécurité ont disparu, le certificat expire dans 4 jours. Il manquait un outil qui surveille non pas si c'est up, mais si c'est aussi bien qu'avant.

III - Croissance 3 mois 2025-11-24 2026-02-18
XP
90%

Genèse

Ça commence par un appel client, trois semaines après un déploiement. “Le site est lent.” On regarde. Le score Lighthouse est passé de 92 à 61. Les headers de sécurité ont disparu après une mise à jour de reverse proxy. Le certificat SSL expire dans 4 jours. Tout était vert sur Uptime Robot. Personne n’a rien vu.

C’est le problème : les outils de monitoring existants répondent à une seule question, “est-ce que c’est up ?”. Mais un site peut être up et se dégrader lentement. Les performances glissent, la sécurité s’érode, la délivrabilité email se dégrade. Personne ne prévient parce que personne ne mesure.

J’ai cherché un outil qui combine le monitoring classique avec des audits de qualité. Uptime Robot fait du ping. Lighthouse fait des audits ponctuels. Datadog fait tout mais coûte une fortune et demande un bac+5 pour la configuration. Il n’existe rien qui dise simplement : “ton site répondait bien la semaine dernière, cette semaine il régresse, voici pourquoi.” C’est le créneau de Granit Golem.

Le nom vient du golem de granit. Une sentinelle patiente qui ne dort jamais. Le genre de gardien qu’on aimerait avoir eu trois semaines plus tôt.

Pourquoi ces choix

Rust pour un SaaS, c’est un choix que je dois souvent justifier. La raison, c’est que le monitoring est un domaine où les erreurs silencieuses sont les pires. Si un check oublie de vérifier un cas, si un type d’alerte est confondu avec un autre, on ne le découvre que quand un client ne reçoit pas la notification qu’il attendait. En Rust, le compilateur refuse de compiler si on oublie un cas dans un match. Un CheckId ne peut pas être passé là où on attend un AuditId. C’est plus lent à écrire, mais ça force une rigueur que je n’aurais pas eue en Node ou Go.

PostgreSQL avec Row Level Security, c’est la réponse à une question qui m’empêchait de dormir : “et si un développeur oublie le filtre WHERE org_id = ? dans une requête ?” Avec la RLS, c’est la base elle-même qui refuse de montrer les données d’une autre organisation. Le filtre est dans la base, pas dans le code. On peut oublier, PostgreSQL n’oubliera pas.

Comment ça marche

On pointe Granit Golem vers un site web ou une API. Il commence à surveiller avec des checks légers toutes les minutes : le site répond-il ? Le certificat SSL est-il valide ? Le DNS résout-il correctement ?

Les audits vont plus loin. On choisit ce qu’on veut mesurer (performance Lighthouse, headers de sécurité, délivrabilité email SPF/DKIM/DMARC…), on règle l’importance de chaque critère, et Granit Golem exécute le tout périodiquement. Le premier audit définit une baseline. Les suivants sont comparés : si quelque chose glisse au-delà d’un seuil, une alerte se déclenche. C’est la drift detection, la raison d’être du projet. Pas juste “est-ce que c’est up”, mais “est-ce que c’est aussi bien qu’avant”.

Les alertes ont un cycle de vie complet : on peut les acquitter (“je suis dessus”), les résoudre manuellement, ou laisser le système les fermer quand le problème se corrige. Des status pages publiques permettent de communiquer l’état sans que les utilisateurs aient besoin de demander.

Les cailloux dans le terreau

Décider seul

Le plus gros défi n’est pas technique. C’est de prendre toutes les décisions architecturales sans personne pour challenger. DDD ou pas ? Quel découpage ? Comment gérer le multi-tenant ? Chaque choix engage la suite. Sans revieweur, les mauvaises décisions se révèlent tard. Le constructeur du state global qui fait 469 lignes, on ne le voit pas grossir jour après jour. C’est quand on veut ajouter un nouveau service qu’on réalise que c’est devenu ingérable.

Les migrations qui s’entrechoquent

En développant sur plusieurs branches en parallèle, deux branches créent une migration avec le même timestamp. On merge, et la base refuse de démarrer. SQLx stocke un checksum de chaque migration : si on modifie une migration déjà appliquée, même une virgule, tout casse. La règle apprise dans la douleur : ne jamais toucher une migration existante, toujours en créer une nouvelle.

L’audit fantôme

Un audit qui crashe pendant la génération du rapport reste bloqué en état “Running” pour toujours. L’audit suivant reçoit un conflit. Sauf que le premier est mort. Il a fallu un job de nettoyage en arrière-plan, une détection au chargement de page, et un fix de memory leak côté frontend. Trois bugs pour un seul symptôme. Le genre de problème qui rappelle pourquoi on fait du monitoring : les choses cassent de manière inattendue.

Le monitoring du monitoring

À un moment, on se demande qui surveille le surveillant. Prometheus a été intégré pour mesurer les métriques du serveur Granit Golem lui-même. Puis on se demande si on devrait surveiller Prometheus. C’est là qu’on s’arrête et qu’on accepte qu’il y a toujours un dernier maillon non surveillé.

L’architecture

Le projet est structuré en Domain-Driven Design, avec une séparation stricte entre les règles métier et le reste. Les règles de monitoring (“un check ne peut pas tourner en même temps qu’un autre”, “le seuil d’alerte doit être supérieur au seuil d’avertissement”) vivent dans des modules qui ne savent rien de la base de données ni du framework web. On peut tester la logique métier sans démarrer PostgreSQL. C’est le genre de discipline qui semble excessive au début et qui évite les régressions trois mois plus tard.

Le frontend est un dashboard Nuxt 3 avec des graphes de tendance, des barres d’uptime et des formulaires pour configurer les audits. Rien de spectaculaire techniquement, mais il fallait que ce soit utilisable par quelqu’un qui n’est pas développeur.

Pourquoi c’est en pause

Le projet a atteint un stade fonctionnel : les checks marchent, les audits produisent des scores, la drift detection lève des alertes. Mais pour inviter de vrais utilisateurs, il manque du polish sur l’alerting (la couverture fonctionnelle est à 46%) et sur l’onboarding. Plutôt que de sortir un produit bancal, j’ai préféré mettre en pause et y revenir quand j’aurai le temps de le finir correctement.

Journal

2026-02-18

Pause. Le produit est utilisable mais pas prêt pour des vrais utilisateurs. L’alerting reste le maillon faible. Plutôt que de bâcler, on attend.

2026-01-25

Grosse journée de corrections. L’accessibilité est ajoutée sur tous les composants d’interface, une vulnérabilité dans une dépendance Rust est corrigée, et le state global monolithique est enfin découpé en quelque chose de maintenable. Le genre de journée pas glamour mais nécessaire.

2026-01-24

Sécurisation multi-tenant. Des tests vérifient qu’une organisation ne peut jamais lire les données d’une autre, même si le code applicatif oublie un filtre.

2025-12-15

Le cœur du produit prend forme. Lighthouse fonctionne comme sonde d’audit, la drift detection compare les scores à une baseline, l’interface permet de régler les poids de chaque critère. L’audit passe du concept au workflow fonctionnel.

2025-11-24

Premier commit. L’architecture complète est posée dès le jour 1. Un pari sur la rigueur dès le départ : structurer proprement même quand personne ne regarde, parce que le code d’aujourd’hui est le legacy de demain.

Stats

Commits1 021
Durée3 mois (nov 2025 → fév 2026)
Contributeursolo

Architecture

Nuxt 3 SPA
REST APIAxum API (:8080)
Axum API (:8080)
SQLx + RLSPostgreSQL 17 + RLSDomain eventsApache Pulsar
PostgreSQL 17 + RLS
Apache Pulsar
Probe Executor
HTTP, TCP, DNS, SSL...Sites / APIs ciblesRésultatsPostgreSQL 17 + RLS
Sites / APIs cibles

Stack technique

Rust (Axum)

Backend API et probes

Forcer la rigueur sur les cas d'erreur dans le monitoring

Nuxt 3

Dashboard et pages publiques

Status pages publiques en SSR, dashboard privé en SPA

PostgreSQL + RLS

Base de données multi-tenant

Isoler les données entre organisations au niveau de la base

Landing page - Continuous Quality Monitoring

Landing page - Continuous Quality Monitoring

Dashboard avec sidebar navigation

Dashboard avec sidebar navigation

Login et présentation produit

Login et présentation produit

Landing page complète - features et pricing

Landing page complète - features et pricing

Landing page - Continuous Quality MonitoringDashboard avec sidebar navigationLogin et présentation produitLanding page complète - features et pricing
Dernier merge, pause stratégique+1 commits

Merge de master depuis GitLab. Le projet entre en pause après un sprint de 3 mois. 1 021 commits, le backend est solide, le frontend fonctionnel, la CI verte. La V1 est à 78% de readiness selon l'audit PO interne.

  • Merge branch master, synchronisation GitLab
Marathon : 40+ commits en une journée+40 commits

La plus grosse journée du projet. Prometheus intégré dans le middleware et le probe executor. Tests E2E pour les alertes (acknowledge, resolution, email via Mailhog). Accessibilité WCAG 2.1 AA sur tous les composants UI. Migration de mysql_async vers sqlx pour corriger une vulnérabilité RUSTSEC. Refactoring du monolithique AppState en Repositories struct. Le tout entre 10h et 23h30.

  • Prometheus : métriques HTTP et probe execution intégrées dans le middleware
  • E2E alerting : lifecycle complet (acknowledge, resolve, email Mailhog)
  • WCAG 2.1 AA : aria-invalid, aria-describedby, aria-live sur tous les composants G*
  • RUSTSEC-2026-0002 : migration mysql_async → sqlx-mysql
  • AppState monolithique → Repositories struct (469 → 50 lignes constructeur)
  • Row Level Security PostgreSQL pour isolation multi-tenant
  • Circuit breaker + SQL statement timeout pour la résilience
  • Page discovery UI pour audits multi-pages
  • Transactional outbox pour les domain events
Sécurité multi-tenant et tests cross-org+15 commits

Isolation defense-in-depth sur tous les handlers : checks, audits, heartbeats, status pages, oncall, agents. Tests cross-org pour vérifier qu'une organisation ne peut jamais lire les données d'une autre. Le billing passe en EUR.

  • Multi-tenant isolation sur 6 domaines (checks, audits, heartbeats, status pages, oncall, agents)
  • Tests cross-org sur toutes les APIs multi-tenant
  • Billing : prix en EUR, indicateur du plan actuel corrigé
Audits qualité et drift detection+30 commits

Le cœur du produit prend forme. Lighthouse intégré comme probe, drift detection avec baseline et scores, sliders de pondération pour les audits, overlay de progression avec cancel. Le frontend se structure avec les composants de résumé par type de check.

  • Lighthouse probe avec API key optionnelle
  • Drift detection : baseline, scores, seuils d'alerte
  • UI : sliders de pondération, progress overlay, cancel audit
  • Composants de résumé par type de check (HTTP, TCP, DNS, SSL...)
Premier commit : les fondations DDD+5 commits

Le projet démarre avec l'architecture complète posée dès le premier jour. Domain-Driven Design strict : shared-kernel, monitoring-domain, monitoring-application, monitoring-infrastructure, api-server. Les 3 premières probes (SSL, PostgreSQL, DNS) arrivent dans les premières heures.

  • Scaffold DDD complet : 5 crates, architecture hexagonale
  • Probes SSL, PostgreSQL et DNS
  • Compilation des tests du monitoring-domain