# Design — HA Entity Scanner & Manager **Date** : 2026-02-21 **Statut** : Approuvé ## Architecture globale ``` Frontend (Vue 3 + Vuetify 3) ──► Backend (FastAPI) ──► Home Assistant SPA :5173 API :8000 :8123 SQLite DB REST + WS ``` - **Frontend** : SPA Vue 3 + Vite + Vuetify 3, appelle `/api/*` - **Backend** : FastAPI, proxy sécurisé vers HA (token jamais exposé côté client) - **DB** : SQLite via SQLModel, 3 tables (entities_cache, entity_flags, audit_log) - **Client HA** : `aiohttp` pour REST (`/api/states`) et WebSocket (`/api/websocket`) - **Déploiement** : Docker + docker-compose, variables d'env `HA_BASE_URL` / `HA_TOKEN` ## Backend — structure des modules | Module | Responsabilité | |--------|---------------| | `app/main.py` | App FastAPI, CORS, lifespan | | `app/config.py` | Settings via pydantic-settings (env vars) | | `app/models.py` | SQLModel : EntityCache, EntityFlag, AuditLog | | `app/database.py` | Init SQLite, get_session | | `app/ha_client.py` | Client aiohttp : REST states + WS registry | | `app/routers/health.py` | `GET /api/health` | | `app/routers/scan.py` | `POST /api/scan` (async background task) | | `app/routers/entities.py` | `GET /api/entities`, `GET /api/entities/{id}` | | `app/routers/actions.py` | `POST /api/entities/actions` | | `app/routers/audit.py` | `GET /api/audit` | | `app/services/scanner.py` | Logique scan : fetch + normalize + upsert DB | | `app/services/entity_actions.py` | Logique disable/enable/hide via WS ou fallback | ## Frontend — composants principaux | Composant | Rôle | |-----------|------| | `App.vue` | Layout principal, header avec statut HA | | `EntityTable.vue` | `v-data-table-server` avec tri, pagination, sélection | | `FilterBar.vue` | Recherche texte + dropdowns domaine/état + chips actives | | `EntityDetail.vue` | Panneau latéral détails + actions | | `AuditLog.vue` | Page journal des actions | | `ScanButton.vue` | Bouton scan + indicateur progression | ## Base de données SQLite ### entities_cache - `entity_id` (PK), `domain`, `friendly_name`, `state` - `attrs_json` (TEXT — attributs HA complets) - `device_class`, `unit_of_measurement`, `area_id`, `device_id`, `integration` - `is_disabled`, `is_hidden`, `is_available` (booléens déduits) - `last_changed`, `last_updated`, `fetched_at` ### entity_flags - `entity_id` (PK), `ignored_local` (bool), `favorite` (bool), `notes` (text) ### audit_log - `id` (PK auto), `ts` (datetime), `action` (text), `entity_ids_json` (text), `result` (text), `error` (text) ## Scan asynchrone `POST /api/scan` lance une `BackgroundTask` FastAPI. Un état en mémoire (`idle`/`scanning`/`done`/`error` + progression) est exposé via `GET /api/health`. Le frontend poll le health pour afficher la progression. ## Désactivation des entités 1. **Méthode principale** : WS API HA `config/entity_registry/update` avec `disabled_by: "user"` 2. **Fallback** : flag `ignored_local=true` en DB locale 3. L'UI affiche un badge distinct selon le mode utilisé (désactivé HA vs ignoré local) 4. Toute action journalisée dans `audit_log` ## Choix techniques - **Python FastAPI** + **aiohttp** (client HA REST + WS) - **SQLModel** (SQLAlchemy + Pydantic) - **Vue 3** + **Vite** + **Vuetify 3** - **Docker** + **docker-compose** - UI en **français** uniquement