Story CP-024: Provisioning Pipeline¶
Module: control-plane Slice: Slice 8d from architecture (split from CP-008) Brand context: [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority: 8 (after CP-022) Depends on: CP-022 Estimated complexity: L
Objective¶
Build the async provisioning pipeline that sets up a tenant's infrastructure after email verification. The pipeline runs 9 idempotent, retryable steps: DB provisioning, data seeding, org structure seeding, Keycloak setup, module gating activation, MinIO storage, matricule counter initialization, notification email, and status update. Also includes the ProfileSelector (employee count → DB profile mapping) and the provisioning status polling endpoint.
Backend Scope¶
Entities & Records¶
DTOs:
public record ProvisioningStatusResponse(
UUID tenantId, String status, // "IN_PROGRESS", "COMPLETED", "FAILED"
int completedSteps, int totalSteps,
@Nullable String currentStep
) {}
Service Layer¶
ProvisioningOrchestrator.java:
- Async event-driven pipeline triggered by TenantStatusChanged event (published by CP-022 on email verification)
- 9 steps, each idempotent and retryable:
| Step | Class | Description |
|---|---|---|
| 1 | DbProvisioningStep |
Profile A (Shared): no-op (shared DB). Profile B (Schema): create PostgreSQL schema. Profile C (DB-per-tenant): create PostgreSQL database, run tenant migrations. Profile D (BYO-DB): validate connection, run tenant migrations. |
| 2 | DataSeedingStep |
Seed country-specific reference data (ITS brackets, CNPS rates, holidays, categories, contract types, salary grids) |
| 3 | OrgStructureSeedingStep |
Create root Entity from company name + 6 default departments (Direction Générale, Ressources Humaines, Comptabilité, Commercial, Production, Informatique) |
| 4 | KeycloakSetupStep |
Create Keycloak client, create admin user with DG role, seed 5 default roles (DG, RH_MANAGER, COMPTABLE, EMPLOYE, MANAGER) |
| 5 | ModuleGatingStep |
Activate selected modules in TenantModule (from registration request) |
| 6 | MinIoSetupStep |
Create tenant-scoped MinIO storage bucket (bucket name: tenant-{tenantId}) |
| 7 | MatriculeCounterStep |
Initialize matricule counter at 1 for tenant (table: tenant_matricule_counters) |
| 8 | NotificationStep |
Send activation email (channel-specific content: "Bienvenue sur Papillon !" for Channel A) |
| 9 | StatusUpdateStep |
Update tenant status: IF free trial → TRIAL (trial period starts, per FR-CP-010). IF payment required → stay PAYMENT_REQUIRED (billing handles activation). |
- Each step: 3 retries with exponential backoff (1s, 4s, 16s)
- On step failure after 3 retries: stop pipeline, do NOT execute remaining steps
- On total failure: tenant status → PROVISIONING_FAILED (internal), alert ALTARYS ops via notification service
- Provisioning status trackable via polling endpoint (frontend shows progress)
- All steps must be idempotent: running the same step twice produces the same result (no duplicate data, no errors)
ProfileSelector.java:
- selectProfile(int declaredEmployeeCount) → String
- IF count <= 200 → "SHARED" (Profile A)
- IF count > 200 → "DB_PER_TENANT" (Profile C)
- MVP threshold = 200 (tentative, configurable)
- Profile B and D assigned by platform admin (not auto-selected)
API Endpoints¶
| Method | Path | Request Body | Response | Auth |
|---|---|---|---|---|
| GET | /api/v1/onboarding/provisioning-status/{tenantId} | — | ProvisioningStatusResponse | Public (with token) |
Validation Rules¶
- Provisioning status endpoint requires a valid token (included in email verification redirect URL)
tenantId: must be a valid UUID matching an existing tenant- Pipeline only starts for tenants in TRIAL or PAYMENT_REQUIRED status (not PENDING_VERIFICATION)
Multi-Tenant Considerations¶
- Provisioning CREATES the tenant context — this is where the tenant's data space is born
- Profile A (Shared): uses existing shared DB with tenant_id column
- Profile B (Schema): creates new PostgreSQL schema per tenant
- Profile C (DB-per-tenant): creates new PostgreSQL database per tenant
- Profile D (BYO-DB): validates provided connection string, runs migrations on external DB
- After provisioning, all subsequent requests for this tenant use the correct data source
- Keycloak client isolation: each tenant gets their own Keycloak client with separate realm/client configuration
Frontend Scope¶
Pages & Routes¶
/provisioning/{tenantId}— Provisioning progress page (polls backend for status)
Components¶
ProvisioningProgressPage.tsx— Step progress indicator showing completed/current/pending steps
UI States (ALL REQUIRED)¶
Provisioning Progress:
| State | Behavior | French Copy |
|---|---|---|
| In progress | Animated step list with checkmarks for completed, spinner for current, grey for pending | "Configuration de votre espace en cours..." |
| Step completing | Checkmark animation on step completion | Step names (see below) |
| Completed | All steps checked, celebration animation, auto-redirect (3s) | "Votre espace est pret ! Redirection en cours..." |
| Failed | Error message + support contact | "Une erreur est survenue lors de la configuration. Notre equipe a ete notifiee et vous contactera sous peu." |
Step names (French — displayed in progress UI):
| Step | French Name |
|---|---|
| 1 | "Preparation de la base de donnees" |
| 2 | "Chargement des donnees de reference" |
| 3 | "Creation de votre structure organisationnelle" |
| 4 | "Configuration de la securite" |
| 5 | "Activation de vos modules" |
| 6 | "Preparation du stockage de documents" |
| 7 | "Initialisation des compteurs" |
| 8 | "Envoi de l'e-mail de bienvenue" |
| 9 | "Finalisation" |
Responsive Behavior¶
- 360px (mobile): Vertical step list, full width. Centered on warm bg (#FFFDF7).
- 1024px+ (desktop): Centered card (max-width 600px) with step list.
Interactions¶
- Page polls
GET /api/v1/onboarding/provisioning-status/{tenantId}every 2 seconds - Each step completion triggers a checkmark animation
- On COMPLETED: 3-second celebration animation → auto-redirect to Keycloak password creation (for free trial) or billing page (for payment required)
- On FAILED: show error message, stop polling, provide support contact email
- Polling stops after COMPLETED or FAILED
French micro-copy:
| Key | French Text |
|---|---|
provisioning.title |
"Configuration de votre espace" |
provisioning.subtitle |
"Cela ne prendra que quelques instants..." |
provisioning.completed |
"Votre espace est pret !" |
provisioning.redirect |
"Redirection en cours..." |
provisioning.failed |
"Une erreur est survenue lors de la configuration." |
provisioning.support |
"Notre equipe a ete notifiee et vous contactera sous peu." |
provisioning.support_email |
"[email protected]" |
Acceptance Criteria¶
AC-070: Provisioning pipeline completes all 9 steps
Given my email is verified and tenant status is TRIAL
When the provisioning pipeline runs
Then the following steps execute in order:
1. DB Provisioning (no-op for Shared, schema create for Schema-per-tenant, DB create + migrate for DB-per-tenant, validate + migrate for BYO-DB)
2. Data Seeding (country-specific reference data: ITS brackets, CNPS rates, holidays, categories, contract types, salary grids)
3. Org Structure Seeding (root Entity from company name + 6 default departments)
4. Keycloak Setup (create client, admin user with DG role, 5 default roles)
5. Module Gating (activate selected modules in TenantModule)
6. MinIO Setup (create tenant-scoped bucket)
7. Matricule Counter Init (set counter to 1)
8. Notification Email (welcome email with channel-specific copy)
9. Status Update (TRIAL if free trial, stay PAYMENT_REQUIRED if not)
And the tenant is fully ready to use
AC-071: Provisioning failure handling
Given the Keycloak step fails during provisioning
When 3 retries with exponential backoff (1s, 4s, 16s) fail
Then the tenant is marked PROVISIONING_FAILED
And an alert is sent to ALTARYS ops
And the remaining steps are not attempted
AC-072: Provisioning steps are idempotent
Given step 5 (Module Gating) completes successfully
When step 5 is re-run due to a retry
Then the same modules are activated (no duplicates, no errors)
And the final result is identical
OHADA & Regulatory Rules¶
- AUDCIF Art. 24: Tenant data isolation must be guaranteed from the moment of provisioning. Each tenant's financial data must be in their own data space.
- Data seeding: Reference data (ITS brackets, CNPS rates) seeded per tenant must match the validated legal data from the country config engine (CP-006/CP-019).
- Default departments: The 6 default departments follow common Ivorian SME structure. Tenants can customize later.
Standards & Conventions¶
docs/standards/java-spring-guidelines.md— §Async processing, §Application Events, §Idempotent operations, §Exponential backoffdocs/standards/database-guidelines.md— §Provisioning pipeline, §Idempotent steps, §Multi-tenant DB profilesdocs/standards/api-guidelines.md— §Public endpoints (provisioning status), §Polling patterndocs/standards/react-typescript-guidelines.md— §Polling pattern, §Animation, §Public pages
Testing Requirements¶
Unit Tests¶
- ProfileSelector: threshold logic (<=200 → SHARED, >200 → DB_PER_TENANT)
- Each provisioning step: idempotent (can run twice without side effects)
- ProvisioningOrchestrator: steps execute in order
- ProvisioningOrchestrator: stops on failure (remaining steps not executed)
- ProvisioningOrchestrator: retry logic (3 retries with exponential backoff)
Integration Tests¶
- Full provisioning pipeline: all 9 steps execute in order for Profile A (Shared)
- Provisioning pipeline for Profile C (DB-per-tenant): DB creation + migrations
- Provisioning retry: simulate step failure → retry succeeds
- Provisioning total failure: 3 retries fail → PROVISIONING_FAILED status + ops alert
- Provisioning status endpoint: returns correct step count and current step
- Idempotency: run pipeline twice → no duplicate data
What QA Will Validate¶
- Provisioning progress page: step-by-step animation
- Completion celebration animation + auto-redirect
- Failure state: error message displayed correctly
- Mobile and desktop layouts
- Polling stops after completion/failure
Out of Scope¶
- Registration form (Step 1) — CP-008
- Email verification — CP-022
- Module selection UI — CP-023
- Payment flow — CP-009
- Password creation flow — Keycloak handles this
- Post-registration dashboard (welcome celebration) — Host shell feature
- Channel B (CRM) onboarding — CP-013
- Channel C (Admin back-office) onboarding — V2
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 (new tenant's data is isolated after provisioning)
- [ ] Offline write+sync works — N/A (provisioning 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 data mutation