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

6.7 KiB
Raw Blame History

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 :

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 :

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 :

r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*method=closeSession'

Modèle par utilisateur (cache)

{
    "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

{
  "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)