Aller au contenu

PRD V0 - Pre-MVP Re-Scoping

Assisted renewal platform for brokers and insurers

Version 0.0.0 → 0.1.0 Sub-version Roadmap


Change Log

Version Date Change
0.0.0 2026-05-20 Initial V0 envelope PRD: 7 sub-version contract, DB profile taxonomy, cross-module anchors, module scope deltas, compliance posture, personas.
0.0.1 2026-05-21 Founder review pass 1: resolved V0-OQ-01 (payment provider: first to accept partnership wins), resolved V0-OQ-03 (Keycloak shared realm + Organizations + per-org IdP), added § 5.8 Keycloak realm strategy locks, switched § 6.2 mitigation #3 to default platform-hosted privacy page, reframed § 2 multi-agency wording. Em-dash characters scrubbed (project writing convention).

§ 1. Purpose of This Document

This document defines V0:
a re-scope of the V1 MVP into 7 demonstrable, independently-shippable sub-versions (v0.0.0 → v0.1.0).
V0 is NOT a throwaway prototype - it uses the same locked stack (Java 26 / Spring Boot 4.0.5 / React 19.2 / PostgreSQL / Keycloak) and applies additive, non-breaking cuts to V1's scope. Every feature in V0 must layer cleanly into V1 without rewrites.

V0 targets a bipolar market: - SME segment (S1–S3, SHARED DB profile): small brokerage firms deploying on V0's shared multi-tenant DB. - Enterprise segment (S6, BYO DB profile): lead prospect NSIA Insurance, deploying on their own PostgreSQL with application-level isolation.

V1 will later add mid-market (S4, SCHEMA profile) and large (S5, DATABASE profile) in V3+.


§ 2. V0 Purpose & Relationship to V1/V2/V3

V0 Objectives

  • Ship a working, production-grade renewal platform in 12–16 weeks (first demo v0.0.0 at ~3–4 weeks) by slicing the V1 MVP into 7 sales-milestone sub-versions.
  • Validate product-market fit via founder presentations and early customer feedback (demo target: Basile presentation; production go-live target: NSIA @ v0.0.4).
  • Foundation for V1/V2: V0 implements critical architectural patterns (tenant-aware datasource resolver, Liquibase/Flyway multi-profile tooling, async tenant-context propagation, audit-log emission stubs) from v0.0.0 onwards so V1 inherits a production-ready platform shape, not scaffolding.

Relationship to V1

  • V1 is the source of truth for what V0 cuts FROM. All cuts are documented deltas (kept / simplified / deferred).
  • No feature in V0 contradicts V1 PRD unless explicitly noted as a V0 simplification and approved by founder.
  • V1 PRD versions remain frozen for the duration of V0 development. V0 PRD annotations (§ 4) reference specific V1 sections.
  • Additive rule: V1 features layer on top of V0 without rewrites. Example: V0 v0.0.1 has basic payment reconciliation; V1 adds advanced retry logic + manual fault resolution on top.

Relationship to V2/V3

  • V2 remains a vision doc (prd-vision-v2-v3.md). No V2 features leak into V0 stories.
  • DB profile timeline revised: V0 ships SHARED + BYO; V1 remains SHARED + BYO; SCHEMA + DATABASE deferred to V3 (unless customer need drives them earlier).
  • Multi-agency in V0: a V0 tenant (cabinet) can have N agencies as sub-units starting at v0.0.2. Per-agency campaign routing is in scope. Multi-agency network consolidation across tenants (group-level reporting, shared admin) remains a V2 concept and stays out of V0.
  • Regulatory posture: V0 accepts ARTCI risk (real WhatsApp + SMS before grants). V1 operationalizes ARTCI authorization paths.

§ 3. V0 Sub-Version Contract

The 7 sub-versions are sales milestones, each independently shippable + demonstrable. Each introduces new business rules, API endpoints, UI flows, and/or compliance posture.

Sub-Version Goal Key Feature Segment Approx. Timeline
v0.0.0 Skeleton: auth, tenant creation, S3-pickup ingestion (cron @02:00 per-tenant), campaign send via real WhatsApp + SMS, signed-link customer landing. No payment, identity verif, link expiration, or agencies. SHARED DB profile only. Orchestrated renewal end-to-end (without payment). S1–S3 Week 3–4
v0.0.1 First payment provider live. Customer selects contracts to pay. Audit-log emission active (payment + link + login). Cabinet admin edits erroneous data before send. ARTCI mitigations: opt-out, consent, privacy notice, no-resend. Idempotency + webhook sig verify mandatory. Official merchant payment + compliance audit trail. S1–S3 Week 5–7
v0.0.2 Cabinet admin imports agencies + agency users. Multi-agency campaign routing (per-agency queue, no per-operator assignment). Branch operators inline edit before send. Identity verification: phone last-4 only. Cabinet admin gets read-only status visibility (no actions). Multi-agency campaigns + basic identity capture. S1–S3 Week 7–9
v0.0.3 UI ingestion upload added (S3 pickup remains permanent). Cabinet admin gains view + revoke + cancel actions after push (still no edit). Self-service file upload + campaign control. S1–S3 Week 9–10
v0.0.4 BYO DB profile live - greenfield onboarding only. No A→D migration in V0 (deferred to V2). NSIA production go-live target. Enterprise single-tenant on customer's own DB. S6 Week 10–12
v0.0.5 SSO / IdP federation on top of Keycloak. Enterprise identity integration. S6 Week 12–13
v0.1.0 Production-hardening: 72h signed-link expiration + observability hooks + rate-limit tuning + ARTCI-grant-driven adjustments (if grants land). V1 readiness gate. End of V0. Production readiness. S1–S6 Week 13–16

Sub-Version → Module → Story Mapping appears in § 8.


§ 4. Per-Module Scope Changes vs V1 PRD

ING (ingestion)

Aspect V1 Scope V0 Scope Status Notes
File format CSV/XLSX; agency_id, customer_type + future-use columns Same Frozen v0.0.0 Column list fixed Day 1 (may be empty-valued). Future-proofs later multi-agency work.
S3 pickup Per V1 PRD §11.1 Cron @02:00 Africa/Abidjan per-tenant, not platform-wide Locked MC-1. Stable UTC±0 timezone; per-tenant isolation.
UI upload Deferred to V1 Arrives v0.0.3 Kept Reduces v0.0.0 scope; cabinet admin uploads via web UI.
Validation rules Full V1 set (V1 PRD §13 + §15) Simplified: drop optional fields early, keep core contract/customer/amount/deadline v0.0.0 only v0.0.1+ adds back incrementally.
Error handling & retry V1: detailed + re-upload v0.0.0: cron idempotent, S3 pickup failure → audit + manual retry; v0.0.3: UI provides feedback loop Simplified Cron crash does NOT unlock stale S3 objects; must be re-uploaded (v0.0.3) or manually cleared.
Agency ingestion N/A (V0 adds agencies) v0.0.2: cabinet admin creates agencies via UI (no bulk import) New Agencies added post-tenant-creation, not via ingestion CSV.

Implications for architecture: ING datasource must be tenant-scoped from v0.0.0. Flyway migrations for ingestion entities must be applyable to both SHARED and BYO profiles (D9).

CP (customer-portal)

Aspect V1 Scope V0 Scope Status Notes
Customer authentication Lightweight: signed-link + challenge (DOB/phone/RCCM) v0.0.0: signed-link only (no challenge); v0.0.2: phone last-4 identity capture Simplified DOB/RCCM capture deferred to V1. v0.0.2 captures customer_type at payment, not full identity verification.
Link validity 48–72h v0.0.0–v0.0.5: no expiration; v0.1.0: 72h Deferred v0.1.0 hardens for production. Temporary posture: long-lived links acceptable for slow-3G resumability.
Link anti-replay Signed-link spec (V1 PRD § 19) v0.0.0: token + signature required; v0.1.0: adds attempt counter + rate-limiting Simplified Anti-replay (state-based) deferred to v0.1.0; signature-based auth only v0.0.0–v0.0.5.
Contract selection Customer picks contracts + amounts v0.0.0–v0.0.1: select all or none; v0.0.2+: per-contract toggle Simplified v0.0.0 ships with all-or-none; later sub-versions add granularity.
Payment flow Full payment integration + reconciliation v0.0.0: no payment; v0.0.1: payment live + webhook reconciliation; v0.0.2+: status polling + retry Phased Payment is a separate slice; CP integrates via PAY module APIs.
Mobile-first 360px V1 requirement Mandatory v0.0.0 onwards Locked MC-4. Non-negotiable for Slow 3G; verified via Slow-3G smoke test before story close.
Payload < 200 KB gzipped V1 requirement Mandatory v0.0.0 onwards Locked MC-4. Critical path: signed-link landing + list contracts only. Payment details lazy-load.
French-native UI V1 requirement Mandatory v0.0.0 onwards (French only) Locked MC-6. No i18n in V0; all strings French.
Form draft survival V1 requirement (form state survives reload) v0.0.0: session state on server (resumable via link reuse); v0.0.1+: form persists on server between retries Simplified No client-side localStorage in v0.0.0 (low-bandwidth context); server holds draft.

Implications for architecture: CP must be aggressively code-split; landing page must load in <200KB gzipped on Slow 3G (critical path). Payment integration is loose (CP calls PAY APIs, does NOT orchestrate retry).

OP (operator-console)

Aspect V1 Scope V0 Scope Status Notes
Campaign engine Cohort selection + multi-step scheduling + A/B testing v0.0.0–v0.0.1: simple send (all contracts matching deadline window, one batch); v0.0.2+: per-agency routing Simplified Campaign rules frozen v0.0.0: renewal_window_days from tenant settings, all matching contracts selected, one send per campaign creation. No scheduling, no segmentation.
Operator actions (pre-send) Bulk edit, approve, flag exceptions v0.0.0: read-only list (no edits); v0.0.1: inline edit before send (cabinet admin only); v0.0.2+: branch operators can edit Phased Approval workflow deferred; v0.0.0 operator only views.
Operator actions (post-send) View status, cancel, revoke, resend v0.0.0: none (fire-and-forget); v0.0.1: view status (read-only); v0.0.3: view + revoke + cancel (cabinet admin only) Phased Granular post-send control deferred; v0.0.0 has no feedback loop.
Multi-agency support Not in V0 v0.0.2: per-agency campaign routing; each branch operator sees their agency contracts only New Introduced v0.0.2; per-agency queue replaces global queue.
Offline sync minimum V1 PRD § 20 (read-only cache of last push + local notes) v0.0.0: online-first (polling only, no service worker); v0.0.1+: same Deferred Offline-sync not in V0. Operator-side remains online-first + polling (no WebSocket).
Desktop-first UI V1 requirement Mandatory v0.0.0 onwards Locked Operator console is desktop/tablet; high-bandwidth assumed.
French UI V1 requirement Mandatory v0.0.0 onwards (French only) Locked MC-6.
Campaign send via NOTIF V1: NOTIF module sends SMS/WhatsApp v0.0.0+: OP calls NOTIF APIs (Spring boundary); NOTIF is separate deployable Locked OP does NOT inline send; sends are async (domain events) with audit logging per send.

Implications for architecture: OP couples loosely to NOTIF + PAY via domain events + API calls. No in-process messaging queue; outbox pattern (D4) ensures reliability.

PAY (payment)

Aspect V1 Scope V0 Scope Status Notes
Payment provider Multi-provider abstraction; providers configured per country v0.0.0: none; v0.0.1: first provider goes live (Paymetrust / Flutterwave / Orange Business TBD); country-profile lookup from v0.0.1 Phased Provider integration is provider-specific. Abstraction in place v0.0.0 (interfaces); first concrete provider v0.0.1.
Merchant account ownership Official merchant accounts only (not personal mobile-money) Mandatory v0.0.0 onwards Locked No exceptions. Signed contract + regulatory compliance per provider.
Idempotency Required (V1 PRD § 11.6) Mandatory v0.0.1 onwards Locked MC-5. Customer may retry; system guarantees one charge.
Webhook signature verification Required (V1 PRD § 11.6) Mandatory v0.0.1 onwards Locked MC-5. Provider webhook handlers MUST verify signature before processing.
Payment status reconciliation V1: webhook + status polling (§ 11.6) v0.0.0: N/A; v0.0.1: webhook-driven primary, polling as fallback; webhook failure → manual reconciliation (audit logged) Phased v0.0.0 has no payment; v0.0.1 implements dual-path reconciliation. Reconciliation SOP documented in operations manual (out of PRD scope).
Payment attempt retry V1: automatic retry + manual override v0.0.0–v0.0.4: none (customer manually retries via link reuse); v0.1.0: minimal auto-retry + observability hooks Deferred v0.0.0–v0.0.4: simplicity over automation. v0.1.0 adds tuning before V1.

Implications for architecture: PAY exposes /api/payments/... (D5); customer-side calls PAY APIs directly (not via OP relay). Webhook handlers are idempotent; audit-log writes via outbox (D7).

TENANT (tenant-admin)

Aspect V1 Scope V0 Scope Status Notes
Tenant creation TENANT PRD §A.3 (TENANT-US-01 + TENANT-US-02) v0.0.0: platform admin creates tenant + cabinet admin user via Keycloak Locked Tenant directory + initial admin provisioning from v0.0.0.
Tenant profile columns country_code, db_profile, notif_mode, etc. (§ 27 of V1 PRD) Same Locked country_code NOT NULL (default CI v0.0.0–v0.0.5, can be changed pre-launch). db_profile ∈ {SHARED, BYO}, default SHARED. notif_mode placeholder (used v0.1.0+ if ARTCI grants land).
DB profile selection Not in V0 v0.0.0: SHARED only (BYO connection string + decryption deferred); v0.0.4: BYO live for greenfield onboarding Phased TENANT S0 (platform admin) uses datasource resolver interface; v0.0.4 provisioning enables BYO profile creation.
Agency management Not in V0 v0.0.0: none; v0.0.2: cabinet admin creates agencies + assigns users New Agencies are V0's organizational layer (sub-units within tenant, not separate tenants).
Cabinet admin delegation Not in V0 Deferred to V1 Out of scope V0: one cabinet admin per tenant (platform admin invites). V1 adds delegated admin.
Billing & invoicing (BILL module) BILL PRD §A.3 Deferred entirely to V1 (out of V0 scope) Deferred V0 ships with no billing UI or invoicing. Platforms → tenant invoicing via BILL in V1.

Implications for architecture: TENANT S0–S1 in V0 (tenant creation + cabinet admin provisioning); multi-agency (S2) in v0.0.2. BILL is a pure V1 module; no placeholder in V0.

AUTH (identity)

Aspect V1 Scope V0 Scope Status Notes
Operator auth (Keycloak) V1 PRD §17 + AUTH PRD §A.3 v0.0.0: Keycloak ROPC (Direct Grant) for cabinet + agency admins; shared papillon realm + Keycloak Organizations (one org per tenant) Locked Keycloak >= 26.6 from v0.0.0. ROPC for simplicity. Operator JWT carries tenant_id claim emitted by a protocol mapper from the user's org id (or org attribute, decision in AUTH arch). See § 5.8 for full strategy.
Customer auth (signed-link) V1 PRD § 19 (signed-link + challenge) v0.0.0: signed-link token (SHA-256 stored, signature-based auth only); challenge deferred; v0.0.2: phone last-4 identity capture Simplified Auth tables on platform DB (D8 revised: AUTH-ADR-01). No HMAC; SHA-256 stored hash only. Attempt counter via Postgres + optimistic locking (AUTH-ADR-03).
Link signing service Part of AUTH in V1 v0.0.0: AUTH owns SignedLinkService (exposed to CP + OP via Spring boundary). Link lifetime = no expiration v0.0.0–v0.0.5; v0.1.0: 72h + attempt-limit Locked ING / OP call SignedLinkService.createLink(...) at campaign send; returns URL-safe token. CP calls SignedLinkService.verifyLink(...) on landing.
SSO / IdP federation Deferred to V1 v0.0.5: per-Organization IdP brokering (OIDC / SAML) with domain-based discovery New v0.0.0 to v0.0.4: Keycloak ROPC only (no external IdP). v0.0.5: each enterprise tenant org gets its own IdP linked at the Organization level. NSIA user types [email protected], gets redirected to NSIA's IdP. IdP mappers auto-place federated users into org groups.
MFA (WhatsApp OTP) V1 PRD (flag: LEGAL-REVIEW) Deferred entirely; v0.0.0–v0.1.0: no OTP, no MFA Deferred Feature flag feature.whatsapp.operator-mfa.enabled=false from v0.0.0 (inherited from identity-arch.md). Requires ARTCI grant before enabling.

Implications for architecture: AUTH module owns signed-link lifecycle + customer session state. Keycloak realm provisioning is part of TENANT S0. Platform DB hosts all AUTH tables (D1).

NOTIF (notifications)

Aspect V1 Scope V0 Scope Status Notes
SMS delivery V1 PRD §11.4 + NOTIF PRD §A.3 v0.0.0: real SMS via official provider (country-specific: Orange Money SMS CI, etc.) Locked Real SMS from v0.0.0; no stub/mock in production. Provider API credentials in platform env.
WhatsApp delivery V1 PRD §11.4 + NOTIF PRD §A.3 (real WA Cloud API) v0.0.0: real WhatsApp Cloud API (Meta) via official business account Locked Real WhatsApp from v0.0.0 [FOUNDER-RISK-ACCEPTED]. ARTCI authorization (B10) deferred; dossier filed in parallel. Mandatory mitigations from v0.0.0: opt-out link, consent checkbox, privacy notice link, audit-log per send, no-resend after opt-out.
Provider selection by country Per country_code + country_profile lookup v0.0.0: country-profile lookup for SMS + WhatsApp providers Locked NOTIF reads tenant.country_codecountry_profile → provider list. Multi-country support (SN, BJ, CM, GA) baked in from v0.0.0 (though only CI enabled in V0).
Email delivery Deferred to V1 Out of V0 scope Out of scope V0 is SMS/WhatsApp only. Email added in V1.
Consent & ARTCI compliance V1 PRD §16 + NOTIF PRD §A.3 Mandatory v0.0.0 onwards Locked [FOUNDER-RISK-ACCEPTED]. Every send includes opt-out link. Cabinet admin sees consent status per customer. Audit-log entry per send (ARTCI audit trail requirement).
Delivery retry & fallback V1: SMS fallback if WhatsApp fails v0.0.0: parallel sends (WhatsApp + SMS simultaneously); no cascading fallback Simplified v0.0.0 tries both; if one fails, audit-log notes failure (no auto-retry in v0.0.0). v0.0.1+: observability hooks added.

Implications for architecture: NOTIF is a control-plane module (D5). OP calls NOTIF APIs (or publishes domain events) to send campaigns. NOTIF must support multiple providers per country_code (country-profile pattern). All sends are audit-logged (D7 outbox).

AUDIT (audit-log)

Aspect V1 Scope V0 Scope Status Notes
Audit events V1 PRD § 18 (full list) v0.0.0: stubs in place for all V1 events (no UI); emission mandatory Phased Emission infra from v0.0.0. No audit console UI in V0 (deferred to V1). Audit entries persisted to tenant DB (outbox pattern).
Event scope Operator actions + payment + notifications + identity v0.0.0: OP sends, NOTIF sends, AUTH links, PAY payments (once live v0.0.1) Phased ING ingestion audited v0.0.0 (file received, validation passed/failed). NOTIF sends audited v0.0.0. AUTH links audited v0.0.0. PAY payments audited v0.0.1+.
Retention V1: 7 years (CIMA + ARTCI requirement) v0.0.0–v0.1.0: no purge (ship as-is); retention policy deferred to V1 Deferred V0 ships with all events retained. Soft-delete + archival policy added in V1.

Implications for architecture: AUDIT module owns append-only audit_entry table (tenant-scoped). Domain event listeners emit audit entries via outbox (D4, D7). No query layer in V0; audit log is append-only.


§ 5. Cross-Cutting Day-1 Architectural Anchors

These patterns are implemented in every V0 sub-version from v0.0.0 onwards. They form the foundation for V1 and enable multi-profile (SHARED / BYO) support.

5.1 Tenant-Aware Datasource Resolver (D1, D2)

Pattern: Spring Boot exposes two logical datasources: platformDataSource (tenant directory, country profiles, billing master, auth tables) + tenantDataSource (business data: contracts, customers, campaigns, audit logs).

  • Tenant resolution happens at request boundary (D3): Keycloak JWT tenant_id (operator) or signed-link decode (customer).
  • Request-scoped context holds currentTenant + currentAgency (v0.0.2+).
  • All business queries are tenant-scoped: WHERE tenant_id = :tenant_id (no exceptions).
  • Platform queries use @Qualifier(\"platformJdbcClient\") (D2); never CrudRepository (which routes to @Primary).
  • Datasource resolver returns SHARED in v0.0.0; switches to BYO in v0.0.4 for eligible tenants.

Implementation: TenantDataSourceResolver, TenantContext, TenantFilter Spring components.

5.2 Liquibase/Flyway Multi-Profile Tooling (D9)

Folder structure:

db/
├── migration/
│   ├── platform/          ← applies once (shared DB)
│   │   ├── V001__init.sql
│   │   └── ...
│   └── tenant/            ← applies to SHARED tenant schema (v0.0.0)
│       │                    AND to BYO-DB during provisioning (v0.0.4)
│       ├── V001__init.sql
│       └── ...

  • Platform migrations run on app startup (v0.0.0).
  • Tenant migrations run on app startup (SHARED DB) AND during BYO provisioning flow.
  • Same migration set for both profiles (no dialect drift).
  • Schema versioning is per-profile (platform vs tenant); never split.

Implementation: Dual-datasource Liquibase config in Spring Boot.

5.3 Async Tenant-Context Propagation

Use case: Campaign send (OP) → NOTIF delivery (async). Keycloak JWT is request-bound; async context must carry tenant_id.

  • Domain events (D4) embed tenantId in payload.
  • Event listeners (e.g., NOTIF consumer) unwrap tenantId and set request context before executing business logic.
  • No thread-local ThreadLocal<TenantContext> (not reliable across thread pools); all async listeners receive tenant_id in event payload.

Implementation: @TransactionalEventListener(AFTER_COMMIT) + domain event payload carries tenantId.

Token format: - Token = 32-byte SecureRandom → Base64url-encoded. - Hash = SHA-256(token) stored in DB (never plaintext token). - URL = /api/portail/{token}/contracts (token is the secret; signature computed client-side if needed).

Validation: - Customer presents token in URL. - Server computes SHA-256(token) and compares stored hash. - If match: token is valid. If no match: invalid. - Attempt counter (Postgres, optimistic locking): incremented on each presentation; after N failures (TBD: 5?), link is revoked.

Lifetime: - v0.0.0–v0.0.5: no expiration (supports Slow 3G resumability over multi-day outages). - v0.1.0: 72h TTL + attempt limit.

Anti-replay (v0.1.0+): token can be reused (resumable sessions); but webhook/payment idempotency prevents double-charge.

5.5 Payment Idempotency & Webhook Verification (PAY)

Idempotency (v0.0.1+): - Customer-facing payment API accepts idempotency key (UUID). - Key stored in Redis with 24h TTL. - Duplicate key → return cached response (same charge ID).

Webhook signature verification (v0.0.1+): - Provider webhook includes HMAC signature header. - Server verifies signature with provider's public key before processing. - Invalid signature → reject with 400. - Webhook handler is idempotent: idempotency key from provider payload (e.g., transaction_id).

5.6 Audit-Log Emission via Outbox Pattern (D4, D7)

Pattern (spring-modulith-events-jdbc): - Business action (e.g., campaign send) publishes domain event. - Event listener emits audit entry (INSERT to audit_entry). - Audit-write failure MUST NOT roll back the business action.

Implementation: - @DomainEvent published within transaction. - @TransactionalEventListener(AFTER_COMMIT, phase = AFTER_COMMIT) fires after business action commits. - Listener INSERT to audit_entry in same tenant-scoped context. - If audit-write fails: log error, alert ops (Sentry), but do NOT roll back business action.

5.7 Compliance Audit Trail (ARTCI + CIMA)

Mandatory fields per V1 PRD § 18: - audit_entry.event_type (e.g., OP_CAMPAIGN_VALIDATED, PAY_CONFIRMED, AUTH_LINK_ISSUED; full list in AUDIT PRD §B.1) - audit_entry.actor_id (operator user ID or system) - audit_entry.actor_type (USER, SYSTEM, WEBHOOK) - audit_entry.subject_id (contract ID, customer ID, payment ID, etc.) - audit_entry.subject_type (CONTRACT, CUSTOMER, PAYMENT, etc.) - audit_entry.details (JSON: message count, delivery status per channel, error reason, etc.) - audit_entry.occurred_at (timestamp) - audit_entry.created_at (when logged)

Audit scope v0.0.0 onwards: - TENANT: tenant creation, cabinet admin provisioning, agency creation (v0.0.2). - ING: file received, validation pass/fail, contracts parsed. - OP: campaign creation, send initiated, cabinet admin view/edit/cancel/revoke. - NOTIF: send attempt per customer per channel, delivery status, opt-out recorded. - AUTH: signed-link created, customer login, challenge success/fail (v0.0.2+). - PAY: payment initiated, webhook received, reconciliation status (v0.0.1+).

5.8 Keycloak Realm Strategy (V0-OQ-03 resolution)

Strategy: shared realm + Keycloak Organizations + per-org IdP brokering. One realm (papillon) holds one Organization per tenant. Picked because Keycloak Organizations (GA in 26.0, matured in 26.6 Apr 2026, FGAP-for-Organizations preview May 2026) closes every historical gap that made realm-per-tenant the safe default, while removing the realm-count scaling cliff.

Concrete locks (binding for AUTH architecture + V1 carry-forward):

  • Keycloak version: >= 26.6 at v0.0.0 launch. Track 26.7 for FGAP-for-Organizations GA.
  • Single realm: papillon. One Organization per tenant. Organization id is the durable identifier; not exposed to clients.
  • Organization attributes carry tenant metadata: tenant_id (internal UUID), country_code (ISO 3166-1 alpha-2), group_id (nullable, reserved for V2).
  • Protocol mapper emits tenant_id JWT claim (from org id or tenant_id attribute, decision in AUTH arch session). Spring side resolution (D3) unchanged.
  • Operator auth: ROPC (Direct Grant) v0.0.0 to v0.0.4. Each operator user is a member of exactly one Organization.
  • v0.0.5: per-org IdP brokering. Each enterprise tenant org can be linked to its own OIDC/SAML IdP. Domain-based discovery (NSIA user types [email protected] to trigger redirect to NSIA's IdP). IdP mappers (Hardcoded Group, Advanced Claim to Group) auto-place federated users into per-org isolated groups.
  • Tenant-admin self-service: until 26.7 ships GA with FGAP-for-Organizations, a thin custom admin UI in the OP module handles cabinet-admin delegation. Flagged as known temporary; expected to be replaced by the standard Admin Console once 26.7 lands.
  • Customer-portal branding (broker logo above the fold): stays in React. Not a Keycloak theme concern (Keycloak only handles operator login).
  • Hybrid carve-out path: any outlier tenant that requires a fundamentally different password policy, MFA flow, or token lifetime not expressible at the shared-realm baseline may be moved to a dedicated realm. Documented, planned for, not pre-paid for.

Trade-offs accepted: - Per-org password policy / MFA / token lifetimes are realm-level in 26.6. We mitigate via the carve-out path above. - Per-org Keycloak login branding is more limited than per-realm themes. Acceptable because customer branding lives in the customer portal, not in Keycloak. - Newer surface area than per-realm (~2 years of production maturity for Organizations). Mitigated by the v0.0.5 performance-testing gate (see § 10 TV).


§ 6. Compliance Posture & Regulatory Risk

6.1 Founder Risk Acceptance

Decision [FOUNDER-RISK-ACCEPTED] (2026-05-20): Real WhatsApp (Meta Cloud API) + SMS to Ivorian end-customers proceeds in v0.0.0 before ARTCI authorizations (B5 + B10) are granted. Founder explicitly accepted regulatory exposure on this date.

Dossier status: - ARTCI authorization request (B5: phone-number processing; B10: cross-border transfer to Meta/WhatsApp Cloud API) filed in parallel. - Expected grant timeline: before V1 GA (estimated 2026-Q3). - If grants are delayed: feature flags gate real sends; v0.1.0 (and onwards) can operate in "consent-only, no-send" mode pending ARTCI grant.

6.2 Mandatory Mitigations (v0.0.0 onwards)

Every NOTIF send must include:

  1. Opt-out link in message body (SMS + WhatsApp): "Répondez STOP pour vous désabonner" or similar.
  2. Consent checkbox on customer payment form (CP): "J'accepte de recevoir des relances par SMS/WhatsApp."
  3. Privacy notice link on customer portal: links to a default platform-hosted privacy page (FR), reflecting the platform's role as technical service provider, the categories of personal data processed, retention, subject rights (access/rectification/erasure), and contact for data requests. Tenant-specific overrides (broker-hosted privacy URL) are deferred to V1 to keep V0 customization overhead low.
  4. Audit-log entry per send (NOTIF module): captures customer phone, message text (or template ID), delivery status, timestamp, channel, operator, tenant.
  5. No-resend after opt-out: once customer replies STOP (or via cabinet admin UI v0.0.3+), NOTIF refuses subsequent sends to that phone number. Audit-log records opt-out.

Breach of any mitigation is a critical bug (fix before next deploy).

6.3 Inherited PRÉLIMINAIRE Flags

The operator-console PRD (v1) carries three PRÉLIMINAIRE compliance flags. V0 inherits them:

  • TV-01: CIMA legal text on contract page (French official CIMA Reg. 01-24 text). Deferred to V1; v0.0.0 does not render it.
  • TV-02: 72h signed-link validity + attempt-limit. Implemented in v0.1.0 (not v0.0.0–v0.0.5).
  • TV-03: WhatsApp + ARTCI authorization. Covered by § 6.1 & 6.2 above.

Temporarily Validated (pending ARTCI confirmation): TV-03 mitigations are sufficient to mitigate regulatory risk during V0. To be confirmed by legal team post-V0.

6.4 Feature Flags (Regulatory Gates)

  • feature.whatsapp.operator-mfa.enabled=false (v0.0.0–v0.1.0): MFA via WhatsApp disabled pending ARTCI grant.
  • feature.artci.sms-whatsapp.enabled=true (v0.0.0–v0.1.0): Real SMS/WhatsApp sending; can be flipped to false if ARTCI grant is delayed.
  • feature.artci.phone-auth.granted=false (v0.0.0–v0.1.0): real-production ingestion of customer phone numbers gated pending ARTCI grant (mémo B5, Loi CI n°2013-450 art. 7 + Décision ARTCI n°2023-0877). Pré-production ingestion authorisée. BLOQUANT V0/V1 production. See docs/prd/ingestion-prd.md line 9.

§ 7. Personas (V1 PRD Naming)

V0 supports the following personas. Each persona appears in one or more sub-versions.

Persona AUTH role (D-2) Company role V0 Earliest Appearance Key Actions
Platform Admin PLATFORM_ADMIN Company employee (Altarys/PAPILLON) v0.0.0 (S0) Create tenant + cabinet admin user in Keycloak; view tenant directory (platform admin console, TBD UI).
Cabinet Admin CABINET_ADMIN (tenant-wide) Head of brokerage or agency network v0.0.0 (S0) Create campaigns, upload files (v0.0.3), view campaign status (v0.0.1), revoke/cancel (v0.0.3); manage agencies (v0.0.2).
Agency Admin CABINET_ADMIN with agency_scope = [single] (see AUTH D-12) Head of a sub-unit (v0.0.2+) v0.0.2 Manage branch operators; assign contracts to operators (deferred to V1). NOT a distinct Keycloak role in V1.
Branch Operator OPERATOR Field agent at an agency v0.0.0 View contracts before send (v0.0.0), inline edit before send (v0.0.2), resolve exceptions (deferred to V1).
End Customer (assuré) none (signed-link only; no Keycloak user) Individual buying insurance v0.0.0 Click signed-link, view contracts + amounts, select contracts (v0.0.2+), pay via merchant (v0.0.1+), receive receipt (v0.0.1+).

§ 8. Sub-Version → Module → Story Mapping

This table maps each sub-version to the modules and their vertical slices (stories). Each story is tagged [V0.0.x].

Sub-Version ING CP OP PAY TENANT AUTH NOTIF AUDIT
v0.0.0 ING-001 (S3 cron setup) CP-001 (signed-link landing + list) OP-001 (campaign creation + send UI) (none) TENANT-001 (tenant create + cabinet admin provision) AUTH-001 (Keycloak realm + ROPC) NOTIF-001 (real SMS/WhatsApp) AUDIT-001 (audit-log table + stubs)
v0.0.1 ING-002 (S3 error handling) CP-002 (payment UI) OP-002 (campaign edit pre-send) PAY-001 (first provider + webhook) (none) AUTH-002 (signed-link token + SHA-256) NOTIF-002 (consent UI + opt-out) AUDIT-002 (payment + send emission)
v0.0.2 ING-003 (validation tweaks) CP-003 (phone identity capture) OP-003 (multi-agency routing) PAY-002 (status polling) TENANT-002 (agency CRUD + users) AUTH-003 (challenge: phone last-4) NOTIF-003 (per-agency queuing) (none)
v0.0.3 ING-004 (UI upload) CP-004 (lazy-load payment details) OP-004 (view + revoke + cancel) (none) (none) (none) (none) (none)
v0.0.4 (none) (none) (none) (none) TENANT-003 (BYO-DB provisioning) AUTH-004 (BYO context routing) (none) (none)
v0.0.5 (none) (none) (none) (none) (none) AUTH-005 (Keycloak IdP federation) (none) (none)
v0.1.0 (none) CP-005 (72h link expiration + rate-limit) OP-005 (observability instrumentation) PAY-003 (retry + observability) (none) AUTH-006 (attempt-limit enforcement) NOTIF-004 (rate-limit + retry) AUDIT-003 (compliance report stubs)

Note: Story count is ~18–20 total stories across 8 modules. Not every module has work in every sub-version; some modules (e.g., BILL, CAMP) are deferred entirely.


§ 9. Volumetry Estimate

Timeline

Phase Duration Deliverable Milestone
v0.0.0 ~3–4 weeks Skeleton (ingestion, campaign send, signed-link landing, real SMS/WhatsApp) Demo-ready (Basile presentation target)
v0.0.1–v0.0.3 ~5 weeks Payment live, multi-agency, UI upload, cabinet control Pilot-ready
v0.0.4–v0.0.5 ~3 weeks BYO profile live, Keycloak IdP NSIA production go-live target
v0.1.0 ~3 weeks Hardening (72h link expiration, rate-limits, ARTCI adjustments) V1 readiness gate
Total ~14–16 weeks 7 sub-versions, 18–20 stories Production-grade renewal platform

Team & Pipelining

  • Pipelined execution: 2–3 developers working in parallel (one on v0.0.0, one on early v0.0.1 stories, third on infrastructure/tooling).
  • AI workflow: each story uses the 7-personality ANALYST → ARCHITECT → DESIGNER → PRODUCT_OWNER → DEVELOPER → REVIEWER → FOUNDER flow (5–7 days per story typical). With pipelining, wall-clock time compresses.
  • Infrastructure setup (Keycloak, Redis, MinIO, Postgres x2, docker-compose.yml) happens in parallel with TENANT S0 and AUTH S0 stories.

Resource Estimate

  • Backend (Java/Spring): ~60% of effort (TENANT, ING, OP, PAY, AUTH, NOTIF, AUDIT modules).
  • Frontend (React): ~30% (CP, OP operator console).
  • DevOps/Infra: ~10% (docker-compose, Keycloak realm, Flyway migrations, multi-datasource config).

§ 10. Open Questions & Temporarily Validated Items

Open Questions Carried from V1 PRD

ID Question Context Owner V0 Status
OQ-A1 Retain tenant_provisioning_run indefinitely vs prune to audit at 90d? TENANT schema Founder Deferred to V1 (v0.0.0 does not prune).
OQ-A2 BYO-DB: ship Flyway DDL pack to tenant DBA, or apply blind under contract clause? TENANT provisioning (v0.0.4) Founder + Legal Deferred to TENANT PRD rework (v0.0.4 session).
OQ-A3 papillon-platform-admin realm role vs separate papillon-admin realm? Keycloak design (AUTH) Founder Deferred to AUTH architecture.
OQ-X1 Will AUTH consume TenantOnboarded synchronously or asynchronously? TENANT ↔ AUTH sync ARCHITECT (AUTH) Resolved: async (brief gap window documented in AUTH-arch).
OQ-X2 Will BILL need a country_profile.fne_endpoint field, or hard-code the CI FNE URL? BILL module (V1) ARCHITECT (BILL) Deferred to V1 (not in V0 scope).

New V0-Specific Open Questions

ID Question Module Owner Resolution
V0-OQ-01 Payment provider selection for v0.0.1: Paymetrust vs Flutterwave vs Orange Business? PAY Founder Resolved (2026-05-21): the first provider to accept partnership wins; selection is procurement-driven, not technical. PAY abstraction is provider-agnostic so the choice is reversible.
V0-OQ-02 Signed-link attempt-limit threshold: 3 vs 5 vs 10 attempts before revoke? AUTH ARCHITECT (AUTH) v0.0.0: no limit; v0.1.0: TBD (recommend 5).
V0-OQ-03 Keycloak realm strategy: one shared realm (multi-tenant) vs one per tenant? AUTH + TENANT ARCHITECT (AUTH) Resolved (2026-05-21): shared papillon realm + Keycloak Organizations (one org per tenant) + per-org IdP brokering at v0.0.5. Keycloak >= 26.6 at v0.0.0; track 26.7 for FGAP-for-Organizations. tenant_id JWT claim emitted via protocol mapper. Hybrid carve-out to a dedicated realm allowed for any outlier tenant that needs a fundamentally different password/MFA policy. See § 5.8 for concrete locks.
V0-OQ-04 ARTCI grant timeline: realistic date? Any interim gating strategy? Compliance Founder + Legal Expected Q3 2026. Interim: feature flags + consent UI (§ 6.2).
V0-OQ-05 When does BILL module enter V0 scope (if ever)? Or strictly V1? BILL Founder Deferred entirely to V1. V0 has no billing UI or e-invoicing.

Temporarily Validated (Pending Confirmation)

Item Status Notes Confirmation Gate
ARTCI risk mitigation sufficiency (TV-03) PRÉLIMINAIRE Opt-out + consent + audit trail + no-resend appear sufficient per memo B10. Requires post-V0 ARTCI confirmation. Legal team post-v0.1.0.
SMS provider availability (Orange Money SMS CI) PRÉLIMINAIRE Assumed available for v0.0.0; procurement TBD. Founder (provider selection V0-OQ-01).
WhatsApp Cloud API availability (for CI) PRÉLIMINAIRE Assumed available; official business account provisioning TBD. Founder (WhatsApp onboarding).
Keycloak 26.6+ with Organizations: scaling under hundreds of orgs per realm PRÉLIMINAIRE Organizations feature is GA since 26.0, matured through 26.6 (Apr 2026). No public load-test data at hundreds-of-orgs scale. Validate during v0.0.5 hardening. Performance testing v0.0.5.
Signed-link resumability without expiration PRÉLIMINAIRE Multi-day Slow-3G resumability requires no link expiration v0.0.0–v0.0.5. Validated v0.1.0 when 72h TTL added? Usability testing + customer feedback.

§ 11. CLAUDE.md Update Plan (Step 2 Preview)

Pending approval of this PRD, Step 2 will:

  1. Revise CLAUDE.md § "Multi-Tenant Model → V1 DB profiles":
  2. Update DB profile timeline: V0 ships SHARED + BYO; SCHEMA + DATABASE deferred to V3 (from prior "V2 = SCHEMA").
  3. Clarify V0 = sub-versions v0.0.0 → v0.1.0, not V1.
  4. Lock the DB profile taxonomy from handoff (§ 3 above).

  5. Add V0 sub-version entry to module ID table:

  6. Extend existing module table to note which sub-versions each module participates in.

  7. Update architectural decision D9 (Flyway multi-profile):

  8. Clarify that tenant migrations apply to both SHARED (v0.0.0) and BYO-DB (v0.0.4) profiles identically.

§ 12. What V0 Ships With vs V1 Ships With

Included in V0

✅ Tenant creation + cabinet admin provisioning (platform admin console TBD) ✅ Multi-agency support (cabinet → agencies + operators) ✅ File ingestion (S3 cron @02:00 per-tenant) ✅ Campaign creation + send (WhatsApp + SMS, real providers, ARTCI mitigations) ✅ Signed-link customer portal (no link expiration v0.0.0–v0.0.5) ✅ Official merchant payment (first provider live v0.0.1) ✅ Payment reconciliation (webhook + polling v0.0.1+) ✅ Audit-log emission (all V1 PRD § 18 events, stubs in place v0.0.0) ✅ Keycloak ROPC auth (operator side) ✅ Datasource resolver interface + dual-profile provisioning (Day 1) ✅ Liquibase/Flyway multi-profile tooling (Day 1) ✅ BYO-DB profile live (greenfield only, v0.0.4) ✅ Keycloak IdP federation (v0.0.5) ✅ 72h signed-link expiration + attempt-limit (v0.1.0)

Deferred to V1

❌ Platform admin console UI (tenant directory, audit log query, billing view) ❌ BILL module (billing + FNE e-invoicing for CI tenants) ❌ Audit-log query UI (admin-only reports) ❌ Cabinet admin delegation (multi-admin per tenant) ❌ Advanced campaign rules (segmentation, branching, A/B testing) ❌ Multi-agency network consolidation + reporting (V2 feature) ❌ Email delivery (SMS/WhatsApp only in V0) ❌ Form draft persistence (form state on server, not client-side) ❌ Offline operator sync (online-first polling, no service worker) ❌ SCHEMA profile (schema-per-tenant) ❌ DATABASE profile (DB-per-tenant on platform infra) ❌ A→D migration (SHARED → BYO migration deferred to V2) ❌ Advanced payment retry + manual reconciliation UI ❌ Customer identity verification (phone last-4 only; full identity deferred to V1)


§ 13. Success Criteria

V0 is successful when:

  1. ✅ All 18–20 stories reach completed status (full test coverage, all ACs met).
  2. ✅ Slow-3G smoke test passes on CP critical path (payload <200KB, usable on 3G, resumable via link reuse).
  3. ✅ ARTCI risk mitigations (opt-out, consent, audit, no-resend) are implemented and tested.
  4. ✅ Keycloak + Redis + MinIO + Postgres x2 + Docker Compose all run locally.
  5. ✅ Multi-profile architecture (SHARED + BYO) is non-breaking + tested.
  6. ✅ v0.1.0 goes to production (NSIA go-live) with no critical incidents in first 30 days.
  7. ✅ Founder can demo v0.0.0 to prospects within 3–4 weeks of development start.

End of PRD V0