# 🔍 Rapport d'Audit Technique StratĂ©gique — Homelab Automation Dashboard v2.0 > **Date de l'audit :** 20 fĂ©vrier 2026 > **Auditeur :** Architecte Logiciel Full-Stack Senior / SpĂ©cialiste DevOps / Expert UI/UX > **Version analysĂ©e :** 2.0.0 > **Stack :** FastAPI · SQLAlchemy Async · SQLite (aiosqlite) · APScheduler · Ansible · WebSocket · HTML/JS/Tailwind/Anime.js --- ## Table des MatiĂšres 1. [SynthĂšse ExĂ©cutive](#1-synthĂšse-exĂ©cutive) 2. [Audit d'Architecture et de SĂ©curitĂ© đŸ›Ąïž](#2-audit-darchitecture-et-de-sĂ©curitĂ©-) 3. [Corrections et Optimisations Code/Performances ⚙](#3-corrections-et-optimisations-codeperformances-) 4. [AmĂ©liorations UI/UX 🎹](#4-amĂ©liorations-uiux-) 5. [IdĂ©es d'Évolution "Next Level" 🚀](#5-idĂ©es-dĂ©volution-next-level-) 6. [Feuille de Route Actionnable đŸ—ș](#6-feuille-de-route-actionnable-) --- ## 1. SynthĂšse ExĂ©cutive ### Vue d'ensemble du Projet Le Homelab Automation Dashboard est une application **self-hosted** impressionnante qui centralise la gestion d'infrastructure via Ansible, avec planification de tĂąches, monitoring Docker via SSH, un terminal SSH intĂ©grĂ© via ttyd, et des notifications push via ntfy. L'application a atteint un niveau de maturitĂ© fonctionnel **solide** avec une architecture bien structurĂ©e (Factory pattern, Repository pattern, sĂ©paration services/routes/schemas/models). ### Points Forts ✅ | Domaine | ApprĂ©ciation | |---------|-------------| | **Architecture modulaire** | Excellente sĂ©paration : `routes/`, `services/`, `models/`, `schemas/`, `crud/`, `core/` | | **Migrations Alembic** | 19 migrations bien structurĂ©es avec convention de nommage | | **ExĂ©cution Ansible async** | `asyncio.create_subprocess_exec` — ne bloque **pas** l'event loop ✅ | | **Service de notification** | Design robuste, never-throw, async, avec templates et filtrage par niveau | | **Gestion des sessions terminal** | Architecture GC + heartbeat + session reuse bien pensĂ©e | | **Docker monitoring** | Collection SSH + semaphore concurrency limiter + upsert/stale cleanup | | **Startup checks** | Service de vĂ©rification des prĂ©requis complet et bien reportĂ© | | **Exceptions typĂ©es** | HiĂ©rarchie d'exceptions mĂ©tier bien conçue (HomelabException) | ### Points d'Attention ⚠ | Domaine | SĂ©vĂ©ritĂ© | RĂ©sumĂ© | |---------|----------|--------| | **Secrets en `.env` committĂ©** | 🔮 Critique | `.env` contient `API_KEY`, `JWT_SECRET_KEY` en clair dans le repo | | **`app_optimized.py` monolithique** | 🟠 Haute | 6585 lignes — fichier "God Object" qui duplique toute l'architecture | | **WebSocket sans authentification** | 🟠 Haute | `/ws` n'exige aucun token/clĂ© API | | **Bootstrap : mot de passe root en transit** | 🟠 Haute | `root_password` transmis en clair dans la requĂȘte HTTP | | **`threading.Lock` dans WebSocket** | 🟡 Moyenne | Devrait ĂȘtre `asyncio.Lock` pour la cohĂ©rence async | | **CORS `allow_origins=["*"]`** | 🟡 Moyenne | PrĂ©sent dans `app_optimized.py` et en production potentielle | | **Coverage Ă  45%** | 🟡 Moyenne | Seuil minimal, certaines zones critiques non couvertes | --- ## 2. Audit d'Architecture et de SĂ©curitĂ© đŸ›Ąïž ### 2.1 Authentification & Gestion des Secrets #### JWT — ImplĂ©mentation Solide avec RĂ©serves L'implĂ©mentation JWT utilise `python-jose` avec `bcrypt` pour le hashing des mots de passe. C'est un bon choix. **✅ Points positifs :** - Hashing bcrypt avec sel alĂ©atoire (`bcrypt.gensalt()`) - Token avec `exp` et `iat` claims - Double mode d'authentification (API Key + JWT Bearer) - Setup initial protĂ©gĂ© (uniquement si 0 utilisateurs) - Changement de mot de passe avec vĂ©rification de l'ancien **🔮 ProblĂšmes critiques :** ```python # auth_service.py, ligne 20 SECRET_KEY = os.environ.get("JWT_SECRET_KEY", "homelab-secret-key-change-in-production") ``` | ProblĂšme | Impact | Recommandation | |----------|--------|----------------| | **ClĂ© secrĂšte par dĂ©faut faible** | Un attaquant connaissant le code source peut forger des JWT valides | GĂ©nĂ©rer une clĂ© de 256 bits minimum au premier dĂ©marrage, stocker dans un fichier protĂ©gĂ© | | **Pas de rotation des clĂ©s** | Compromission permanente si la clĂ© est exposĂ©e | ImplĂ©menter JWK (JSON Web Key) avec rotation pĂ©riodique | | **Pas de refresh token** | L'utilisateur doit se reconnecter aprĂšs expiration | Ajouter un systĂšme refresh/access token | | **Pas de rĂ©vocation de token** | Impossible de dĂ©connecter un utilisateur compromis | Maintenir une blacklist en cache (Redis ou in-memory) | #### `.env` CommitĂ© dans le Repository ``` # .env (commitĂ© dans git !) API_KEY=dev-key-1234567890 JWT_SECRET_KEY=dev-key-67890 ``` **🔮 CRITIQUE :** Le fichier `.env` est **commitĂ©** et contient des secrets en clair. MĂȘme si ce sont des valeurs de dĂ©veloppement, cela crĂ©e un risque car : 1. Les dĂ©veloppeurs pourraient dĂ©ployer avec ces valeurs 2. L'historique Git conserve les secrets mĂȘme aprĂšs suppression **Recommandations :** 1. Ajouter `.env` au `.gitignore` immĂ©diatement 2. Conserver uniquement un `.env.example` avec des valeurs placeholder 3. Utiliser `python-dotenv` avec validation obligatoire des secrets au dĂ©marrage 4. Pour la production, envisager HashiCorp Vault ou `docker secrets` #### Gestion des ClĂ©s SSH **✅ Points positifs :** - Recherche intelligente multi-emplacement (`find_ssh_private_key`) - VĂ©rification des permissions sur Linux/Mac - Support de multiples types de clĂ©s (RSA, Ed25519, ECDSA) **⚠ Points d'attention :** ```python # ssh_utils.py, ligne 103 & terminal_service.py, ligne 363 "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null", ``` Cela dĂ©sactive la vĂ©rification TOFU (Trust On First Use), ce qui est acceptable pour un homelab mais devrait ĂȘtre configurable. ```python # docker_service.py, ligne 88 known_hosts=None, # Accept any host key (homelab environment) ``` **Recommandation :** Ajouter un paramĂštre `STRICT_HOST_KEY_CHECKING` configurable avec une valeur par dĂ©faut `no` pour le homelab, `yes` pour la production. #### Bootstrap — Mot de Passe Root en Transit ```python # routes/bootstrap.py, ligne 98 result = bootstrap_host( host=request.host, root_password=request.root_password, # ⚠ En clair dans la requĂȘte automation_user=request.automation_user ) ``` Le mot de passe root est transmis dans le corps de la requĂȘte HTTP. En l'absence de HTTPS, il circule en clair. **Recommandations :** 1. **Exiger HTTPS** pour les endpoints sensibles (bootstrap, auth) 2. Ajouter un avertissement dans les logs si la requĂȘte arrive en HTTP 3. Envisager un chiffrement cĂŽtĂ© client avec une clĂ© Ă©phĂ©mĂšre (Diffie-Hellman) 4. Limiter le rate-limiting sur `/api/bootstrap` (anti brute-force) ### 2.2 Robustesse de l'API FastAPI #### Architecture Dual — Le ProblĂšme `app_optimized.py` L'application maintient **deux architectures parallĂšles** : | Fichier | Lignes | RĂŽle | |---------|--------|------| | `app/factory.py` + routes modulaires | ~10k+ | Architecture propre, modulaire | | `app/app_optimized.py` | **6585** | Monolithe qui duplique tout | **🟠 ProblĂšme majeur :** `app_optimized.py` est un "God File" de 6585 lignes contenant : - ModĂšles Pydantic (dupliquĂ©s de `schemas/`) - Services (dupliquĂ©s de `services/`) - Routes (dupliquĂ©es de `routes/`) - Gestion de base de donnĂ©es en mĂ©moire **et** SQLite synchrone - Un scheduler complet **Recommandation :** Supprimer `app_optimized.py` et ne conserver que l'architecture modulaire. Ce fichier semble ĂȘtre l'ancienne version monolithique conservĂ©e "au cas oĂč" mais il crĂ©e de la confusion et un risque de rĂ©gression. #### Gestion de la Base de DonnĂ©es SQLite Async **✅ Excellente configuration :** ```python # models/database.py engine = create_async_engine(DATABASE_URL, pool_pre_ping=True, future=True) # Pragmas SQLite bien configurĂ©s cursor.execute("PRAGMA foreign_keys=ON") cursor.execute("PRAGMA journal_mode=WAL") # Avec fallback sur DELETE ``` **✅ Session management correct :** ```python async def get_db() -> AsyncGenerator[AsyncSession, None]: async with async_session_maker() as session: try: yield session except Exception: await session.rollback() raise finally: await session.close() ``` **⚠ Points d'attention :** 1. **Pas de connection pooling avancĂ©** : SQLite single-writer peut devenir un bottleneck sous charge Ă©levĂ©e. Envisager `pool_size` et `max_overflow` quand/si migration vers PostgreSQL. 2. **`expire_on_commit=False`** : C'est le bon choix pour l'async, mais peut causer des donnĂ©es stale si les sessions sont longues. Actuellement OK car les sessions sont scoped aux requĂȘtes. 3. **Migration Alembic dans `init_db()`** : L'exĂ©cution de `alembic upgrade head` Ă  chaque dĂ©marrage est robuste mais peut ĂȘtre lente si beaucoup de migrations. Ajouter un check "already at head" avant d'exĂ©cuter. ### 2.3 Communication WebSocket #### WebSocket Manager — Simple mais Fonctionnel ```python # websocket_service.py class WebSocketManager: def __init__(self): self.active_connections: List[WebSocket] = [] self.lock = Lock() # ⚠ threading.Lock au lieu de asyncio.Lock ``` **🟡 ProblĂšme : `threading.Lock` en contexte async** L'utilisation de `threading.Lock` dans la mĂ©thode `broadcast` (qui est `async`) peut causer un deadlock si jamais le lock est contenu quand l'event loop essaie d'envoyer un message WebSocket qui nĂ©cessite un `await`. ```python # Actuel (problĂ©matique) async def broadcast(self, message: dict): with self.lock: # ⚠ Bloque le thread de l'event loop for connection in self.active_connections: await connection.send_json(message) # ← await sous un Lock synchrone ``` **La correction devrait ĂȘtre :** ```python async def broadcast(self, message: dict): async with self._lock: # asyncio.Lock disconnected = [] for connection in self.active_connections: try: await connection.send_json(message) except Exception: disconnected.append(connection) for conn in disconnected: self.active_connections.remove(conn) ``` **🔮 WebSocket sans authentification :** ```python # routes/websocket.py, ligne 22-32 @router.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): await ws_manager.connect(websocket) # ⚠ Aucune vĂ©rification d'identitĂ© ``` N'importe qui peut se connecter au WebSocket et recevoir toutes les notifications systĂšme (tĂąches, bootstrap, statuts). C'est un **vecteur de fuite d'information**. **Recommandation :** VĂ©rifier le JWT via query parameter lors du handshake WebSocket : ```python @router.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): token = websocket.query_params.get("token") if not token or not decode_token(token): await websocket.close(code=4001, reason="Authentication required") return await ws_manager.connect(websocket) ``` #### Terminal WebSocket Proxy Le proxy terminal (`/terminal/ws/{session_id}`) a une **bonne implĂ©mentation de sĂ©curitĂ©** : - ✅ Token vĂ©rifiĂ© via hash SHA-256 - ✅ `secrets.compare_digest` pour la comparaison (timing-safe) - ✅ Session validĂ©e en base de donnĂ©es **⚠ ProblĂšme mineur dans le proxy :** ```python # websocket.py, ligne 104 data = await reader.readexactly(1024) # ⚠ Attend exactement 1024 octets ``` `readexactly` attend exactement N bytes ou lĂšve `IncompleteReadError`. Cela peut causer des latences si le terminal envoie moins de 1024 bytes. Utiliser `reader.read(4096)` Ă  la place : ```python data = await reader.read(4096) if not data: break ``` ### 2.4 Planificateur de TĂąches (APScheduler) **✅ Configuration solide :** - `coalesce=True` : Ă©vite les exĂ©cutions multiples si le scheduler rattrape son retard - `max_instances=1` : empĂȘche les exĂ©cutions parallĂšles du mĂȘme job - `misfire_grace_time` configurable - Persistance en base de donnĂ©es avec rechargement au dĂ©marrage **⚠ Risque de "Schedule Orphan" :** Si l'application crash pendant l'exĂ©cution d'un schedule, le `ScheduleRun` restera en statut `running` indĂ©finiment. Ajouter une vĂ©rification au dĂ©marrage pour marquer les runs "orphelins" comme `failed`. **⚠ Jobs Docker hardcodĂ©s :** ```python # factory.py, lignes 182-198 scheduler_service.scheduler.add_job( docker_service.collect_all_hosts, trigger="interval", seconds=60, # Toutes les minutes id="docker_collect", ) ``` Les intervalles sont hardcodĂ©s. Rendre configurable via variables d'environnement (`DOCKER_COLLECT_INTERVAL`, `DOCKER_ALERTS_INTERVAL`). --- ## 3. Corrections et Optimisations Code/Performances ⚙ ### 3.1 Anti-Patterns IdentifiĂ©s #### AP-1 : Fichier Monolithique `app_optimized.py` | MĂ©trique | Valeur | |----------|--------| | Lignes | 6585 | | Classes | ~30+ | | Fonctions | ~200+ | | Impact | Maintenance, lisibilitĂ©, testabilitĂ© | **Action :** Supprimer ce fichier et s'appuyer uniquement sur l'architecture modulaire existante (qui est dĂ©jĂ  complĂšte et fonctionnelle). #### AP-2 : Import Circulaire ProtĂ©gĂ© par Try/Except ```python # notification_service.py, lignes 32-47 try: from schemas.notification import (...) except ModuleNotFoundError: from app.schemas.notification import (...) ``` Ce pattern indique une incertitude sur le `sys.path`. C'est un symptĂŽme de `app_optimized.py` qui fonctionne avec un chemin diffĂ©rent. **Action :** AprĂšs suppression de `app_optimized.py`, utiliser uniquement les imports absolus `from app.schemas...`. #### AP-3 : Double SystĂšme de Persistance (HybridDB) Le service `HybridDB` (`services/hybrid_db.py`) maintient des donnĂ©es **en mĂ©moire** (listes Python) en parallĂšle avec SQLite. Cela crĂ©e une incohĂ©rence potentielle. ```python # routes/bootstrap.py, ligne 140 db.logs.insert(0, log_entry) # ← MĂ©moire ``` vs. ```python # Ailleurs dans le code repo = LogRepository(session) await repo.create(...) # ← SQLite ``` **Action :** Migrer entiĂšrement vers le pattern Repository + SQLite. Le `HybridDB` est un vestige de l'ancienne architecture. #### AP-4 : Fonctions Synchrones Bloquantes ```python # ssh_utils.py, lignes 128-133 result = subprocess.run( # ⚠ BLOQUE l'event loop ssh_cmd, capture_output=True, text=True, timeout=timeout + 10 ) ``` La fonction `bootstrap_host()` utilise `subprocess.run` synchrone et est appelĂ©e depuis une route `async` : ```python # routes/bootstrap.py, ligne 98 result = bootstrap_host(...) # ← Appel synchrone dans une route async ``` Cela **bloque l'event loop** pendant toute la durĂ©e du bootstrap (jusqu'Ă  120 secondes). **Correction :** ```python # Utiliser asyncio.to_thread pour les opĂ©rations bloquantes result = await asyncio.to_thread( bootstrap_host, host=request.host, root_password=request.root_password, automation_user=request.automation_user ) ``` Ou mieux, réécrire `bootstrap_host` avec `asyncio.create_subprocess_exec` comme `ansible_service.execute_playbook` le fait dĂ©jĂ  correctement. #### AP-5 : `asyncio.create_task` Sans RĂ©fĂ©rence ```python # routes/bootstrap.py, ligne 152 asyncio.create_task(notification_service.notify_bootstrap_success(host_name)) ``` Les tĂąches créées avec `asyncio.create_task` sans rĂ©fĂ©rence peuvent ĂȘtre garbage-collectĂ©es avant leur fin si rien ne les retient. De plus, les exceptions non attrapĂ©es dans ces tĂąches seront silencieusement perdues. **Correction :** ```python # Stocker une rĂ©fĂ©rence et ajouter un callback d'erreur background_tasks = set() task = asyncio.create_task(notification_service.notify_bootstrap_success(host_name)) background_tasks.add(task) task.add_done_callback(background_tasks.discard) ``` Ou utiliser `BackgroundTasks` de FastAPI : ```python from fastapi import BackgroundTasks @router.post("", response_model=CommandResult) async def bootstrap_ansible_host( request: BootstrapRequest, background_tasks: BackgroundTasks, api_key_valid: bool = Depends(verify_api_key) ): # ... background_tasks.add_task(notification_service.notify_bootstrap_success, host_name) ``` ### 3.2 Goulots d'Étranglement IdentifiĂ©s #### GE-1 : Scan SystĂšme de Fichiers pour les Logs de TĂąches ```python # app_optimized.py, lignes 519-565 def _build_index(self, force: bool = False): for year_dir in self.base_dir.iterdir(): for month_dir in year_dir.iterdir(): for day_dir in month_dir.iterdir(): for md_file in day_dir.glob("*.md"): # Parse chaque fichier ``` Ce scan rĂ©cursif du systĂšme de fichiers Ă  chaque appel (avec un cache de 60 secondes) sera lent si des centaines/milliers de fichiers de logs s'accumulent. **Optimisation :** Le service `TaskLogService` dans `services/task_log_service.py` devrait indexer les logs en base de donnĂ©es plutĂŽt que scanner le filesystem. CrĂ©er une table `task_logs_index` : ```sql CREATE TABLE task_logs_index ( id TEXT PRIMARY KEY, filename TEXT NOT NULL, path TEXT NOT NULL, task_name TEXT, target TEXT, status TEXT, date TEXT, source_type TEXT, created_at TIMESTAMP, metadata_json TEXT ); ``` #### GE-2 : Docker Collection SĂ©quentielle par HĂŽte La collecte Docker utilise un semaphore de 5, ce qui est bien, mais chaque hĂŽte fait 4 commandes SSH sĂ©quentielles (`docker version`, `docker ps`, `docker images`, `docker volume ls`). **Optimisation :** Combiner les commandes en une seule session SSH : ```python combined_cmd = """ echo '---VERSION---' docker version --format '{{.Server.Version}}' echo '---CONTAINERS---' docker ps -a --format '{{json .}}' --no-trunc echo '---IMAGES---' docker images --format '{{json .}}' echo '---VOLUMES---' docker volume ls --format '{{json .}}' """ stdout, stderr, code = await self._ssh_exec(conn, combined_cmd, timeout=30) # Parser les sections ``` Cela rĂ©duit le nombre de round-trips SSH de 4 Ă  1 par hĂŽte. #### GE-3 : `index.html` Monolithique (247 KB) Le fichier `index.html` fait **247 KB** et `main.js` fait **617 KB**. Ces fichiers ne sont ni minifiĂ©s ni compressĂ©s. **Optimisations :** 1. Activer la compression gzip/brotli via middleware FastAPI 2. Ajouter des headers de cache (`Cache-Control`, `ETag`) 3. Diviser `main.js` en modules ES (chargement paresseux des sections) ### 3.3 AmĂ©liorations des Pratiques de Code #### Python — Bonnes Pratiques | # | Recommandation | Fichier(s) | PrioritĂ© | |---|---------------|------------|----------| | 1 | Utiliser `Annotated` de typing pour les dĂ©pendances FastAPI | Toutes les routes | Basse | | 2 | Remplacer `@app.on_event("startup")` par les `lifespan` events (FastAPI 0.93+) | `factory.py` | Moyenne | | 3 | Ajouter des type hints manquants dans `HybridDB` | `services/hybrid_db.py` | Basse | | 4 | Utiliser `logging` au lieu de `print()` dans `factory.py` | `factory.py` (15+ prints) | Moyenne | | 5 | Remplacer les f-strings dans les loggers par `%s` formatage | Partout | Basse | | 6 | Ajouter `__slots__` aux dataclasses de configuration | `core/config.py` | Basse | | 7 | Utiliser `enum.StrEnum` pour les statuts (`"running"`, `"failed"`, etc.) | `schemas/`, `models/` | Moyenne | #### Python — SĂ©curitĂ© du Code ```python # routes/bootstrap.py, ligne 92-94 — Import Ă  l'intĂ©rieur de la fonction import logging import traceback logger = logging.getLogger("bootstrap_endpoint") ``` **Recommandation :** DĂ©placer les imports et la crĂ©ation du logger au niveau du module (en haut du fichier). #### JavaScript — Bonnes Pratiques | # | Recommandation | Fichier | PrioritĂ© | |---|---------------|---------|----------| | 1 | Migrer de `var` vers `const/let` | `main.js` | Moyenne | | 2 | Utiliser ES Modules (`import/export`) au lieu du scope global | `main.js` et `*.js` | Haute | | 3 | Ajouter un linter (ESLint) avec config stricte | Projet | Moyenne | | 4 | ImplĂ©menter le debouncing sur les appels API frĂ©quents | `main.js` | Moyenne | | 5 | Ajouter une couche d'abstraction API (fetch wrapper) | `main.js` | Haute | ### 3.4 Correctifs Prioritaires #### FIX-1 : `require_admin` ne vĂ©rifie pas le bon champ ```python # core/dependencies.py, lignes 161-162 payload = user.get("payload", {}) # ⚠ Le champ "payload" n'existe pas ! role = payload.get("role", "viewer") ``` Le dictionnaire user retournĂ© par `get_current_user_optional` contient `role` directement, pas dans un sous-dictionnaire `payload`. La vĂ©rification admin ne fonctionnera **jamais** pour les utilisateurs JWT. **Correction :** ```python async def require_admin(user: dict = Depends(get_current_user)) -> dict: if user.get("type") == "api_key": return user role = user.get("role", "viewer") # Directement dans le dict if role != "admin": raise HTTPException(status_code=403, detail="Droits administrateur requis") return user ``` #### FIX-2 : Fuite mĂ©moire potentielle dans WebSocket Le `WebSocketManager` ne nettoie les connexions mortes que lors d'un `broadcast`. Si aucun broadcast n'est envoyĂ© pendant longtemps, les connexions mortes s'accumulent. **Correction :** Ajouter un heartbeat pĂ©riodique : ```python async def _heartbeat_loop(self): while True: await asyncio.sleep(30) await self.broadcast({"type": "ping"}) ``` #### FIX-3 : Terminal proxy — `readexactly` vs `read` ```python # routes/websocket.py, ligne 104 data = await reader.readexactly(1024) # Bloque jusqu'Ă  avoir exactement 1024 bytes ``` **Correction :** `data = await reader.read(4096)` --- ## 4. AmĂ©liorations UI/UX 🎹 ### 4.1 Ergonomie du Tableau de Bord #### Dashboard — Structure RecommandĂ©e Le dashboard actuel charge un fichier HTML monolithique de 247 KB. Voici les amĂ©liorations ergonomiques recommandĂ©es : | Zone | AmĂ©lioration | Impact | |------|-------------|--------| | **Navigation** | Sidebar rĂ©tractable avec icĂŽnes et badges de notification | Haute | | **Page d'accueil** | Ajouter des "sparklines" (micro-graphiques) pour les mĂ©triques | Moyenne | | **Filtres** | Filtrage en temps rĂ©el avec chips/tags visuels | Haute | | **Breadcrumbs** | Ajouter une navigation hiĂ©rarchique | Moyenne | | **Raccourcis clavier** | `Ctrl+K` pour recherche rapide, `Ctrl+T` pour nouveau terminal | Moyenne | | **Dark/Light mode** | Toggle avec persistance en `localStorage` | Moyenne | #### Gestion des Erreurs — Feedback Visuel Actuellement, les erreurs sont probablement affichĂ©es dans des `alert()` ou des toasts basiques. Voici un systĂšme plus professionnel : **SystĂšme de Toast Notifications Ă  4 Niveaux :** ``` ┌─────────────────────────────────────────┐ │ ✅ SUCCESS │ │ "Playbook vm-upgrade.yml exĂ©cutĂ©" │ │ 3 hĂŽtes mis Ă  jour en 45s │ │ ░░░░░░░░░░░░░░░░░░░░░░ auto-dismiss 5s │ └─────────────────────────────────────────┘ ┌─────────────────────────────────────────┐ │ ❌ ERROR │ │ "Bootstrap Ă©chouĂ© pour srv-backup" │ │ Connection timeout aprĂšs 30s │ │ [Voir les logs] [RĂ©essayer] │ │ â–ș Reste affichĂ© jusqu'au dismiss │ └─────────────────────────────────────────┘ ``` **ImplĂ©mentation recommandĂ©e :** - Position : coin supĂ©rieur droit, empilĂ©es - Auto-dismiss : 5s pour success/info, sticky pour errors - Actions contextuelles intĂ©grĂ©es ("Voir les logs", "RĂ©essayer") - Animation entrĂ©e/sortie via Anime.js ### 4.2 IntĂ©gration Anime.js — Suggestions | Animation | DĂ©clencheur | Effet | |-----------|------------|-------| | **Task Progress** | Pendant l'exĂ©cution | Barre de progression animĂ©e avec shimmer | | **Host Status Change** | WebSocket event | Pulse animation sur le badge de statut | | **Docker Container Start/Stop** | Action utilisateur | Icon spin + color morph | | **Page Transition** | Navigation SPA | Fade-in avec translate-Y lĂ©ger (16px) | | **Card Hover** | Mouse enter | Scale(1.02) + shadow elevation subtile | | **Data Loading** | Fetch en cours | Skeleton screens avec wave animation | | **Error Shake** | Validation Ă©chouĂ©e | Shake horizontal (6px, 3 cycles, 400ms) | ### 4.3 Composants UI RecommandĂ©s #### Terminal SSH — AmĂ©liorations Le terminal SSH intĂ©grĂ© est une fonctionnalitĂ© killer. AmĂ©liorations suggĂ©rĂ©es : 1. **Split panes** : Permettre de diviser le terminal en panneaux horizontaux/verticaux 2. **Quick commands** : Palette de commandes prĂ©-dĂ©finies (sidebar ou dropdown) 3. **Session history** : Recall des commandes prĂ©cĂ©dentes avec recherche fuzzy 4. **Tab management** : Onglets pour multiples sessions, avec indicateur d'activitĂ© 5. **Copy-paste amĂ©liorĂ©** : Double-clic pour sĂ©lection de mot, click-and-drag pour sĂ©lection #### Playbook Editor — AmĂ©liorations 1. **Syntax highlighting YAML** : DĂ©jĂ  intĂ©grĂ© via CodeMirror ✅ 2. **Live linting** : IntĂ©grer ansible-lint en temps rĂ©el (via WebSocket) 3. **Variables autocomplete** : ComplĂ©tion automatique des variables de groupe 4. **Diff view** : Voir les changements avant sauvegarde 5. **Template snippets** : BibliothĂšque de snippets de tĂąches courantes ### 4.4 AccessibilitĂ© (a11y) | Aspect | État Actuel | Recommandation | |--------|------------|----------------| | **Contraste** | À vĂ©rifier | WCAG AA minimum (ratio 4.5:1) | | **Navigation clavier** | Probablement partielle | `tabindex` sur tous les Ă©lĂ©ments interactifs | | **Screen reader** | Non implĂ©mentĂ© | Ajouter `aria-label`, `aria-live` pour les mises Ă  jour dynamiques | | **Focus visible** | Par dĂ©faut navigateur | Personnaliser le style de focus (`outline`) | --- ## 5. IdĂ©es d'Évolution "Next Level" 🚀 ### 5.1 Gestion des Secrets (Vault) **Objectif :** Centraliser et sĂ©curiser tous les secrets (mots de passe, clĂ©s API, tokens). **Architecture proposĂ©e :** ``` ┌─────────────────────────────────────────────┐ │ Homelab Secrets Manager │ ├────────────────────────────────────────────── │ ┌─────────┐ ┌──────────┐ ┌────────────┐ │ │ │ Ansible │ │ Docker │ │ Services │ │ │ │ Vault │ │ Secrets │ │ Credentials│ │ │ └─────────┘ └──────────┘ └────────────┘ │ ├────────────────────────────────────────────── │ Backend: AES-256-GCM encryption at rest │ │ Master Key: derived via PBKDF2 from │ │ user password + hardware fingerprint │ └─────────────────────────────────────────────┘ ``` **ImplĂ©mentation par phases :** 1. **Phase 1 :** Chiffrement des secrets en base (clĂ©s SSH, tokens ntfy) 2. **Phase 2 :** Interface UI pour gĂ©rer les secrets (CRUD + audit log) 3. **Phase 3 :** IntĂ©gration avec `ansible-vault` pour les playbooks ### 5.2 IntĂ©gration Proxmox **Objectif :** GĂ©rer les VMs et containers LXC directement depuis le dashboard. **FonctionnalitĂ©s proposĂ©es :** | FonctionnalitĂ© | ComplexitĂ© | Valeur | |---------------|-----------|--------| | Lister VMs/CTs avec statut | Faible | Haute | | Start/Stop/Restart VM | Moyenne | Haute | | CrĂ©er VM from template | Haute | Moyenne | | Monitoring CPU/RAM/IO | Moyenne | Haute | | Snapshots management | Moyenne | Moyenne | | Console VNC/SPICE intĂ©grĂ©e | Haute | Haute | **Approche technique :** - Utiliser l'API REST de Proxmox VE (`/api2/json/`) - Authentification via token PVE (pas de mot de passe stockĂ©) - WebSocket pour le streaming des mĂ©triques en temps rĂ©el ### 5.3 Monitoring AvancĂ© #### MĂ©triques SystĂšme Enrichies ``` ┌──────────────────────────────────────────┐ │ CPU History (24h) │ │ ██████████░░░░░░░░░ 52% avg │ │ ▁▂▃▅▆▇█▇▅▃▂▁▁▂▃▅▇█▇▅▃▂▁ │ ├─────────────────────────────────────────── │ Memory ████████████████░░ 78% (12/16GB)│ │ Swap █░░░░░░░░░░░░░░░░ 3% (0.5/16GB)│ │ Disk / ██████████░░░░░░░ 62% (120/200G)│ │ Network ↑ 12 Mbit/s ↓ 45 Mbit/s │ └──────────────────────────────────────────┘ ``` **Stack recommandĂ© :** - **Collection :** Via Ansible ad-hoc (dĂ©jĂ  capable) ou node_exporter - **Stockage :** SQLite pour 7 jours, puis agrĂ©gation/cleanup automatique - **Visualisation :** Graphiques temps rĂ©el en JavaScript (Chart.js ou D3.js) - **Alerting :** IntĂ©gration avec ntfy (dĂ©jĂ  en place) #### Alerting Intelligent Passer d'alertes simples (seuil dĂ©passĂ©) Ă  un systĂšme plus sophistiquĂ© : 1. **Rate of change :** Alerter si le CPU augmente de >30% en 5 minutes 2. **Anomaly detection :** Baseline automatique + dĂ©tection de dĂ©viation 3. **Correlation :** "Disk full → Service crash" → alerte unifiĂ©e 4. **Escalation :** ntfy (info) → email (warning) → SMS/appel (critique) ### 5.4 IntĂ©gration Docker Compose AvancĂ©e **FonctionnalitĂ©s proposĂ©es :** 1. **Visualisation des stacks** : Graphe de dĂ©pendances entre containers 2. **Logs en streaming** : `docker logs -f` via WebSocket 3. **Compose file editor** : Édition avec validation en temps rĂ©el 4. **One-click deploy** : Upload et dĂ©ploiement de stacks docker-compose 5. **Auto-update** : VĂ©rification et mise Ă  jour automatique des images (comme Watchtower) ### 5.5 CI/CD Self-Hosted **Pipeline proposĂ©e pour le dashboard lui-mĂȘme :** ``` ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ │ Push │ → │ Lint & │ → │ Build │ → │ Deploy │ │ Git │ │ Test │ │ Docker │ │ Auto │ └─────────┘ └──────────┘ └─────────┘ └──────────┘ │ │ │ │ └──── Gitea/Forgejo ──── ── GitHub Actions ────┘ ``` **Pour les services managĂ©s du homelab :** - Interface de dĂ©ploiement "GitOps-like" - Rollback automatique si health check Ă©choue - Historique de dĂ©ploiement avec diff ### 5.6 Multi-Tenant & Multi-User | FonctionnalitĂ© | Description | |---------------|-------------| | **RĂŽles granulaires** | Viewer, Operator, Admin avec permissions par section | | **Audit trail** | Log de toutes les actions utilisateur avec IP/timestamp | | **Workspaces** | SĂ©parer les environnements (prod, staging, lab) | | **API tokens** | Tokens scoped avec date d'expiration | | **2FA** | Authentification Ă  deux facteurs (TOTP) via un app authenticator | --- ## 6. Feuille de Route Actionnable đŸ—ș ### Phase 1 : Gains Rapides (1-2 semaines) 🏃 *Objectif : Corriger les failles critiques et les quick wins sans refactoring majeur.* | # | Action | Effort | Impact | Fichier(s) | |---|--------|--------|--------|-----------| | 1.1 | ⚠ **Ajouter `.env` au `.gitignore`** et crĂ©er `.env.example` | 5 min | 🔮 Critique | `.gitignore`, `.env.example` | | 1.2 | 🔒 **Authentifier le WebSocket `/ws`** avec token JWT | 2h | 🔮 Haute | `routes/websocket.py` | | 1.3 | 🐛 **Corriger `require_admin`** (champ `role` mal lu) | 15 min | 🔮 Haute | `core/dependencies.py` | | 1.4 | 🔄 **Remplacer `threading.Lock` par `asyncio.Lock`** dans WebSocketManager | 30 min | 🟡 Moyenne | `services/websocket_service.py` | | 1.5 | 🐛 **Corriger `readexactly` → `read`** dans le proxy terminal | 5 min | 🟡 Moyenne | `routes/websocket.py` | | 1.6 | ⚡ **Wrapper `bootstrap_host` avec `asyncio.to_thread`** | 30 min | 🟠 Haute | `routes/bootstrap.py` | | 1.7 | 📝 **Remplacer `print()` par `logging`** dans factory.py | 1h | 🟱 Basse | `factory.py` | | 1.8 | 🔑 **GĂ©nĂ©rer un JWT_SECRET_KEY alĂ©atoire** au premier dĂ©marrage si non dĂ©fini | 1h | 🔮 Haute | `services/auth_service.py` | ### Phase 2 : Objectifs Ă  Moyen Terme (1-2 mois) 🎯 *Objectif : Consolider l'architecture et amĂ©liorer l'expĂ©rience utilisateur.* | # | Action | Effort | Impact | |---|--------|--------|--------| | 2.1 | đŸ—‘ïž **Supprimer `app_optimized.py`** et le `HybridDB` | 2-3j | Architecture | | 2.2 | 🔐 **ImplĂ©menter refresh tokens** + blacklist de tokens | 2j | SĂ©curitĂ© | | 2.3 | 📊 **Indexer les logs de tĂąches en base** (remplacer le scan filesystem) | 2j | Performance | | 2.4 | ⚡ **Optimiser la collecte Docker** (commandes SSH combinĂ©es) | 1j | Performance | | 2.5 | 🎹 **ImplĂ©menter le systĂšme de toast notifications** | 2j | UI/UX | | 2.6 | đŸ–„ïž **Ajouter le split-pane et les onglets** au terminal | 3j | UI/UX | | 2.7 | 🔔 **Heartbeat WebSocket** avec reconnexion automatique cĂŽtĂ© JS | 1j | FiabilitĂ© | | 2.8 | 📩 **Migrer vers FastAPI `lifespan`** (remplacer `on_event`) | 1j | Architecture | | 2.9 | đŸ§Ș **Augmenter la couverture de tests Ă  65%** (focus : auth, scheduler, WebSocket) | 3-5j | QualitĂ© | | 2.10 | đŸ—œïž **Activer la compression gzip** et les headers de cache statique | 2h | Performance | | 2.11 | đŸ“± **AmĂ©liorer le responsive** (breakpoints tablette + mobile) | 2j | UI/UX | | 2.12 | ⚙ **Rendre configurables** les intervalles Docker et les limites de pagination | 1j | Ops | ### Phase 3 : Vision Ă  Long Terme (3-6 mois) 🔭 *Objectif : Transformer le dashboard en plateforme homelab de rĂ©fĂ©rence.* | # | Action | Effort | Impact | |---|--------|--------|--------| | 3.1 | 🔐 **Secrets Manager** — Chiffrement des secrets en base + UI | 1-2 sem | SĂ©curitĂ© | | 3.2 | đŸ–„ïž **IntĂ©gration Proxmox** — API + Dashboard VMs | 2-3 sem | Feature | | 3.3 | 📊 **Monitoring avancĂ©** — Graphiques historiques + anomaly detection | 2-3 sem | Feature | | 3.4 | 🐳 **Docker Compose Manager** — Stacks + logs streaming + deploy | 2-3 sem | Feature | | 3.5 | đŸ‘„ **Multi-user avec RBAC** — RĂŽles granulaires + audit trail | 2 sem | SĂ©curitĂ© | | 3.6 | 🔑 **2FA (TOTP)** — Authentification Ă  deux facteurs | 1 sem | SĂ©curitĂ© | | 3.7 | 🚀 **CI/CD Pipeline** — Auto-deploy du dashboard + rollback | 2 sem | DevOps | | 3.8 | 🔄 **Migration PostgreSQL** (optionnel) — Pour scalabilitĂ© multi-instance | 1-2 sem | Architecture | | 3.9 | đŸ“± **PWA** — Notifications push natives, mode offline partiel | 1-2 sem | UI/UX | | 3.10 | 🔌 **Plugin System** — Architecture extensible pour intĂ©grations tierces | 3-4 sem | Architecture | ### Matrice de Prioritisation ``` IMPACT ÉLEVÉ ↑ ┌────────┌────────┐ │ 1.1 │ 2.1 │ │ 1.2 │ 2.2 │ │ 1.3 │ 2.3 │ │ 1.6 │ 3.1 │ │ 1.8 │ 3.5 │ ├────────┌───────── │ 1.4 │ 2.6 │ │ 1.5 │ 2.9 │ │ 1.7 │ 3.2 │ │ 2.10 │ 3.4 │ │ 2.7 │ 3.10 │ └────────┌────────┘ EFFORT FAIBLE EFFORT ÉLEVÉ ↓ IMPACT FAIBLE ``` --- ## Annexe A : MĂ©triques du Projet | MĂ©trique | Valeur | |----------|--------| | Fichiers Python | 144 | | Fichiers JS | 8 (app) | | Fichier HTML | 1 (monolithique) | | Migrations Alembic | 19 | | Routes API | 22 routers | | ModĂšles SQLAlchemy | 20 | | Schemas Pydantic | 20 | | Services | 16 | | CRUD Repositories | 14+ | | Tests backend | ~45% coverage | | Tests frontend | PrĂ©sents (vitest) | | Taille `app_optimized.py` | 6585 lignes ⚠ | | Taille `index.html` | 247 KB ⚠ | | Taille `main.js` | 617 KB ⚠ | ## Annexe B : SĂ©curitĂ© — Checklist de DĂ©ploiement Production ``` [ ] .env absent du repository Git [ ] JWT_SECRET_KEY est une chaĂźne alĂ©atoire de 64+ caractĂšres [ ] API_KEY est unique et complexe [ ] HTTPS activĂ© (reverse proxy nginx/traefik) [ ] CORS restreint aux origines autorisĂ©es [ ] WebSocket authentifiĂ© par JWT [ ] Rate limiting activĂ© sur /api/auth et /api/bootstrap [ ] Logs de sĂ©curitĂ© activĂ©s (tentatives de connexion, accĂšs refusĂ©s) [ ] Rotation des logs configurĂ©e [ ] Backups de la base de donnĂ©es automatisĂ©s [ ] SSH key permissions = 600 [ ] StrictHostKeyChecking configurable (pas hardcodĂ© Ă  "no") [ ] Docker socket non exposĂ© directement [ ] ttyd bind sur localhost uniquement (si reverse proxy) ``` --- > **📌 Note finale :** Ce projet est remarquablement bien structurĂ© pour un projet homelab. L'architecture modulaire avec Factory Pattern, Repository Pattern, et la sĂ©paration claire des responsabilitĂ©s tĂ©moignent d'une excellente comprĂ©hension des patterns d'architecture logicielle. Les correctifs et amĂ©liorations proposĂ©s dans ce rapport visent Ă  renforcer une base dĂ©jĂ  solide pour atteindre un niveau Enterprise-grade tout en conservant la flexibilitĂ© et l'agilitĂ© qui font le charme d'un projet homelab. *Rapport gĂ©nĂ©rĂ© le 20 fĂ©vrier 2026 — Homelab Automation Dashboard v2.0.0*