# 11 — Module Specifications

Per module: **Routes** (prefix, verbs; all declare a permission from 07), **Validation**, **Services**, **Audit** (events from 13), **Failures**, **Tests/AC** (beyond the shared ISO suite and those in 10). Entities are in 04, permissions in 07, states in 12. Route paths use public ULIDs, never integers.

Shared rules: every state-changing route is POST/PUT/PATCH/DELETE with CSRF; list routes support server-side filter, sort (allowlisted columns), cursor or page pagination capped at 100; every list and export applies tenant and scope in SQL; validation errors return 422 with field messages; unknown ID or foreign tenant = 404; permission failure = 403 and an `authz.denied` event.

## M01 Platform administration and onboarding
Routes: `/platform/tenants` (list, create, show, suspend, reactivate, close) · `/platform/presets` · `/platform/support-grants` · `/platform/health`.
Validation: slug `[a-z0-9-]{3,40}`, reserved-word blocklist (`www`, `auth`, `files`, `admin`, `api`…), unique; owner email format; preset exists.
Services: `TenantProvisioner` (creates tenant, keys, default roles, settings snapshot, first owner invitation, in one transaction), `SupportGrantService`.
Failures: provisioning is atomic (rollback leaves no half tenant); suspended tenant users see a neutral suspended page and cannot authenticate to tenant context; closing triggers a retention timer, not immediate deletion.
AC: provision five presets; provisioning failure injected at each step leaves zero rows; suspension blocks all tenant routes and jobs (jobs are parked, not lost).

## M02 Business configuration and branding
Routes: `/settings/{group}` · `/settings/modules` · `/branding/theme` (draft, preview, publish, rollback) · `/branding/assets` · `/settings/templates`.
Validation: typed per setting (14 §1); colour contrast calculated; assets size/type/dimensions, SVG sanitised through an allowlist parser; module toggles check dependencies.
Failures: invalid theme cannot publish; assets that fail sanitising are rejected with a reason; concurrent edits use `row_version` (409 with merge hint).
AC: preview does not affect other users; rollback restores exact tokens; changes audited.

## M03 Authentication, roles and permissions
Routes: `/login`, `/logout`, `/register` (member self-registration only when the tenant enables it), `/verify-email/{token}`, `/password/forgot|reset`, `/account/security` (sessions, MFA), `/switch-tenant`, `/staff`, `/roles`, `/invitations/{token}`.
Validation: email normalised and length-limited; password min 12, max 128, breached-password check optional, no composition rules beyond length; TOTP codes with ±1 step; tokens single-use.
Failures: uniform responses for unknown accounts (including invitation and registration flows); throttling; expired or reused token message does not reveal account state.
AC: see P1.

## M04 CRM, prospects and clients
Routes: `/clients` (list/search/filters/saved views), `/clients/{id}` tabs: overview, memberships, billing, attendance, training, health, documents, communications, consents, security, notes, custom fields · `/prospects` and pipeline stages · `/clients/{id}/merge` · `/data-requests`.
Validation: phone normalised (E.164), email format, SA ID number checksum (Luhn-style check) when provided, DOB plausible and age rule for minors, custom fields typed per definition, required-by-config enforced.
Services: `ClientService`, `ConsentService`, `AgreementService`, `DocumentService`, `DataRequestService`, `DuplicateDetector` (blind index + normalised name/phone, suggest merge, never auto-merge).
Failures: duplicate detection warns; merge moves related records in one transaction and records a tombstone mapping; uploads rejected with specific reasons; decrypt failure surfaces a safe error and a `security.crypto.fail` event.
AC: see P3. Tabs load lazily and each applies its own permission (a user may see Overview but not Health).

## M05 Membership plans and contracts
Routes: `/plans`, `/plans/{id}/versions`, `/clients/{id}/contracts` (create, sign, freeze, unfreeze, cancel, renew), `/contracts/{id}`.
Validation: dates, minimum term, price non-negative, freeze limits, plan version must be published, waiver version current.
Failures: overlapping contracts policy (block or allow per plan); backdating needs permission and reason; price changes never touch sold contracts.
AC: see P4.

## M06 Check-in and access
Routes: `/checkin` (kiosk/staff desk with search or QR), `/checkin/token` (rotating QR for portal), `/attendance` (history), `/access/policies`.
Validation: idempotency key required; branch must belong to the actor's scope.
Failures: duplicate scans inside the window return the original decision; clock skew handled with server time only; denied decisions show reason codes and a permitted override flow.
AC: see P4 and the evaluation order in 12 §5.

## M07 Trainers and assignments
Routes: `/trainers`, `/clients/{id}/assignments`, `/trainers/{id}/schedule`, `/packages`.
Validation: assignment dates non-overlapping per role; a trainer must hold the trainer role.
Failures: removing a trainer with future appointments forces reassignment or cancellation choice.
AC: assigned scope enforced in SQL across search, reports and exports.

## M08 Training plans and assessments
Routes: `/clients/{id}/programmes`, `/exercises`, `/clients/{id}/assessments`, `/goals`.
Validation: measurements in metric with unit conversion at the edge; health fields flagged for encryption.
Failures: published programme versions are immutable; edits create a new version.
AC: progress charts read real assessment data with data-table alternative.

## M09 Classes, appointments, bookings and waitlists
Routes: `/classes`, `/classes/{id}/sessions`, `/timetable`, `/bookings`, `/appointments`, `/availability`.
Validation: capacity ≥ 1; start < end; instructor and room free; booking window and cancellation policy.
Failures: race conditions covered by locking (12 §6); instructor change notifies bookers; session cancellation refunds credits and notifies.
AC: see P5.

## M10 Billing and invoicing
Routes: `/invoices` (create draft, edit draft, issue, void, send, download PDF), `/payments` (record, allocate), `/clients/{id}/billing`, `/billing/series`.
Validation: lines non-empty, quantity > 0, amounts in minor units, tax rate valid for date, currency equals tenant or explicit multi-currency allowance.
Failures: issuing is one transaction (number, snapshot, ledger entries); PDF generation failure does not roll back issuing, the document is regenerated from the snapshot.
AC: see P6. SA tax invoice fields (supplier name, VAT number, "Tax Invoice", sequential number, date, description, amounts, VAT amount) present when the tenant is VAT registered.

## M11 Recurring billing and provider integration
Routes: `/billing/schedules`, `/webhooks/{provider}` (unauthenticated except signature), `/billing/payment-methods` (hosted fields), `/billing/dunning`.
Validation: webhook body size limit, signature and timestamp window.
Failures: provider outage queues retries; uncertain state parks for reconciliation; webhooks respond within provider timeout by doing minimal work and queuing the rest.
AC: see P6.

## M12 Refunds, credit notes, expenses and reconciliation
Routes: `/refunds`, `/credit-notes`, `/expenses`, `/reconciliation`, `/adjustments`, `/approvals`.
Validation: refund ≤ refundable; expense category and receipt type/size; reconciliation file formats (CSV import, documented mapping).
Failures: unmatched lines stay open with an assignee; closing a period locks it (corrections post to the next period with reference).
AC: see P6.

## M13 Point of sale and receipts
Routes: `/pos`, `/pos/sessions`, `/pos/sales`, `/receipts/{id}`.
Validation: stock availability, price from catalogue (override needs permission), payment total equals sale total.
Failures: failed card payment leaves cart intact; hold-and-resume carts; sale creation atomic across invoice, payment and stock.
AC: see P7.

## M14 Inventory, suppliers and purchase orders
Routes: `/products`, `/stock`, `/stock/adjustments`, `/suppliers`, `/purchase-orders`.
Validation: SKU unique per tenant; quantities decimals respecting unit precision; PO receive cannot exceed ordered without permission.
Failures: concurrent adjustments detected via `row_version`; stocktake workflow (count sheet, variance approval).
AC: see P7.

## M15 Staff, shifts and commissions
Routes: `/staff/{id}`, `/shifts`, `/timesheets`, `/commissions`.
Validation: shifts don't overlap per staff; commission rules reference products, packages or sessions with effective dates.
Failures: late edits to a closed pay period create adjustments.
AC: see P10.

## M16 Facilities, equipment and maintenance
Routes: `/facilities`, `/equipment`, `/maintenance`.
Validation: serial uniqueness per tenant; schedule intervals.
Failures: equipment out of service blocks room/bookings that depend on it.
AC: see P10.

## M17 Email, templates and communications
Routes: `/settings/email` (SMTP A/B, test connection), `/templates`, `/announcements`, `/outbox`, `/clients/{id}/communications`, `/unsubscribe/{token}`.
Validation: SMTP host/port/encryption allowlist, credentials write-only (never displayed back), templates must only use allowlisted placeholders and sanitised HTML, announcements target by consented segments only.
Failures: transport test shows precise error class (DNS, TLS, auth, relay denied); both transports failing raises a platform alert; outbox views show real states.
AC: see P1 and P8.

## M18 Member portal and PWA
Routes: `/portal` (home), `/portal/bookings`, `/portal/membership`, `/portal/invoices`, `/portal/profile`, `/portal/checkin`, `/manifest.webmanifest`, `/sw.js`, `/offline`.
Validation: all inputs through the same services with `own` scope.
Failures: stale-session handling; offline page shows what is unavailable; update flow for new service worker versions without losing form state.
AC: see P9.

## M19 Reports, analytics and exports
Routes: `/reports/{key}` (members, retention, attendance, class utilisation, revenue, aged debtors, tax summary, stock valuation, commissions), `/exports`.
Validation: date ranges bounded, filters allowlisted.
Failures: long reports run as queued jobs with progress; totals are checked against ledger totals in tests; exports expire and are deleted by retention job; CSV output neutralises spreadsheet formula injection (prefix `'` for cells starting `=`, `+`, `-`, `@`).
AC: see P10.

## M20 Audit, security and monitoring
Routes: `/audit` (filter, export), `/security/events`, `/security/sessions`, `/platform/monitoring`.
Validation: filters allowlisted; exports permissioned and themselves audited.
Failures: chain verification failure raises a platform alert and a tenant-visible notice.
AC: see P1.

## M21 Backups and restore
Routes (platform only): `/platform/backups` (status, run now, destinations, restore tests), CLI `backup:run`, `backup:verify`, `restore:test`, `restore:execute`.
Failures: method auto-selected and reported; partial runs resume; upload failure retried; verification mismatch marks the backup unusable and alerts.
AC: see P11.

## M22 System settings, diagnostics and deployment
Routes: `/platform/diagnostics`, CLI `migrate`, `diagnose`, `maintenance:on|off`, `install`.
Failures: migration failure leaves the system in maintenance mode with a recorded state; installer refuses to run twice.
AC: see P11.
