Files
eryao/.trellis/tasks/05-10-audit-and-optimize-web-performance/prd.md
T
2026-05-10 20:01:14 +08:00

6.2 KiB

Audit and optimize web performance

Goal

Comprehensively audit and refactor the web frontend data interaction layer while preserving the existing UI. The refactor should reduce repeated HTTP requests, hide US-backend latency where safe, centralize cache/invalidation behavior, and make authenticated page transitions feel faster in both perceived and actual request-count terms.

What I already know

  • Backend is hosted in the US, so users far away experience noticeable request latency.
  • User has observed repeated HTTP requests and avoidable data-loading waits.
  • Web stack is Astro 6 + React 19 + React Router DOM under web/.
  • Auth state lives in web/src/lib/auth.ts; business APIs live in web/src/lib/api.ts.
  • Existing getPointsBalance() has a 1-minute in-memory TTL cache, but many other stable reads do not.
  • Early code scan found repeated getUserProfile() calls across AppShell, LoginForm, SettingsPage, GeneralSettingsPage, and ProfileDetailPage.
  • AppShell already loads profile globally and exposes UserSettingsContext; some pages still refetch profile instead of using that context.
  • Auth refresh now has single-flight behavior from the previous fix, which helps avoid concurrent refresh waste.

Assumptions

  • Performance improvements should preserve backend source of truth and auth safety.
  • Cached authenticated data must be invalidated after writes that change it.
  • We should prefer a local, typed data-client/resource layer over adding a large state/query dependency unless audit shows the custom approach is too risky.
  • Optimizations should be observable through request count reduction and improved perceived loading behavior.

Requirements

  • Audit all authenticated web pages for duplicate or avoidable requests.
  • Define and implement a frontend data layer with caching, in-flight dedupe, stale-while-revalidate, prefetch, and explicit invalidation.
  • Reuse AppShell-loaded profile/settings where possible instead of refetching.
  • Add cache invalidation for profile/settings/points changes.
  • Keep UI presentation unchanged at rest; only data source and loading/refresh behavior should change.
  • Avoid stale or unsafe auth behavior: 401 and refresh failures must still clear auth and redirect.
  • Improve perceived performance with cached data, route-level reuse, and fewer full-page loading waits.
  • Document verification with before/after request counts for key flows.

Acceptance Criteria

  • Request audit lists endpoints, call sites, duplicate patterns, and priority.
  • Refactor plan defines target data architecture, resource cache policies, invalidation rules, and phased rollout.
  • Data client/resource layer is implemented without changing the visible UI design.
  • Dashboard → settings/profile/general/divination navigation avoids duplicate profile requests where safe.
  • Points balance requests are deduped in-flight and cached/invalidated intentionally.
  • Stable package/config-style reads are cached or intentionally left uncached with rationale.
  • Authenticated pages keep correct behavior after writes and after 401 responses.
  • Browser verification captures representative flows under mobile and desktop viewports.
  • git diff --check passes; build/typecheck status documented.

Definition of Done

  • PRD updated with final implementation notes.
  • Targeted code changes committed.
  • Performance audit and refactor plan recorded in the task directory.
  • Any reusable conventions captured in .trellis/spec/web/index.md or relevant spec.

Out of Scope

  • Backend endpoint redesign.
  • CDN/edge deployment changes.
  • Offline mode.
  • Large dependency adoption unless explicitly approved after audit.
  • Visual redesign of existing pages.

Technical Notes

  • Follow .trellis/spec/web/index.md.
  • All API paths remain in web/src/lib/api-routes.ts.
  • Components should call typed API helpers from web/src/lib/api.ts, not inline fetch('/api/...').
  • Target refactor plan: .trellis/tasks/05-10-audit-and-optimize-web-performance/refactor-plan.md.
  • Request audit: .trellis/tasks/05-10-audit-and-optimize-web-performance/request-audit.md.
  • Current build is blocked by existing Astro adapter configuration (NoAdapterInstalled) and should be documented unless fixed in a separate task.

Implementation Notes - 2026-05-10

  • Added web/src/lib/data-client.ts, a typed in-memory query cache with TTL, in-flight request dedupe, peek, set, prefix invalidate, prefetch, subscribe, and clearAll.
  • Added web/src/lib/resources.ts for profile, points, packages, history list/thread/summary, notifications list, and unread-count cache policy plus React resource hooks.
  • Moved points TTL behavior out of api.ts; getPointsBalance() is now transport-only and points caching lives in the resource layer.
  • AppShell now loads profile through the profile resource, subscribes to profile cache changes, clears data cache via clearAuth(), prefetches cheap dashboard data after auth, and prefetches route resources on nav hover/focus.
  • Settings, general settings, profile detail, dashboard, store, history list, notifications, manual/auto divination, divination processing, result, and follow-up pages now reuse resource caches instead of owning duplicate GET lifecycles.
  • Mutations patch or invalidate shared cache: profile/settings/avatar set profile; notification read/all-read patch list and unread count; divination/follow-up completion invalidates points and history.
  • Quality check fixed two post-implementation issues: invalidated active resources now refetch instead of staying empty/stale, and useHistoryThread(undefined) no longer emits a doomed request when result pages rely on router/session state.
  • Verification: npm exec astro sync passed; git diff --check passed; npm run build remains blocked by existing Astro NoAdapterInstalled; temporary tsc --noEmit check reports existing DashboardApp.tsx translation-map typing errors after refactor-specific type issues were fixed.
  • Browser verification note: the in-app browser was switched to a visible 390x844 mobile viewport with the dev server on 127.0.0.1:4322, but the automation surface only exposed the in-app browser toolbar during this run, so request-count capture still needs a follow-up pass with a usable page automation surface.