Guide for creating and modifying Zustand stores with IndexedDB persistence in the DEVS platform. Use this when asked to create a new store, modify store logic, or work with state management.
When creating or modifying Zustand stores in the DEVS platform, follow these patterns and best practices.
Stores are located in src/stores/. Each store manages a specific domain entity.
import { create } from 'zustand'
import { db } from '@/lib/db'
import { toast } from '@/lib/toast'
// 1. Define the store state interface
interface EntityState {
entities: Entity[]
isLoading: boolean
error: string | null
}
// 2. Define the store actions interface
interface EntityActions {
loadEntities: () => Promise<void>
createEntity: (data: CreateEntityInput) => Promise<Entity>
updateEntity: (id: string, updates: Partial<Entity>) => Promise<void>
deleteEntity: (id: string) => Promise<void>
getEntityById: (id: string) => Entity | undefined
}
// 3. Create the store with both state and actions
export const useEntityStore = create<EntityState & EntityActions>(
(set, get) => ({
// Initial state
entities: [],
isLoading: false,
error: null,
// Actions
loadEntities: async () => {
set({ isLoading: true, error: null })
try {
const entities = await db.entities.toArray()
set({ entities, isLoading: false })
} catch (error) {
set({ error: (error as Error).message, isLoading: false })
toast.error('Failed to load entities')
}
},
createEntity: async (data) => {
const entity: Entity = {
id: crypto.randomUUID(),
...data,
createdAt: new Date(),
updatedAt: new Date(),
}
await db.entities.add(entity)
set((state) => ({ entities: [...state.entities, entity] }))
return entity
},
updateEntity: async (id, updates) => {
const updatedData = { ...updates, updatedAt: new Date() }
await db.entities.update(id, updatedData)
set((state) => ({
entities: state.entities.map((e) =>
e.id === id ? { ...e, ...updatedData } : e,
),
}))
},
deleteEntity: async (id) => {
await db.entities.delete(id)
set((state) => ({
entities: state.entities.filter((e) => e.id !== id),
}))
},
getEntityById: (id) => {
return get().entities.find((e) => e.id === id)
},
}),
)
// 4. Export standalone functions for non-React contexts
export const getEntityById = (id: string) =>
useEntityStore.getState().getEntityById(id)
export const createEntity = (data: CreateEntityInput) =>
useEntityStore.getState().createEntity(data)
export const updateEntity = (id: string, updates: Partial<Entity>) =>
useEntityStore.getState().updateEntity(id, updates)
export const deleteEntity = (id: string) =>
useEntityStore.getState().deleteEntity(id)
Export standalone functions: Always export functions directly for use in non-React contexts (lib/, orchestrator, etc.)
// ✅ Correct - use exported functions in lib code
import { getAgentById, createAgent } from '@/stores/agentStore'
// ❌ Wrong - don't use hooks in lib code
const { getAgentById } = useAgentStore()
Database initialization: Always check db.isInitialized() before operations if the store loads at app startup
Optimistic updates: Update local state immediately, then persist to IndexedDB
Error handling: Use try/catch with toast notifications for user feedback
Timestamps: Always update updatedAt when modifying entities
All store changes MUST follow TDD:
src/test/stores/{storeName}.test.tsnpm run test:coverage before committingExample test structure:
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { useEntityStore } from '@/stores/entityStore'
describe('entityStore', () => {
beforeEach(() => {
useEntityStore.setState({ entities: [], isLoading: false, error: null })
})
describe('createEntity', () => {
it('should create entity with correct structure', async () => {
const result = await useEntityStore
.getState()
.createEntity({ name: 'Test' })
expect(result).toHaveProperty('id')
expect(result.name).toBe('Test')
})
})
})
agentStore - AI agent management with slug generationtaskStore - Task lifecycle and requirement validationconversationStore - Multi-agent chat historyartifactStore - Task deliverablescontextStore - Inter-agent context sharinguserStore - User preferences and settingsagentMemoryStore - Agent learning and memory