Aller au contenu

Story CP-016 : Interface Journal d'Audit + Contrôle d'Accès

Module : control-plane Slice : Slice 4 from architecture (split from CP-004) Brand context : [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority : 4 Depends on : CP-004 Estimated complexity : M


Objectif

Construire l'interface de visualisation du journal d'audit et l'endpoint de requête avec filtres. Le DG peut parcourir, filtrer et inspecter les entrées d'audit. Les utilisateurs non-DG se voient refuser l'accès. Cette story s'appuie sur l'infrastructure AuditService et AuditEntry de CP-004.


Périmètre Backend

Entités & Records

Aucune nouvelle entité. Utilise l'entité AuditEntry de CP-004.

DTOs (depuis CP-004, utilisés par l'endpoint de requête) :

public record AuditEntryResponse(
    UUID id, UUID userId, String userFullName, Instant timestamp,
    String entityType, UUID entityId, String moduleCode,
    AuditAction action, JsonNode beforeValue, JsonNode afterValue,
    JsonNode metadata
) {}

public record AuditPageResponse(
    List<AuditEntryResponse> entries, int totalCount, int page, int pageSize
) {}

public record AuditQueryParams(
    @Nullable String entityType,
    @Nullable UUID entityId,
    @Nullable UUID userId,
    @Nullable AuditAction action,
    @Nullable String moduleCode,
    @Nullable Instant dateFrom,
    @Nullable Instant dateTo,
    int page,    // default 0
    int pageSize // default 50
) {}

Couche Repository

Utilise AuditRepository de CP-004 : - findByFilters(UUID tenantId, AuditQueryParams) → Page<AuditEntry> — Requête paginée avec filtres optionnels sur entity_type, entity_id, user_id, action, module_code, plage de dates

Couche Service

AuditService.java (ajout au AuditService de CP-004) : - query(AuditQueryParams params) → AuditPageResponse — Requête tenant-scopée pour l'UI. Scoped automatiquement par TenantContext.current().tenantId().

Endpoints API

Méthode Chemin Corps de requête Réponse Auth
GET /api/v1/audit Paramètres de requête (filtres) AuditPageResponse ROLE_DG

Règles de validation

  • entity_type max 100 caractères
  • module_code max 20 caractères
  • Plage de dates de requête : date_from doit être antérieur à date_to
  • Taille de page : 1–100 (défaut 50)
  • Seul ROLE_DG peut accéder à cet endpoint (403 pour tous les autres rôles)

Périmètre Frontend

Pages & Routes

  • /admin/audit — Page de visualisation du journal d'audit

Composants

  • AuditTrailPage.tsx — Journal d'audit filtrable et paginé
  • AuditEntryCard.tsx — Entrée d'audit unique (vue carte mobile)
  • AuditEntryRow.tsx — Ligne de tableau (vue bureau)
  • AuditDetailSheet.tsx — Bottom sheet (mobile) / panneau latéral (bureau) affichant le diff avant/après complet
  • AuditFilterBar.tsx — Chips de filtres : Module, Action, Plage de dates

États UI (TOUS REQUIS)

État Comportement Texte en Français
Loading Squelette : 5 placeholders de cartes d'entrée
Empty Illustration + message "Aucune activité enregistrée pour cette période."
Error Toast rouge "Une erreur est survenue. Veuillez réessayer."
Offline Message hors ligne pleine page "Le journal d'audit n'est pas disponible hors ligne."
Success Entrées affichées avec pagination
Unauthorized Redirection ou message "Accès non autorisé"

Comportement responsive

  • 360px (mobile) : Liste chronologique. Chaque carte d'entrée affiche : date/heure, nom d'utilisateur, libellé d'action lisible, nom d'entité entre guillemets, badge module, lien "Détails -->".
  • 768px (tablette) : Vue tableau compacte.
  • 1024px+ (bureau) : Tableau pleine largeur avec colonnes : Date/Heure, Utilisateur, Action, Entité, Module, Résumé. Lignes extensibles affichant le diff avant/après en ligne. Filtres avancés : sélecteur de plage de dates, dropdown module, cases à cocher type d'action, recherche d'utilisateur.

Interactions

  • Filtres : Dropdown Module, Type d'action (Création/Modification/Suppression), Sélecteur de plage de dates. Les filtres s'empilent sous forme de chips.
  • Pagination : Bouton "Charger plus..." en bas (mobile). Numéros de pages (bureau).
  • Vue détail : Appuyer sur "Détails -->" sur n'importe quelle entrée → bottom sheet (mobile) / panneau latéral (bureau) affichant :
  • Action, Entité, Par (utilisateur), Date
  • Section "Modifications" montrant le avant/après champ par champ
  • Affichage Avant/Après : Format lisible :
    Nom
      Avant: Production
      Apres: Prod.
    

Micro-textes français pour l'UI d'audit :

Clé Texte Français
audit.title "Journal d'audit"
audit.filter.module "Module"
audit.filter.action "Action"
audit.filter.date "Période"
audit.action.create "Création"
audit.action.update "Modification"
audit.action.delete "Suppression"
audit.detail.title "Détail de l'audit"
audit.detail.action "Action"
audit.detail.entity "Entité"
audit.detail.by "Par"
audit.detail.date "Date"
audit.detail.changes "Modifications"
audit.detail.before "Avant"
audit.detail.after "Après"
audit.load_more "Charger plus..."
empty.audit "Aucune activité enregistrée pour cette période."

Critères d'acceptation

AC-029: Audit query with filters
Given 50 audit entries exist for my tenant
When I call GET /api/v1/audit?entityType=Employee&action=CREATE&dateFrom=2026-02-01
Then I receive only audit entries matching all three filters

AC-031: Audit UI displays timeline
Given I am DG and navigate to /admin/audit
When the page loads
Then I see a chronological list of audit entries with filters at the top

AC-032: Audit detail view shows before/after
Given an UPDATE audit entry for a department rename
When I tap "Détails -->" on the entry
Then I see the before/after diff in human-readable format: "Nom -- Avant: Production -- Apres: Prod."

AC-033: Audit accessible only to DG
Given I am authenticated with role EMPLOYE
When I navigate to /admin/audit
Then I am redirected or shown "Acces non autorise"

Règles OHADA & Réglementaires

  • AUDCIF Art. 24 : Le visualiseur d'audit fournit au DG la traçabilité de toutes les mutations de données, satisfaisant l'exigence de visibilité de conservation sur 10 ans.
  • AUDCIF Art. 22 : Les entrées d'audit affichées sont immuables — l'UI est en lecture seule. Aucune action d'édition ou de suppression n'existe.
  • Loi 2013-450 : Le visualiseur du journal d'audit restreint au rôle DG applique la responsabilité pour l'accès aux données personnelles.

Standards & Conventions

  • docs/standards/react-typescript-guidelines.md — §Composants liste/tableau, §Pattern filtres, §Détail en bottom sheet, §Pagination
  • docs/standards/api-guidelines.md — §Pagination, §Conventions de paramètres de requête

Exigences de test

Tests unitaires

  • AuditService.query() : combinaisons de filtres (entity_type, action, plage de dates, module)
  • AuditService.query() : pagination (page, pageSize)
  • Génération du diff avant/après pour l'affichage lisible

Tests d'intégration

  • GET /api/v1/audit — avec plusieurs combinaisons de filtres
  • GET /api/v1/audit — pagination (50 par page, page suivante)
  • GET /api/v1/audit — isolation tenant (requêtes du tenant A, pas de données du tenant B)
  • GET /api/v1/audit — rôle EMPLOYE → 403
  • GET /api/v1/audit — rôle DG → 200

Ce que le QA validera

  • La page d'audit se charge avec les entrées en ordre chronologique inverse
  • Les filtres fonctionnent : Module, Type d'action, Plage de dates
  • La vue détail affiche correctement le diff avant/après
  • La pagination ("Charger plus...") charge la page suivante
  • La page affiche le message hors ligne quand déconnecté
  • Le DG peut accéder à la page d'audit ; EMPLOYE ne peut pas
  • Tous les points de rupture s'affichent correctement (360px, 768px, 1024px)

Hors périmètre

  • Export CSV du journal d'audit — V2
  • Requête d'audit inter-tenant (pour l'admin plateforme) — CP-012
  • Journal d'audit pour les actions de la console admin — CP-012

Définition de Done

  • [ ] L'endpoint GET /api/v1/audit avec filtres retourne les données paginées correctes
  • [ ] Toutes les pages frontend s'affichent correctement à 360px, 768px, 1024px
  • [ ] Les 6 états UI implémentés (loading, empty, error, offline, success, unauthorized)
  • [ ] Les micro-textes français correspondent exactement à la spec design
  • [ ] Tous les critères d'acceptation passent manuellement
  • [ ] Tests unitaires écrits et passants
  • [ ] Tests d'intégration écrits et passants
  • [ ] Accès DG uniquement appliqué (403 pour les autres rôles)
  • [ ] Pas de any TypeScript — tous les types explicites
  • [ ] Pas de types Java bruts — tous les génériques explicites