Story CP-029: Admin Console — Module Override + Country Config + Metrics¶
Module: control-plane Slice: Slice 12b from architecture (split from CP-012) Brand context: ALTARYS ENTERPRISE (Admin Console — corporate, data-dense, desktop-only) Priority: 14 Depends on: CP-012 Estimated complexity: M
Objective¶
Extend the ALTARYS operator admin console (built in CP-012) with four power-user features: module override (promotional access grants), country configuration editor (with unverified-rate highlighting), platform metrics dashboard, and CRM registration review (FR-CP-101). These features allow operators to fine-tune tenant access, manage regulatory reference data, monitor platform health, and review CRM-created tenants at a glance.
Backend Scope¶
API Endpoints (Admin-only)¶
All endpoints require PLATFORM_ADMIN role (Keycloak-managed, separate from tenant roles). The admin app shell, auth, and Keycloak client are already set up in CP-012.
Scheduled Jobs¶
PreHireTransitionJob (runs daily, iterates all tenants):
- Scheduled service that transitions PRE_HIRE employees to ACTIVE on hire_date.
- Per ADR-16: Uses ThreadLocal fallback for TenantContext propagation in @Scheduled context (ScopedValue is for HTTP requests only). Sets TenantContext before each tenant's queries, clears after.
- Processes all tenants sequentially. For each tenant: query employees where status = PRE_HIRE AND hire_date <= today, transition each to ACTIVE, publish EmployeeStatusChanged.
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| POST | /api/v1/admin/tenants/{id}/modules/{code}/override | {status, expiryDate?} |
204 | PLATFORM_ADMIN |
| GET | /api/v1/admin/metrics | — | PlatformMetricsResponse | PLATFORM_ADMIN |
| GET | /api/v1/admin/config/countries/{code} | — | CountryConfigResponse | PLATFORM_ADMIN |
| PUT | /api/v1/admin/config/countries/{code}/rates/{rateId} | {value, isVerified} |
204 | PLATFORM_ADMIN |
| GET | /api/v1/admin/crm-registrations | ?week=&flagged= | Page |
PLATFORM_ADMIN |
| POST | /api/v1/admin/crm-registrations/{id}/flag | {reason} |
204 | PLATFORM_ADMIN |
Module override: Temporarily activates a module for a tenant (promotional access). Optional expiry date. Audit logged.
PlatformMetricsResponse:
public record PlatformMetricsResponse(
Map<String, Integer> tenantsByStatus, // e.g. {"ACTIVE": 80, "TRIAL": 30, ...}
int totalActiveEmployees,
BigDecimal mrr, // Monthly Recurring Revenue in XOF
Map<String, Integer> modulePopularity, // e.g. {"PAYROL": 95, "LEAVE": 110}
List<WeeklyGrowthPoint> tenantGrowth, // last 12 weeks
Map<String, Integer> paymentMethodSplit // e.g. {"MOBILE_MONEY": 60, "BANK_TRANSFER": 20}
) {}
public record WeeklyGrowthPoint(
LocalDate weekStart,
int newTenants,
int totalTenants
) {}
Multi-Tenant Considerations¶
- All endpoints query across ALL tenants (admin-scoped, not tenant-scoped)
- Metrics are aggregated platform-wide — no tenant_id filter
- Country config edits affect ALL tenants in that country
Frontend Scope¶
Pages & Routes¶
These pages are added to the existing admin app (AdminLayout from CP-012):
/metrics— Platform metrics dashboard/config/country— Country configuration editor/crm-registrations— CRM registration review (weekly report, flag suspicious)
Module override UI is added as a tab/action within the existing TenantDetailPage (built in CP-012).
Components¶
MetricsPage.tsx— KPI cards + chartsCountryConfigEditor.tsx— Two-panel layout: category selector + data tableCrmRegistrationReviewPage.tsx— Weekly report table with flag action- Module override section within
TenantDetailPage.tsxModules tab
UI States¶
Metrics Page:
| State | Behavior | French Copy |
|---|---|---|
| Loading | Skeleton cards and chart placeholders | — |
| Error | Error banner | "Impossible de charger les métriques" |
| Success | KPI cards + charts | — |
Country Config Editor:
| State | Behavior | French Copy |
|---|---|---|
| Loading | Table skeleton | — |
| Empty | No rates for selected category | "Aucun taux configuré pour cette catégorie" |
| Error | Error banner | "Erreur de chargement de la configuration" |
| Success | Editable data table | — |
| Save success | Toast notification | "Configuration mise à jour" |
CRM Registration Review:
| State | Behavior | French Copy |
|---|---|---|
| Loading | Table skeleton | — |
| Empty | No CRM registrations this week | "Aucune inscription CRM cette semaine" |
| Success | Table with flag action | — |
| Flag confirm | Confirmation dialog | "Signaler cette inscription comme suspecte ?" |
Module Override Dialog:
| State | Behavior | French Copy |
|---|---|---|
| Form | Module selector + optional expiry date | "Accorder l'accès promotionnel" |
| Confirm | Confirmation dialog | "Confirmer l'accès au module {code} pour {tenant} ?" |
| Success | Toast notification | "Accès au module accordé" |
| Error | Error banner in dialog | "Impossible d'accorder l'accès" |
Key Interactions¶
Country config editor: Left panel: country selector (CI) + config categories (e.g. CNPS, Impôts). Right panel: editable data table. Unverified rates (is_verified=false) shown with orange background + "Non verifie" badge. Admin can toggle is_verified. Save button per row or bulk save.
Module override (within TenantDetailPage Modules tab): "Accorder l'accès" button next to unsubscribed modules → dialog with optional expiry date → confirmation → audit logged.
Platform Metrics¶
| Metric | Display |
|---|---|
| Total tenants by status | Horizontal stacked bar |
| Total active employees | Big number with trend |
| MRR (Monthly Recurring Revenue) | Big number with trend |
| Module popularity | Horizontal bar chart |
| Tenant growth | Line chart (last 12 weeks) |
| Payment method split | Pie chart |
Acceptance Criteria¶
AC-098: Admin overrides module access
Given tenant "TechCI" does not subscribe to PAYROL
When the admin grants promotional access with expiry 2026-04-01
Then PAYROL is ACTIVE for TechCI until 2026-04-01
And the override is recorded in audit
AC-099: Country config editor shows unverified rates
Given CNPS AV ceiling has is_verified=false
When the admin views country config
Then the AV row has orange background and "Non verifie" badge
AC-115: CRM registration review
Given 5 tenants were created via CRM channel this week
When the admin views /crm-registrations
Then all 5 CRM-created tenants are listed with creation date, company name, and channel
And the admin can flag a suspicious registration with a reason
And flagged registrations are visually marked
AC-100: Platform metrics display
Given the admin navigates to /metrics
Then KPI cards show total tenants, employees, MRR
And charts display tenant growth and module popularity
OHADA & Regulatory Rules¶
- Module override is audit-logged — satisfies accountability requirements.
- Country config rates have
is_verifiedflag to track which regulatory rates need official confirmation. Unverified rates are visually flagged to prevent inadvertent use.
Standards & Conventions¶
docs/standards/react-typescript-guidelines.md— §Chart components, §Admin patternsdocs/standards/api-guidelines.md— §Admin endpointsdocs/standards/database-guidelines.md— §Country configuration tables
Testing Requirements¶
Unit Tests¶
- Module override: expiry date handling, status transition, audit entry creation
- Metrics aggregation: correct counts by status, MRR calculation (BigDecimal)
- Country config: rate update with is_verified toggle
Integration Tests¶
- Module override: grant → verify module active → expiry passes → module inactive
- Metrics endpoint returns correct aggregated data
- Country config update: edit rate → verify persisted → verify is_verified flag
- Authorization: non-admin user → 403 on all endpoints
What QA Will Validate¶
- Country config editor: view, edit, is_verified toggle, orange badge on unverified
- Metrics dashboard shows data and charts render
- Module override dialog flow end-to-end
- All new pages accessible from admin sidebar navigation
Out of Scope¶
- Admin app shell, layout, auth, tenant list, payments, suspension — CP-012 (already built)
- Advanced reporting/analytics — V2
- Automated alerts based on metrics — V2
- Country config bulk import — V2
- Module override auto-expiry cron job — V2 (manual check on access)
Definition of Done¶
- [ ] All backend endpoints implemented and returning correct responses
- [ ] All frontend pages render correctly at 1024px+ (desktop-only)
- [ ] All UI states implemented (loading, empty, error, success) — no offline state needed
- [ ] French copy correct
- [ ] All acceptance criteria pass manually
- [ ] Unit tests written and passing
- [ ] Integration tests written and passing
- [ ] Multi-tenant isolation verified — admin can see all, tenants cannot see admin
- [ ] Offline write+sync works — N/A (admin console always online)
- [ ] No TypeScript
any— all types explicit - [ ] No Java raw types — all generics explicit
- [ ] API responses follow standard envelope format
- [ ] Audit trail entries created for every admin action (module override, config edit)