From 90c5c154a7596910da6c15d165216add473b0efb Mon Sep 17 00:00:00 2001 From: oussi Date: Thu, 2 Apr 2026 11:20:45 +0200 Subject: [PATCH] docs: add design spec for Utilisateurs tab and Amadea log monitoring Co-Authored-By: Claude Sonnet 4.6 --- .../specs/2026-04-02-users-tab-design.md | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-02-users-tab-design.md diff --git a/docs/superpowers/specs/2026-04-02-users-tab-design.md b/docs/superpowers/specs/2026-04-02-users-tab-design.md new file mode 100644 index 0000000..7673ebb --- /dev/null +++ b/docs/superpowers/specs/2026-04-02-users-tab-design.md @@ -0,0 +1,188 @@ +# Design — Onglet Utilisateurs Amadea + +**Date :** 2026-04-02 +**Statut :** Approuvé + +--- + +## Contexte + +Ajouter un onglet "Utilisateurs" à l'application de supervision, affichant en temps réel les utilisateurs connectés à Amadea Web 8 x64, leur statut d'activité, et un graphique d'utilisation horaire. Le chemin des logs Amadea et les seuils de statut sont rendus configurables dans l'onglet Configuration existant. + +--- + +## Architecture générale + +### Nouveaux fichiers + +- **`user_monitor.py`** — classe `UserMonitor` : thread de fond, parsing des logs, cache thread-safe. Miroir exact de `SystemMonitor`. + +### Fichiers modifiés + +| Fichier | Modification | +|---|---| +| `config_manager.py` | Ajout des clés `amadea_log_path` et `user_status_thresholds` dans la config par défaut | +| `app.py` | Instanciation de `UserMonitor`, routes `/users` et `/api/users` | +| `templates/base.html` | Lien "Utilisateurs" dans la navbar | +| `templates/settings.html` | 2 nouveaux blocs de configuration | +| `templates/users.html` | Nouvelle page (tableau + graphique CSS) | + +### Flux de données + +``` +UserMonitor (background thread) + ├─ parse awevents_YY-MM-DD_*.log → activité utilisateur + déconnexions explicites + └─ parse isoft_YY-MM-DD_*.log → événements de session (login/timeout) + ↓ cache thread-safe (dict par login) +/api/users → JSON +/users → rendu Jinja2 initial + auto-refresh JS (30s, même pattern que dashboard) +``` + +--- + +## Parsing et modèle de données + +### Sélection des fichiers du jour + +Les fichiers de logs suivent le pattern `PREFIX_YY-MM-DD_N.ext` (ex: `awevents_26-04-02_1.log`). + +- Date du jour formatée en `%y-%m-%d` (ex: `26-04-02` pour 2026-04-02) +- Tous les fichiers du jour sont lus, triés par index `N` croissant +- Si plusieurs fichiers du même jour existent (index incrémental), ils sont tous parsés dans l'ordre + +### Format `awevents_YY-MM-DD_N.log` (source principale) + +``` +2026-03-30 10:34:24.034;INFO ;;;;"login=JENKINS,action=SelectionChange,Label=BAO_Main/..." +``` + +Regex d'extraction : +```python +r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*login=([^,]+),action=([^,]+),Label=(.+)"?$' +``` + +- `timestamp` → groupe 1 +- `login` → groupe 2 (identifiant utilisateur) +- `action` → groupe 3 (SelectionChange, Action, Click, ValueChange…) +- `label` → groupe 4 (contexte UI) + +**Déconnexion explicite :** ligne dont le label contient `se deconnecter` + +### Format `isoft_YY-MM-DD_N.log` (complément sessions) + +``` +2026-03-30 10:33:05.830;INFO ;"ISExecutingThread...";...;"method=OpenUserSession,...,login=JENKINS" +``` + +Regex pour login réussi : +```python +r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*method=OpenUserSession.*login=([A-Za-z0-9_]+)' +``` + +Regex pour timeout de session : +```python +r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*method=closeSession' +``` + +### Modèle par utilisateur (cache) + +```python +{ + "login": str, # identifiant (ex: "JENKINS") + "last_action_time": datetime, # horodatage de la dernière action + "last_action_label": str, # label de la dernière action (tronqué à 60 chars) + "action_count_24h": int, # nombre d'actions dans les dernières 24h + "status": str, # "actif" | "inactif" | "deconnecte" + "explicit_logout": bool, # True si déconnexion explicite détectée + "connected_since": datetime | None, # heure de la première action du jour (premier awevents du jour pour cet utilisateur) +} +``` + +### Règles de statut + +Seuils configurables (clé `user_status_thresholds`, défauts : `active_minutes=5`, `inactive_minutes=30`) : + +| Condition | Statut | +|---|---| +| Déconnexion explicite détectée | DÉCONNECTÉ | +| Dernière action > `inactive_minutes` | DÉCONNECTÉ | +| Dernière action entre `active_minutes` et `inactive_minutes` | INACTIF | +| Dernière action < `active_minutes` | ACTIF | + +### Graphique d'activité horaire + +Comptage du nombre d'utilisateurs distincts ayant au moins une action par tranche horaire (H:00 → H:59). Données issues uniquement des fichiers du jour (`awevents_*.log`). + +Pour le sélecteur "7 derniers jours" : si les fichiers zippés ne sont pas disponibles (cas nominal en prod), afficher un `alert-info` : *"Les données historiques des jours précédents ne sont pas disponibles (fichiers archivés)."* + +--- + +## Configuration + +### Nouvelles clés dans `config.json` + +```json +{ + "amadea_log_path": "C:\\ProgramData\\ISoft\\Amadea Web 8 x64\\data\\logs", + "user_status_thresholds": { + "active_minutes": 5, + "inactive_minutes": 30 + } +} +``` + +### Nouveaux blocs dans `settings.html` + +**Bloc 1 — Chemin des logs Amadea** (même style `card` + `form-control` + `btn btn-primary`) : +- Champ texte pré-rempli avec la valeur actuelle +- Bouton "Enregistrer" +- Route POST : `/settings/amadea-log-path` + +**Bloc 2 — Seuils statut utilisateurs** (même style que le bloc "Seuils d'alerte") : +- Champ numérique "Actif si dernière action < N min" (défaut: 5) +- Champ numérique "Inactif si dernière action < N min" (défaut: 30) +- Bouton "Enregistrer" +- Route POST : `/settings/user-thresholds` + +--- + +## Interface utilisateurs (`users.html`) + +### Tableau + +Colonnes : **Utilisateur | Statut | Dernière action | Actions (24h) | Depuis** + +Tri par défaut : Actifs → Inactifs → Déconnectés (ordre de priorité statut). + +Badges Bootstrap cohérents avec l'existant : +- ACTIF → `ACTIF` +- INACTIF → `INACTIF` +- DÉCONNECTÉ → `DÉCONNECTÉ` + +### Graphique d'activité + +Barres CSS Bootstrap (divs avec hauteur proportionnelle), aucune librairie externe. +Une barre par heure de la journée (00h–23h), largeur fixe, hauteur = `(valeur / max) * 100%`. +Couleur : `bg-primary`. Tooltip au survol (attribut `title`). + +### Auto-refresh + +`setInterval` toutes les 30 secondes, appel `fetch('/api/users')`, même pattern que `refreshMetrics()` dans `dashboard.html`. + +### Gestion d'erreurs + +| Cas | Affichage | +|---|---| +| Dossier de logs introuvable | `alert alert-warning` avec le chemin configuré | +| Aucun fichier du jour trouvé | `alert alert-info "Aucun log disponible pour aujourd'hui"` | +| Fichier verrouillé/illisible | Ignoré silencieusement, parsing continue | +| Aucun utilisateur détecté | Message `text-muted` dans le tableau | + +--- + +## Choix techniques + +- **Librairie graphique** : barres CSS Bootstrap pures (aucune dépendance externe) +- **Thread** : daemon thread (comme `SystemMonitor`), s'arrête avec l'application +- **Encodage fichiers** : `utf-8` avec `errors='ignore'` pour tolérer les caractères invalides +- **Performance** : les fichiers `isoft_*.log` peuvent être très volumineux (index > 80). Le parsing lit ligne par ligne sans charger le fichier en mémoire (`for line in f`)