# 10 — Phased Implementation Backlog

Each phase ends with: files changed, migrations added, features implemented, tests **executed** (with results), failures remaining, security considerations, next phase. A phase is done only when its acceptance criteria (AC) pass in an actual run. No phase starts without approval of the previous one.

Test IDs: `ISO` isolation · `SEC` security · `FIN` financial · `ENC` encryption · `MAIL` · `BAK` backup · `PWA` · `A11Y` · `MIG` migration · `UNIT/INT`.

## P1 — Foundation (core, tenancy, IAM, audit, queue/mail transport, **isolation suite**)
Scope: local env install matching target stack (PHP 8.4/8.5, MariaDB 11.4/11.8) · repo skeleton, Composer, PHPUnit, PHPStan · Core kernel · migrator + CLI · tenancy + `TenantScopedRepository` · IAM (users, memberships, sessions, Argon2id, CSRF, throttle, email verify/reset, TOTP) · roles/permissions engine + `Gate` · audit writer + hash chain · job queue + cron runner · SMTP A/B transports + outbox state machine + template engine with placeholder allowlist (each later phase ships the templates for the events it introduces; P8 adds the editor, history and announcements) · redactor/logging · Storage/Cache/Queue/Mailer/Clock interfaces.
AC:
1. `composer test` runs on the target PHP/MariaDB versions; suite green with output captured.
2. Isolation suite exists **before** modules and covers ISO-1…ISO-20 (including origin isolation and tenant-switch handoff) for all routes/repositories available in P1, including raw-SQL cross-tenant FK inserts failing.
3. Static scan fails the build when a repository query lacks tenant scoping (proved by a deliberately broken fixture).
4. 100 % of routes declare a permission; CI test fails otherwise.
5. Login throttle blocks after N failures (configurable) and responses for unknown vs known email are indistinguishable (timing within tolerance).
6. Session ID changes on login and privilege change; fixation test passes.
7. Audit rows hash-chain verifies; tamper test (modified row via maintenance connection) is detected; `app` DB user cannot UPDATE/DELETE `audit_log`.
8. Mail: primary failure → fallback used; ambiguous outcome sets `unknown` and is not re-sent; retries cap enforced (tests with fake transports plus one real SMTP smoke test if credentials available).
9. Migration from empty DB and re-run is idempotent; checksum drift detection works.

## P2 — Platform admin, tenant onboarding, config, presets, branding (M01, M02, design system)
AC: create a tenant from each of 5 presets → modules/terminology/navigation differ accordingly · preset version bump does not alter existing tenants' overrides (test) · settings validated with typed definitions; invalid rejected · theme draft/preview/publish/rollback works; contrast failure blocked · support-grant lifecycle (create, expire, revoke, tenant-visible, audited) · design-system components render at 360/768/1280 with no horizontal scroll · SVG lint passes (no emoji/icon fonts) · A11Y automated checks on shell, forms, table.

## P3 — CRM, clients, encryption, documents & consents (M04)
AC: ENC: envelope round-trip, wrong AAD/row/tenant fails, tamper fails, key rotation re-encrypts all test rows, MK re-wrap works · C3 fields unreadable in DB dump and in backups · blind index equality works, differs per tenant · health view requires scope + writes audit · custom fields/visibility/retention enforced · consent and agreement versions immutable (update attempt fails) · client profile tabs wired to real data · documents encrypted, authorised stream, foreign ID 404 · data export/correction/deletion workflow functions end-to-end with due-date tracking · minors consent rule enforced · ISO suite extended to M04 passing.

## P4 — Memberships & attendance (M05, M06)
AC: plan versioning (sold contracts keep snapshot) · lifecycle tests: start, freeze, unfreeze, cancel, renew, expire (time-travel with injected Clock) · events append-only · check-in decision matrix tests (active, expired, frozen, outside hours, wrong branch, duplicate scan with idempotency) · every decision audited · payment-status condition seam present with "no hold" implementation documented · ISO extended.

## P5 — Trainers, programmes, classes, bookings (M07, M09, M08)
AC: assigned-client scope enforced in SQL (PT cannot see unassigned client by ID or search) · concurrency test: 50 parallel bookings on capacity 10 → exactly 10 booked, rest waitlisted · cancellation promotes waitlist in same transaction · package ledger never negative unless policy allows · programme/assessment health fields encrypted · ISO extended.

## P6 — Billing, payments, recurring, refunds, credit notes, expenses, reconciliation (M10, M11, M12)
AC: FIN: Money value object property tests (no float drift, rounding, tax inclusive/exclusive) · invoice numbers gap-free under concurrency · issued snapshot unchanged after price/plan edits · allocation can't exceed payment or invoice balance · duplicate provider event processed once (replay test) · invalid signature rejected · uncertain payment → `unknown` then reconciled · refund > paid blocked; self-approval blocked; limits enforced · credit notes reference original · test provider cannot be enabled in production mode · separate status machines verified (invoice/payment/membership/access) · no PAN/CVV anywhere (log + DB scan test) · ISO extended incl. webhooks.

## P7 — Inventory & POS (M14, M13)
AC: concurrent sale test (no oversell when policy forbids) · stock = Σ movements reconciliation test · PO receive creates movements · POS sale creates invoice+payment+movements atomically (rollback on failure) · receipt snapshot printable and branded · register open/close variance recorded.

## P8 — Templates & communications (M17b)
AC: placeholder allowlist rejects unknown/foreign-tenant tokens · all required templates present (verification, reset, invitation, renewal, expiry, payment reminder, invoice, receipt, booking, announcement) in HTML + text · communication history per client · unsubscribe/marketing consent honoured · queue monitoring page shows real depth/age/failures · "queued" never shown as "delivered".

## P9 — Member portal & PWA (M18)
AC: manifest per tenant valid (installability checked) · service worker caches only the static allowlist; test proves authenticated responses are never cached and logout leaves no sensitive cache · offline banner · member can book/cancel/view invoices/update profile using same services with `own` scope · ISO extended · A11Y/responsive checks on portal.

## P10 — Staff, facilities, reports, exports (M15, M16, M19)
AC: shifts/commission records immutable with adjustments · report totals equal source ledger totals (cross-check tests) · exports run as queued jobs, tenant-scoped, permissioned, audited, expiring links · export excludes C3 unless explicitly permitted and step-up · maintenance schedule generates tickets.

## P11 — Backups, diagnostics, installer, hardening (M21, M22) — **go-live gate**
AC: BAK: both DB export methods produce restorable archives (restore into scratch DB, per-table counts+checksums match) · encrypted archive can't be opened without backup key · off-site upload verified and retrieved · retention pruning correct · master-key absence from archives proven by scan · diagnostics page reports PHP/ext/DB/cron/queue/backup/disk · installer + upgrader from clean cPanel staging succeed; second run refuses · MIG: upgrade from each prior released schema · full security review checklist (OWASP ASVS L2 selected items) · penetration-style probes (SQLi, XSS, CSRF, IDOR, upload) pass · documentation complete · POPIA checklist signed off by owner.

## Backlog hygiene
Items discovered later are added with ID, module, AC, test. Priorities: security/integrity > correctness > usability > polish.
