Venus

L'interface de supervision est une application Vue 3 + Vite
intégrée directement au package unique venus :
un seul package.json et un seul node_modules
pilotent à la fois le backend NestJS et le frontend Vue.
Le dossier web/ ne contient plus que les sources
(index.html + src/) ; toute la configuration
(Vite, Vitest, tsconfig web) vit à la racine de venus.
Venus dialogue en GraphQL sur /graphql
(même origine), puis relaie les flux vers les services métier.
Saturn : inventaire, actions, DNS et DHCP.
Mercure : consultation et traitement des logs.
Venus sert le SPA compilé (web/dist) via
ServeStaticModule, en excluant /graphql.
Il n'y a plus de conteneur central-web distinct.
Stack NestJS + GraphQL
La couche Venus combine un backend NestJS et une passerelle GraphQL dans le meme service.
- NestJS structure les modules metier, les resolvers et les adaptateurs.
- GraphQL expose un point d'entree unifie (
/graphql) pour le frontend. - BFF : Venus agrege les donnees Saturn et Mercure pour limiter la complexite cote UI.
Arborescence
central/venus/
├── package.json # package unique (Nest + Vue)
├── tsconfig.json # config serveur (NestJS, CommonJS)
├── tsconfig.web.json # config frontend (Vue, ESM)
├── nest-cli.json
├── vite.config.ts # root = web/, sortie web/dist
├── vitest.config.ts
├── src/ # backend NestJS (gateway GraphQL/CQRS)
└── web/
├── index.html
└── src/
├── main.ts # bootstrap de l'application
├── router/ # routes UI
├── views/ # pages de supervision
├── services/api.ts # client GraphQL
└── components/ # composants UI
Build & développement
npm run build— construit le web (build:web:vue-tsc+vite build→web/dist) puis le serveur (build:server:nest build→dist).npm run dev— lance en parallèlevite build --watchetnest start --watch.npm run test:web— tests unitaires Vitest.
En conteneur, l'override docker-compose.central.dev.yml exécute ces deux
processus dans un seul conteneur central-venus (plus de service séparé).
Accès API (GraphQL)
Le frontend central consomme l'endpoint GraphQL de venus :
- URL par défaut :
/graphql(même origine, servie parvenus) - variable d'environnement optionnelle :
VITE_VENUS_URL
Exemples d'opérations côté web :
healthnodesactionsenqueueActionqueryLogsdnsRecords,upsertDnsRecord,deleteDnsRecord,syncDnsdhcpRecords,upsertDhcpRecord,deleteDhcpRecord
Fonctionnement détaillé de Venus
Venus joue un rôle de couche d'orchestration entre le frontend et les services backend.
- Les resolvers GraphQL reçoivent la requête UI et appliquent la validation d'entrée.
- Les services NestJS traduisent la requête GraphQL en appels REST vers Saturn ou Mercure.
- Les réponses sont normalisées pour exposer un contrat stable au frontend.
- Les erreurs backend sont transformées en erreurs GraphQL explicites pour l'interface.
Cycle typique d'une requête :
- La vue frontend envoie une query ou mutation sur
/graphql. - Le resolver Venus route vers le service métier concerné.
- Le service appelle Saturn ou Mercure.
- Venus reformate et retourne la réponse GraphQL au frontend.
Documentation des queries
Query health
Permet de vérifier rapidement la disponibilité de Venus et des dépendances critiques.
query Health {
health {
status
timestamp
dependencies {
name
status
latencyMs
}
}
}
Query nodes
Retourne la liste des nodes visibles dans la flotte avec leur état.
query Nodes($limit: Int, $search: String) {
nodes(limit: $limit, search: $search) {
id
name
ip
status
lastSeenAt
}
}
Variables possibles :
{
"limit": 50,
"search": "zone-nord"
}
Query queryLogs
Interroge les logs via Mercure, avec filtres par node, niveau et période.
query QueryLogs($nodeId: String, $level: String, $limit: Int) {
queryLogs(nodeId: $nodeId, level: $level, limit: $limit) {
items {
timestamp
nodeId
level
message
}
total
}
}
Variables possibles :
{
"nodeId": "node-01",
"level": "error",
"limit": 100
}
Query dnsRecords
Lit les enregistrements DNS gérés par la flotte.
query DnsRecords($zone: String) {
dnsRecords(zone: $zone) {
id
host
type
value
ttl
}
}
Documentation des mutations
Mutation enqueueAction
Enfile une action opérateur vers un node (pilotage relais, vannes, etc.).
mutation EnqueueAction($input: EnqueueActionInput!) {
enqueueAction(input: $input) {
actionId
status
queuedAt
}
}
Exemple de variables :
{
"input": {
"nodeId": "node-01",
"type": "relay.toggle",
"payload": {
"relayId": "r1",
"state": true
}
}
}
Mutation upsertDnsRecord
Crée ou met à jour un enregistrement DNS.
mutation UpsertDnsRecord($input: UpsertDnsRecordInput!) {
upsertDnsRecord(input: $input) {
id
host
value
ttl
}
}
Mutation deleteDnsRecord
Supprime un enregistrement DNS par identifiant.
mutation DeleteDnsRecord($id: ID!) {
deleteDnsRecord(id: $id) {
success
message
}
}
Mutation upsertDhcpRecord
Crée ou met à jour une entrée DHCP.
mutation UpsertDhcpRecord($input: UpsertDhcpRecordInput!) {
upsertDhcpRecord(input: $input) {
id
mac
ip
hostname
}
}
Mutation deleteDhcpRecord
Supprime une entrée DHCP.
mutation DeleteDhcpRecord($id: ID!) {
deleteDhcpRecord(id: $id) {
success
message
}
}
Bonnes pratiques d'utilisation
- Utiliser des variables GraphQL plutôt que des valeurs en dur.
- Demander uniquement les champs nécessaires pour réduire la charge réseau.
- Limiter
queryLogsaveclimitet filtres (nodeId,level) pour les vues temps réel. - Prévoir un rafraîchissement progressif (polling) avec gestion des erreurs réseau côté UI.
Organisation UI
Le frontend central est orienté parc de nodes :
- liste des nodes connectés ;
- statut réseau ;
- actions de pilotage ;
- accès aux logs agrégés.
- administration DNS et DHCP depuis le menu Infrastructure.
- vue Network → Flotte listant les machines du réseau ayant émis un health state Kafka (voir Flotte & santé réseau).
La vue Network → Flotte s'actualise automatiquement par polling HTTP
GraphQL (fleet) toutes les 15 s, avec pause quand l'onglet navigateur est
caché puis reprise avec refresh immédiat au retour au premier plan.
La vue Network → Flotte → Détail instance affiche aussi les logs récents du
node (logs GraphQL filtrés par nodeId), issus de Mercure/Kafka.
Un filtre de niveau (info, warn, error, debug) est disponible dans cette
section pour cibler rapidement les événements opérationnels.
Cette vue inclut aussi un bloc Capteur eau (microcontrôleur) qui lit les métriques
remontées par l'agent via meta.plugin_metrics (ex: water_raw, moisture).
Sans trame série émise par le microcontrôleur, le bloc reste en mode "aucune mesure".
Authentification
L'authentification est portée par Saturn (fournisseur native) : utilisateurs,
rôles hiérarchiques, sessions et tokens sont stockés en PostgreSQL (tables iam_*).
Le fournisseur se choisit dans l'env du conteneur Saturn : AUTH_PROVIDER=native|none.
- Login : HTTP Basic uniquement ; verrouillage après
AUTH_MAX_LOGIN_ATTEMPTSéchecs. - Tokens : access token JWT HS256 (
AUTH_ACCESS_TOKEN_TTL), refresh token opaque haché en base, rotation à chaque refresh ; un refresh token rejoué hors fenêtre de grâce (10 s) révoque toute la session. Durée max de session :AUTH_SESSION_MAX_TTL. - Endpoints OAuth2 :
/api/auth/token,/api/auth/revoke(RFC 7009),/api/auth/introspect(RFC 7662),/api/auth/userinfo,/api/auth/config. - Permissions :
ressource:actionavec jokers*etressource:*. Rôles composites seedés :admin⊃operator⊃viewer. Saturn contrôle chaque route REST ; Venus contrôle les opérations non Saturn (logs,fleet,health,iam). - Canal machine :
POST /api/consignes/sync(agents) reste sans authentification utilisateur. - Admin : menu Sécurité → Utilisateurs & accès (utilisateurs, rôles, sessions).
- Bootstrap : au premier démarrage, l'utilisateur
AUTH_ADMIN_USERNAMEest créé avecAUTH_ADMIN_PASSWORD(ou un mot de passe aléatoire affiché une fois dans les logs).