# CLAUDE.md

Guidance for Claude Code in this repo (QRMiddleLayer, a Phoenix app, being renamed Bank Bridge Middle Layer).

## YSP card integration plan

Goal: Postman → QRMiddleLayer → YSP card endpoints, with the YSP simulator's response coming back in Postman. Longer term: app → MMS Portal → Bank Bridge Middle Layer → YSP prepaid-card endpoints (load card, transactions, block card, ...). The step-by-step working list is in `YSP_CARD_STEPS.md`.

Requirements from the meeting: endpoint criticality tiers (load card must never fail silently or double-load; card block is critical), request/response bodies logged to the DB, support-friendly error messages, testing prioritised.

### Decisions
- `ysp-simulator/` is a separate Mix project in this repo (Plug + Bandit, port 4180, `/_sim/*` controls). Keep it a separate server from the middle layer; it is a test double.
- YSP sits behind a client module (`DaProductApp.YspCard`) with a configurable base URL (`YSP_CARD_BASE_URL` in `config/runtime.exs`). The simulator is just another URL.
- No rename work (not the author's call). Use "Bank Bridge" only in new docs and messages.
- Criticality lives in one table (`YspCard.Endpoints`): `:critical` = load/fund account, debit/credit, fund transfer, amount refund, card lock/unlock/block, account closure, card replacement, PIN set/change; `:standard` = balance, transactions, card details, limits, status.
- Critical calls are never retried blindly or applied twice.
- Don't commit or push unless asked.

### Sprints (in order; each ends with something demoable)
1. **Thin vertical slice (the first demo).** `YspCard` client, `/api/card/*` routes (balance, load, block first) and a thin controller in `router.ex`. It forwards to the simulator and returns the response body in Postman. Reuse `utils/txn_ref_generator.ex` for `txnRefNo`. Ship a committed Postman collection and a README snippet.
2. **Support-friendly errors.** `YspCard.ErrorMessages` maps appendix 7.3 codes (simulator `ResponseCodes`) and the middle layer's own errors to a plain cause and suggested action. A correlation id per request (`x-correlation-id` header, logged). Every `/api/card/*` response becomes `{"ysp_response": <YSP body verbatim or null>, "human_readable_output": {...}}`. Postman collection and README updated. No DB needed.
3. **DB call log.** Migration and schema `ysp_api_calls`: correlation_id (the id from Sprint 2), endpoint, criticality, txn_ref_no, request_body, response_body, http_status, response_code, error_message, attempt, latency_ms, status (`pending|succeeded|failed|unknown`), timestamps. Write `pending` before sending, update after. Mask PAN/PIN/CVV. Follow `lib/da_product_app/activity/` and `EventLogger` conventions. Tests: row on success, failure, timeout.
4. **Simulator failure controls and critical-path safety.** Extend `/_sim/fail_next` modes: `error_code`, `timeout`, `latency_ms`, `drop_response_after_apply` (`ysp-simulator/lib/ysp_simulator/router.ex`, `store.ex`, `handlers/load_card.ex`, `handlers/card_status.ex`; docs in `docs/simulator-routes.md`, `docs/behaviour/`). Critical calls: `txnRefNo` persisted before send, never blind-retried, unknown outcome marked `unknown` and reconciled via 4.20 Status Request, `TIDEXT` treated as "already applied, reconcile", unique constraint on (endpoint, txn_ref_no). Standard calls: bounded retry with backoff (mirror `YspNotificationService`). Tests: load twice, block twice, response dropped. Then polish: read-only JSON/LiveView list of recent `ysp_api_calls` filterable by txnRefNo or correlation id; extend `ysp-simulator/demo.sh`; write a summary for managers.

### Testing
- Simulator: `mix test` in `ysp-simulator/` for each new `/_sim` mode (helpers in `test/support/card_api_helpers.ex`).
- Middle layer: `mix test` for logging, retry/no-retry per tier, reconcile and error mapping, written with each sprint.
- End to end: `mix run --no-halt` in `ysp-simulator/` (port 4180), `YSP_CARD_BASE_URL=http://localhost:4180`, `mix phx.server` (dev port 4006), then run the Postman collection.

### Constraints
- Keep each sprint's diff small and listed.
- Update `ysp-simulator/docs/behaviour/` for any simulator behaviour change.

### Open items
- **`/api/card/*` has no authentication** (same as the other `/api` routes). Fine against the simulator; must be fixed before `YSP_CARD_BASE_URL` points at real YSP. Raise it at the end of Sprint 1 and again at the end of Sprint 4.
