Skip to content

web: honest offline and write-failure messaging across all stores #231

Description

@rghvgrv

Parent

#196 — PRD: Angular web client for SubVora (parity minus reminders)

What to build

A consistency pass over every store so network failures tell the truth. The web client has no offline story by design — no service worker, no local mirror, no write queue — which makes the wording load-bearing: a failed save must say the change was not saved, or the user walks away believing it landed. Reads may keep showing what is already on screen; writes may not pretend.

Implementation Steps

  1. Audit — go through every store (dashboard, subscriptions list, subscription detail, categories, payment sources, settings) and confirm reads use toDisplayMessage while every create/update/delete/mark-paid path uses toWriteFailureMessage.
  2. Disable writes when offline — expose an isOnline signal (from navigator.onLine plus the online/offline events) and disable submit and destructive actions while offline, with a banner explaining why — mirroring the mobile client's behaviour rather than letting the user fill a form that cannot be sent.
  3. Keep reads visible — make sure a failed refresh never blanks a populated screen; the previous data stays with an error banner above it.
  4. One reporting path — route every store's message through the shared Notifier/banner rather than per-screen ad hoc snackbars, so wording cannot drift.
  5. Spec — a spec per store asserting the write path produces the write-failure wording on a status-0 error, and that a failed reload leaves previously loaded data in place.

Agent Routing

agent_routing:
  complexity_hint: medium
  required_capability: balanced
  parallel_safe: false
  cost_preference: balanced
  speed_preference: balanced
  ownership_scope:
    - src/SubVora.Web/src/app/features/**
    - src/SubVora.Web/src/app/core/api/api-error.ts
    - src/SubVora.Web/src/app/layout/shell.component.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

  • Touches every store built so far; no endpoint or contract changes.
  • Architectural rule: there are no offline writes anywhere in SubVora - no outbox, no replay, no conflict resolution (decision Offline writes are discarded — no outbox, no replay on reconnect #144). Do not add one here.
  • Wording is ported from the mobile ApiErrorMapper so the two clients say the same thing in the same situation.

Acceptance criteria

  • Every write path states that a failed change was not saved; no message implies queuing or later sync.
  • Write actions are disabled with an explanation while the browser reports itself offline.
  • A failed refresh leaves previously loaded data on screen with an error banner rather than blanking it.

Blocked by

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestready-for-agentReady for autonomous agent execution

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions