Files
igny8/docs/30-FRONTEND/STORES.md
IGNY8 VPS (Salman) c777e5ccb2 dos updates
2026-01-20 14:45:21 +00:00

12 KiB

Zustand State Management

Last Verified: January 20, 2026
Version: 1.8.4
Framework: Zustand 4 with persist middleware


Store Architecture

All stores in /frontend/src/store/ use Zustand with TypeScript.

Key Patterns:

  • persist middleware for localStorage persistence
  • Async actions for API calls
  • Selectors for derived state

Available Stores (11 total):

Store File Purpose
Auth authStore.ts Authentication, user session, account
Site siteStore.ts Site selection/management
Sector sectorStore.ts Sector management within sites
Planner plannerStore.ts Planner module state
Billing billingStore.ts Credits, billing info
Notification notificationStore.ts App notifications
Settings settingsStore.ts User preferences
Module moduleStore.ts Module enable/disable state
Column Visibility columnVisibilityStore.ts Table column preferences
Page Size pageSizeStore.ts Table pagination preferences
Onboarding onboardingStore.ts Onboarding wizard state

Auth Store (authStore.ts)

Purpose: User authentication and session management

interface AuthState {
  user: User | null;
  account: Account | null;
  isAuthenticated: boolean;
  accessToken: string | null;
  refreshToken: string | null;
  isLoading: boolean;
  error: string | null;
}

interface AuthActions {
  login(email: string, password: string): Promise<void>;
  logout(): void;
  register(data: RegisterData): Promise<void>;
  refreshAccessToken(): Promise<void>;
  fetchUser(): Promise<void>;
  updateUser(data: UserUpdate): Promise<void>;
}

Persistence: accessToken, refreshToken in localStorage

Usage:

const { user, login, logout, isAuthenticated } = useAuthStore();

Site Store (siteStore.ts)

Purpose: Site selection and management

interface SiteState {
  sites: Site[];
  currentSite: Site | null;
  isLoading: boolean;
  error: string | null;
}

interface SiteActions {
  fetchSites(): Promise<void>;
  createSite(data: SiteCreate): Promise<Site>;
  updateSite(id: string, data: SiteUpdate): Promise<Site>;
  deleteSite(id: string): Promise<void>;
  setCurrentSite(site: Site): void;
}

Persistence: currentSite.id in localStorage

Auto-selection: If no site selected and sites exist, auto-selects first site


Sector Store (sectorStore.ts)

Purpose: Sector selection and management within sites

interface SectorState {
  sectors: Sector[];
  currentSector: Sector | null;
  isLoading: boolean;
  error: string | null;
}

interface SectorActions {
  fetchSectors(siteId: string): Promise<void>;
  createSector(data: SectorCreate): Promise<Sector>;
  updateSector(id: string, data: SectorUpdate): Promise<Sector>;
  deleteSector(id: string): Promise<void>;
  setCurrentSector(sector: Sector): void;
}

Persistence: currentSector.id in localStorage

Dependency: Reloads when currentSite changes


Module Store (moduleStore.ts)

Purpose: Track which modules are enabled/disabled

interface ModuleState {
  modules: ModuleSettings;
  isLoading: boolean;
  error: string | null;
}

interface ModuleSettings {
  planner_enabled: boolean;
  writer_enabled: boolean;
  linker_enabled: boolean;
  optimizer_enabled: boolean;
  automation_enabled: boolean;
  integration_enabled: boolean;
  publisher_enabled: boolean;
}

interface ModuleActions {
  fetchModules(): Promise<void>;
  updateModules(settings: Partial<ModuleSettings>): Promise<void>;
  isModuleEnabled(module: ModuleName): boolean;
}

Usage:

const { isModuleEnabled } = useModuleStore();
if (isModuleEnabled('planner')) { /* show planner */ }

Currently used for: Sidebar visibility only


Billing Store (billingStore.ts)

Purpose: Credit balance and usage tracking

interface BillingState {
  balance: CreditBalance | null;
  usage: CreditUsage[];
  limits: PlanLimits | null;
  isLoading: boolean;
  error: string | null;
}

interface CreditBalance {
  ideaCredits: number;
  contentCredits: number;
  imageCredits: number;
  optimizationCredits: number;
}

interface BillingActions {
  fetchBalance(): Promise<void>;
  fetchUsage(period?: string): Promise<void>;
  fetchLimits(): Promise<void>;
}

Refresh triggers:

  • After content generation
  • After image generation
  • After optimization (when implemented)

Planner Store (plannerStore.ts)

Purpose: Keywords, clusters, and content ideas state

interface PlannerState {
  keywords: Keyword[];
  clusters: Cluster[];
  ideas: ContentIdea[];
  selectedKeywords: string[];
  filters: KeywordFilters;
  isLoading: boolean;
  error: string | null;
}

interface PlannerActions {
  fetchKeywords(siteId: string, sectorId?: string): Promise<void>;
  createKeyword(data: KeywordCreate): Promise<Keyword>;
  bulkDeleteKeywords(ids: string[]): Promise<void>;
  autoCluster(keywordIds: string[]): Promise<void>;
  generateIdeas(clusterId: string): Promise<void>;
  setFilters(filters: Partial<KeywordFilters>): void;
  selectKeywords(ids: string[]): void;
}

Writer Store (writerStore.ts)

Purpose: Tasks and content management

interface WriterState {
  tasks: Task[];
  content: Content[];
  currentContent: Content | null;
  filters: TaskFilters;
  isLoading: boolean;
  isGenerating: boolean;
  error: string | null;
}

interface WriterActions {
  fetchTasks(siteId: string, sectorId?: string): Promise<void>;
  createTask(data: TaskCreate): Promise<Task>;
  generateContent(taskId: string): Promise<Content>;
  fetchContent(contentId: string): Promise<Content>;
  updateContent(id: string, data: ContentUpdate): Promise<Content>;
  generateImages(contentId: string): Promise<void>;
  publishToWordPress(contentId: string): Promise<void>;
}

Generation state: isGenerating tracks active AI operations


Automation Store (automationStore.ts)

Purpose: Automation pipeline state and control

interface AutomationState {
  config: AutomationConfig | null;
  currentRun: AutomationRun | null;
  pipeline: PipelineOverview | null;
  history: AutomationRun[];
  logs: AutomationLog[];
  isLoading: boolean;
  error: string | null;
}

interface AutomationActions {
  fetchConfig(siteId: string): Promise<void>;
  updateConfig(data: ConfigUpdate): Promise<void>;
  startRun(siteId: string): Promise<void>;
  pauseRun(runId: string): Promise<void>;
  resumeRun(runId: string): Promise<void>;
  cancelRun(runId: string): Promise<void>;
  fetchPipeline(siteId: string): Promise<void>;
  fetchLogs(runId: string): Promise<void>;
}

Polling: Active runs trigger status polling every 5 seconds


Integration Store (integrationStore.ts)

Purpose: WordPress integration management

interface IntegrationState {
  integrations: SiteIntegration[];
  currentIntegration: SiteIntegration | null;
  syncStatus: SyncStatus | null;
  isLoading: boolean;
  isSyncing: boolean;
  error: string | null;
}

interface IntegrationActions {
  fetchIntegrations(siteId: string): Promise<void>;
  createIntegration(data: IntegrationCreate): Promise<SiteIntegration>;
  testConnection(id: string): Promise<TestResult>;
  triggerSync(id: string): Promise<void>;
  fetchSyncStatus(id: string): Promise<SyncStatus>;
}

UI Store (uiStore.ts)

Purpose: UI state (sidebar, modals, notifications)

interface UIState {
  sidebarOpen: boolean;
  sidebarCollapsed: boolean;
  theme: 'light' | 'dark' | 'system';
  notifications: Notification[];
}

interface UIActions {
  toggleSidebar(): void;
  collapseSidebar(): void;
  setTheme(theme: Theme): void;
  addNotification(notification: Notification): void;
  removeNotification(id: string): void;
}

Persistence: theme, sidebarCollapsed in localStorage


Notification Store (notificationStore.ts) - v1.2.0

Purpose: In-app notifications for AI task completions and system events

type NotificationType = 'success' | 'error' | 'warning' | 'info';
type NotificationCategory = 'ai_task' | 'system' | 'info';

interface Notification {
  id: string;
  apiId?: number;           // Server ID for synced notifications
  type: NotificationType;
  category: NotificationCategory;
  title: string;
  message: string;
  timestamp: Date;
  read: boolean;
  actionLabel?: string;
  actionHref?: string;
  metadata?: {
    taskId?: string;
    functionName?: string;
    count?: number;
    credits?: number;
  };
}

interface NotificationStore {
  notifications: Notification[];
  unreadCount: number;
  isLoading: boolean;
  lastFetched: Date | null;
  
  // Actions
  addNotification(notification: Omit<Notification, 'id' | 'timestamp' | 'read'>): void;
  markAsRead(id: string): void;
  markAllAsRead(): void;
  removeNotification(id: string): void;
  clearAll(): void;
  fetchFromAPI(): Promise<void>;
  syncWithAPI(): Promise<void>;
}

Features:

  • In-memory queue for optimistic UI updates
  • API sync for persistent notifications
  • Auto-dismissal with configurable timeout
  • Read/unread state tracking
  • Category-based filtering (ai_task, system, info)

API Integration: Uses notifications.api.ts service:

  • fetchNotifications() - List with pagination
  • fetchUnreadCount() - Unread count
  • markNotificationRead() - Mark single as read
  • markAllNotificationsRead() - Mark all as read
  • deleteNotification() - Delete notification

Usage:

const { notifications, unreadCount, addNotification, markAsRead } = useNotificationStore();

// Add AI task completion notification
addNotification({
  type: 'success',
  category: 'ai_task',
  title: 'Content Generated',
  message: 'Generated 5 articles successfully',
  metadata: { count: 5, credits: 250 }
});

Store Dependencies

authStore
    │
    └── siteStore (loads after auth)
           │
           └── sectorStore (loads when site changes)
                  │
                  ├── plannerStore (scoped to site/sector)
                  ├── writerStore (scoped to site/sector)
                  ├── automationStore (scoped to site)
                  └── integrationStore (scoped to site)

notificationStore (global, polls/syncs independently)

moduleStore (global, loads once per account)
billingStore (global, loads once per account)
onboardingStore (global, syncs with UserSettings backend)
uiStore (local only, no API)

Onboarding Store (onboardingStore.ts) (v1.3.2)

Purpose: Manages onboarding wizard and guide screen state

interface OnboardingState {
  isGuideDismissed: boolean;
  isGuideVisible: boolean;
  isLoading: boolean;
  lastSyncedAt: Date | null;
}

interface OnboardingActions {
  dismissGuide(): Promise<void>;
  showGuide(): void;
  toggleGuide(): void;
  loadFromBackend(): Promise<void>;
  syncToBackend(dismissed: boolean): Promise<void>;
}

Persistence:

  • Local: onboarding-storage in localStorage
  • Backend: UserSettings with key workflow_guide_dismissed

Features:

  • Cross-device sync via backend UserSettings
  • Rate-limited sync (max every 5 minutes)
  • Graceful fallback if backend unavailable

Usage:

const { isGuideVisible, dismissGuide, showGuide } = useOnboardingStore();

// Show onboarding wizard
if (isGuideVisible) {
  return <OnboardingWizard onDismiss={dismissGuide} />;
}

// Re-show guide button
<Button onClick={showGuide}>Show Guide</Button>

Store Files Location

frontend/src/store/
├── authStore.ts
├── siteStore.ts
├── sectorStore.ts
├── moduleStore.ts
├── billingStore.ts
├── notificationStore.ts    # v1.2.0
├── onboardingStore.ts
├── pageSizeStore.ts
├── plannerStore.ts
├── writerStore.ts
├── automationStore.ts
├── integrationStore.ts
├── uiStore.ts
└── index.ts (re-exports)

Best Practices

  1. Always scope to site/sector when fetching module data
  2. Check module enabled before showing features
  3. Handle loading states in UI components
  4. Clear store on logout to prevent data leaks
  5. Use selectors for derived/filtered data

Planned Changes

Item Description Priority
Add linkerStore State for internal linking results Medium
Add optimizerStore State for optimization results Medium
Better error typing Typed error codes per store Low
DevTools integration Zustand devtools middleware Low