8b620c8c6a
Build Kvitt images / build (push) Failing after 3h10m35s
K0 ran on the owner's SJ Prio Mastercard on 2026-10-24; the report docs/spikes/K0-enable-banking.md holds aggregates only. SPEC v0.36 answers every K0 TODO(spec) of §9.12: D-177 K0's outcome and the owner's assumptions (partner card, pending->booked, next-day session; verified by K1's owner steps), D-178 the windowed history fetch (100-row cap, no continuation key: 30-day windows split at 100 rows), D-179 the transaction mapping (merchant from remittance_information, booking date else value date, FEE debits to handle, debtor/CPAN fields never stored), D-180 the artwork cropped to the card (1313 x 829) and committed for Android and the web. K plans, prompts/README and HANDOFF follow; K1 to K3 spec text goes into v0.37. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
6.6 KiB
Markdown
51 lines
6.6 KiB
Markdown
# PLAN-K3: Card purchases, web
|
||
|
||
## 1. Goal
|
||
The card features of FR-22 in the web client (D-174): W-21 Kortköp, W-22 Anslut kort with BankID by QR in the browser, W-23 the connection's settings, the sidebar entry, "Skapa utgift" through W-5 with the prefill of CP-9, the card line on W-6, "Från kortköp" on W-3, and `matchCardPurchase` in TypeScript passing its vectors.
|
||
|
||
## 2. Read first
|
||
1. SPEC §15 (§15.3 strings and layout, §15.5 data, §15.6 rows W-3, W-5, W-6, W-21 to W-23, the navigation paragraph), §9.12 (CP-1 to CP-14, with K0's answers in v0.36), FR-22, §13.3 rows S-23 to S-27, the "Card callback page" and "Card purchase strings" tables, §14.3.3, §14.3.4 E-36 to E-44, §14.5.8, §14.7; D-174, D-169, D-170, D-172, D-177 to D-180 (K0's results and the artwork).
|
||
2. K1's `contracts/openapi.yaml` and `web/src/api/schema.d.ts` (regenerated by K1), `contracts/examples/E-36-*` to `E-44-*`, `contracts/test-vectors/match_card_purchase.json`.
|
||
3. `web/README.md`, `web/src/app/` (routes, layout, sidebar), `web/src/api/` (client, snapshot), `web/src/lib/domain/`, `web/src/components/`, `web/src/features/{expenses,accounts,settings}/`; `docs/ux/design-spec.md` §2 and the S-23 to S-27 design (K2's report, if landed).
|
||
4. `CLAUDE.md` (web gate, web layering).
|
||
|
||
## 3. Already established
|
||
- Card data is read through E-40 into an in-memory card snapshot next to the household snapshot (§15.5: pulled from 0 on load, from its cursor on focus and after every card write); nothing persisted across a reload; writes (E-44) go at once, no queue.
|
||
- Connect: E-37 with `client` `web`; the browser goes to the returned URL in the same tab; the bank shows its QR for BankID on the phone; the callback page's link returns to `/app/cards?attempt=<id>`, where W-21 polls E-38 every 2 seconds until the attempt ends, then drops the parameter (CP-2).
|
||
- "Skapa utgift" opens W-5 at `/app/expenses/new?cardPurchase=<id>` (plus `&account=<id>` from W-3's "Från kortköp", `/app/cards?account=<id>`); W-5 prefills per CP-9, runs the §9.11 suggestion as for any new expense, and after an accepted save sends E-44 with the new expense id.
|
||
- Artwork (D-174, D-180): `web/src/features/cards/assets/card-sj-prio-mastercard.png` is committed (the same file as Android's, 1313 × 829, cropped to the card, transparent only at its rounded corners and in the notch on the right edge). The cards feature imports it (Vite emits it under `/app/assets/` with a hashed name) and maps the image key `sj_prio_mastercard` to it from the first commit, drawn at its own aspect ratio (`object-fit: contain`, no clipping, no background), `alt` the card's name; for any unknown key, the drawn fallback of D-173 (CSS: aspect ratio 1.586, radius 16 px, the `green` category token's light value, the name in white). Served from the server's own origin (CSP `img-src 'self'`). Do not edit or re-encode the PNG.
|
||
- Strings: the keys of §13.3's table (K2 adds them to `docs/ux/strings.csv`; `npm run i18n:import` regenerates the dictionaries); web-only strings get `web_cards_` keys in `web/src/features/cards/i18n/{sv,en}.json`.
|
||
- The sidebar and bottom bar gain "Kortköp" after Home (D-172).
|
||
|
||
## 4. Owned paths
|
||
From SPEC §14.7 (row K3): `web/src/features/cards/**` (new); in shared code the route in `web/src/app/`, the sidebar entry and `web/src/lib/domain/` (`matchCardPurchase` and its vector test); `web/src/features/expenses/**` (W-5's prefill and link, W-6's card line), `web/src/features/accounts/**` (W-3's "Från kortköp"), `web/src/features/settings/**` (W-13's row); the regenerated i18n dictionaries. Not `web/src/api/schema.d.ts` (K1), `docs/ux/**`, `server/**`, `contracts/**`, `android/**`.
|
||
|
||
## 5. Deliverables
|
||
- The card snapshot and API calls; W-21 (header, filters, day groups, the purchase panel or dialog with every action of S-23's sheet, match chips, the `?attempt=` and `?account=` handling), W-22 (catalogue with artwork, history choice, "Anslut med BankID"), W-23 (as S-26 with the disconnect dialog); W-5, W-6, W-3 and W-13 changes; the sidebar entry.
|
||
- `matchCardPurchase` passing `match_card_purchase.json` in `web/src/lib/vectors.test.ts` (or the domain's vector test), listed as ported.
|
||
- Tests: pages against the fake server with every state of §13.3 (no connection, first fetch, loaded, empty filter, expiring, expired, fetch failed, long content), the attempt polling, E-44 outcomes (`expense_already_linked`, `not_found`), the prefill rules.
|
||
|
||
## 6. Steps
|
||
1. Worktree: from `/Users/jhag/projects/kvitt`, `git worktree add .claude/worktrees/agent-k3 -b agent-k3 main`; in it `git reset --hard main`; `npm ci` in `web/`; `tools/install-git-hooks.sh`.
|
||
2. Confirm SPEC v0.36 is on `main`. K3 may start before K1 lands, against the spec and the fake server; before its gate it rebases on K1 (the generated types and the vectors are K1's) and on K2 (the card strings in `docs/ux/strings.csv`; then `npm run i18n:import`). If K1 or K2 has not landed when the rest is done, stop and report.
|
||
3. Build; check manually against a throwaway server (`cargo run -p kvitt-server -- serve` with a temporary `KVITT_DATA_DIR` and `KVITT_EB_API_URL` pointed at a stub, as K1's tests do), never the owner's development or Pi data.
|
||
4. Gate (§7). Commit on `agent-k3`, `git rebase main`, rerun the gate. Never merge, push or remove the worktree.
|
||
|
||
## 7. Gate
|
||
The web gate, from `web/`: `npm run check`. Report the real result lines (test files, tests).
|
||
|
||
## 8. HUMAN steps (relayed by the orchestrator in chat, after K1 is deployed and an image with K3 is deployed)
|
||
1. On the laptop, `https://kvitt.suorra.duckdns.org/app/` › Inställningar › Anslut kort: the SJ Prio card shows "Ansluten" if the phone connected it (yes/no). Kortköp lists the same purchases as on the phone (yes/no).
|
||
2. Kortköp › a purchase › "Skapa utgift" › "Spara": the purchase is under "Kopplade" on the laptop and on the phone after a sync (yes/no).
|
||
3. If the card is not connected yet or after "Koppla från": Anslut kort › SJ Prio Mastercard › "Anslut med BankID": the bank's page shows a QR; scan it with BankID on the phone; "Tillbaka till Kvitt" opens Kortköp with your purchases (yes/no each).
|
||
|
||
## 9. Out of scope
|
||
- The server and the contract (K1), the app (K2); `docs/ux/strings.csv` (K2); a card notification and bulk add (D-171).
|
||
|
||
## 10. Report
|
||
- Branch `agent-k3`, head commit after rebasing; gate lines.
|
||
- `web_cards_` strings added; proposed decision entries and spec text for anything beyond §15.6 and §9.12 (numbered from the brief); HUMAN steps outstanding worded for relay; open questions with SPEC section numbers.
|
||
|
||
## 11. Numbering
|
||
Decisions from the start prompt (`TODO(spec)` if none was given). Proposed spec text goes into SPEC **v0.37** (v0.36 recorded K0's results; K1, K2 and K3 share v0.37).
|