Aller au contenu

Story Index: ingestion (ING) — v0.0.0

Module: ingestion Total stories: 6 Decomposed from: docs/architecture/ingestion-arch.md (approved — ARCHITECT session 2026-05-21) PRD reference: docs/prd/ingestion-prd.md + docs/prd/prd-v0.md §4 + §8 Design reference: N/A — v0.0.0 has no human-facing UI (architecture §1.1). Design doc will be required from v0.0.3 (UI upload + atelier). Date: 21/05/2026

Dependency Graph

ING-001  (scaffold: TestContainers, fixtures, empty migrations)
   ├──> ING-002  (scheduler + MinIO client + tenant iteration + ING_UPLOAD_RECEIVED)
   │       │
   │       └──> ING-004  (commit TX + reject + dedup + ImportCommitted)
   └──> ING-003  (parsers + validator + phone normalizer) ──> ING-004
                                                                ├──> ING-005  (startup recovery + ARTCI prod gate)
                                                                │       │
                                                                │       └──> ING-006  (cross-cutting IT pack)
                                                                └──> ING-006

External prerequisites (must land before ING-002 starts dev): - TENANT-001 (TenantConfigCache, default-agency provisioning, customer/contract base tables) - AUDIT-001 (AuditEventBuilder, outbox, PiiHasher) - AUDIT catalog extension OQ-X10 admitting ING_* event types - OQ-X11 (TENANT provisions papillon-ingestion-inbox bucket + per-tenant credentials) - OQ-X12 (TENANT confirms additive ALTER strategy on customer/contract) - OQ-X13 (OP confirms ImportCommitted consumption — no-op listener acceptable)

Story List

# Story ID Title Side Depends On Complexity Status
1 ING-001 Dev environment + test infrastructure + empty migrations BACKEND TENANT-S0, AUDIT-S0 S Backlog
2 ING-002 Scheduler + MinIO inbox client + tenant iteration skeleton BACKEND ING-001, TENANT-001, AUDIT-001, OQ-X10–11 S Backlog
3 ING-003 CSV/XLSX parsing + row validation + phone normalization BACKEND ING-001 M Backlog
4 ING-004 Commit transaction + reject path + SHA-256 dedup + ImportCommitted BACKEND ING-002, ING-003, TENANT-001, OQ-X10/12 M Backlog
5 ING-005 Startup recovery + ARTCI feature-flag prod gate + structured logging BACKEND ING-004 S Backlog
6 ING-006 Cross-cutting integration test pack (isolation, large file, magic byte, crash, flag) BACKEND ING-005 M Backlog

Concurrency Tiers

Tier Stories Can Start After
0 ING-001 TENANT-S0 + AUDIT-S0 merged
1 ING-002, ING-003 ING-001 merged + AUDIT catalog OQ-X10 + TENANT-001 (for 002)
2 ING-004 ING-002 AND ING-003 merged
3 ING-005 ING-004 merged
4 ING-006 ING-005 merged (test scaffolding may start earlier)

PRD Acceptance Criteria Coverage

Architecture §11 lists 5 binding ACs for ING-001 + 3 ACs for ING-S0 scaffolding. Each story below adds its own technical ACs as required by the 2–4-per-story rule.

Architecture / PRD source ACs Assigned To
arch §11 ING-S0 scaffolding smoke boot, migrations apply, fixtures parse ING-001 (3 ACs) ✅
arch §11 ING-001 AC-1 (happy-path commit) clean 5-row CSV → COMMITTED + audit + processed move + event ING-004 (AC-001) ✅
arch §11 ING-001 AC-2 (all-or-nothing reject + sidecar) tainted XLSX → PARSE_FAILED + sidecar + audit ING-004 (AC-002) ✅
arch §11 ING-001 AC-3 (SHA-256 duplicate path) re-dropped file → DUPLICATE row + audit + move, no business write ING-004 (AC-003) ✅
arch §11 ING-001 AC-4 (prod feature-flag closed) prod + flag=false → tick is no-op + WARN log ING-005 (AC-001) ✅
arch §11 ING-001 AC-5 (startup crash recovery) PICKED_UP >5min → PARSE_FAILED + move + audit ING-005 (AC-003) ✅
arch §12 A4/A10 (cross-tenant SHA-256 isolation) same hash, two tenants → both COMMIT, no cross-write ING-006 (AC-001) ✅
arch §8 perf budget + §12 A5 (heap) 5 000 rows ≤10 s parse + ≤5 s commit, <256 MB heap ING-006 (AC-002) ✅
arch §5.1 crash matrix (stages 3, 5a, 5b) three crash points → idempotent recovery by next tick ING-006 (AC-003) ✅
arch §7.6 A1 magic-byte spoof + AC-4 release gate combo OOXML-bytes-with-.csv-ext → PARSE_FAILED; prod flag closed smoke ING-006 (AC-004) ✅
arch §11 ING-002 technical (scheduler+MinIO+upload audit) cron iterates, ING_UPLOAD_RECEIVED, local tick endpoint, large-file reject ING-002 (AC-001/2/3) ✅
arch §11 ING-003 technical (parse + validate kernel) clean parse, tainted anomalies, 5001-row cutoff, magic-byte mismatch ING-003 (AC-001..004) ✅
arch §11 ING-001 prerequisite (ING-S0) 3 smoke ACs ING-001 (AC-001..003) ✅
TOTAL 21 ACs 21 assigned ✅

Coverage verified: every architecture-§11 binding AC is owned by exactly one story; every architecture-§12/§13 cross-cutting concern is covered by ING-006; ING-002 / ING-003 carry derivative technical ACs proportional to the code they introduce.

Implementation Order

  1. ING-001 — scaffolding unblocks every downstream story.
  2. ING-002 — wires the scheduler skeleton + MinIO client. Independent of ING-003 (parallel-developable in tier 1).
  3. ING-003 — pure parser/validator kernel. Independent of ING-002.
  4. ING-004 — closes the v0.0.0 happy path; merges ING-002 + ING-003 wiring into a transactional commit FSM with audit + ImportCommitted. Production-blocking until ING-005 lands the ARTCI flag.
  5. ING-005 — flips the v0.0.0 release switch (ARTCI prod gate) + adds crash-recovery resilience. After this story, v0.0.0 ING is functionally complete on dev/staging.
  6. ING-006 — release gate: cross-cutting integration test pack. v0.0.0 ING ships only when this is green.

Notes

  • All six stories are backend-only — Wireframe: N/A — backend only everywhere. The Frontend / UI-States blocks in each story are intentionally marked N/A.
  • Compliance posture: ARTCI loi 2013-450 Art. 14 → PRÉLIMINAIRE (see ING-005). CIMA Reg. 01-24 → not directly engaged in v0.0.0 (no payment / regulatory output from ING).
  • The [LEGAL-REVIEW] startup WARN is acknowledged for v0.0.0 dev/staging (gate is open in non-prod by design).
  • Forward-compat checkpoints (not v0.0.0 work, restated for visibility): V0.0.2 ING-007 (DOB + branche reintroduced + code_agence resolution); V0.0.3 ING-008+ (UI upload, atelier, history). These will be decomposed in a future /decompose invocation, NOT here.