Status: Accepted Date: 2026-02-06 Deciders: Reflections Maintainers
Context
The web app needs predictable data fetching/caching, lightweight local UI state, and realtime awareness of ingestion/pipeline updates without over-complicating architecture.Decision
Adopt a layered frontend state model:- Next.js App Router for route/layout composition.
- TanStack React Query for server-state fetching, caching, and invalidation.
- Zustand for UI/session-local state slices.
- Supabase Realtime broadcast subscription for pipeline status updates, mapped to targeted React Query invalidations.
Alternatives considered
Alternative 1: React context + custom fetch cache only
Pros:- Fewer external dependencies.
- Reinvents stale/cache/invalidation semantics.
- More bespoke code and consistency risk.
Alternative 2: Global Redux-only state for everything
Pros:- Single state container.
- Higher boilerplate for server-state workflows.
- Less natural fit for request lifecycle caching.
Alternative 3: Polling-only for pipeline updates
Pros:- Simpler than realtime subscriptions.
- Slower UI freshness or higher API load.
- Inferior user feedback during ingestion lifecycle changes.
Consequences
Benefits:- Clear split between server state and UI-local state.
- Efficient invalidation-based updates for pipeline events.
- Familiar patterns for frontend developers.
- Multiple state technologies to maintain and document.
- Realtime dependency requires client env and connection health handling.
Implementation notes
- Query client initialization is in the providers layer.
- Zustand stores handle UI-local state like voice sessions, sidebar, and graph visualization.
- Realtime subscription and cache invalidation are implemented in a dedicated hook that maps pipeline events to React Query invalidations.
- Supabase realtime client lifecycle is encapsulated in a dedicated module.

