Parent
#196 — PRD: Angular web client for SubVora (parity minus reminders)
What to build
Maintaining payment sources: edit a label or type in place, and delete one behind a confirmation. Unlike categories, the delete endpoint reports no affected count, so subscriptions referencing a deleted source simply lose their label — the list must be refreshed rather than left showing a stale one.
Edit and delete are kept in one slice deliberately: both are a single call against the same row with no consequence semantics to separate, unlike the category slices.
Implementation Steps
- API methods — add
update(id, label, sourceType) and remove(id) to core/api/payment-sources-api.service.ts (200 / 204, 404 when not owned).
- Inline edit — in
features/payment-sources/payment-sources.component.ts, allow editing label and type in place with save and cancel, reusing the create validation.
- Delete — reuse
shared/confirm-dialog.component.ts, naming the source and stating that subscriptions using it will no longer show a payment source.
- Store methods —
update replaces the item; remove drops it on 204 and on 404 (already gone, with "Not found." reported); other failures keep the row and report the write-failure message.
- Propagate — after a successful update or delete, refresh the subscriptions list store if it holds data, so
paymentSourceLabel cells are not stale.
- Spec —
payment-sources.store.spec.ts additions: update replaces exactly one item; delete removes it; a 404 removes it and reports the message; the subscriptions store refresh fires only when loaded.
Agent Routing
agent_routing:
complexity_hint: easy
required_capability: balanced
parallel_safe: true
cost_preference: low
speed_preference: balanced
ownership_scope:
- src/SubVora.Web/src/app/features/payment-sources/**
- src/SubVora.Web/src/app/core/api/payment-sources-api.service.ts
verification:
- cd src/SubVora.Web && npx ng test --no-watch
Technical Context Snapshot
Current stack in scope
- UI: Angular (20+) standalone components with signals and built-in control flow, Angular Material (Material 3) as the only component library, SCSS. Static SPA — no SSR, no service worker.
- State: signal-backed injectable stores, one per domain area, mirroring the MAUI ViewModel split in
src/SubVora.Mobile/ViewModels one-to-one. No NgRx.
- API access: hand-written models plus one service per API controller under
src/SubVora.Web/src/app/core/api. Enums travel as JSON strings (JsonStringEnumConverter in Program.cs), so TypeScript string-literal unions are exact.
- Backend consumed unchanged: ASP.NET Core
net10.0, /api/v1/, JWT bearer in the Authorization header, tokens in JSON bodies (no cookies).
- Tests: Angular CLI unit-test builder (Vitest runner; Karma is deprecated) with
HttpTestingController. Stores, interceptors, mappers and utils only — no component-DOM or browser automation.
Dependencies in scope
- Reuse:
@angular/*, @angular/material, rxjs, and the utilities already added under src/SubVora.Web/src/app/core. No chart library, no date library, no HTTP wrapper library.
- New dependency additions allowed for this slice: no. If a dependency looks unavoidable, stop and raise it on the issue rather than adding it.
Architecture alignment
- Preserve the repo's load-bearing rules (CLAUDE.md): burn-rate maths is server-side and counts cycles, never days; currency conversion is a read-time projection and stored amounts are never overwritten; nothing advances
next_billing_date on a timer; provider matching stays one SQL query; the mobile SQLite cache stays a read-only mirror.
- There is deliberately no shared DTO project. Web models mirror the API's JSON contract by convention — a contract change means editing both sides.
create-git-issue provides routing hints only and assigns no concrete agent or model.
run-with-it remains the final runtime routing authority.
Integration touchpoints
- Consumes PUT /api/v1/payment-sources/{id} (200) and DELETE /api/v1/payment-sources/{id} (204), both 404 when not owned.
- Subscription DTOs carry paymentSourceLabel denormalised, so an update or delete requires refreshing the subscriptions list.
- Unlike category deletion, this endpoint returns no affected count — do not invent one.
Acceptance criteria
Blocked by
Parent
#196 — PRD: Angular web client for SubVora (parity minus reminders)
What to build
Maintaining payment sources: edit a label or type in place, and delete one behind a confirmation. Unlike categories, the delete endpoint reports no affected count, so subscriptions referencing a deleted source simply lose their label — the list must be refreshed rather than left showing a stale one.
Edit and delete are kept in one slice deliberately: both are a single call against the same row with no consequence semantics to separate, unlike the category slices.
Implementation Steps
update(id, label, sourceType)andremove(id)tocore/api/payment-sources-api.service.ts(200 / 204, 404 when not owned).features/payment-sources/payment-sources.component.ts, allow editing label and type in place with save and cancel, reusing the create validation.shared/confirm-dialog.component.ts, naming the source and stating that subscriptions using it will no longer show a payment source.updatereplaces the item;removedrops it on 204 and on 404 (already gone, with "Not found." reported); other failures keep the row and report the write-failure message.paymentSourceLabelcells are not stale.payment-sources.store.spec.tsadditions: update replaces exactly one item; delete removes it; a 404 removes it and reports the message; the subscriptions store refresh fires only when loaded.Agent Routing
Technical Context Snapshot
Current stack in scope
src/SubVora.Mobile/ViewModelsone-to-one. No NgRx.src/SubVora.Web/src/app/core/api. Enums travel as JSON strings (JsonStringEnumConverterinProgram.cs), so TypeScript string-literal unions are exact.net10.0,/api/v1/, JWT bearer in theAuthorizationheader, tokens in JSON bodies (no cookies).HttpTestingController. Stores, interceptors, mappers and utils only — no component-DOM or browser automation.Dependencies in scope
@angular/*,@angular/material,rxjs, and the utilities already added undersrc/SubVora.Web/src/app/core. No chart library, no date library, no HTTP wrapper library.Architecture alignment
next_billing_dateon a timer; provider matching stays one SQL query; the mobile SQLite cache stays a read-only mirror.create-git-issueprovides routing hints only and assigns no concrete agent or model.run-with-itremains the final runtime routing authority.Integration touchpoints
Acceptance criteria
Blocked by