From f9f805cd8b28638534db70db58ee83afee92f6c1 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Thu, 28 May 2026 19:46:54 +0200 Subject: [PATCH] =?UTF-8?q?chore:=20init=20projet=20=E2=80=94=20spec=20des?= =?UTF-8?q?ign=20+=20design=20system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec complète dans docs/superpowers/specs/2026-05-28-inventaire-hdd-design.md : architecture 2 conteneurs Docker (FastAPI + nginx), script Python stdlib only, SQLite avec serial comme clé de vérité, API ingest + dashboard + agents IA. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 50 + consigne.hd | 240 ++++ design_system/README.md | 304 +++++ design_system/components/ui-kit.jsx | 656 +++++++++++ design_system/consigne_design_system.md | 363 ++++++ design_system/examples/exemple-minimal.html | 115 ++ design_system/examples/exemple-tout.html | 1015 +++++++++++++++++ design_system/tokens/tokens.css | 204 ++++ design_system/tokens/tokens.gnome.css | 378 ++++++ design_system/tokens/tokens.json | 136 +++ .../specs/2026-05-28-inventaire-hdd-design.md | 294 +++++ 11 files changed, 3755 insertions(+) create mode 100644 CLAUDE.md create mode 100644 consigne.hd create mode 100644 design_system/README.md create mode 100644 design_system/components/ui-kit.jsx create mode 100644 design_system/consigne_design_system.md create mode 100644 design_system/examples/exemple-minimal.html create mode 100644 design_system/examples/exemple-tout.html create mode 100644 design_system/tokens/tokens.css create mode 100644 design_system/tokens/tokens.gnome.css create mode 100644 design_system/tokens/tokens.json create mode 100644 docs/superpowers/specs/2026-05-28-inventaire-hdd-design.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..85b6e55 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,50 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Projet + +Script bash one-shot d'inventaire disques (HDD/SSD/NVMe) pour systèmes Debian/Proxmox. Exécuté manuellement une seule fois par machine — pas de cron, pas de daemon, pas de service. + +## Lancement + +```bash +# Local +bash inventaire_hdd.sh + +# À distance (via Gitea) +curl -fsSL https:////mes_hdd/raw/branch/main/inventaire_hdd.sh | bash +``` + +## Architecture du script + +`inventaire_hdd.sh` suit ce pipeline : + +1. Détection machine (hostname, IP via `ip route`) +2. Listage des disques entiers via `lsblk -d -o NAME,TYPE` +3. Pour chaque disque : modèle/série via `lsblk` puis `smartctl -i` en fallback +4. État SMART via `smartctl -H` + `smartctl -A` (traduit en français simple) +5. Type (HDD/SSD/NVMe) via `/sys/block//queue/rotational` +6. Montage/espace via `df -h` +7. Lien `by-id` via `/dev/disk/by-id/` +8. Génération rapport Markdown → `hdd.md` dans le répertoire du script (ou `pwd` si exécuté via pipe) + +## Publication MQTT (à implémenter) + +Le script doit aussi publier un JSON retenu vers : +- broker : `10.0.0.3:1883` (sans auth) +- topic : `hdd/inventaire/` +- flag retain (`mosquitto_pub -r`) + +Format JSON attendu : voir `consigne.hd` section "Format de message conseillé". + +## Prérequis système + +- `smartmontools` (smartctl) — optionnel, géré gracieusement +- `util-linux` (lsblk) +- `mosquitto-clients` (mosquitto_pub) — pour la publication MQTT +- `coreutils` (df, hostname), `iproute2` (ip) + +## Robustesse + +Le script doit continuer l'inventaire même si un disque échoue, si smartctl est absent, ou si le système est une VM sans accès SMART. Chaque erreur est captée localement (pas de `set -e`). diff --git a/consigne.hd b/consigne.hd new file mode 100644 index 0000000..e0b4f44 --- /dev/null +++ b/consigne.hd @@ -0,0 +1,240 @@ +# Consigne pour Claude Code — inventaire HDD/SMART vers MQTT + +## Contexte +Gilles veut un **script Linux lancé une seule fois par machine** pour inventorier les disques d’un système Debian ou Proxmox. + +Le script doit fonctionner sur : +- une machine physique +- une VM +- une VM avec disques pass-through +- une VM avec PCI passthrough si les disques apparaissent dans l’OS invité + +Le but est de **collecter un snapshot à l’instant T** puis de **publier le résultat sur MQTT**. + +Le script doit être stocké dans le même dépôt que le reste du projet : +- dépôt local : `mes_hdd` +- chemin local du projet : `/home/gilles/projects/mes_hdd/` + +Le fichier de consigne doit être copié dans ce projet sous le nom : +- `consigne.hd` + +--- + +## Objectif principal +Créer un script qui : +1. détecte les disques visibles par l’OS +2. identifie chaque disque dans le système +3. lit l’état SMART quand c’est possible +4. récupère la taille du disque +5. récupère les partitions et le taux d’utilisation des points de montage +6. publie un **message MQTT retenu** (`retain`) sur le broker de Gilles +7. s’arrête après une exécution unique + +Il ne faut **pas** prévoir de cron ni d’agent permanent. + +--- + +## Broker MQTT cible +Le script doit publier vers : +- hôte : `10.0.0.3` +- port : `1883` +- sans user ni mot de passe + +Le message doit être **retenu sur le serveur MQTT**. + +La publication doit donc utiliser l’équivalent de : +- `mosquitto_pub ... -r` + +--- + +## Résultat attendu +Le script doit produire un **payload structuré**, idéalement en JSON, contenant au minimum : +- hostname +- IP principale +- date/heure de collecte +- liste des disques +- identifiant système du disque : `sda`, `sdb`, `nvme0n1`, etc. +- chemin du périphérique : `/dev/sdX`, `/dev/nvmeXn1`, etc. +- modèle +- numéro de série +- type : HDD / SSD / NVMe / inconnu +- capacité totale +- partitions détectées +- point de montage associé +- espace libre +- espace total +- taux d’utilisation +- état SMART +- état SMART expliqué en français simple +- remarque / statut + +--- + +## Exigences sur l’état SMART +L’état SMART doit être compréhensible par un novice, en français. + +Exemples de libellés attendus : +- `Bon état` +- `Attention` +- `Défaillance probable` +- `SMART indisponible` + +Le script peut aussi ajouter une explication courte, par exemple : +- `Bon état : aucun problème SMART détecté` +- `Attention : certains indicateurs SMART sont dégradés` +- `Défaillance probable : prévoir le remplacement du disque` + +Le but est que la lecture côté MQTT soit immédiatement compréhensible. + +--- + +## Exigences sur l’identification système +Le script doit identifier clairement les disques visibles sous Linux : +- `sda`, `sdb`, `sdc`, … +- `nvme0n1`, `nvme1n1`, … +- si possible, inclure aussi le lien `/dev/disk/by-id/...` + +L’objectif est de relier : +- le nom logique dans l’OS +- le modèle du disque +- le numéro de série +- les partitions +- le point de montage +- l’usage réel + +--- + +## Exigences sur les partitions et l’espace +Pour chaque disque, si des partitions ou des montages existent, récupérer : +- la liste des partitions +- le point de montage +- l’espace libre +- l’espace total +- le taux d’utilisation + +Si un disque n’a pas de filesystem monté, le script doit l’indiquer clairement. + +--- + +## Robustesse +Le script doit rester robuste si : +- un disque ne répond pas +- `smartctl` échoue +- un disque n’est pas monté +- SMART n’est pas accessible depuis l’environnement +- le système est une VM et ne voit pas tous les disques physiques sous-jacents + +Le script ne doit pas casser l’inventaire global si un disque est problématique. + +--- + +## Mode d’exécution +Le script doit être **exécuté une seule fois** par machine. + +Il ne faut pas créer : +- de service permanent +- de daemon +- de cron +- de timer systemd + +Le mode attendu est une exécution manuelle ou à distance ponctuelle. + +--- + +## Publication MQTT +Le script doit publier le résultat : +- sur un topic dédié par machine, par exemple `hdd/inventaire/` +- en **JSON** si possible +- avec le mode **retain** activé + +Le message retenu permettra à un client MQTT de relire le dernier état plus tard. + +--- + +## Format de message conseillé +Exemple de structure JSON : + +```json +{ + "hostname": "pve1", + "ip": "10.0.3.205", + "timestamp": "2026-05-28T15:30:00+02:00", + "disks": [ + { + "device": "sda", + "path": "/dev/sda", + "by_id": "/dev/disk/by-id/...", + "model": "ST1000LM024", + "serial": "...", + "type": "HDD", + "capacity": "1T", + "smart": "Bon état", + "smart_detail": "Bon état : aucun problème SMART détecté", + "partitions": [ + { + "name": "sda1", + "mountpoint": "/mnt/data", + "free": "500G", + "total": "1T", + "used_percent": 50 + } + ] + } + ] +} +``` + +--- + +## Fichier de sortie local +Même si la destination principale est MQTT, le script peut aussi générer localement : +- un fichier JSON temporaire +- ou un fichier Markdown de debug si utile + +Mais ce n’est pas obligatoire. + +--- + +## Lancement à distance +Prévoir une méthode simple pour exécuter le script à distance, par exemple : +- `curl ... | bash` +- ou téléchargement puis exécution +- ou script brut servi depuis le dépôt Gitea + +La méthode distante doit être : +- documentée +- reproductible +- sans secret en clair + +--- + +## Source de vérité fonctionnelle +Le script doit s’appuyer sur des outils simples et standards : +- `lsblk` +- `df` +- `smartctl` +- `hostname` +- `ip` +- `mosquitto_pub` + +--- + +## Critères de qualité +- code lisible +- exécution unique +- sortie JSON claire +- état SMART compréhensible en français +- publication MQTT retenue +- aucune dépendance inutile +- pas de cron +- pas d’agent permanent + +--- + +## Attendu de Claude Code +Claude Code doit : +1. proposer l’architecture minimale du script +2. créer le script dans `mes_hdd` +3. documenter le topic MQTT et le format JSON +4. prévoir la publication retenue +5. vérifier que le résultat est simple à exploiter sur MQTT diff --git a/design_system/README.md b/design_system/README.md new file mode 100644 index 0000000..a0ee628 --- /dev/null +++ b/design_system/README.md @@ -0,0 +1,304 @@ +# mon design system — Gruvbox seventies + +> Design system rétro-futuriste pour applications de monitoring, ops, IoT, domotique. +> Orange brûlé, fond brun délavé en sombre / gris clair usé en clair. +> **Version 1.0** · deux thèmes (dark + light), 14+ composants React, palette GTK pour GNOME. + +--- + +## 🚀 Démarrage rapide (web) + +```html + + + + + + + + + + + + + + + + + + +
+ + + + + +``` + +Pour voir tout fonctionner, ouvre `examples/exemple-minimal.html`. + +--- + +## 📂 Contenu du package + +``` +export/ +├── README.md ← Ce fichier +├── consigne_design_system.md ← Brief pour agents IA (Claude, ChatGPT…) +├── tokens/ +│ ├── tokens.css ← Variables CSS web (dark + light) +│ ├── tokens.gnome.css ← GTK 4 / libadwaita (apps GNOME) +│ └── tokens.json ← Format générique (Tailwind, Figma…) +├── components/ +│ └── ui-kit.jsx ← 14 composants React (Button, IconButton, Toggle, Tooltip, +│ StatusLed, BatteryGauge, RadialGauge, BigRadialGauge, +│ Popup, TreeNav, Sparkline, LineChart, Icon, …) +└── examples/ + └── exemple-minimal.html ← Démo minimale autoportante +``` + +--- + +## 🎨 Ce qui est paramétrable + +### 1. Thème global + +```html + +``` + +Tu peux mettre `data-theme` sur **n'importe quel parent** pour basculer un sous-arbre uniquement (utile pour une preview en mode opposé dans un menu de réglages). + +### 2. Toutes les couleurs (CSS variables) + +Édite `tokens.css` ou surcharge dans ton propre CSS : + +```css +:root[data-theme="dark"] { + --accent: #fe8019; /* Couleur principale (orange seventies) */ + --accent-soft: #d65d0e; + --bg-1: #2a231d; /* Fond app */ + --bg-3: #3c332a; /* Cartes */ + --ink-1: #f2e5c7; /* Texte */ + --ok: #4dbb26; + --warn: #fabd2f; + --err: #fb4934; + --blue: #3db0d1; /* Datavis additionnel */ + --purple: #c882c8; +} +``` + +**4 statuts** (ok / warn / err / info) + **2 couleurs datavis** (blue / purple) + **6 niveaux de fond** + **4 niveaux d'encre** + **3 niveaux de bordure**. + +### 3. Polices + +Trois familles, toutes substituables : + +| Variable | Usage | Défaut | +|-----------------|-------------------------------------|---------------------| +| `--font-ui` | Interface (titres, corps, boutons) | Inter | +| `--font-mono` | Données, code, valeurs numériques | JetBrains Mono | +| `--font-terminal` | Logs, terminal embarqué, vibe rétro | Share Tech Mono | + +Pour changer, remplace simplement les `@import` Google Fonts et redéfinis les variables. + +### 4. Ombres et relief + +```css +--tile-3d /* Relief 3D marqué pour cartes */ +--shadow-1, -2, -3 /* Niveaux d'élévation */ +--shadow-press /* Inset pour état pressé */ +--hover-glow /* Halo accent au survol */ +``` + +### 5. Composants — props paramétrables + +Chaque composant accepte des props pour personnaliser sans toucher au CSS. Exemples : + +```jsx + + + + + + + + + + + + + Contenu + + + +``` + +Voir la doc complète des props : `Component Reference.html` dans le projet original. + +--- + +## 🐧 Utilisation dans une app GNOME (GTK 4 / libadwaita) + +Charge `tokens/tokens.gnome.css` comme provider CSS au démarrage de l'app. + +**Python (PyGObject)** : +```python +from gi.repository import Gtk, Gdk + +css_provider = Gtk.CssProvider() +css_provider.load_from_path("tokens.gnome.css") +Gtk.StyleContext.add_provider_for_display( + Gdk.Display.get_default(), + css_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION +) +``` + +**GJS** : +```javascript +const provider = new Gtk.CssProvider(); +provider.load_from_path('tokens.gnome.css'); +Gtk.StyleContext.add_provider_for_display( + Gdk.Display.get_default(), + provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION +); +``` + +**Rust (gtk4-rs)** : +```rust +let provider = gtk::CssProvider::new(); +provider.load_from_path("tokens.gnome.css"); +gtk::style_context_add_provider_for_display( + &gdk::Display::default().unwrap(), + &provider, + gtk::STYLE_PROVIDER_PRIORITY_APPLICATION, +); +``` + +Le fichier override directement les couleurs sémantiques de libadwaita (`@window_bg_color`, `@accent_color`, etc.) ET ajoute des styles spécifiques pour les widgets courants : `button.suggested-action`, `entry`, `switch`, `scale`, `progressbar`, `notebook`, `popover`… + +Classes CSS supplémentaires à appliquer via `add_css_class()` : +- `.tile` / `.card` — Tuile en relief 3D +- `.mono` — Texte monospace JetBrains Mono +- `.terminal` — Texte terminal Share Tech Mono +- `.status.ok` / `.status.warn` / `.status.error` / `.status.info` — Badge de statut + +--- + +## 🔧 Intégration dans d'autres outils + +### Tailwind CSS + +Convertis `tokens.json` en `tailwind.config.js` : + +```js +const tokens = require('./tokens/tokens.json'); +module.exports = { + theme: { + extend: { + colors: { + accent: tokens.themes.dark.accent.primary.value, + ok: tokens.themes.dark.status.ok.value, + // … + }, + fontFamily: { + sans: [tokens.typography.fonts.ui.family, ...tokens.typography.fonts.ui.fallback], + mono: [tokens.typography.fonts.mono.family], + }, + }, + }, +}; +``` + +### Figma / outils de design + +`tokens.json` suit un schéma compatible avec la plupart des plugins de tokens (Figma Tokens, Style Dictionary). Importe-le directement. + +### Variables Sass / SCSS + +```scss +@use 'sass:map'; +$tokens: ( + accent: #fe8019, + bg-1: #2a231d, + ok: #4dbb26, +); +// … +``` + +--- + +## ⚙️ Personnalisation avancée + +### Créer un thème dérivé + +Duplique `tokens.css`, change le nom du sélecteur (`[data-theme="ocean"]` par exemple) et modifie les variables. Charge les deux fichiers — `data-theme` choisira automatiquement. + +### Ajouter une couleur status custom + +```css +:root[data-theme="dark"] { + --critical: #ff0080; + --critical-glow: rgba(255, 0, 128, 0.45); +} +``` + +Utilisable ensuite partout : `` nécessite une PR dans `ui-kit.jsx` (carte `map` dans `StatusLed`), mais en raw CSS tu peux utiliser la variable directement. + +### Désactiver les effets + +Tous les effets de `transition` / `transform` / `box-shadow` sont concentrés dans les classes `.interactive`, `.bg-hover`, `.gauge-hover`. Surcharge-les en CSS si besoin : + +```css +.interactive { transition: none !important; } +``` + +--- + +## ✅ Checklist d'intégration + +- [ ] Polices Google Fonts chargées (Inter, JetBrains Mono, Share Tech Mono) +- [ ] Font Awesome 6 chargé +- [ ] `tokens.css` (web) **ou** `tokens.gnome.css` (GTK) chargé +- [ ] Attribut `data-theme="dark"` (ou "light") sur `` ou un parent +- [ ] React 18 + Babel chargés (uniquement pour `ui-kit.jsx`) +- [ ] `ui-kit.jsx` chargé en `type="text/babel"` + +--- + +## 📋 Statuts du système + +| Couleur | Token | Hex (dark) | Hex (light) | Usage | +|---------|--------|------------|-------------|-----------------------------| +| Accent | `--accent` | `#fe8019` | `#af3a03` | Primaire, focus, sélection | +| OK | `--ok` | `#4dbb26` | `#3c911c` | Succès, état nominal | +| Warn | `--warn` | `#fabd2f` | `#b57614` | Attention, latence élevée | +| Err | `--err` | `#fb4934` | `#9d0006` | Erreur, alerte critique | +| Info | `--info` | `#83a598` | `#427b58` | Information neutre | +| Blue | `--blue` | `#3db0d1` | `#2d82a3` | Datavis catégorie 2 | +| Purple | `--purple` | `#c882c8` | `#8c468c` | Datavis catégorie 3 | + +--- + +## 🤖 Pour les agents IA + +Si tu utilises ce design system avec une IA (Claude, GPT, Copilot, etc.), partage-lui le fichier **`consigne_design_system.md`**. Il y trouvera toutes les règles d'utilisation, conventions, contre-exemples à éviter. + +--- + +**Licence** · Usage libre dans tes projets. Pas de garantie. diff --git a/design_system/components/ui-kit.jsx b/design_system/components/ui-kit.jsx new file mode 100644 index 0000000..92f9e76 --- /dev/null +++ b/design_system/components/ui-kit.jsx @@ -0,0 +1,656 @@ +/* ============================================================ + ui-kit.jsx + Composants haute-fid Gruvbox Seventies. + Tout est purement décoratif/interactif côté composant. + Effets : transparence (glass), hover glow, click 3D, tooltips. + ============================================================ */ + +const { useState, useRef, useEffect } = React; + +/* ============================================================ + Icônes — Font Awesome 6 Free. + Mapping nom logique → classe FA. Le CSS de FA est chargé en CDN + dans le . Le composant garde la MÊME API qu'avant (name, + size, style) pour ne rien casser ailleurs. + ============================================================ */ +const ICON_MAP = { + cpu: 'microchip', + memory: 'memory', + disk: 'hard-drive', + network: 'network-wired', + clock: 'clock', + grid: 'table-cells', + list: 'list', + cog: 'gear', + alert: 'triangle-exclamation', + bell: 'bell', + server: 'server', + chart: 'chart-line', + bars: 'chart-simple', + terminal: 'terminal', + refresh: 'arrows-rotate', + play: 'play', + pause: 'pause', + power: 'power-off', + sun: 'sun', + moon: 'moon', + search: 'magnifying-glass', + close: 'xmark', + chevR: 'chevron-right', + chevL: 'chevron-left', + chevD: 'chevron-down', + chevU: 'chevron-up', + plus: 'plus', + filter: 'filter', + download: 'download', + folder: 'folder', + node: 'circle-nodes', + user: 'user', +}; + +const Icon = ({ name, size = 16, style }) => { + const fa = ICON_MAP[name] || 'circle-question'; + return ( +