# Fidelity UK PlanViewer provider Viktor's UK workplace pension is hosted at `pv.planviewer.fidelity.co.uk`. There is no public API for individual members — the provider reverse-engineers the private JSON backend at `prd.wiciam.fidelity.co.uk/cvmfe/api/*` that the SPA itself calls, and uses Playwright only to keep a long-lived login session alive. ## Architecture ``` ┌─────────────┐ storage_state.json ┌──────────────────┐ │ Vault KV │◀─── (quarterly reseed) ───│ fidelity-seed │ │ broker-sync │ │ (headed browser) │ └──────┬──────┘ └──────────────────┘ │ ▲ │ loads on start │ Viktor runs once ▼ when session expires ┌────────────────────┐ │ Monthly CronJob │ │ broker-sync-fidelity│ └────────────┬────────┘ │ headless Chromium ▼ ┌─────────────────────────────────┐ ┌────────────────────────────────┐ │ pv.planviewer.fidelity.co.uk │◀─────│ navigate dashboard → capture │ │ (SPA) │ │ fresh sid/fid/tbid/rid headers │ └─────────────────────────────────┘ └──────────────┬─────────────────┘ │ ┌───────────▼─────────────┐ │ httpx JSON calls │ │ prd.wiciam.../cvmfe/api│ └───────────┬─────────────┘ │ ┌────────────────────▼────────────────────┐ │ DEPOSIT × N (employee + employer) │ │ BUY × N (fund unit purchases, per date) │ └────────────────────┬────────────────────┘ │ ┌────────────────▼────────────────┐ │ Wealthfolio account │ │ type = WORKPLACE_PENSION │ │ currency = GBP │ └──────────────────────────────────┘ ``` ## One-time seed (Viktor) ```bash # on your laptop (macOS / Linux with a desktop): cd broker-sync poetry install poetry run playwright install chromium poetry run broker-sync fidelity-seed --out /tmp/fidelity_storage_state.json # chromium opens — log in to PlanViewer, tick "Remember device", press Enter # stage to Vault vault kv patch secret/broker-sync \ fidelity_storage_state=@/tmp/fidelity_storage_state.json \ fidelity_plan_id= rm /tmp/fidelity_storage_state.json # don't leave credentials lying around ``` Re-seed when the monthly CronJob fails with `FidelitySessionError` (expect every 30-90 days, depending on how long Fidelity honours the remember-device cookie). ## One-time backfill ```bash kubectl -n broker-sync create job fidelity-backfill \ --from=cronjob/broker-sync-fidelity kubectl -n broker-sync logs -f job/fidelity-backfill # expect: fidelity-ingest: fetched=N new=N imported=N failed=0 ``` ## Monthly cron - Schedule: `0 3 5 * *` (3am UTC on the 5th of each month — after mid-month payroll settles in Viktor's scheme) - CronJob: `broker-sync-fidelity` in namespace `broker-sync` - Resource: small, ≤512 MiB memory (Chromium for ~2 min, then idle) - Alert: `BrokerSyncFidelityFailed` fires on 2 consecutive failures ## Runbook — `BrokerSyncFidelityFailed` 1. Check pod logs: `kubectl -n broker-sync logs job/broker-sync-fidelity-`. 2. If the error is `FidelitySessionError`: session expired, re-run the seed on Viktor's laptop (see above). 3. If the error is a 404 / 5xx from `prd.wiciam.fidelity.co.uk`: likely an API path change. Check DevTools for the new endpoint, update the provider, ship a new image. 4. If Playwright can't launch Chromium: check that the image still has Chromium installed (`playwright install chromium` at build time). ## Data model notes - **Salary sacrifice scheme**: all employee + employer contributions are pre-tax from gross salary. No HMRC basic-rate relief line. - Emits two `DEPOSIT` per month (employee, employer) with `comment` carrying the source tag `fidelity::` for audit. - Emits one `BUY` per fund unit purchase, `symbol` = Fidelity fund code / ISIN. Units × unit price should reconcile to the cash deposited ±pennies. ## Not yet implemented - Endpoint paths: waiting on Viktor's DevTools POST cURL for transactions + holdings views. Until pasted, `fidelity-ingest` raises `FidelityProviderConfigError` to fail loudly. - Infra: CronJob + Vault secret wiring + Prometheus alert in `infra/stacks/broker-sync/main.tf` — pending first successful manual run.