# Consigne de dev — Optimisation, observabilité, tokens Hermes, nettoyage DB et découverte machines > **Type** : mission d'**investigation + design optimisation** (PAS d'implémentation). > **Langue** : français. > **Livrable final attendu** : spec prête à passer en plan d'implémentation. --- ## 0. Contexte Cette tâche regroupe les optimisations transverses de `system_update` : - suivi RAM/CPU/base de données dans le footer ; - optimisation des tokens échangés avec Hermes sans perte de donnée ; - auto-nettoyage de la base et des logs anciens ; - découverte de machines disponibles lors de l'ajout, notamment scan du port SSH `22` ; - sécurisation des mots de passe, secrets et entrées sensibles. À lire avant de travailler : - `CLAUDE.md` - `tache5.md` (backend, historique JSON, automatisations) - `tache6.md` (Hermes, MCP, skills) - `shared/types.ts` - `server/db/schema.ts` - `server/index.ts` - `server/jobs/worker.ts` - `client/src/styles/app.css` - `design_system/consigne_design_system.md` Sources web utiles : - OpenAI prompt caching : https://platform.openai.com/docs/guides/prompt-caching - OpenAI latency optimization : https://platform.openai.com/docs/guides/latency-optimization - SQLite WAL : https://www.sqlite.org/wal.html - SQLite PRAGMA / optimize / wal_checkpoint : https://www.sqlite.org/pragma.html - SQLite VACUUM : https://www.sqlite.org/lang_vacuum.html - Nmap Reference Guide : https://nmap.org/book/man.html - Nmap port scanning options : https://nmap.org/book/port-scanning-options.html - MCP sampling / context : https://modelcontextprotocol.io/specification/draft/client/sampling --- ## 1. Objectif Concevoir une couche d'optimisation et d'observabilité qui permette : - de voir l'état technique de la webapp dans le footer ; - de remonter des métriques simples par machine pour les tuiles et Hermes ; - de limiter les tokens envoyés à Hermes tout en conservant toutes les données brutes côté webapp ; - de réduire la taille de la base et des logs anciens avec une politique contrôlée ; - de découvrir automatiquement des machines candidates sur le réseau local lors de l'ajout ; - de renforcer la gestion des mots de passe et secrets côté UI/backend. --- ## 2. Footer observabilité Le footer doit afficher des métriques compactes et utiles : ```text SYSTEM UPDATE · 4 machines · APT 12 · Docker 2 · CPU 8% · RAM 214 MB · DB 42 MB · WAL 3 MB · Jobs 1 · 06:42 ``` Métriques minimales : - nombre de machines ; - updates APT totales ; - updates Docker totales ; - jobs en cours ; - CPU process/backend ; - RAM process/backend ; - taille DB SQLite ; - taille WAL/SHM si SQLite WAL ; - dernier nettoyage ; - état Hermes : connected/disconnected ; - état scheduler : running/paused. Ces métriques concernent le backend `system_update`, pas le monitoring détaillé des hôtes distants. ### Métriques simples par machine Prévoir en complément un snapshot `machine_metrics_simple` par machine : - CPU : load average + nombre de coeurs ; - RAM : total/utilisé/disponible ; - disque : `df -h` lisible et valeurs en bytes ; - inodes ; - uptime ; - température optionnelle si disponible. Usage : - badge/alerte dans la tuile machine ; - rapport global Hermes ; - détection simple disque plein avant upgrade ; - pré-check avant Docker prune ou full-upgrade. Ce n'est pas un remplaçant à Prometheus/Netdata : seulement une mesure légère, agentless, via SSH. Le design doit respecter le design system : - police `Share Tech Mono` ; - cellules compactes ; - icônes via ui-kit si besoin ; - pas de couleurs hors tokens ; - tooltips sur métriques peu évidentes. API à concevoir : ```text GET /api/system/status GET /api/system/metrics GET /api/system/storage ``` Exemple JSON : ```json { "server": { "status": "ok", "uptimeSeconds": 4200, "cpuPercent": 8.2, "memoryRssBytes": 224395264, "memoryHeapUsedBytes": 58200000 }, "database": { "path": "./data/system-update.db", "sizeBytes": 44040192, "walBytes": 3145728, "shmBytes": 32768, "lastOptimizeAt": "2026-06-05T06:00:00Z" }, "jobs": { "running": 1, "queued": 0, "lastScheduleAt": "2026-06-05T06:00:00Z" }, "hermes": { "status": "connected", "lastHealthAt": "2026-06-05T06:41:00Z" } } ``` --- ## 3. Sécurisation mots de passe et secrets Objectif : - éviter toute fuite de mot de passe SSH/sudo/token ; - améliorer l'UX de saisie sans diminuer la sécurité ; - préparer la transition vers clés SSH et politiques de rotation. À concevoir : - stockage chiffré au repos déjà existant à conserver et renforcer ; - séparation mot de passe SSH / mot de passe sudo ; - option "sudo identique au mot de passe SSH" côté formulaire, sans duplication visible ; - bouton afficher/masquer local dans le champ, jamais de log ; - validation minimale : champ vide, port, utilisateur ; - masquage systématique dans logs, terminal, rapports, erreurs API, Hermes/MCP ; - rotation des credentials par machine ; - test de connexion après modification ; - audit d'accès aux secrets ; - jamais de secret dans `UpdateSnapshot`, `ExecutionResult`, rapports Markdown, prompts Hermes, MCP tools ; - interdire stockage navigateur/localStorage/sessionStorage ; - préparer support clés SSH : - clé privée chiffrée ; - passphrase optionnelle ; - fingerprint ; - validation host key ; - ProxyJump futur ; - préparer auth webapp future : - réseau de confiance au MVP ; - reverse proxy/TLS/VPN ; - option comptes utilisateurs/MFA à documenter. Exemple JSON public machine, sans secret : ```json { "machineId": "vm_mqtt", "auth": { "method": "password", "username": "gilles", "hasSudoPassword": true, "lastCredentialTestAt": "ISO", "credentialStatus": "ok" } } ``` Erreurs à prévoir : - `credential_missing` - `credential_decrypt_failed` - `ssh_auth_failed` - `sudo_auth_failed` - `host_key_changed` - `secret_redaction_failed` Le design doit préciser comment masquer les motifs sensibles dans : - stdout/stderr ; - exceptions backend ; - terminal live ; - rapports ; - notifications ; - payloads Hermes. --- ## 4. Optimisation tokens Hermes sans perte de données Principe : > Ne jamais perdre la donnée. Archiver le brut, stocker le JSON complet, envoyer à Hermes un résumé déterministe compact avec références permettant de recharger le détail via MCP. La webapp doit conserver : - log brut complet ; - JSON complet ; - rapport Markdown ; - historique ; - diff réel ; - erreurs structurées. Hermes reçoit par défaut : - snapshot réduit ; - lignes importantes ; - compteurs ; - risques ; - références (`snapshotId`, `executionId`, `reportRef`) ; - liens MCP pour charger le détail à la demande. ### Méthodes de réduction Le design doit prévoir : - reducers déterministes par domaine : - APT ; - Docker ; - post-install ; - reboot ; - erreurs ; - déduplication : - APT : `os_family + package + from + to + origin` ; - Docker : `image + fromDigest + toDigest` ; - post-install : `profileId + version + status` ; - pagination MCP ; - champs courts mais explicites ; - tri stable ; - IDs/références au lieu de répéter les blocs ; - envoi du diff plutôt que snapshot complet quand Hermes connaît déjà l'état précédent ; - résumés hiérarchiques : - global ; - machine ; - action ; - erreur ; - outils MCP `get_detail` pour recharger ce qui manque. ### Prompt caching Les docs OpenAI recommandent de mettre le contenu statique au début des prompts pour bénéficier du cache de préfixe. Design attendu : - préfixe stable Hermes : - rôle ; - règles sécurité ; - contrat JSON ; - mode opératoire ; - données variables à la fin ; - ne pas injecter les logs bruts dans le préfixe ; - mesurer `cached_tokens` quand le fournisseur le renvoie ; - garder les tool schemas stables. ### Exemple payload réduit Hermes ```json { "kind": "global_update_summary", "generatedAt": "ISO", "machines": [ { "id": "vm_mqtt", "name": "vm_mqtt", "status": "updates_available", "apt": { "count": 4, "rebootRequired": false }, "docker": { "updates": 1, "pruneBytes": 734003200 }, "refs": { "snapshotId": "snap_123", "latestExecutionId": "exec_456" } } ], "dedup": { "aptGroups": 3, "dockerGroups": 1 } } ``` Hermes peut ensuite appeler : ```text get_machine_snapshot(machineId, snapshotId) get_machine_execution(machineId, executionId) get_report(reportRef) ``` --- ## 5. Mesure et budget tokens Prévoir une table ou collection `hermes_usage` : - session ; - runId ; - promptTokens ; - cachedTokens ; - completionTokens ; - totalTokens ; - payloadKind ; - payloadBytes ; - reductionRatio ; - model/provider si disponible. Exemple : ```json { "runId": "hermes_run_1", "payloadKind": "global_update_summary", "rawBytes": 940000, "reducedBytes": 18000, "promptTokens": 5200, "cachedTokens": 2100, "completionTokens": 900, "reductionRatio": 0.019 } ``` Objectifs : - savoir combien coûte un rapport global ; - détecter les payloads trop gros ; - ajuster les reducers ; - éviter une dérive silencieuse. --- ## 6. Auto-nettoyage base de données et logs Objectif : - conserver l'historique utile ; - éviter une base ou un dossier `reports/` qui grossit indéfiniment ; - préserver les rapports importants ; - permettre export avant purge. ### Politique de rétention Paramètres à concevoir : ```json { "retention": { "rawLogsDays": 30, "snapshotsDays": 90, "executionsDays": 180, "reportsDays": 365, "importantMessagesDays": 730, "keepFailedExecutionsDays": 365, "keepUnacknowledgedWarningsForever": true, "keepPinnedReportsForever": true } } ``` Règles : - ne jamais supprimer un rapport épinglé ; - garder plus longtemps les erreurs ; - garder plus longtemps les messages importants extraits des logs ; - ne pas supprimer automatiquement les warnings non acquittés sur évolution majeure, sécurité, dépôt obsolète ou dépréciation ; - conserver les derniers N snapshots par machine même si anciens ; - purge en tâche planifiée ; - rapport de purge en JSON ; - mode dry-run obligatoire avant suppression manuelle. Les logs bruts peuvent être supprimés avant les messages importants. Les messages extraits doivent garder : - source (`apt`, `docker`, `post_install`, `ssh`) ; - catégorie ; - sévérité ; - résumé sans secret ; - référence vers le log si encore présent ; - statut acquitté/non acquitté ; - date de première et dernière observation. ### SQLite maintenance SQLite WAL est déjà utilisé dans le projet. À spécifier : - `PRAGMA optimize` périodique ; - `PRAGMA wal_checkpoint(TRUNCATE)` après purge importante ; - `VACUUM` seulement en maintenance contrôlée, car il peut être coûteux et nécessite de l'espace temporaire ; - suivi `dbBytes`, `walBytes`, `freelistCount` ; - politique de sauvegarde avant purge majeure. Exemple tâche : ```json { "action": "database_cleanup", "mode": "dry_run", "deleteCandidates": { "rawLogs": 120, "snapshots": 450, "executions": 12 }, "estimatedBytesReclaimable": 734003200 } ``` --- ## 7. Découverte de machines lors de l'ajout Ajouter dans l'UI "Ajouter une machine" un bouton : ```text [scanner le réseau] ``` But : - trouver des hôtes avec port SSH ouvert ; - afficher une liste de candidats ; - préremplir hostname/IP/port ; - permettre test de connexion. ### Méthodes de découverte MVP recommandé : - scan d'un CIDR configuré : `10.0.0.0/22` ; - détecter port `22/tcp` ouvert ; - récupérer host key via `ssh-keyscan` ou équivalent ; - optionnel : reverse DNS / mDNS ; - affichage candidates dans la webapp. Avec Nmap : ```text nmap -p 22 --open 10.0.0.0/22 ``` `nmap` doit être considéré ici comme outil d'administration réseau contrôlé, pas comme outil offensif. Le scan est limité aux CIDR autorisés et à des ports explicitement configurés. Pour une intégration backend : - utiliser sortie XML `-oX -` et parser proprement ; - ne pas parser du texte humain si une sortie structurée est disponible ; - limiter fréquence et concurrence ; - timeout ; - allowlist réseau ; - confirmation utilisateur. Alternative sans nmap : - scanner TCP simple côté Node ; - plus portable mais moins riche ; - suffisant pour port 22 ouvert ; - pas de fingerprint OS/service. Le design doit comparer MVP `nmap` vs TCP scanner maison. ### JSON candidats ```json { "scanId": "scan_1", "cidr": "10.0.0.0/22", "startedAt": "ISO", "finishedAt": "ISO", "status": "ok", "candidates": [ { "host": "10.0.0.3", "port": 22, "service": "ssh", "hostKeyFingerprint": "SHA256:...", "reverseDns": "vm_mqtt.home", "alreadyKnown": false } ] } ``` ### Sécurité découverte réseau - scan uniquement sur plages autorisées en paramètres ; - désactivé par défaut hors réseau local ; - journaliser scans ; - pas de scan agressif ; - pas de détection intrusive ; - bouton manuel ou schedule explicitement activé. --- ## 8. Paramètres optimisation Créer une section paramètres : ```text Paramètres ├─ Observabilité │ ├─ afficher CPU/RAM/DB dans footer │ ├─ intervalle refresh métriques │ └─ seuils warning ├─ Hermes / tokens │ ├─ mode payload compact │ ├─ limite tokens par rapport │ ├─ reducers actifs │ └─ mesurer usage tokens ├─ Nettoyage │ ├─ rétention logs │ ├─ rétention snapshots │ ├─ rétention warnings importants │ ├─ conserver warnings non acquittés │ ├─ purge auto │ └─ dry-run ├─ Secrets │ ├─ rotation credentials │ ├─ masquage logs │ ├─ méthode auth password/ssh-key │ └─ host key policy └─ Découverte réseau ├─ CIDR autorisés ├─ port SSH ├─ méthode nmap/TCP └─ timeout ``` --- ## 9. Livrables attendus À produire sous `docs/` : 1. Design footer observabilité. 2. Contrat `/api/system/metrics`. 3. Stratégie réduction tokens Hermes sans perte de données. 4. Contrat de mesure usage tokens. 5. Politique de rétention DB/logs/rapports. 6. Plan maintenance SQLite. 7. Design découverte machines SSH. 8. Comparatif nmap vs scanner TCP. 9. Paramètres optimisation. 10. Spec sécurisation mots de passe/secrets. 11. Politique de conservation des messages importants non acquittés. 12. Découpage en sous-jalons. --- ## 10. Définition de terminé - Le footer métriques est spécifié. - Les données brutes restent archivées. - Hermes reçoit un payload compact mais rehydratable. - La mesure tokens est prévue. - L'auto-nettoyage DB/logs est sûr et configurable. - Les messages importants restent analysables même après purge des logs bruts. - La découverte de machines SSH est spécifiée avec garde-fous. - Les mots de passe/secrets sont masqués, chiffrés, testables et jamais envoyés à Hermes/MCP. - Aucun code de production n'est livré pendant cette mission de design. --- ## 11. Technos à utiliser — checklist - [ ] SQLite maintenance : WAL, checkpoint, optimize, vacuum contrôlé. - [ ] Reducers déterministes avant Hermes. - [ ] Mesure usage tokens Hermes. - [ ] `nmap` optionnel pour découverte contrôlée. - [ ] Scanner TCP maison comme alternative MVP. - [ ] `ssh-keyscan` ou équivalent pour fingerprints. - [ ] Chiffrement secrets au repos. - [ ] Redaction logs/UI/Hermes/MCP. - [ ] Schedules de cleanup. - [ ] Metrics backend exposées via API. - [ ] Docker volumes compatibles purge/logs. ## 12. URLs utiles - SQLite WAL : https://www.sqlite.org/wal.html - SQLite `PRAGMA optimize` : https://www.sqlite.org/pragma.html#pragma_optimize - SQLite VACUUM : https://www.sqlite.org/lang_vacuum.html - Nmap reference guide : https://nmap.org/book/man.html - OpenSSH `ssh-keyscan` : https://man.openbsd.org/ssh-keyscan - OWASP Secrets Management Cheat Sheet : https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html - OWASP Logging Cheat Sheet : https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html - OpenAI prompt caching : https://platform.openai.com/docs/guides/prompt-caching - Docker volumes : https://docs.docker.com/engine/storage/volumes/ ## 13. Liens parent/enfant avec les autres tâches - Parents : - `tache5.md` pour API/jobs/rétention. - `tache1.9.md` pour tables metrics/cleanup/discovery. - `tache6.md` pour Hermes/tokens. - Enfants : - `tache3.md` pour footer, smartphone et paramètres. - `tache8.md` pour cache local, tokens client et metrics. - Validation : `validation_tache7.md`.