Architecture
Un core, des apps réellement indépendantes
Kubuno n'est pas un monolithe. Un petit core en Rust orchestre une constellation de modules autonomes — chacun son processus, son dépôt et ses paquets — qui dialoguent par HTTP et par des événements partagés. Voici comment tout s'emboîte.
Les couches
Six couches, des responsabilités nettes
Le core (Rust + Axum)
Une passerelle unique : reverse-proxy (HTTP et WebSocket), authentification, bus d'événements, file de jobs et accès au stockage. Il pilote le cycle de vie des modules mais ne contient aucune logique métier.
Des modules indépendants
Chaque app est un processus séparé sur 127.0.0.1, livré en paquet natif (.deb, .rpm, macOS, Windows) ou installé à chaud depuis la marketplace, sans redémarrer le core.
Frontend chargé au runtime
Un host React 19 unique charge l'UI de chaque module à la volée via des import maps ESM. Toutes les apps partagent un shell, une session et un design cohérents.
PostgreSQL, triple emploi
Un seul moteur joue trois rôles : base de données, bus d'événements (LISTEN/NOTIFY) et file de jobs (SKIP LOCKED). Ni Redis, ni broker externe.
Isolé & sécurisé
Un schéma PostgreSQL dédié par app, un bac à sable seccomp qui fait échouer execve (sauf pour les rares modules qui appellent légitimement un binaire, comme le transcodage vidéo), et des routes internes signées par un secret dérivé par module.
Prêt pour les agents IA (MCP)
Chaque module peut déclarer des outils Model Context Protocol ; le core les agrège derrière un endpoint /mcp unique, authentifié par jeton d'API. Un assistant agit alors sur votre instance avec vos droits. Désactivé par défaut.
Extensible par conception
Des points d'extension bien définis (routes, événements, entrées de menu) laissent la communauté ajouter des modules sans toucher au core.
Sous le capot
Le cycle de vie d'une requête
De l'ouverture du navigateur à l'écriture en base, sans jamais quitter votre serveur.
Chargement du shell
Le navigateur charge le host React ; les import maps résolvent chaque module vers son entrée ESM /modules/<id>/entry.js.
Appel authentifié
L'app envoie sa requête au core en HTTPS, accompagnée d'un JWT (avec refresh token en cookie HttpOnly).
Le core fait office de passerelle
Il vérifie l'identité, puis agit en reverse-proxy vers le module concerné sur 127.0.0.1:31xx, avec un en-tête interne signé (X-Internal-Secret).
Le module agit
Le module lit ou écrit dans son schéma PostgreSQL, puis publie un événement via NOTIFY.
Réactions & tâches de fond
Les autres modules réagissent à l'événement (LISTEN) ; les traitements longs partent dans la file de jobs (SKIP LOCKED).
Envie d'aller plus loin ?
La documentation technique détaille le core, le manifeste des modules, les points d'extension et la sécurité.
Lire la doc technique