Problem Statement / Feature Objective
The dashboard fetches data from four distinct backend services: Soroban RPC (contract state), telemetry WebSocket (real-time readings), REST API (metadata, tariffs, user config), and spatial tile CDN (Mapbox vector tiles). Each service has different latency profiles, error semantics, and caching requirements. React Concurrent Mode's Suspense must be leveraged to coordinate these data fetching layers, showing appropriate fallback UIs (skeleton loaders, partial data displays) while deeper data streams resolve. A Suspense boundary architecture must define named boundaries per domain, with a fallback cascade: if a parent boundary's data fails, children render an error state instead of their own loading states.
Technical Invariants & Bounds
- Suspense boundaries: four primary boundaries (blockchain, telemetry, metadata, spatial). Two composite boundaries: dashboard (blockchain + telemetry) and map (metadata + spatial).
- Fallback cascade: if blockchain boundary catches an error, the dashboard boundary renders an error panel with a "Retry" button, and telemetry boundary inside it does NOT attempt to fetch (saves bandwidth).
- Timeout thresholds: blockchain Suspense timeout = 10 seconds (Soroban RPC may be slow); telemetry timeout = 3 seconds (WebSocket should be fast); metadata timeout = 5 seconds; spatial timeout = 8 seconds.
- Data freshness: Suspense resources use a stale-while-revalidate pattern: instant render with cached data while re-fetching in background. Cache TTLs: blockchain 30s, telemetry 5s, metadata 120s, spatial 300s.
- Error recovery: on boundary error, a retry button dispatches a CACHE_INVALIDATE action for that resource group, then re-mounts the Suspense boundary.
Codebase Navigation Guide
- src/utils/suspenseResource.ts - Factory for creating Suspense-compatible resources (wrapping fetch + cache + throw promise pattern).
- src/hooks/useSuspenseResource.ts - Hook that returns cached data or throws the promise for Suspense.
- src/components/boundaries/ - React components: BlockchainBoundary, TelemetryBoundary, MetadataBoundary, SpatialBoundary, DashboardBoundary, MapBoundary.
- src/store/slices/cacheSlice.ts - Manages cache TTLs, invalidation keys, and resource freshness timestamps.
- src/pages/Dashboard.tsx - Top-level page composing boundaries with proper nesting.
- src/services/soroban.ts - Must support promise-based wrapping for Suspense integration.
Implementation Blueprint
- Create src/utils/suspenseResource.ts: a factory createResource(fetchFn, cacheKey, ttlMs) that returns { read(), prefetch(), invalidate() }. read() checks cache: if cached and fresh, return data; if cached but stale, return data but trigger background re-fetch; if not cached, throw a promise. Track promise status with states: pending, resolved, rejected.
- Build the boundary components in src/components/boundaries/: each is a React.Suspense with a fallback component (SkeletonLoader for each domain). On error, use an ErrorBoundary wrapper that catches thrown errors and renders an ErrorPanel with retry button.
- Wire the cascade: DashboardBoundary wraps both BlockchainBoundary and TelemetryBoundary. If BlockchainBoundary's ErrorBoundary catches, it sets a shared context value cascadeBlocked: true. TelemetryBoundary's resource read() checks this context and skips fetching if cascadeBlocked.
- Implement the stale-while-revalidate in cacheSlice: a resource entry has { data, fetchedAt, ttlMs, isStale }. useSuspenseResource checks isStale: if true, immediately returns cached data and schedules a background fetch. The background fetch dispatches CACHE_UPDATED on completion.
- On retry action, dispatch CACHE_INVALIDATE for the domain's cache group. This sets fetchedAt to 0 for all entries in the group. Re-mount the boundary by forcing a key change (increment errorBoundaryKey).
- Write tests using React Testing Library with fake timers: render a boundary, verify fallback appears, resolve the promise, verify content appears. Test error state and retry cycle.
Problem Statement / Feature Objective
The dashboard fetches data from four distinct backend services: Soroban RPC (contract state), telemetry WebSocket (real-time readings), REST API (metadata, tariffs, user config), and spatial tile CDN (Mapbox vector tiles). Each service has different latency profiles, error semantics, and caching requirements. React Concurrent Mode's Suspense must be leveraged to coordinate these data fetching layers, showing appropriate fallback UIs (skeleton loaders, partial data displays) while deeper data streams resolve. A Suspense boundary architecture must define named boundaries per domain, with a fallback cascade: if a parent boundary's data fails, children render an error state instead of their own loading states.
Technical Invariants & Bounds
Codebase Navigation Guide
Implementation Blueprint