Aller au contenu

Story AB-019 : Tableau de Bord RH (Backend + Frontend)

Module : absence-management Tranche : VS-AB-014 de l'architecture Contexte de marque : [LES DEUX] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priorité : 19 Dépend de : AB-009, AB-011 Peut se développer en parallèle avec : AB-018, AB-020 Ordre de fusion : Après AB-009 et AB-011 Complexité estimée : M PRD User Stories : US-ABS-008


Objectif

Fournir aux responsables RH et aux DG un tableau de bord synthétique affichant les indicateurs clés d'absence : nombre de demandes en attente d'approbation, taux d'absence, nombre d'absents aujourd'hui, congés à venir et avertissements pour les employés avec un solde faible. Le tableau de bord inclut une liste compacte des demandes en attente avec des actions inline et un aperçu calendrier de 2 semaines.


Périmètre Backend

Entités et Enregistrements

Enregistrements de réponse :

public record DashboardSummaryResponse(
    int pendingApprovalsCount,
    BigDecimal absenceRatePercent,           // (jours d'absence / jours ouvrables du mois en cours) x 100, 1 décimale
    int absentToday,
    int lowBalanceEmployeesCount,            // employés avec solde de congé annuel < 5 jours
    List<UpcomingLeave> upcomingLeavesThisWeek,
    List<PendingApprovalSummary> recentPendingApprovals
) {}

public record UpcomingLeave(
    UUID leaveRequestId,
    UUID employeeId,
    String employeeName,                     // abrégé : "DIALLO F."
    LocalDate startDate,
    LocalDate endDate,
    String leaveType
) {}

public record PendingApprovalSummary(
    UUID leaveRequestId,
    UUID employeeId,
    String employeeName,                     // abrégé : "DIALLO F."
    LocalDate startDate,
    LocalDate endDate,
    String leaveType,
    int numberOfDays,
    Instant submittedAt
) {}

Couche Repository

Utilise les repositories existants d'AB-002 et AB-009 : - LeaveRequestRepository — compter PENDING_APPROVAL, interroger les congés approuvés à venir - LeaveBalanceLedgerRepository — pour le calcul du taux d'absence - LeaveEmployeeProfileRepository — pour le comptage des employés à solde faible - Requêtes personnalisées : - countByTenantIdAndStatus(UUID tenantId, LeaveStatus status) — comptage des demandes en attente - findApprovedLeavesOverlappingDate(UUID tenantId, LocalDate date) — absents aujourd'hui - findUpcomingApprovedLeaves(UUID tenantId, LocalDate fromDate, LocalDate toDate) — congés à venir cette semaine - findRecentPendingApprovals(UUID tenantId, int limit) — dernières demandes en attente (limite=5) - countEmployeesWithBalanceBelow(UUID tenantId, BigDecimal threshold) — comptage des soldes faibles

Couche Service

DashboardService.java :

  • getSummary(UUID tenantId) : DashboardSummaryResponse
  • pendingApprovalsCount : COUNT des LeaveRequests avec status=PENDING_APPROVAL
  • absenceRatePercent : (total des jours d'absence du mois en cours / total des jours ouvrables du mois en cours) x 100, calculé à la volée avec BigDecimal
  • absentToday : COUNT des employés actuellement en congé approuvé (période de congé incluant aujourd'hui)
  • lowBalanceEmployeesCount : COUNT des employés avec solde de congé annuel < 5 jours
  • upcomingLeavesThisWeek : congés approuvés débutant dans la semaine en cours (lundi-dimanche)
  • recentPendingApprovals : 5 dernières demandes d'approbation en attente, triées par submittedAt desc

Objectif de performance : < 500ms pour un tenant de 50 employés (utiliser des requêtes COUNT, pas de scans complets)

Points de terminaison API

Méthode Chemin Paramètres de requête Réponse Auth
GET /api/v1/absence/dashboard/summary ApiResponse<DashboardSummaryResponse> HR_MANAGER, DG

Règles de validation

  • Seuls HR_MANAGER et DG peuvent accéder au tableau de bord — 403 pour les autres rôles
  • Aucune validation d'entrée nécessaire (pas de paramètres de requête au-delà de l'auth)

Considérations Multi-Tenant

  • Toutes les requêtes incluent tenantId depuis ScopedValue<TenantContext>
  • Le calcul du taux d'absence est limité aux employés du tenant uniquement
  • Le seuil de solde faible (5 jours) est codé en dur en MVP — configurable en V2
  • Fonctionne avec les 4 profils de base de données (conçu pour BYO-DB en priorité)

Périmètre Frontend

RAPPEL SYNCHRONISATION HORS LIGNE (Papillon — CRITIQUE) : Le tableau de bord est une vue d'agrégation en lecture seule. Les données du tableau de bord en cache sont servies hors connexion avec un bandeau indiquant les données périmées. Les actions d'approbation depuis le tableau de bord sont en ligne uniquement. Voir docs/standards/offline-sync-guidelines.md.

Pages et Routes

Route Page Description
/absences/tableau-de-bord AbsenceDashboardPage Tableau de bord absences RH/DG

Composants

  • KpiCard — Carte métrique avec icône, label, valeur et couleur de fond optionnelle
  • PendingApprovalCard — Carte d'approbation compacte avec nom de l'employé, dates, type de congé et boutons d'action inline
  • MiniCalendarTimeline — Widget aperçu calendrier 2 semaines (réutilise la logique CalendarTimeline d'AB-018 sous forme compacte)
  • GhostLink — Lien de navigation avec icône flèche
  • WelcomeEmptyState — État vide plein écran pour les nouveaux tenants

États UI (TOUS REQUIS)

État Comportement Copie Française
Chargement 4 petits rectangles squelette (KPIs) + 2 rectangles moyens (listes)
Vide (nouveau tenant) EmptyState avec illustration de fusée "Bienvenue dans la gestion des absences" / CTA : "Configurer les parametres"
Erreur Toast + bouton réessayer "Impossible de charger le tableau de bord."
Hors ligne Données en cache + bandeau données périmées "Hors connexion — derniere synchro : {time}"
Succès N/A (tableau de bord en lecture seule)

Comportement Responsive

Mobile (360px — Papillon en priorité) : - 4 cartes KPI en grille 2x2 : 1. "En attente" — comptage en attente, bg=warning-light, appuyable → navigue vers /absences/approbations 2. "Taux d'absence" — pourcentage, bg=neutral-light 3. "Absents aujourd'hui" — comptage, bg=neutral-light 4. "Soldes bas" — comptage (employés avec < 5 jours), bg=amber-light - Section "Demandes récentes" : - PendingApprovalCards compactes avec nom de l'employé, dates, type - Boutons inline "Approuver" (primary, sm) + "Voir" (ghost, sm) - Maximum 5 cartes affichées - Section "Calendrier (2 semaines)" : - MiniCalendarTimeline montrant un instantané de 14 jours - Lien ghost "Voir toutes les approbations" → /absences/approbations - Lien ghost "Voir le calendrier complet" → /absences/calendrier - Toutes les cibles tactiles >= 48px

Desktop (1024px+ — Enterprise en priorité) : - 4 cartes KPI en ligne horizontale unique - Mise en page 2 colonnes sous les KPIs : - Colonne gauche : "Demandes en attente" — liste des approbations en attente avec actions inline - Colonne droite : "Calendrier (2 semaines)" — aperçu calendrier 2 semaines - Liens ghost en bas de chaque section - Clic sur le nom d'un employé dans la liste en attente → naviguer vers le détail du solde employé

Interactions

  • Appui sur la carte KPI "En attente" → naviguer vers /absences/approbations
  • Appui sur "Approuver" sur la carte en attente → approbation inline (PATCH vers l'endpoint d'approbation d'AB-011), la carte s'anime à la sortie en cas de succès
  • Appui sur "Voir" sur la carte en attente → naviguer vers le détail de la demande de congé
  • Appui sur le nom d'un employé depuis le contexte du tableau de bord → naviguer vers le détail du solde employé (AB-021)
  • Liens ghost → naviguer vers la liste complète des approbations ou le calendrier complet
  • Pull-to-refresh (mobile) → recharger le résumé du tableau de bord
  • Auto-refresh : le tableau de bord se recharge toutes les 60 secondes quand l'onglet est actif

Micro-Copie Française

  • dashboard.title: "Tableau de bord — Absences"
  • dashboard.kpi.pending: "En attente"
  • dashboard.kpi.absence_rate: "Taux d'absence"
  • dashboard.kpi.absent_today: "Absents aujourd'hui"
  • dashboard.kpi.low_balance: "Soldes bas"
  • dashboard.recent_requests: "Demandes recentes"
  • dashboard.calendar_preview: "Calendrier (2 semaines)"
  • dashboard.view_all_approvals: "Voir toutes les approbations"
  • dashboard.view_full_calendar: "Voir le calendrier complet"
  • dashboard.approve: "Approuver"
  • dashboard.view: "Voir"
  • dashboard.welcome: "Bienvenue dans la gestion des absences"
  • dashboard.welcome_cta: "Configurer les parametres"
  • dashboard.error: "Impossible de charger le tableau de bord."
  • dashboard.offline: "Hors connexion — derniere synchro : {time}"
  • dashboard.low_balance_warning: "{count} employes ont un solde inferieur a 5 jours"

Critères d'Acceptation

AC-060 : Le tableau de bord RH affiche les indicateurs clés
Étant donné que je suis HR_MANAGER
Quand j'ouvre le tableau de bord Absences
Alors je vois : le nombre de demandes en attente (badge), le taux d'absence (%), le nombre d'absents aujourd'hui, le nombre d'employés à solde faible, les congés à venir cette semaine

AC-061 : Le détail du solde employé est accessible depuis le tableau de bord
Étant donné que je clique sur le nom d'un employé dans la liste des approbations en attente
Quand la vue détail s'ouvre
Alors je vois le grand livre complet des acquisitions, déductions, ajustements et reports

AC-062 : Les approbations en attente sont actionnables depuis le tableau de bord
Étant donné qu'il y a des demandes d'approbation en attente
Quand je consulte le tableau de bord
Alors je peux approuver ou naviguer vers le détail directement depuis les cartes du tableau de bord

AC-063 : Le nouveau tenant voit l'état de bienvenue
Étant donné qu'un nouveau tenant CI vient d'activer le module ABSMGT
Quand le RH ouvre le tableau de bord
Alors il voit l'EmptyState de bienvenue avec le CTA pour configurer les paramètres

Règles OHADA et Réglementaires

N/A — le tableau de bord est une fonctionnalité d'affichage/agrégation sans exigences réglementaires.


Standards et Conventions

  • docs/standards/java-spring-guidelines.md — §Patterns REST controller, §Autorisation RBAC, §Optimisation des requêtes
  • docs/standards/database-guidelines.md — §Pattern repository multi-tenant, §BigDecimal pour les calculs de taux, §Optimisation des requêtes COUNT
  • docs/standards/api-guidelines.md — §Patterns endpoints GET, §Enveloppe ApiResponse
  • docs/standards/react-typescript-guidelines.md — §Patterns de composants, §CSS Modules, §i18n, §Patterns de grille responsive
  • docs/standards/design-system.md — §Card, §Button (variantes inline), §EmptyState, §Toast, §GhostLink
  • docs/standards/offline-sync-guidelines.md — §Données en lecture seule en cache, §Bandeau de données périmées, §Actions en ligne uniquement (approbation)
  • docs/standards/multi-datasource-patterns.md — §Requêtes repository limitées au tenant

Exigences de Test

Tests Unitaires

  • DashboardService.getSummary() : 3 demandes en attente → pendingApprovalsCount=3
  • DashboardService.getSummary() : 0 demandes en attente → pendingApprovalsCount=0
  • DashboardService.getSummary() : 2 employés absents aujourd'hui → absentToday=2
  • DashboardService.getSummary() : 15 jours d'absence dans le mois avec 22 jours ouvrables → absenceRatePercent=68.2 (BigDecimal)
  • DashboardService.getSummary() : 0 jour d'absence → absenceRatePercent=0.0
  • DashboardService.getSummary() : 4 employés avec solde < 5 jours → lowBalanceEmployeesCount=4
  • DashboardService.getSummary() : congés à venir filtrés à la semaine en cours uniquement
  • DashboardService.getSummary() : approbations en attente récentes limitées à 5, triées par submittedAt desc

Tests d'Intégration

  • GET /dashboard/summary en tant que HR_MANAGER → 200, toutes les métriques présentes
  • GET /dashboard/summary en tant que DG → 200, même accès que HR_MANAGER
  • GET /dashboard/summary en tant que EMPLOYEE → 403
  • GET /dashboard/summary en tant que MANAGER → 403
  • Nouveau tenant sans données → pendingApprovalsCount=0, absenceRatePercent=0.0, absentToday=0
  • Multi-tenant : les métriques du tenant A n'incluent pas les données du tenant B

Ce que QA Validera

  • Le tableau de bord s'affiche à 360px avec la grille KPI 2x2
  • Les cartes KPI affichent les valeurs correctes et sont appuyables
  • La carte "En attente" navigue vers la page des approbations
  • Les cartes d'approbation en attente affichent les boutons Approuver/Voir inline
  • L'approbation inline fonctionne (la carte s'anime à la sortie en cas de succès)
  • L'aperçu calendrier 2 semaines s'affiche correctement
  • Les liens ghost naviguent vers les pages correctes
  • Le nouveau tenant voit l'EmptyState de bienvenue avec le CTA
  • Hors ligne : données en cache affichées avec bandeau de données périmées, bouton Approuver désactivé
  • Desktop : 4 KPIs en ligne, mise en page 2 colonnes dessous

Hors Périmètre

  • Filtres avancés (Enterprise V2)
  • Export CSV/Excel/PDF (Enterprise V2)
  • 6-8 KPIs pour l'édition Enterprise (V2)
  • Mise en page du tableau de bord personnalisable / glisser-déposer de widgets (V2)
  • Tendances historiques / graphiques (V2)
  • Mises à jour en temps réel via WebSocket (V2 — polling utilisé en MVP)

Définition de Done

  • [ ] Tous les endpoints backend implémentés et retournant les réponses correctes
  • [ ] Toutes les pages frontend s'affichent correctement à 360px, 768px, 1024px
  • [ ] Les 5 états UI implémentés (chargement, vide, erreur, hors ligne, succès)
  • [ ] La micro-copie française correspond exactement à la spécification design
  • [ ] Tous les critères d'acceptation passent manuellement
  • [ ] Tests unitaires écrits et passants
  • [ ] Tests d'intégration écrits et passants
  • [ ] Isolation multi-tenant vérifiée — toutes les métriques limitées au tenant
  • [ ] La lecture hors ligne fonctionne (Papillon) — données en cache affichées avec bandeau de données périmées, actions bloquées
  • [ ] Pas de any TypeScript
  • [ ] Pas de types bruts Java — tous les génériques explicites
  • [ ] Les réponses API suivent le format d'enveloppe standard
  • [ ] Performance vérifiée : < 500ms pour un tenant de 50 employés