# requirements.md

## Functional Requirements

### Identity & Tenancy
- Multi-tenant: every record carries `tenant_id`; session-resolved, never request-supplied.
- Roles: `admin`, `adviser`, `support`. Permission-based gating (`scenario.create`, `simulation.run`, `funds.manage`, `report.view`, `admin.settings`).
- Session-based auth; passwords hashed; audit log on sensitive actions.

### Client Management
- CRUD on clients (name, age, life expectancy, UK GDPR consent, NI number encrypted).
- Decrypt-at-read for PII fields (AES-256-GCM, UK GDPR Art.32).
- Life expectancy default 87 years (ONS UK average).

### Scenario Management
- CRUD on scenarios linked to a client.
- Scenario fields: name, risk profile (`conservative|moderate|aggressive`), inflation rate
  (default 2.5% — ONS CPI target), annual withdrawal (target net), simulation years.
- Multiple scenarios per client (what-if).
- Each scenario owns 1..N assets.

### Asset Configuration
- **Current asset types:** `cash`, `unit_trust` (OEIC), `sipp` (SIPP drawdown), `isa`, `workplace_pension`, `state_pension`.
- Per asset: name, type, current value, equity/bond/cash weights, drawdown rate, priority order, optional fund link.
- **SIPP:** 25% PCLS tax-free (`TAXABLE_FRACTION = 0.75`); minimum access age 57 (2028); remainder subject to HMRC Income Tax.
- **ISA:** Fully tax-free growth and withdrawals (`TAXABLE_FRACTION = 0.0`); fully liquid.
- **State Pension:** Income stream (not a capital pot). Full rate £221.20/week (£11,502.40/yr, 2024/25). Requires 35 NI qualifying years. Inflated each year by triple-lock proxy (CPI). `withdraw()` always returns 0.0; subtracted from annual income target before drawing from the portfolio.
- Phase 3 adds: LISA, defined-benefit pension income, annuity income, offshore bond, VCT.

### Fund Database
- UK fund universe seeded with IA sector classifications and verified provenance flag.
- Per fund: ISIN, SEDOL (`sedol` column; `jse_code` retained for migration compatibility),
  name, fund manager, IA sector/category, fund type (unit_trust, etf, oeic, money_market, other),
  TER, risk rating, inception date, source, `is_verified`.
- Per-fund annual performance history (`fund_performance` table).
- Admin UI for manual capture + CSV upload for funds and performance.
- Ingest-run history with success/failure counts.

### Simulation Engine
- Monte Carlo with N = 500 (default) or 1000 runs.
- Monthly cashflow: 12 sub-periods per year, compound monthly returns.
- Sequence-of-returns honoured (withdraw BEFORE returns).
- **HMRC Income Tax gross-up** inside the loop (per current tax year).
- **State Pension income** subtracted from annual withdrawal target before portfolio drawdown.
- Shortfall failure: <80% of target net income for 3 consecutive years = failed run.
- Risk-profile rebalancing on drawdown >15% (conservative).

### Tax Engine (HMRC)
- `HmrcTaxCalculator.php` — DB-backed bracket calculator.
- 2024/25 brackets: £0–£12,570 @ 0%; £12,570–£50,270 @ 20%; £50,270–£100,000 @ 40%;
  £100,000–£125,140 @ 60% (PA taper); £125,140+ @ 45%.
- Methods: `calculateTax()`, `netIncome()`, `effectiveRate()`, `grossUp()`, `grossUpPension()`.
- `tenant_id = 0` holds global HMRC defaults; per-tenant rows may override per tax year.

### Reporting
- Dashboard: success-rate ring, verdict, withdrawal/tax/net display, 2 charts (paths + bands),
  confidence-bands table, previous-runs history.
- PDF report (4 logical pages):
  1. Header + headline + tax + assets (SIPP / ISA / State Pension breakdown)
  2. Portfolio Paths chart + Confidence Bands chart
  3. Confidence-bands year-by-year table
  4. Recommendations + FCA disclosure disclaimer + footer
- CSV export of run data (gated by plan tier).
- One-click PDF download via jsPDF + html2canvas (no server-side library required).
- Server-side mPDF supported (drop-in install) for text-based PDFs.

### Billing & Quotas
- **Stripe** as payment provider (replaces PayFast).
- Plan tiers: Free (credit-based), Lite, Plus, Pro.
- Per-plan feature gates: csv, pdf, max runs/month, max clients.
- Credit packs for Free tier.
- Quota tracking; exceeded → 429 + upsell.
- Prices in GBP (`price_gbp` column; `price_zar` retained for migration compatibility via `COALESCE`).

### Admin Portal
- Funds management (list, edit, performance entry, CSV import).
- Ingest-run history.
- HMRC tax-bracket admin per tax year.
- Market data: FTSE All-Share, UK Gilts, SONIA, ONS CPI.

---

## Non-Functional Requirements

### Performance
- Single simulation completes in <3 seconds on shared cPanel (500 runs × 25 years × 12 months).
- Fund search returns in <300ms.
- Dashboard initial load <1s.

### Security
- Native prepared statements (`PDO::ATTR_EMULATE_PREPARES = false`).
- Session-based auth, secure cookies (`HttpOnly`, `Secure`, `SameSite=Lax`).
- Triple-verification on irreversible flows (delete, billing, permissions).
- Input sanitisation at every entry point; output escaping for HTML and SVG.
- Tenant isolation enforced at repository level (every WHERE includes `tenant_id`).
- UK GDPR consent required before client save.
- No PII or financial data in URLs or query strings.

### Scalability (shared-hosting-aware)
- No background workers. Cron jobs only for scheduled ingest.
- Stateless PHP request handling.
- DB-backed sessions optional but not default.
- Vendor-less: no Composer, no Node, no Docker — single-tenant cPanel can run this.

### Compliance
- **UK GDPR / Data Protection Act 2018** — lawful basis Art.6; encryption Art.32;
  right to erasure Art.17 (`ConsentWithdrawn` event handler); consent withdrawal Art.7(3).
- **FCA COBS** — suitability disclosure on every PDF report; adviser remains responsible banner.
- Audit log retained for the regulatory minimum (6 years for FCA-regulated firms).

---

## Business Rules

- An adviser may only see clients within their tenant.
- A simulation run is immutable once persisted; re-runs create new rows.
- Verified fund data cannot be overwritten by unverified ingest.
- Withdrawal-amount field on a scenario is **net**; the engine grosses it up for HMRC Income Tax.
- **State Pension income reduces the gross-up target** — engine subtracts annual State Pension
  income from the annual withdrawal target before drawing from the portfolio.
- SIPP drawdown: 25% PCLS is already tax-free; subsequent income draws are fully taxable.
- ISA: all withdrawals are tax-free regardless of amount.
- SIPP minimum access age: 57 from 2028 (55 currently). Engine enforces this on `SippAsset`.
- Free tier exhausts a credit per simulation; paid tiers count against a monthly quota.
- Inflation applied to next year's net target; tax brackets static across simulation years
  (Phase 5: inflate brackets).
- Strategy recommendations are informational only — the adviser remains FCA-responsible.
