Aller au contenu

Story AB-019: HR Dashboard (Backend + Frontend)

Module: absence-management Slice: VS-AB-014 from architecture Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 19 Depends on: AB-009, AB-011 Can develop concurrently with: AB-018, AB-020 Merge order: After AB-009 and AB-011 Estimated complexity: M PRD User Stories: US-ABS-008


Objective

Provide HR managers and DGs with an at-a-glance dashboard showing key absence metrics: pending approval count, absence rate, absent today count, upcoming leaves, and low-balance employee warnings. The dashboard includes a compact pending approvals list with inline actions and a 2-week calendar preview.


Backend Scope

Entities & Records

Response records:

public record DashboardSummaryResponse(
    int pendingApprovalsCount,
    BigDecimal absenceRatePercent,           // (days off / working days in current month) x 100, 1 decimal
    int absentToday,
    int lowBalanceEmployeesCount,            // employees with annual balance < 5 days
    List<UpcomingLeave> upcomingLeavesThisWeek,
    List<PendingApprovalSummary> recentPendingApprovals
) {}

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

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

Repository Layer

Uses existing repositories from AB-002 and AB-009: - LeaveRequestRepository — count PENDING_APPROVAL, query upcoming approved leaves - LeaveBalanceLedgerRepository — for absence rate calculation - LeaveEmployeeProfileRepository — for low-balance employee count - Custom queries: - countByTenantIdAndStatus(UUID tenantId, LeaveStatus status) — pending count - findApprovedLeavesOverlappingDate(UUID tenantId, LocalDate date) — absent today - findUpcomingApprovedLeaves(UUID tenantId, LocalDate fromDate, LocalDate toDate) — this week's upcoming - findRecentPendingApprovals(UUID tenantId, int limit) — latest pending requests (limit=5) - countEmployeesWithBalanceBelow(UUID tenantId, BigDecimal threshold) — low balance count

Service Layer

DashboardService.java:

  • getSummary(UUID tenantId): DashboardSummaryResponse
  • pendingApprovalsCount: COUNT of LeaveRequests with status=PENDING_APPROVAL
  • absenceRatePercent: (total absence days in current month / total working days in current month) x 100, computed on-the-fly with BigDecimal
  • absentToday: COUNT of employees currently on approved leave (leave period includes today)
  • lowBalanceEmployeesCount: COUNT of employees with annual leave balance < 5 days
  • upcomingLeavesThisWeek: approved leaves starting within the current week (Monday-Sunday)
  • recentPendingApprovals: latest 5 pending approval requests, ordered by submittedAt desc

Performance target: < 500ms for 50-employee tenant (use COUNT queries, not full scans)

API Endpoints

Method Path Query Params Response Auth
GET /api/v1/absence/dashboard/summary ApiResponse<DashboardSummaryResponse> HR_MANAGER, DG

Validation Rules

  • Only HR_MANAGER and DG can access the dashboard — 403 for other roles
  • No input validation needed (no request parameters beyond auth)

Multi-Tenant Considerations

  • All queries include tenantId from ScopedValue<TenantContext>
  • Absence rate calculation scoped to tenant's employees only
  • Low balance threshold (5 days) is hardcoded in MVP — configurable in V2
  • Works across all 4 DB profiles (designed for BYO-DB first)

Frontend Scope

OFFLINE SYNC REMINDER (Papillon — CRITICAL): Dashboard is a read-only aggregation view. Cached dashboard data is served when offline with a stale-data banner. Approval actions from dashboard are online-only. See docs/standards/offline-sync-guidelines.md.

Pages & Routes

Route Page Description
/absences/tableau-de-bord AbsenceDashboardPage HR/DG absence dashboard

Components

  • KpiCard — Metric card with icon, label, value, and optional background color
  • PendingApprovalCard — Compact approval card with employee name, dates, leave type, and inline action buttons
  • MiniCalendarTimeline — 2-week calendar preview widget (reuses CalendarTimeline logic from AB-018 in compact form)
  • GhostLink — Navigation link with arrow icon
  • WelcomeEmptyState — Full-page empty state for new tenants

UI States (ALL REQUIRED)

State Behavior French Copy
Loading 4 small shimmer rectangles (KPIs) + 2 medium rectangles (lists)
Empty (new tenant) EmptyState with rocket illustration "Bienvenue dans la gestion des absences" / CTA: "Configurer les parametres"
Error Toast + retry button "Impossible de charger le tableau de bord."
Offline Cached data + stale-data banner "Hors connexion — derniere synchro : {time}"
Success N/A (read-only dashboard)

Responsive Behavior

Mobile (360px — Papillon primary): - 4 KPI cards in 2x2 grid: 1. "En attente" — pending count, bg=warning-light, tappable → navigates to /absences/approbations 2. "Taux d'absence" — percentage, bg=neutral-light 3. "Absents aujourd'hui" — count, bg=neutral-light 4. "Soldes bas" — count (employees with < 5 days), bg=amber-light - "Demandes recentes" section: - Compact PendingApprovalCards with employee name, dates, type - Inline "Approuver" (primary, sm) + "Voir" (ghost, sm) buttons - Max 5 cards displayed - "Calendrier (2 semaines)" section: - MiniCalendarTimeline showing 14-day snapshot - "Voir toutes les approbations" ghost link → /absences/approbations - "Voir le calendrier complet" ghost link → /absences/calendrier - All touch targets >= 48px

Desktop (1024px+ — Enterprise primary): - 4 KPI cards in single horizontal row - 2-column layout below KPIs: - Left column: "Demandes en attente" — pending approvals list with inline actions - Right column: "Calendrier (2 semaines)" — 2-week calendar preview - Ghost links at bottom of each section - Click on employee name in pending list → navigate to employee balance detail

Interactions

  • Tap KPI "En attente" card → navigate to /absences/approbations
  • Tap "Approuver" on pending card → inline approval (PATCH to approval endpoint from AB-011), card animates out on success
  • Tap "Voir" on pending card → navigate to leave request detail
  • Tap employee name from dashboard context → navigate to employee balance detail (AB-021)
  • Ghost links → navigate to full approvals list or full calendar
  • Pull-to-refresh (mobile) → re-fetch dashboard summary
  • Auto-refresh: dashboard re-fetches every 60 seconds when tab is active

French Micro-Copy

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

Acceptance Criteria

AC-060: HR dashboard shows key metrics
Given I am HR_MANAGER
When I open the Absence dashboard
Then I see: pending approval count (badge), absence rate (%), absent today count, low balance employee count, upcoming leaves this week

AC-061: Employee balance detail accessible from dashboard
Given I click on an employee's name in the pending approvals list
When the detail view opens
Then I see the full ledger of accruals, deductions, adjustments, and carry-overs

AC-062: Pending approvals are actionable from dashboard
Given there are pending approval requests
When I view the dashboard
Then I can approve or navigate to detail directly from the dashboard cards

AC-063: New tenant sees welcome state
Given a new CI tenant has just activated the ABSMGT module
When HR opens the dashboard
Then they see the welcome EmptyState with CTA to configure settings

OHADA & Regulatory Rules

N/A — dashboard is a display/aggregation feature with no regulatory requirements.


Standards & Conventions

  • docs/standards/java-spring-guidelines.md — §REST controller patterns, §RBAC authorization, §Query optimization
  • docs/standards/database-guidelines.md — §Multi-tenant repository pattern, §BigDecimal for rate calculations, §COUNT query optimization
  • docs/standards/api-guidelines.md — §GET endpoint patterns, §ApiResponse envelope
  • docs/standards/react-typescript-guidelines.md — §Component patterns, §CSS Modules, §i18n, §Responsive grid patterns
  • docs/standards/design-system.md — §Card, §Button (inline variants), §EmptyState, §Toast, §GhostLink
  • docs/standards/offline-sync-guidelines.md — §Cached read-only data, §Stale-data banner, §Online-only actions (approval)
  • docs/standards/multi-datasource-patterns.md — §Tenant-scoped repository queries

Testing Requirements

Unit Tests

  • DashboardService.getSummary(): 3 pending requests → pendingApprovalsCount=3
  • DashboardService.getSummary(): 0 pending requests → pendingApprovalsCount=0
  • DashboardService.getSummary(): 2 employees absent today → absentToday=2
  • DashboardService.getSummary(): 15 absence days in month with 22 working days → absenceRatePercent=68.2 (BigDecimal)
  • DashboardService.getSummary(): 0 absence days → absenceRatePercent=0.0
  • DashboardService.getSummary(): 4 employees with balance < 5 days → lowBalanceEmployeesCount=4
  • DashboardService.getSummary(): upcoming leaves filtered to current week only
  • DashboardService.getSummary(): recent pending approvals limited to 5, ordered by submittedAt desc

Integration Tests

  • GET /dashboard/summary as HR_MANAGER → 200, all metrics present
  • GET /dashboard/summary as DG → 200, same access as HR_MANAGER
  • GET /dashboard/summary as EMPLOYEE → 403
  • GET /dashboard/summary as MANAGER → 403
  • New tenant with no data → pendingApprovalsCount=0, absenceRatePercent=0.0, absentToday=0
  • Multi-tenant: tenant A metrics do not include tenant B data

What QA Will Validate

  • Dashboard renders at 360px with 2x2 KPI grid
  • KPI cards show correct values and are tappable
  • "En attente" card navigates to approvals page
  • Pending approval cards show inline Approuver/Voir buttons
  • Inline approve works (card animates out on success)
  • 2-week calendar preview renders correctly
  • Ghost links navigate to correct pages
  • New tenant sees welcome EmptyState with CTA
  • Offline: cached data shown with stale banner, approve button disabled
  • Desktop: 4 KPIs in row, 2-column layout below

Out of Scope

  • Advanced filters (Enterprise V2)
  • CSV/Excel/PDF export (Enterprise V2)
  • 6-8 KPIs for Enterprise edition (V2)
  • Customizable dashboard layout / widget drag-and-drop (V2)
  • Historical trends / charts (V2)
  • Real-time WebSocket updates (V2 — polling used in MVP)

Definition of Done

  • [ ] All backend endpoints implemented and returning correct responses
  • [ ] All frontend pages render correctly at 360px, 768px, 1024px
  • [ ] All 5 UI states implemented (loading, empty, error, offline, success)
  • [ ] French micro-copy matches design spec exactly
  • [ ] All acceptance criteria pass manually
  • [ ] Unit tests written and passing
  • [ ] Integration tests written and passing
  • [ ] Multi-tenant isolation verified — all metrics scoped to tenant
  • [ ] Offline read works (Papillon) — cached data displayed with stale banner, actions blocked
  • [ ] No TypeScript any
  • [ ] No Java raw types — all generics explicit
  • [ ] API responses follow standard envelope format
  • [ ] Performance verified: < 500ms for 50-employee tenant