Story Index: identity (AUTH) — V0 envelope (v0.0.0 → v0.1.0)¶
Module: identity Total stories: 12 (AUTH-001 … AUTH-012) Decomposed from: docs/architecture/identity-arch.md (approved — Emmanuel BLONVIA, 23/05/2026) — §0 V0 Envelope Deltas + §11 Vertical Slices PRD reference: docs/prd/identity-prd.md + docs/prd/prd-v0.md + docs/prd/papillon-v0-stories-par-sous-version.md Design reference: docs/design/identity-design.md Date: 28/05/2026
Scope of this pass: the full V0 envelope for AUTH, across every V0 sub-version that carries an AUTH deliverable (v0.0.0, v0.0.1, v0.0.2, v0.0.4, v0.0.5, v0.1.0). Each story header carries a Version target line stating its V0 sub-version. Features that are NOT in any V0 sub-version (operator MFA, remember-device, step-up MFA, bypass codes, password reset, full operator user management) are V1 and are intentionally excluded here — see "Deferred to V1" and "Open Questions" below.
Dependency Graph¶
AUTH-001 (skeleton + schema + Keycloak realm) [v0.0.0] Tier 0 — merge first
├── AUTH-002 (operator ROPC login + JWT filter + guard) [v0.0.0]
├── AUTH-003 (TenantOnboarded → Org + bootstrap admin) [v0.0.0]
│ └── AUTH-004 (operator activation: set password) [v0.0.0]
│ └── AUTH-008 (BYO-DB cross-DB agency validation) [v0.0.4]
│ └── AUTH-009 (enterprise IdP federation) [v0.0.5] (also needs AUTH-002)
└── AUTH-005 (SignedLinkService: issue + verify) [v0.0.0]
├── AUTH-006 (auto-revoke on AllContractsPaid) [v0.0.1]
├── AUTH-007 (last-4 phone challenge + capture) [v0.0.2]
│ └── AUTH-011 (attempt-limit + lockout + revoke)[v0.1.0]
├── AUTH-010 (72h expiry effective) [v0.1.0]
└── AUTH-012 (Redis rate-limit on verify) [v0.1.0]
External prerequisites: TENANT-S0 (two Postgres datasources, Redis, docker-compose) and AUDIT-S0 before AUTH-001; TENANT TenantOnboarded for AUTH-003; PAY AllContractsPaid for AUTH-006; TENANT TenantAwareDataSourceResolver BYO branch for AUTH-008; CP-005 / NOTIF-004 shared Redis rate-limit primitive for AUTH-012.
Story List¶
| # | Story ID | Title | Sub-version | Side | Depends On | Complexity | Status |
|---|---|---|---|---|---|---|---|
| 1 | AUTH-001 | Module skeleton + platform schema + Keycloak realm | v0.0.0 | BACKEND | TENANT-S0, AUDIT-S0 | M | Backlog |
| 2 | AUTH-002 | Operator login (password-only ROPC) + JWT filter + guard | v0.0.0 | OPERATOR | AUTH-001 | M | Backlog |
| 3 | AUTH-003 | TenantOnboarded → Keycloak Org + bootstrap CABINET_ADMIN | v0.0.0 | BACKEND | AUTH-001 | M | Backlog |
| 4 | AUTH-004 | Operator activation flow (set password via invitation) | v0.0.0 | OPERATOR | AUTH-003 | S | Backlog |
| 5 | AUTH-005 | SignedLinkService foundation — issuance + click verification | v0.0.0 | BACKEND | AUTH-001 | M | Backlog |
| 6 | AUTH-006 | Signed-link auto-revocation when all contracts paid | v0.0.1 | BACKEND | AUTH-005 | S | Backlog |
| 7 | AUTH-007 | Customer identity challenge — last-4 phone digits + capture | v0.0.2 | BACKEND | AUTH-005 | M | Backlog |
| 8 | AUTH-008 | BYO-DB readiness — cross-DB agency-scope write validation | v0.0.4 | BACKEND | AUTH-003 | S | Backlog |
| 9 | AUTH-009 | Enterprise identity federation — per-Organization IdP brokering | v0.0.5 | BACKEND | AUTH-003, AUTH-002 | L | Backlog |
| 10 | AUTH-010 | Signed-link expiration (72h TTL) becomes effective | v0.1.0 | BACKEND | AUTH-005 | S | Backlog |
| 11 | AUTH-011 | Challenge attempt-limit + 30-min lockout + 3-cycle revoke | v0.1.0 | BACKEND | AUTH-007 | M | Backlog |
| 12 | AUTH-012 | Signed-link verification rate-limiting (shared Redis) | v0.1.0 | BACKEND | AUTH-005 | S | Backlog |
Stories by V0 sub-version¶
| Sub-version | AUTH deliverable (V0 envelope arch §0.1) | Stories |
|---|---|---|
| v0.0.0 | Shared realm papillon + Keycloak Organizations; operator ROPC login (no MFA); auth schema; TenantOnboarded bootstrap; SignedLinkService foundation |
AUTH-001, AUTH-002, AUTH-003, AUTH-004, AUTH-005 |
| v0.0.1 | Signed-link wired to the merchant-payment journey; SHA-256-hash-at-rest; auto-revoke on full payment | AUTH-006 |
| v0.0.2 | Customer identity challenge = last-4 phone digits (first-access capture); counter shown, no lockout yet | AUTH-007 |
| v0.0.4 | BYO-DB tenants: cross-DB agency-scope write validation; AUTH stays on platform DB | AUTH-008 |
| v0.0.5 | Enterprise identity federation: per-Organization OIDC/SAML brokering + domain discovery | AUTH-009 |
| v0.1.0 | Production hardening: 72h expiry effective; attempt-limit + lockout + permanent revoke; Redis rate-limit | AUTH-010, AUTH-011, AUTH-012 |
Concurrency Tiers¶
| Tier | Stories | Can Start After |
|---|---|---|
| 0 | AUTH-001 | TENANT-S0 + AUDIT-S0 merged |
| 1 | AUTH-002, AUTH-003, AUTH-005 | AUTH-001 merged |
| 2 | AUTH-004 (after 003), AUTH-006 (after 005), AUTH-007 (after 005) | their Tier-1 dependency merged |
| 3 | AUTH-008 (after 003), AUTH-009 (after 003+002), AUTH-010 (after 005), AUTH-011 (after 007), AUTH-012 (after 005) | their dependencies merged |
PRD / Architecture Acceptance Criteria Coverage¶
| Source | ACs / rules | Assigned To |
|---|---|---|
| arch §0 V0 deltas (AUTH-001) + §11 S0 (skeleton) | migrations, realm, health, JWT parse | AUTH-001 (AC-001..004) ✅ |
| AUTH-OP-02 login portion + R-OP-001/008/009/013 (no-MFA V0 carve-out) | password login, generic error, account states, JWT filter | AUTH-002 (AC-001..004) ✅ |
| AUTH-ADM-04 + R-ADM-007 (TenantOnboarded bootstrap + Org) | provisioning, idempotency, reinvite | AUTH-003 (AC-001..003) ✅ |
| AUTH-OP-01 (activation) | activate, expired/used, already-active | AUTH-004 (AC-001..003) ✅ |
| AUTH-CP-01 + R-CP-001..004/018 + AUTH-NFR-10/11 (issuance + verify) | bulk issue, block missing hmac, verify+branding, tenant guard | AUTH-005 (AC-001..004) ✅ |
| AUTH-CP-07 + R-CP-014/015 (auto-revoke on paid) | all-paid revoke, partial no-revoke, revoked click | AUTH-006 (AC-001..003) ✅ |
| V0 envelope line 26 (AUTH-003, last-4 challenge) + R-CP-007/008/009 | correct/wrong challenge, first-access capture | AUTH-007 (AC-001..003) ✅ |
| R-ADM-009 / AUTH-TV-07 (BYO cross-DB agency validation) | reject bad UUID, both DB profiles, auth on platform DB | AUTH-008 (AC-001..003) ✅ |
| AUTH-ADM-08 (per-Organization IdP brokering) | domain redirect, group+claim mapping, misconfig fallback | AUTH-009 (AC-001..003) ✅ |
| AUTH-CP-05 + R-CP-005 + AUTH-NFR-03 (72h expiry) | expired reject, valid within TTL, no TTL extension | AUTH-010 (AC-001..003) ✅ |
| AUTH-CP-04 + R-CP-010..013 + ADR-AUTH-03 (lockout/revoke + concurrency) | 5-attempt lockout, cycle reset, 3-cycle revoke, no double-increment | AUTH-011 (AC-001..004) ✅ |
| V0 envelope line 29 (AUTH-006, rate-limit) + arch R4 | 429 over-threshold, shared primitive, fail-open | AUTH-012 (AC-001..003) ✅ |
| TOTAL | 40 ACs | 40 assigned ✅ |
Implementation Order¶
- AUTH-001 — skeleton + schema + realm; unblocks everything.
- AUTH-002 / AUTH-003 / AUTH-005 (parallel) — operator login, tenant bootstrap, signed-link foundation. These complete the v0.0.0 backbone.
- AUTH-004 — operator activation (needs the invitation from AUTH-003). Closes v0.0.0.
- AUTH-006 — auto-revoke-on-paid (v0.0.1, needs PAY).
- AUTH-007 — last-4 challenge (v0.0.2).
- AUTH-008 — BYO-DB cross-DB agency validation (v0.0.4).
- AUTH-009 — enterprise IdP federation (v0.0.5).
- AUTH-010 / AUTH-011 / AUTH-012 (parallel) — v0.1.0 production hardening: expiry, attempt-limit/lockout, rate-limit. This is the V1-readiness gate for AUTH.
Deferred to V1 (NOT in any V0 sub-version — excluded from this pass)¶
Per the approved arch (§0.4 "Hors V0") and design (version flags), these are V1 and are intentionally not decomposed here:
- Operator SMS OTP / MFA + WhatsApp fallback (AUTH-OP-02 MFA portion, AUTH-OP-03). Flag feature.whatsapp.operator-mfa.enabled=false is wired from v0.0.0 but unimplemented.
- Remember-device 15-day cookie (R-OP-005).
- Step-up MFA on sensitive actions + the full step-up action list (AUTH-OP-05, R-OP-010).
- MFA bypass codes (AUTH-OP-04, R-OP-007).
- Session idle/absolute timeout enforcement + warning banner (AUTH-OP-06, R-OP-011) — note: the idle banner is partly in-scope per design, but enforcement is coupled to the V1 session model; decompose with the V1 pass.
- Password reset / forgot-password self-service (AUTH-ADM-03) — OPS runbook in V0.
- Full operator user management: invite further users, role/scope edit UI, deactivate cascade (AUTH-ADM-01/02, AUTH-OP-07, R-ADM-001..006, R-OP-012).
- Tenant lifecycle cascades: TenantSuspended / TenantReactivated / TenantSoftDeleted handlers + the write-side of the tenant-status guard (AUTH-ADM-05/06/07, R-OP-014..017). v0.0.0 codes the guard read-path with only ACTIVE; the suspend/reactivate cascade that writes SUSPENDED/DELETED is V1.
- Platform-admin cross-tenant auth: PLATFORM_ADMIN sentinel queries, cross-tenant audit, last-admin guard (AUTH-PA-01, R-PA-001..003, R-ADM-008). The reinvite endpoint (AUTH-003) is the only platform-admin surface in V0.
- DOB / RCCM challenge factors + operator DOB/RCCM reveal (AUTH-CP-02/03, AUTH-NFR-09). V0 uses the last-4 challenge only.
- HMAC token + anti-replay on signed links (arch §0.2 / §0.4) — V1 end-state.
Open Questions (for the human PRODUCT_OWNER / DESIGNER / LEGAL)¶
- OQ-AUTH-V0-1 (scope conflict — customer UI timing):
papillon-v0-stories-par-sous-version.mdplaces customer signed-link viewing ("ouvrir son espace via lien signé, consulter ses contrats") in v0.0.0, but the approved arch §0.2 + design version-map defer the customer-facing signed-link UI to v0.0.1. These stories follow arch+design: v0.0.0 ships the SignedLinkService backend foundation only (AUTH-005); the customer landing/challenge React screens are CP-module stories landing from v0.0.1. Confirm. - OQ-AUTH-V0-2 (scope conflict — user management timing): the V0 sub-version doc places "Cabinet Admin créer et affecter des utilisateurs à une agence" and Agency-Admin/Branch-Operator scoping in v0.0.2, but the approved PRD/design tag full operator user management as V1. This pass delivers only the v0.0.4 cross-DB agency-scope validation primitive (AUTH-008) and the v0.0.0 bootstrap admin (AUTH-003); the self-service user-management UI is left to the V1 pass. Confirm whether user management should be pulled into V0.0.2.
- OQ-AUTH-V0-3 (federation scope tension): PRD §C.5 (V1-authored) lists federated SSO/SAML as V3, while §A.3 AUTH-ADM-08 + D-11 + the V0 envelope pull per-Organization OIDC/SAML brokering forward to v0.0.5. AUTH-009 follows the V0 envelope (v0.0.5). Confirm.
- OQ-AUTH-V0-4 (missing French copy): the design doc specifies challenge copy for the DOB and RCCM variants but NOT for the v0.0.2 last-4 phone digits variant (design §10 screen 10). AUTH-007 carries derived French strings that must be confirmed by the DESIGNER.
- PRD doc bug: the heading for AUTH-ADM-01 (operator invite) is missing in
identity-prd.md(its body sits unlabelled under "Operator user management"). Worth fixing at source. (Not blocking — AUTH-ADM-01 is a V1 story.) - Inherited legal flags (do not block V0 dev, carried per story):
[LEGAL-REVIEW]red flag #5 — civil opposability of the magic link as proof of consent =INCERTAIN - avocat requis(any future use of the link as consent proof stays blocked; V0 uses it for authentication only). AUTH-OQ-01 (CIMA Reg. 01-24 acceptability, AUTH-TV-01), AUTH-OQ-03 (cybersecurity reg), AUTH-OQ-04 (cross-border WhatsApp transfer — keeps the operator-MFA-WhatsApp flag off), AUTH-OQ-05/06 (landing-page info surface + lawful basis) all remain open and are pre-production legal items.
Notes¶
- Customer-facing screens are CP-owned. The signed-link landing, challenge form, lockout/expired/revoked/already-paid screens are served via the CP module boundary (arch §3.4). The AUTH customer stories (AUTH-005/006/007/010/011/012) are therefore BACKEND and ship the verification services plus the exact French copy for CP to render. Only the operator auth screens (login AUTH-002, activation AUTH-004) are AUTH-owned UI.
- No wireframes exist for AUTH (
docs/wireframes/identity/not present); every story uses the design doc section reference instead. - Slow-3G smoke test (arch §13.6) is required before any customer-facing behaviour (via CP) is declared DONE: landing < 5 s, challenge round-trip < 3 s, total payload < 200 KB gzipped (AUTH-NFR-01).
- All AUTH tables stay on the platform datasource (ADR-AUTH-01) for every story and both V1 DB profiles (SHARED / BYO).
- V0 signed-link posture (arch §0.2): SHA-256 (no HMAC), no expiry and no attempt-limit through v0.0.5; expiry + attempt-limit + rate-limit arrive at v0.1.0 (AUTH-010/011/012); HMAC + anti-replay stay V1.