# stack.md

## Backend
- **PHP 8.5+** (primary). `declare(strict_types=1)` enforced in every file. Readonly properties used heavily on domain objects.
- **Custom PSR-4 autoloader** mapping `App\` → `app/`. No Composer at runtime (mPDF is the only optional Composer dep, vendored manually if installed).
- **PDO native prepared statements** (`ATTR_EMULATE_PREPARES => false`). Note: `LIMIT` can't be a bound parameter — must be sanitised and inlined.

## Front-End
- **Vanilla JavaScript.** No framework, no build step.
- **Chart.js** loaded from CDN for dashboard charts.
- **jsPDF + html2canvas** loaded from CDN inside the PDF report itself for client-side PDF generation.
- **Inline-SVG** for embedded charts in the PDF (`app/Reporting/SvgChart.php`).
- Server-rendered PHP views with one shared `_layout.php`.
- **Locale:** `en-GB`; currency symbol `£` throughout JS number formatting.

## Automation / Integration
- **PHP CLIs** (`bin/funds-sync.php`, `bin/funds-inspect.php`) for batch ingest.
- **OpenFIGI API** (`app/Integration/OpenFigiClient.php`) — cURL-based; called on-demand from admin fund forms to populate missing fund metadata. Lookup by ISIN or SEDOL. Key stored in `OPENFIGI_API_KEY` env var.
- **Stripe** (`app/Billing/StripeBilling.php`) — payment processing for UK GBP billing. Keys stored in `STRIPE_SECRET_KEY` and `STRIPE_WEBHOOK_SECRET` env vars.
- **Python** earmarked for future tasks (fund-data scraping, EDI integration) — not on the critical path today.
- **Cron jobs** for monthly fund refreshes.

## Database
- **MySQL 8.x** (`utf8mb4`).
- All schema in `database/*.sql`, hand-applied via phpMyAdmin.
- Key UK-specific tables: `uk_tax_2025.sql` (HMRC brackets), `uk_market_data.sql` (FTSE/Gilts/SONIA/CPI), `uk_state_pension_schema.sql` (NI/State Pension tables).

## Hosting
- **Shared cPanel hosting** (Linux / Apache / PHP-FPM), UK datacentre.
- No SSH for Composer or Node.
- 30-second PHP execution limit (hard ceiling for simulation perf budget).

## Constraints
- **No heavy external dependencies.** Anything new must be:
  - native PHP, or
  - a single-file drop-in (e.g. TCPDF, mPDF as manual vendor zip), or
  - a CDN-loaded JS library used client-side only.
- **No Docker, no Kubernetes, no Node.** Optimised for low-resource shared environments.
- **No background workers.** Cron + on-demand request handling only.

## Libraries actually in use

| Library | Where | Why |
|---|---|---|
| Chart.js (CDN) | Dashboard charts | Already-familiar, well-supported |
| jsPDF (CDN) | PDF report download | Client-side PDF generation, no server install |
| html2canvas (CDN) | PDF report download | Captures the report DOM into the PDF |
| mPDF (optional vendor zip) | Server-side PDF | Text-based PDF when available — falls back to client-side if not |
| Native PHP `ZipArchive` + `SimpleXML` | `XlsxReader.php` | Read .xlsx without PHPSpreadsheet/Composer |
| PHP `curl_*` (native ext) | `OpenFigiClient.php` | HTTP calls to OpenFIGI API for fund metadata enrichment |

## What we deliberately don't use

- No ORM (Eloquent, Doctrine) — repositories with hand-written SQL keep auditability high (important for FCA audit trail).
- No template engine (Twig, Blade) — PHP IS the template engine.
- No JavaScript bundler — easier debugging on production, no source-map pain.
- No NPM/Yarn — every JS file is hand-written.
- No CI/CD pipeline yet — git push + cPanel File Manager upload (see `deployment.md`).
