Aller au contenu

Story Index: customer-portal (CP) — V0 Envelope

Module: customer-portal Total stories: 8 (V0 envelope only — v0.0.0 → v0.1.0) Decomposed from: docs/architecture/customer-portal-arch.md (§0 V0 deltas + §11 Vertical Slice Decomposition) — approved by Emmanuel BLONVIA 05/23/2026 PRD reference: docs/prd/customer-portal-prd.md (V1 contract + FSD) + docs/prd/prd-v0.md (V0 envelope) Design reference: docs/design/customer-portal-design.md (DESIGNER, 28/05/2026) — canonical screens CP-S1…CP-S11, §8 micro-copy, §9 components, §10 compliance UI. Stories were reconciled against it on the date below. Wireframes: docs/wireframes/customer-portal/CP-001/ exists (CP-S1 prototype.tsx + README.md). CP-002/CP-003 prototypes pending per design §12. Date: 29/05/2026

Stories are authored in simple English for the Claude DEVELOPER personality; they will be translated to French for human developers via the DeepL /translate pipeline later.

⚠ Notes flagged for the human PO

  1. Design doc reconciled (was previously absent). docs/design/customer-portal-design.md landed on main after the first decomposition pass; the stories were re-diffed against it and patched (BrokerHeader/StickyPayBar/NetworkBanner/StepIndicator component names + file paths, exact §8 French micro-copy, the CP-S2 droit-de-rétractation block placement, the CP-S3 initiation loading treatment, the CP-S4 receipt banner structure, the CP-S5/S6 pending + mapped-reason copy incl. the INDISPONIBLE typo fix and the RETOUR_INCOHÉRENT retry-suppression rule). CP-001 now points to its existing prototype.
  2. ⚠ Design-vs-V0-scope divergence — kept V0 scope, flagged here (human PO decision). The design doc (§2 / §11) assigns the full CP-S7 "Lien remplacé", CP-S8 "Déjà réglé" and CP-S9 "Mentions légales" page to V0.0.0–V0.0.2, and is even internally inconsistent (§2 says CP-S7 = V0.0.2, §11 says CP-S7 = V0.0.0). The locked PO scope keeps those full screens in V1 / CP-006 (CP-10 / CP-12 / CP-13). Per the directive not to re-debate V0 scope, the scope is unchanged: in V0 only the mentions-légales footer link + content-version read ship; the full CP-S7/S8/S9 screens remain V1. When a link is revoked/expired mid-V0, CP defers to AUTH (hard reload → AUTH-owned screen) rather than rendering a CP-owned screen. Re-confirm or adjust at the V1 PO pass.
  3. V0 envelope only. This pass decomposes CP-S0 → CP-005 (v0.0.0 → v0.1.0). The V1 hardening slice CP-006 (CP-S7 "lien remplacé", CP-S9 mentions-légales page, CP-S8/CP-13 "déjà réglé" receipt re-download, full anti-replay, AUTH DOB/RCCM challenge, fine-grained selection) is out of the V0 envelope — listed under "Hors Scope V0". Re-decompose it in the V1 PO pass.
  4. CP-002 split. The architecture flags CP-002 (7 ACs) as a split candidate. It is split into CP-002a (summary+consent), CP-002b (initiation+return), CP-002c (receipt) so each story holds 3–4 ACs.

V0 envelope → stories

Sub-version Design screens CP scope (per arch §0 + §11) Stories
[V0.0.0] CP-S1 Dev/test infra (reuse TENANT-S0 stack + WireMock PAY). Landing signed-link + contract list (read-only), session cookie, all-or-none selection, server-side draft, offline banner. No payment. Frozen CP schema baseline. Publishes customer.session_opened. CP-S0, CP-001
[V0.0.1] CP-S2, CP-S3, CP-S4 Live payment via PAY: summary + audited consent + rétractation; initiation + PSP redirect + return/status resolution + PaymentConfirmed listener; receipt screen + reçu download + NOTIF receipt push. CP-002a, CP-002b, CP-002c
[V0.0.2] CP-S5, CP-S6 Pending "vérification en cours" screen + TanStack Query polling; failed screen + mapped French reasons + manual retry; per-contract toggle (replaces all-or-none); phone-last-4 capture at payment. CP-003
[V0.0.3] Lazy-load payment/receipt bundle + CI bundle-budget gate (≤ 180 KB gzipped landing path). CP-004
[V0.1.0] CP-S10 (AUTH-owned skin) Prod hardening: 72 h link TTL enforced + attempt counter + reverse-proxy rate limiting. CP-005

Dependency Graph

CP-S0    [V0.0.0] Dev + test infra (reuse TENANT-S0 + WireMock)
CP-001   [V0.0.0] Landing + contract list + session cookie + all-or-none + frozen schema baseline
CP-002a  [V0.0.1] Summary + consent + rétractation (no PAY call yet)
CP-002b  [V0.0.1] Payment initiation + PSP redirect + return/status + PaymentConfirmed listener
CP-002c  [V0.0.1] Receipt screen + reçu download + NOTIF receipt push
   ├───────────────┬───────────────┐
   ▼               ▼               ▼
CP-003          CP-004          CP-005
[V0.0.2]        [V0.0.3]        [V0.1.0]
Pending+poll    Lazy-load +     Link TTL +
+retry+toggle   budget gate     attempt counter
+phone-last4                    + rate limiting

(CP-005 depends on CP-002b; CP-004 depends on CP-003. CP-003/004/005 all build on the CP-002 chain and can be sequenced or parallelised after CP-002c.)

Story List

# Story ID Title Side Sub-ver Design screen Depends On Concurrent With Complexity Status
0 CP-S0 Dev environment + test infra BACKEND V0.0.0 TENANT-S0 S TODO
1 CP-001 Landing + contract list + session cookie + all-or-none (no payment) CUSTOMER+BE V0.0.0 CP-S1 CP-S0 M TODO
2 CP-002a Pre-payment summary + consent capture CUSTOMER+BE V0.0.1 CP-S2 CP-001 M TODO
3 CP-002b Payment initiation + PSP redirect + return/status CUSTOMER+BE V0.0.1 CP-S3 CP-002a M TODO
4 CP-002c Receipt screen + reçu download + NOTIF push CUSTOMER+BE V0.0.1 CP-S4 CP-002b S TODO
5 CP-003 Pending + polling + retry + per-contract toggle + phone-last-4 CUSTOMER+BE V0.0.2 CP-S5, CP-S6 CP-002c CP-004, CP-005 M TODO
6 CP-004 Lazy-load bundle + CI budget gate CUSTOMER+BE V0.0.3 CP-003 CP-005 S TODO
7 CP-005 Link TTL + attempt counter + rate limiting CUSTOMER+BE V0.1.0 CP-S10 CP-002b CP-003, CP-004 M TODO

Concurrency Tiers

Tier Stories Can start after
T0 CP-S0 TENANT-S0 (serial; merge first)
T1 CP-001 CP-S0
T2 CP-002a CP-001
T3 CP-002b CP-002a
T4 CP-002c CP-002b
T5 CP-003, CP-005 CP-002c (CP-005 needs CP-002b)
T6 CP-004 CP-003

PRD Acceptance Criteria Coverage (V0 envelope)

PRD User Story ACs in V0 Assigned to Coverage
CP-01 (landing + list) list render, broker identity, greeting, list-updated notice CP-001
CP-02 (expand row details) expand, missing-detail copy CP-001
CP-03 (selection) all-or-none + total (CP-001); per-contract toggle (CP-003) CP-001 + CP-003
CP-04 (summary + consent) summary, eligibility re-check, rétractation, consent capture CP-002a
CP-05 (initiate payment) initiate+303, CP-S3 loading, init-fail surface CP-002b
CP-06 (return) status routing, resumable in-flight CP-002b
CP-07 (reçu) receipt screen, download, NOTIF push CP-002c
CP-08 (pending) pending screen, poll cadence, resume, expired-pending CP-003
CP-09 (failed) mapped reasons, retry preserves selection CP-003 (+ init-fail surface in CP-002b)
CP-11 (connection drops) offline banner + selection safety (CP-001); 72 h TTL leg (CP-005) CP-001 + CP-005
TOTAL (V0) all V0-envelope ACs All assigned ✅ 100% of V0 envelope

Design screen coverage (V0)

Screen Title In V0? Assigned to
CP-S1 Contract list CP-001
CP-S2 Récapitulatif + consentement CP-002a
CP-S3 Initiation paiement (redirect loading) CP-002b
CP-S4 Reçu CP-002c
CP-S5 Vérification en cours (pending) CP-003
CP-S6 Échec du paiement CP-003
CP-S7 Lien remplacé ❌ V1 (CP-006) — (AUTH defers in V0)
CP-S8 Déjà réglé ❌ V1 (CP-006)
CP-S9 Mentions légales (full page) ❌ V1 (CP-006) footer link only in V0
CP-S10 Lien expiré (AUTH-owned skin) CP-005
CP-S11 Tenant suspendu (AUTH 503) ❌ V1 AUTH-owned

CP-S7/S8/S9 are placed in V1 per the locked scope (see Note 2), diverging from design §2/§11 which list them in V0. Flagged for the human PO.

Hors Scope V0 (re-decomposed in the V1 PO pass)

These PRD/arch/design items are not in the V0 envelope and are listed in the "Out of Scope" of the relevant stories: - CP-006 (V1) — full hardening slice: CP-S7 "lien remplacé" (REVOKED reason=REISSUED), CP-S9 / CP-12 Mentions-légales page render (GET /mentions-legales full page + customer_mentions_legales_viewed), CP-S8 / CP-13 "déjà réglé" receipt re-download (GET /{token}/recus + cp_readonly_sessions cookie, post-ALL_PAID auto-revoke), full anti-replay, AUTH DOB/RCCM challenge integration, fine-grained selection. (The footer mentions-légales link + content-version read exist from V0; only the full page render is V1.) - CP-14 (operator timeline) — file-detail timeline of CP audit events belongs to the OP module (OP queries AUDIT; no CP API surface). Covered in operator-console decomposition. - Refund / dispute form (CP-OQ-06) — V1: operational only (call the agency). - V2/V3: per-contract partial-amount payment, installments, claims/attestation/doc upload, broker quittance download, multi-language, multi-currency (XAF), in-portal chat, WebSocket/SSE push, embedded PSP checkout, customer self-service re-issuance, AUTH OTP step-up.

  1. CP-S0 — dev/test infra; merge before any CP story.
  2. CP-001 — landing + contract list + frozen schema baseline (first demo-able v0.0.0 milestone).
  3. CP-002a → CP-002b → CP-002c — the v0.0.1 payment chain (summary/consent → initiation/return → receipt).
  4. CP-003 + CP-005 (after CP-002c; CP-005 needs CP-002b) — pending/polling/toggle + TTL/rate-limit hardening.
  5. CP-004 — lazy-load + bundle-budget gate (after CP-003; closes v0.0.3).

Bloquants to clear before dev-start

  • [LEGAL-REVIEW] BLOQUANT — magic-link as opposable consent = INCERTAIN - avocat requis (audit red flag #5). Per compliance-discipline.md, an INCERTAIN item blocks production implementation and the dependent stories do not enter the shippable backlog until a qualified lawyer clears the civil qualification of the magic link as opposable consent in Ivorian law. Every CP story (CP-001 onward) carries this gate. Related INCERTAIN: CP-OQ-02 (probative value of un-pre-checked checkbox consent), CP-OQ-05 (anonymous mandataire receipt acceptability), CP-OQ-01 (CIMA Reg 01-24 article-anchored mandatory fields). These may force field changes in the per-contract panel.
  • AUDIT catalog: the AUDIT event_type catalog (AUDIT §B.1) must admit every CP code before any audited CP story merges — customer_session_opened, customer_contract_list_viewed, customer_contract_details_missing, customer_selection_changed, customer_summary_viewed, customer_consent_captured, customer_mentions_legales_viewed, customer_payment_initiated, customer_payment_initiation_failed, customer_payment_return_mismatch, customer_payment_status_polled, customer_payment_confirmed, customer_payment_failed, customer_payment_expired_pending, CP_RECU_DOWNLOADED, customer_offline_banner_shown, customer_link_replaced_landing, customer_already_paid_landing, customer_support_contact_clicked. (AUDIT API rejects unknown event types — CLAUDE.md rule #3.)
  • AUTH signed-link service (SignedLinkService.verifyAndOpen, customerSessionAuthFilter) available for CP-001.
  • TENANT TenantConfigCache (broker identity surface) available for CP-001.
  • ING ContractRepository.findEligibleForFile available for CP-001.
  • PAY sandbox (initiate, getStatus, getReceiptUrls) + events (PaymentConfirmed/PaymentFailed/PaymentExpiredPending) for CP-002b/c.
  • NOTIF cp_payment_receipt template (NOTIF-US-11) registered for CP-002c.

Compliance — synthesis

Status Items Policy
VÉRIFIÉ Single-use magic link admitted (CIMA 001-2024 art. 26 + Loi CI 2013-546 arts. 5+8); double-clic (art. 20); droit de rétractation 14 j affiché avant paiement (CIMA art. 24); mentions précontractuelles (CIMA arts. 22-23 + Loi 2013-546 art. 19); tenant isolation; audit trail; XOF minor units Implementable
PRÉLIMINAIRE ([LEGAL-REVIEW]) CP-TV-01 (CIMA mandatory-info working set), CP-TV-02 (checkbox consent as digital proof) Implementable with warning; surfaced at point of use
INCERTAIN (BLOQUANT) Magic-link as opposable consent (red flag #5); CP-OQ-01 article-anchored fields; CP-OQ-02 probative value; CP-OQ-05 mandataire receipt Blocks production ship. Build may proceed behind the gate; does NOT enter shippable backlog until legal clears

Each story carries the explicit list of compliance rules it touches, with article/assumption reference and status.

Decomposition Quality Checks

  • [x] Every story has 2–4 ACs (CP-S0 3 technical ACs; CP-004 2 ACs; CP-001/002b/003 4 ACs; CP-002a/002c/005 3 ACs)
  • [x] Vertical slice with 5+ ACs split (CP-002 7 ACs → CP-002a/b/c)
  • [x] Every in-scope V0 PRD AC assigned to ≥ 1 story
  • [x] Every in-scope V0 design screen assigned (CP-S1→001, CP-S2→002a, CP-S3→002b, CP-S4→002c, CP-S5/S6→003, CP-S10→005); CP-S7/S8/S9/S11 marked V1
  • [x] Self-containment: story + standards + design = full implementation context
  • [x] No circular dependencies (DAG verified)
  • [x] Story IDs sequential, zero-padded where applicable, uppercase prefix (CP-002 split a/b/c per established AUDIT-001a/b/c precedent)
  • [x] French copy for every UI state on every UI-bearing story, reconciled against design §8
  • [x] Compliance rules carry status + [LEGAL-REVIEW] where needed; INCERTAIN bloquant flagged at module + story level; no INCERTAIN marker altered in this review
  • [x] Out-of-scope explicit per story; V1 items collected in "Hors Scope V0"
  • [x] V0 envelope coverage: 100%
  • [x] [CUSTOMER stories] explicit connectivity behavior section in each
  • [x] Design doc reconciled (stale "no design doc" flag removed); design-vs-V0-scope divergence (CP-S7/S8/S9) flagged for the human PO rather than silently resolved

Decomposition completed 28/05/2026; reconciled against customer-portal-design.md on 29/05/2026. V0 envelope only. Stories in simple English for Claude DEVELOPER; translate via /translate for human devs. Merge onto main after founder review, then hand to developers.