Story CP-012: Admin Console — Tenant List + Payment Confirmation + Suspension¶
Module: control-plane Slice: Slice 12a from architecture (split from original CP-012) Brand context: ALTARYS ENTERPRISE (Admin Console — corporate, data-dense, desktop-only) Priority: 12 Depends on: CP-001, CP-002, CP-003, CP-004, CP-005, CP-006, CP-007, CP-008, CP-009, CP-010 Estimated complexity: L
Objective¶
Build the core ALTARYS operator admin console — a separate React application (desktop-only, no offline) for managing tenants, confirming bank transfer payments, and suspending/reactivating tenants. This story establishes the admin app shell (AdminLayout, routing, auth), the tenant list with filtering/pagination, tenant detail view, pending payments dashboard, and suspension/reactivation flows. Module override, country config, and metrics are handled in CP-029.
Backend Scope¶
API Endpoints (Admin-only)¶
All endpoints require PLATFORM_ADMIN role (Keycloak-managed, separate from tenant roles).
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| GET | /api/v1/admin/tenants | ?status=&segment=&channel=&search= | Page |
PLATFORM_ADMIN |
| GET | /api/v1/admin/tenants/{id} | — | AdminTenantDetailResponse | PLATFORM_ADMIN |
| POST | /api/v1/admin/tenants/{id}/suspend | {reason} |
204 | PLATFORM_ADMIN |
| POST | /api/v1/admin/tenants/{id}/reactivate | — | 204 | PLATFORM_ADMIN |
| DELETE | /api/v1/admin/tenants/{id} | — | 204 (soft delete) | PLATFORM_ADMIN |
| GET | /api/v1/admin/payments/pending | — | List |
PLATFORM_ADMIN |
| POST | /api/v1/admin/payments/{id}/confirm | — | 204 | PLATFORM_ADMIN |
| GET | /api/v1/admin/audit | Cross-tenant audit query | Page |
PLATFORM_ADMIN |
Tenant suspension: Sets status=SUSPENDED, requires reason text, creates audit entry, sends ACCOUNT_SUSPENDED email.
Multi-Tenant Considerations¶
- Admin endpoints are NOT tenant-scoped — they query across ALL tenants
- Admin console uses a separate Keycloak client with PLATFORM_ADMIN role
- All admin actions recorded in audit trail with admin's user_id
Frontend Scope (Separate React App)¶
Application Setup¶
- Separate React app:
frontend-admin/directory (Vite + TypeScript + React 19) — separate monorepo top-level directory alongsidefrontend/(Papillon) and futurefrontend-enterprise/(Decision D3) - Desktop-only: min-width 1024px, no mobile layouts
- No offline: no PWA, no service workers, no IndexedDB
- Design language: Corporate navy/blue (NOT Papillon warm amber)
- Primary:
#1E3A5F, Accent:#2563EB, Background:#F9FAFB - Typography: Inter 14px body (denser than Papillon 16px)
- See design spec §15.1 for full admin token set
Pages & Routes¶
/dashboard— Tenant list with KPI summary cards/tenants/:id— Tenant detail (tabbed: Informations, Modules, Paiements, Audit, Actions)/payments— Pending payments dashboard
Components¶
AdminLayout.tsx— Sidebar nav (200px) + main contentTenantListPage.tsx— Data table with filters, sorting, paginationTenantDetailPage.tsx— Tabbed detail viewPendingPaymentsPage.tsx— Grouped tables (bank transfers, failed, overdue)
UI States¶
Tenant List:
| State | Behavior | French Copy |
|---|---|---|
| Loading | Table skeleton | — |
| Empty | "Aucun tenant trouvé" | — |
| Error | Error banner above table | "Erreur de chargement" |
| Success | Data table with pagination | — |
Key Interactions¶
Tenant list: Dense table. Columns: Status, Entreprise, Segment, Employés, Canal, Créé, Paiement. Row click → tenant detail. Filters: Status dropdown, Segment dropdown, Canal dropdown, Date range. Search bar. Export CSV button.
Pending payments: Auto-refresh every 5 minutes. "Confirmer" button → confirmation dialog → invoice PAID → tenant status updated → email sent. "Relancer" sends payment reminder email.
Tenant suspension: Requires typed reason. Confirmation dialog. Sends ACCOUNT_SUSPENDED email.
Status icons in tenant table:
| Status | Icon | Color |
|---|---|---|
| ACTIVE | ● |
--admin-success (#059669) |
| TRIAL | ◐ |
--admin-accent (#2563EB) |
| ACTIVE_INCOMPLETE | ● |
--admin-warning (#D97706) |
| ACTIVE_PAYMENT_PENDING | ⚠ |
--admin-warning |
| PAYMENT_REQUIRED | ⚠ |
--admin-warning |
| SUSPENDED | ✕ |
--admin-error (#DC2626) |
| DELETED | ◌ |
--admin-text-secondary |
| PENDING | ◌ |
--admin-text-secondary |
| PENDING_VERIFICATION | ◌ |
--admin-text-secondary |
Acceptance Criteria¶
AC-095: Admin sees all tenants
Given 142 tenants exist on the platform
When the admin views the tenant list
Then all 142 are listed with pagination (20 per page)
And filters work for status, segment, channel, date
AC-096: Admin confirms bank transfer payment
Given a tenant has status ACTIVE_PAYMENT_PENDING
When the admin clicks "Confirmer le paiement"
Then the invoice is marked PAID
And the tenant status transitions to ACTIVE (or ACTIVE_INCOMPLETE)
And a PAYMENT_RECEIVED email is sent to the tenant admin
AC-097: Admin suspends tenant with reason
Given a tenant with status ACTIVE
When the admin suspends with reason "Non-paiement persistant"
Then the tenant status is SUSPENDED
And the reason is recorded in audit trail
And an ACCOUNT_SUSPENDED email is sent
OHADA & Regulatory Rules¶
- Admin actions (suspend, payment confirmation) are logged in the audit trail — satisfies accountability requirements.
- Payment confirmation creates a legal record of the transaction.
Standards & Conventions¶
docs/standards/react-typescript-guidelines.md— §Data tables, §Admin patternsdocs/standards/api-guidelines.md— §Admin endpoints, §Pagination, §Filtering
Testing Requirements¶
Unit Tests¶
- Admin API authorization: PLATFORM_ADMIN required for all endpoints
- Suspension: reason required, status transition valid
- Payment confirmation: invoice status transition
Integration Tests¶
- Full admin flow: list → detail → suspend → reactivate
- Payment confirmation: invoice + tenant status update
- Cross-tenant queries (admin can see all tenants)
- Authorization: non-admin user → 403 on admin endpoints
What QA Will Validate¶
- Tenant list displays correctly with all columns
- Filters and sorting work
- Payment confirmation flow end-to-end
- Suspension flow with reason
- Admin console only accessible with PLATFORM_ADMIN role
Out of Scope¶
- Module override, country config editor, metrics dashboard — CP-029
- Channel C (admin creates tenant) — V2
- Bulk operations (suspend multiple, etc.) — V2
- Automated alerts (email to admin on suspicious activity) — V2
- Advanced reporting/analytics — V2
- Mobile admin view — Not planned (desktop-only tool)
- Admin console offline mode — Not needed
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