State Management

chevron-rightRelevant source fileshashtag

Purpose and Scope

This document describes the frontend state management architecture in Automatos AI, covering the hybrid approach using React Query for server state, Zustand for client state, and React Context for global configuration. For backend API structure, see API Router Organization. For real-time updates via WebSocket/SSE, see Real-Time Updates.

Sources: frontend/package.json:43,70,138


State Management Architecture

The frontend employs a three-layer state management strategy to handle different types of application state:

Architecture Diagram: State Management Layers

spinner

Sources: frontend/components/chatbot/chat.tsx:1-100, frontend/package.json:43,70,138


Server State Management (React Query)

React Query (@tanstack/react-query) manages all server-side data fetching, caching, and synchronization. The query client is configured at the application root via QueryClientProvider.

Query Client Configuration

The query client is provided at the top level of the application in the provider hierarchy:

Key characteristics:

  • Automatic background refetching with 60-second stale time

  • Workspace-scoped cache keys for multi-tenant isolation

  • Request deduplication

  • Optimistic updates for mutations

  • Admin workspace override support

Sources: frontend/hooks/use-unified-analytics.ts:1-10

Workspace-Scoped Caching

All queries include workspace context in their cache keys to prevent data leakage between workspaces. The wsScope() function provides this scoping:

Cache key structure:

  • First element: Feature namespace (e.g., 'unified-analytics')

  • Second element: Workspace scope (e.g., 'own', '__all__', or specific workspace ID)

  • Remaining elements: Resource type and parameters

This ensures that when an admin switches workspaces, the cache correctly refetches data for the new workspace context.

Sources: frontend/hooks/use-unified-analytics.ts:12-38, frontend/lib/api-client.ts:83-91

Admin Workspace Override

The system supports admin users viewing analytics for specific workspaces or all workspaces via a module-level override:

Admin workspace switcher pattern frontend/components/analytics/admin-workspace-switcher.tsx:14-35:

  1. Admin selects workspace from dropdown

  2. Calls setAdminWorkspaceOverride(workspaceId) or setAdminWorkspaceOverride('__all__')

  3. Invalidates all analytics queries: queryClient.invalidateQueries({ queryKey: ['unified-analytics'] })

  4. Queries refetch with new workspace context

  5. Override is cleared on component unmount

The '__all__' sentinel value instructs backend endpoints to skip workspace filtering and return platform-wide data.

Sources: frontend/lib/api-client.ts:83-91, frontend/components/analytics/admin-workspace-switcher.tsx:1-48

Query Patterns

Server state is accessed through custom hooks that wrap React Query. Analytics hooks follow a consistent pattern:

Hook
Return Type
Cache Key
Stale Time

useAnalyticsOverview(days)

Overview stats

['unified-analytics', wsScope(), 'overview', days]

60s

useAgentAnalytics(days)

Agent stats + memory

['unified-analytics', wsScope(), 'agents', days]

60s

useWorkflowAnalytics(days)

Workflow + recipe stats

['unified-analytics', wsScope(), 'workflows', days]

60s

useCostAnalyticsUnified(days)

Cost breakdown

['unified-analytics', wsScope(), 'costs', days]

60s

useModelComparison(ids, period)

Model comparison

['unified-analytics', wsScope(), 'llm', 'comparison', ids, period]

60s

useAdminDashboard(period)

Platform-wide stats

['unified-analytics', wsScope(), 'admin', 'dashboard', period]

60s

Sources: frontend/hooks/use-unified-analytics.ts:18-38,41-91,105-237

Query Implementation Pattern

Unified analytics queries use a safe request wrapper to prevent cascading failures:

This pattern:

  • Wraps each API call in safeRequest() to isolate failures

  • Falls back to sensible defaults if endpoints fail

  • Aggregates data from multiple backend endpoints

  • Uses workspace-scoped cache keys

Sources: frontend/hooks/use-unified-analytics.ts:41-91

Cache Invalidation

Mutations invalidate related queries using query key prefixes:

Common invalidation patterns:

  • Specific query: invalidateQueries({ queryKey: ['unified-analytics', wsScope(), 'agents', 30] })

  • Feature namespace: invalidateQueries({ queryKey: ['unified-analytics'] })

  • Prefix match: invalidateQueries({ queryKey: ['unified-analytics', 'costs'] })

Sources: frontend/hooks/use-unified-analytics.ts:624-640, frontend/components/analytics/admin-workspace-switcher.tsx:28-35


Client State Management (Zustand)

Zustand manages transient UI state that doesn't need server persistence. The primary store is useWorkspaceStore, which manages the widget architecture.

Workspace Store Architecture

Store location: frontend/stores/workspace-store.ts (inferred from usage)

spinner

Sources: frontend/components/chatbot/chat.tsx:20,53-56, frontend/components/workspace/Canvas.tsx:10-14

Widget State Structure

The workspace store maintains widget state as shown in usage patterns:

Widget State Properties (from frontend/components/chatbot/chat.tsx:53-56):

  • widgetIds: string[] - Ordered list of widget IDs

  • widgets: Record<string, Widget> - Widget data by ID

  • activeWidgetId: string | null - Currently selected widget

  • isWidgetTrayOpen: boolean - Tray visibility state

Widget Actions (from frontend/components/chatbot/chat.tsx:54-55,59-63):

  • addWidget(widgetData) - Create new widget

  • removeWidget(id) - Delete widget

  • updateWidget(id, updates) - Modify widget data

  • setActiveWidget(id) - Switch active widget

  • clearWidgets() - Remove all widgets

  • toggleWidgetTray() - Show/hide widget tray

Widget Creation Example

From the Chat component's tool-data handler (frontend/components/chatbot/chat.tsx:108-149):

Sources: frontend/components/chatbot/chat.tsx:108-149


Context Providers

React Context provides global configuration and authentication state throughout the application.

Provider Hierarchy

The provider tree structure:

spinner

Sources: frontend/middleware.ts:1-18

Authentication Context (Clerk)

Provider: ClerkProvider from @clerk/nextjs

Provides authentication state and user information. The API client uses Clerk tokens for backend authentication:

API client integration frontend/lib/api-client.ts:98-163:

Token is automatically injected into all backend requests as Authorization: Bearer <token> header.

Middleware integration frontend/middleware.ts:1-18:

  • Route protection via clerkMiddleware

  • Public routes: /sign-in, /sign-up, /sso-callback, /api/webhooks

  • Protected routes require authentication

Sources: frontend/middleware.ts:1-18, frontend/lib/api-client.ts:98-163

Workspace Context

Provider: WorkspaceProvider

Provides current workspace information:

  • Workspace ID

  • Workspace name

  • Member role

  • Workspace settings

The workspace ID is sent to the backend via the X-Workspace-ID header in all API requests. The backend's get_request_context_hybrid() dependency resolves this header to create the RequestContext:

All database queries are scoped to workspace_id unless admin_all_workspaces=True (set when admin uses X-Workspace-ID: __all__ header).

Sources: orchestrator/core/auth/dependencies.py:29-42, orchestrator/core/auth/hybrid.py:1-40

Theme Context

Provider: ThemeProvider from next-themes

Manages dark/light mode preferences:

  • Persisted to localStorage

  • System preference detection

  • CSS variable updates

Sources: frontend/package.json:106


State Synchronization Patterns

The system coordinates state between server, client, and UI layers using several patterns.

State Flow Diagram

spinner

Sources: frontend/components/chatbot/chat.tsx:98-149

Real-Time Updates

The system uses Server-Sent Events (SSE) for streaming updates from the backend:

Event types (from frontend/components/chatbot/chat.tsx:103-300):

  • text-delta - Streaming text content

  • tool-data - Tool execution results

  • data-usage - Token usage updates

  • routing-decision - Agent routing information

Handler pattern:

Sources: frontend/components/chatbot/chat.tsx:98-300

Cache Invalidation Events

React Query cache is invalidated on specific events:

Event
Invalidated Queries
Trigger

Agent created

['agents']

Mutation success

Recipe executed

['recipes', recipeId], ['executions']

Execution complete

Plugin installed

['marketplace'], ['workspace-plugins']

Installation success

Chat deleted

['chats']

Delete mutation

Sources: Architecture diagrams


Usage Patterns and Examples

Pattern 1: Widget Management in Chat

The Chat component demonstrates coordinated state management (frontend/components/chatbot/chat.tsx:52-64,108-212):

Sources: frontend/components/chatbot/chat.tsx:52-212

Pattern 2: Canvas Widget Display

The Canvas component reads from the workspace store (frontend/components/workspace/Canvas.tsx:38-61):

Sources: frontend/components/workspace/Canvas.tsx:38-61

Pattern 3: Server State with Authentication

Components use React Query with Clerk authentication context (frontend/components/chatbot/chat-widget.tsx:118-233):

Sources: frontend/components/chatbot/chat-widget.tsx:118-233

Pattern 4: Tool Suggestions with Analytics

Dynamic tool suggestions combine server state and analytics tracking (frontend/components/chatbot/chat.tsx:410-462):

Sources: frontend/components/chatbot/chat.tsx:410-462, frontend/lib/analytics.ts:1-26


State Persistence

Local Storage

Certain UI preferences are persisted to browser localStorage:

Key
Data
Managed By

theme

'dark' | 'light' | 'system'

ThemeProvider

clerk_*

Authentication tokens

ClerkProvider

Widget preferences

Canvas layout

(Future enhancement)

Session Storage

Ephemeral session data:

  • Active chat ID

  • Draft messages

  • Temporary widget state

Server-Side Persistence

Server state persisted via PostgreSQL:

  • User profiles

  • Agents and configurations

  • Workflow recipes

  • Chat history

  • Marketplace items

Sources: Architecture diagrams


API Client Architecture

The apiClient singleton handles all HTTP communication with the backend, including authentication, workspace headers, and mock data support.

API Client Structure

spinner

Sources: frontend/lib/api-client.ts:93-300

Request Header Assembly

Every request includes workspace and authentication headers:

Header flow:

  • Authorization: Bearer <jwt> → Backend validates with Clerk JWKS

  • X-Workspace-ID: <uuid> → Backend filters data to specific workspace

  • X-Workspace-ID: __all__ → Backend skips workspace filter (admin only)

Sources: frontend/lib/api-client.ts:93-300, orchestrator/core/auth/hybrid.py:20-70

Mock Data System

The API client includes a development-only mock system that falls back to mock data when real APIs fail:

Page-level mock configuration frontend/lib/api-client.ts:55-78:

Components set their page context using:

Sources: frontend/lib/api-client.ts:55-300

Base URL Configuration

The API client resolves the backend URL from multiple sources:

Priority order:

  1. Runtime injection via window.__NEXT_PUBLIC_API_URL__

  2. Build-time environment variable NEXT_PUBLIC_API_URL

  3. Runtime fallback

  4. Empty string (relative URLs)

Sources: frontend/lib/api-client.ts:101-117


State Management Code Symbols

Key Imports

Sources: frontend/hooks/use-unified-analytics.ts:1-10, frontend/lib/api-client.ts:1-100

Store Selectors

Zustand store selectors follow this pattern:

Sources: frontend/components/chatbot/chat.tsx:53-56, frontend/components/workspace/Canvas.tsx:38-42


Performance Considerations

React Query Optimizations

Analytics queries use consistent stale time configuration:

Optimizations:

  • Stale time: 60 seconds for analytics queries, prevents excessive refetching

  • Workspace-scoped keys: Cache isolated per workspace, no cross-tenant pollution

  • Request deduplication: Multiple components requesting same data share single request

  • Parallel requests: Promise.all() with safeRequest() wrapper for fault tolerance

Sources: frontend/hooks/use-unified-analytics.ts:41-91

Safe Request Pattern

The safeRequest() wrapper isolates API failures to prevent cascading errors:

If any endpoint fails, the query returns partial data instead of failing completely.

Sources: frontend/hooks/use-unified-analytics.ts:48-59

Zustand Optimizations

  • Selector-based subscriptions: Components only re-render when selected state changes

  • Immer integration: Immutable state updates with mutable syntax

  • No provider overhead: Direct store access without context

Widget State Optimization

Widget data is stored as a map (Record<string, Widget>) for O(1) lookups:

Sources: frontend/components/workspace/Canvas.tsx:38-49

Admin Dashboard Optimization

The admin analytics page uses period-based queries with selective invalidation:

The wsScope() in cache keys ensures that switching workspaces invalidates only the relevant queries, not the entire cache.

Sources: frontend/components/analytics/analytics-admin.tsx:165-296


Debugging State

React Query Devtools

Enable React Query Devtools in development:

Zustand Devtools

Zustand stores can integrate with Redux DevTools:

State Inspection

Browser console commands:

Sources: frontend/package.json:43,138


Last updated