Files
supervision/docs/superpowers/specs/2026-04-02-users-tab-design.md
2026-04-02 11:20:45 +02:00

189 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 → `<span class="badge bg-success">ACTIF</span>`
- INACTIF → `<span class="badge bg-warning text-dark">INACTIF</span>`
- DÉCONNECTÉ → `<span class="badge bg-secondary">DÉCONNECTÉ</span>`
### Graphique d'activité
Barres CSS Bootstrap (divs avec hauteur proportionnelle), aucune librairie externe.
Une barre par heure de la journée (00h23h), 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`)