Granit Golem

Sentinelle de monitoring qualité

Sur Azure, le prix d'un health-check explose : de quelques centimes à plusieurs euros pièce. Aucun outil self-hosted ne coche mes cases, alors je l'écris moi-même. Au passage, je lâche Claude Code à fond pour voir : le projet 'rikiki' vire en plateforme SaaS industrielle, et je passe un mois à éponger le bazar généré.

Tableau de bord : surveillance en temps réel, tout au vert.
Un check en détail : latence et disponibilité suivies dans le temps.
Les projets : une quarantaine de checks répartis, tous sains.
Status page publique : uptime sur 90 jours.
Les quatre piliers : checks, audits, drift, alerting.
Landing page, Continuous Quality Monitoring.

Voir Granit Golem

granit-golem.com · monitoring qualité, self-hosted

Le coup de la facture

Mars 2025. Je relis une facture Azure, et un poste me saute aux yeux.

Le health-check qui me coûtait quelques centimes en réclame désormais plusieurs euros. Par sonde. La migration a fait gonfler le prix unitaire sans prévenir. Reportez ça sur tous les endpoints que je surveille, à la cadence où je les interroge, et le total devient grotesque. Tout ça pour vérifier que des services daignent encore répondre.

Alors je fais le tour de ce qui se fait en self-hosted.

Uptime Kuma ? Du ping, et pas grand-chose au-delà. Uptime Robot, Checkly, Datadog : très solides, mais impossibles à mettre sous les yeux d’un client sans rougir. Et aucun ne fait ce que je cherche en premier, du monitoring décrit comme du code : mes checks posés dans un fichier YAML, versionnés, passés en revue, où je garde la main rien qu’en tenant le fichier à jour.

Le reste de ma liste de courses ? Personne ne le coche non plus.

Une status page que je puisse montrer à un client sans baisser les yeux. Des scénarios qui sortent du HTTP brut (une base posée dans un réseau privé, vous ne la sondez pas au curl : il faut un agent local qui va chercher la donnée et la rapatrie). Et de quoi avaler un coffre-fort type Vault, parce que des credentials d’API en clair sur la machine même qui fait du monitoring, l’idée me hérisse.

Le vrai manque est ailleurs. Personne ne mesure la dérive.

Tous ces outils répondent à une question, une seule : est-ce que c’est up ? Sauf qu’un service peut renvoyer un beau 200 et se déliter en sourdine. Le payload JSON change de forme. Les en-têtes de sécurité s’évaporent après une mise à jour du reverse proxy. Le temps de réponse glisse de 200 ms à 1,2 s, et aucun seuil ne bronche.

Personne ne s’en aperçoit, parce que personne ne regarde à cet endroit-là.

C’est exactement là que je veux poser Granit.

Des mois plus tard, voilà à quoi ça ressemble : la latence d'un endpoint, suivie dans la durée. Mesurer la dérive, c'est lire cette courbe, pas se contenter d'un voyant vert.
Des mois plus tard, voilà à quoi ça ressemble : la latence d'un endpoint, suivie dans la durée. Mesurer la dérive, c'est lire cette courbe, pas se contenter d'un voyant vert.

Des mois dans ma tête, une semaine au clavier

Le projet a vécu un an avant d’exister. Surtout entre mes deux oreilles.

À quoi il sert au juste ? Qu’est-ce que j’y mets, qu’est-ce que je laisse à la porte ? Et la question qui revient sans cesse : pourquoi le faire moi-même plutôt que de bricoler trois outils existants ? Des carnets de notes, et pas une ligne de code.

La première vraie tentative tombe en mars 2025. Une mouture en TypeScript, écrite en moins d’une semaine, avec un objectif unique : déverser de la donnée de health-checking dans un ELK que j’avais déjà sous la main. Ça tournait. C’était glouton, à peine maintenable, mais ça prouvait que l’idée tenait debout.

Pendant ce temps, une autre question me trottait dans la tête, sans rapport apparent : Claude Code, jusqu’où ça permet d’accélérer ?

L’envie de marier les deux est venue toute seule. Granit servirait de cobaye pour pousser Claude Code dans ses retranchements, et au passage je récupérerais un outil de monitoring dont je me servirais pour de bon. Le beurre et l’argent du beurre, sur un projet censé rester tout petit. Rikiki, même. Une seule mission : surveiller en continu, traquer la dérive.

Premier arbitrage, calculette en main : ça doit tenir sur une machine minuscule. Donc un backend qui ne gaspille rien, donc Rust.

Deuxième arbitrage, plus opportuniste : profiter de la R&D pour me frotter à Vue et à Nuxt, que je maîtrisais mal. L’appli devra un jour digérer beaucoup de texte (un terrain où Angular se traîne lamentablement), autant apprendre maintenant. Je m’éloigne de ma stack habituelle, TypeScript et Angular, en sachant très bien ce que je fais.

Le piège du rikiki

Novembre 2025. La réécriture en Rust démarre pour de bon, et avec elle, la frénésie.

Claude génère du code. Beaucoup. ÉNORMÉMENT. Je pousse le curseur au maximum, j’en abuse sans vergogne : je code entre midi et deux, je code depuis mon téléphone dans les transports, je code la nuit.

En six semaines, l’inventaire donne le vertige : une CLI, un parcours d’inscription, des alertes, des checks, des audits, et même un bus de messages Apache Pulsar que je n’ai jamais pris la peine de brancher. Une liste au Père Noël, montée d’un seul tenant.

Et un chantier monstre.

Sauf que le chantier, c’était à moitié le plan. Mon métier chez siliceum, c’est d’industrialiser des produits bancals : reprendre des applications gorgées de dette technique et les remettre d’aplomb jusqu’à ce qu’elles tiennent la prod. Alors autant m’en fabriquer une exprès, à toute allure, pour voir jusqu’où Claude va et ce qu’il laisse à éponger derrière lui.

L’éponge, je n’ai pas eu à l’attendre longtemps.

Les murs

Le réveil, je l’ai eu en me cognant contre deux murs.

À partir de là, Granit n’est plus un jouet.

Tout ce qui fait souffrir une appli SaaS en production se rejoue ici, en condensé et en accéléré : multi-tenancy, isolation, observabilité, déploiement, et la qualité d’un code abattu à la chaîne par une machine. De fil en aiguille, Granit est devenu la colonne vertébrale de mes essais de fiabilisation chez siliceum, et l’outillage que j’ai forgé autour a fini par déborder largement de son cas d’origine.

Un mois sans toucher aux features

Depuis un mois, Granit ne reçoit plus la moindre fonctionnalité. Freeze total.

Rien que du durcissement. Sur un projet qui me démange en permanence (dix idées qui grattent en continu, dont une seule que je m’autorise), la décision a un coût. C’est pourtant le seul moyen de passer du prototype à un outil sur lequel je peux m’appuyer les yeux fermés.

Pendant ce mois, j’ai greffé des pipelines de correction automatique et serré toute la démarche qualité : non-régression, instrumentation, le moindre recoin sous surveillance.

Côté performance, le saut est franc. Je suis passé de « je rame à tenir mille checks par minute sur un vCPU » à « j’en encaisse cinquante mille sans broncher ». Ce qui réclamait une grosse machine se contente maintenant d’un VPS de rien du tout.

J’ai consolidé les parcours utilisateurs critiques. Ajouté l’internationalisation, qui manquait à l’appel. Je me suis même offert une refonte graphique complète, histoire de juger sur pièce si le détour valait la peine.

Pour mesurer l’ampleur de la chose, il faudrait éplucher l’historique : 1 229 commits sur ce seul mois de durcissement, dont une bonne part signée par le daemon Forge pendant que je dormais. Chaque ligne relue tout de même (au café, je vous l’accorde).

Tout sur une seule machine

Comment héberger une plateforme entière, ses deux environnements et tout son monitoring sans y laisser un salaire ? Au démarrage, je n’avais pas la réponse : tout vivait sur Clever Cloud.

Sauf qu’en empilant le multi-environnement (dev et prod) et un monitoring digne de ce nom, l’addition dépassait les cent euros par mois. Pour un projet perso, c’est non.

Je bascule donc sur un VPS, le jour où mon socle « cloud » maison est prêt (Traefik et Docker, la fondation de tordu-jardin). Deux bénéfices d’un coup : Granit redevient abordable, et le bac à sable de Claude s’agrandit, du code jusqu’à l’infra et le self-hosting.

Et quand je dis que ce VPS héberge tout, c’est à prendre au pied de la lettre. Pour un projet « rikiki », j’ai fini par entasser de quoi faire tourner une vraie société.

Deux Granit y cohabitent, un dev et un prod (la prod ne pose aucune question de confidentialité : je ne stocke aucun credential d’utilisateur). À côté, une chaîne d’observabilité complète, avec une astuce dont je tire une petite fierté : Granit se surveille lui-même, en rejouant sur sa propre carcasse les checks qu’il propose aux clients.

La chaîne d'observabilité

Émetteurs

  • Granit prod
  • Granit dev
  • Navigateurs users

Collecte

  • Prometheusmétriques
  • Lokilogs
  • PostHogreal user monitoring
  • Self-checksGranit surveille Granit

Restitution

  • Grafanadashboards
  • Alertmanageralertes
Et Granit se surveille lui-même : les checks vendus aux clients tournent aussi sur Granit, histoire de comparer les deux et de repérer une dérive de mes propres résultats.

La base de données, elle, reste tapie dans le réseau privé. Verrouillée, jamais exposée.

Le serveur tient 99,9 % du temps, en blue-green : plusieurs mises en production par jour, sans la moindre coupure. Et par-dessus, un circuit entièrement agentique, du bug repéré jusqu’à la prod.

Sans ce circuit, impossible de tenir ce rythme sans tout envoyer dans le mur.

Tout repose sur Forge, le daemon qui lit les tickets, réveille les agents et ouvre les merge requests. Il a si bien joué son rôle qu’il prend son envol : je l’extrais en Ardente Forge, un plugin Claude Code que je pourrai brancher sur n’importe quel autre projet.

Du bug détecté au déploiement

Boucle Ardente Forgeagents

  1. Détection

    Un check ou un audit lève une alerte. Un ticket GitLab s'ouvre tout seul.

  2. Analyse

    Forge lance un agent qui diagnostique et propose un correctif.

  3. Merge request

    L'agent pousse le fix dans une MR dédiée.

  4. Review agent

    Un second agent relit, challenge, commente.

  5. Feu vert humain

    Je jette un dernier coup d'œil et je valide. Le seul humain de la boucle.

Pipeline CI/CDbloquante

  1. Tests & audits

    cargo test, Vitest, Playwright, audit Marble Minotaure. Tout doit passer.

  2. Build & push

    Image Docker construite, puis poussée sur la registry privée.

  3. Deploy blue-green

    Bascule sans coupure sur le VPS, plusieurs fois par jour.

Le seul moment où j'interviens à la main, c'est le feu vert. Le reste tourne tout seul, la nuit comprise.

Le socle de confiance

Faire confiance à du code poussé par une machine pendant que je dors, vous y arriveriez, vous ? Moi, pas sans garde-fous. Voici le filet tendu sous le circuit : il tourne sur chaque merge request, et il bloque.

Backend Rustbloquant
  • Compilation + cargo check
  • Clippyle linter Rust, réglé en mode tatillon
  • cargo auditfailles connues (CVE) dans les dépendances
  • Couverture de tests
  • Mutation testingon injecte des bugs exprès pour vérifier que les tests les attrapent
  • Tendance de dette techniquesuit l'évolution des warnings et TODO dans le temps
Frontendbloquant
  • Lint + typecheck
  • Vitest + couverture
  • Accessibilité (a11y)navigable au clavier, lisible par un lecteur d'écran
  • Lighthousele score de perf et SEO de Google
  • Budget de bundlealerte si le JS livré dépasse un seuil
  • Cohérence i18ntoutes les clés de traduction présentes dans chaque langue
  • Audit du design systeml'UI respecte les tokens et composants maison
  • Diff de screenshotscompare l'avant/après en image, repère le pixel qui a bougé
E2E & QAbloquant
  • Playwright sur les parcours critiques
  • Audit qualité autoMarble Minotaure : un agent qui explore le site et le challenge seul
  • Détection de tests flakyrepère les tests qui passent ou échouent au hasard
  • Smoke tests dev / staging / prodcheck minimal après déploiement : est-ce que ça démarre ?
  • UAT en productiontests d'acceptation joués sur la vraie prod
Sécuritébloquant
  • Gitleaksdétecte un secret commité par erreur
  • Scan de l'image Dockercherche les failles connues dans l'image
  • Génération du SBOMl'inventaire de tout ce que contient l'image
  • Signature de l'imagepreuve cryptographique qu'elle vient bien de la CI
Infra & API
  • Lint des migrations SQL
  • Hadolintle linter des Dockerfile
  • Lint des fichiers compose
  • OpenAPI à jourle contrat d'API généré colle au code

Tout ça tourne sur chaque merge request, en bloquant. Les tests verts ne suffisent pas : c'est l'empilement de gardes-fous qui dit que je peux déployer.

Où ça en est

Granit est sorti du freeze. Place à une phase de consolidation, puis à un premier déploiement, le vrai.

Le programme des semaines qui viennent : embarquer une poignée d’utilisateurs désintéressés, leur lisser l’onboarding, repérer ce qui coince, et remettre ça. En interne, c’est déjà le quotidien. Granit surveille l’intégralité de ce qui tourne sur tordu-jardin (une vingtaine d’applis modifiées et monitorées), il est en place sur plusieurs outils siliceum, et il remonte de la donnée d’applis partenaires.

Le tableau de bord, sur l'instance qui surveille tout mon parc : une quarantaine de checks, tout au vert.
Le tableau de bord, sur l'instance qui surveille tout mon parc : une quarantaine de checks, tout au vert.

Elle arrivera, c’est promis, en même temps que les audits plus poussés et les scénarios qui débordent du HTTP brut. Au fur et à mesure.

Et comme il reste beaucoup à raconter, je compte déterrer Granit dans plusieurs carnets. Les déboires méritent mieux qu’un paragraphe expédié.

Le premier de la série est déjà en ligne : comment Granit est découpé en couches, pour réutiliser le même cœur dans le runner, le cloud et la CLI.

À très vite pour la suite.

Stack technique

Backend

Rust + Axum

Rigueur du compilateur, perfs natives sur une petite machine

API

REST + OpenAPI auto-généré

Documentation à jour par construction

Base de données

PostgreSQL 16 + RLS

L'isolation multi-tenant est garantie par la base, pas par le code

Frontend

Nuxt 3 + Vue 3 + Pinia

SSR pour les pages publiques, SPA pour le dashboard

Observabilité

Loki + Grafana + Prometheus

Logs, dashboards et métriques de l'auto-surveillance

RUM

PostHog

Real user monitoring sur l'appli elle-même

Tests

Vitest + Playwright + cargo test

E2E sur l'alerting, unit sur le domaine

CI / CD

GitLab CI + daemon Forge

Pipelines bloquantes, automatisation agentique

Audits CI

Marble Minotaure

L'auditeur QA maison qui surveille Granit