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): DashboardSummaryResponsependingApprovalsCount: COUNT of LeaveRequests with status=PENDING_APPROVALabsenceRatePercent: (total absence days in current month / total working days in current month) x 100, computed on-the-fly with BigDecimalabsentToday: COUNT of employees currently on approved leave (leave period includes today)lowBalanceEmployeesCount: COUNT of employees with annual leave balance < 5 daysupcomingLeavesThisWeek: 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
tenantIdfromScopedValue<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 colorPendingApprovalCard— Compact approval card with employee name, dates, leave type, and inline action buttonsMiniCalendarTimeline— 2-week calendar preview widget (reuses CalendarTimeline logic from AB-018 in compact form)GhostLink— Navigation link with arrow iconWelcomeEmptyState— 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 optimizationdocs/standards/database-guidelines.md— §Multi-tenant repository pattern, §BigDecimal for rate calculations, §COUNT query optimizationdocs/standards/api-guidelines.md— §GET endpoint patterns, §ApiResponse envelopedocs/standards/react-typescript-guidelines.md— §Component patterns, §CSS Modules, §i18n, §Responsive grid patternsdocs/standards/design-system.md— §Card, §Button (inline variants), §EmptyState, §Toast, §GhostLinkdocs/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=3DashboardService.getSummary(): 0 pending requests → pendingApprovalsCount=0DashboardService.getSummary(): 2 employees absent today → absentToday=2DashboardService.getSummary(): 15 absence days in month with 22 working days → absenceRatePercent=68.2 (BigDecimal)DashboardService.getSummary(): 0 absence days → absenceRatePercent=0.0DashboardService.getSummary(): 4 employees with balance < 5 days → lowBalanceEmployeesCount=4DashboardService.getSummary(): upcoming leaves filtered to current week onlyDashboardService.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