Spaces:
Running
Search History System
Overview
MiniSearch keeps a local-first record of every search so agents can resurface text results, image results, and generated responses without hitting remote services again. All persistence lives inside the browser via Dexie/IndexedDB and is never synced to external servers, preserving the privacy posture of the app.
Data Model and Storage
The HistoryDatabase Dexie instance stores three related tables:
searchesβ canonical log of each query plus hydrated results payloads (text, image, run metadata, source, pin state).llmResponsesβ snapshot of every AI answer tied to its originating search run, enabling restoration of the assistant output.chatHistoryβ chronological record of chat turns (user/assistant roles) scoped byconversationId(thesearchRunId).
All three tables share a searchRunId foreign key so restoring a specific run can bring back the search results, saved AI response, and chat transcript atomically. @client/modules/history.ts#86-409
Cleanup Guarantees
To keep IndexedDB lean, inserts trigger performCleanup(), which enforces:
- Retention window β non-pinned entries older than
historyRetentionDaysare deleted in batches of 100. - Max entries β if the total exceeds
historyMaxEntries, the oldest unpinned rows past the limit are removed. - Pin protection β pinned entries are skipped by both retention and max-entry sweeps.
Cleanup is gated by historyAutoCleanup, so advanced users can opt out. These knobs come from the settings store and can be updated at runtime. @client/modules/history.ts#148-201 @client/modules/settings.ts#44-48
Hook API
useSearchHistory exposes the canonical API surface for components:
- Fetches recent searches (optionally paginated) and exposes filtered/grouped views.
- Provides fuzzy search, pin toggling, delete/clear operations, and error retry helpers.
- Keeps derived state such as grouped sections (Today/Yesterday/etc.) in sync with the settings flag
historyGroupByDate. - Refreshes itself on an interval so the History UI stays live even if other tabs mutate the DB.
Because the hook writes via Dexie directly, any component can call addSearchToHistory to persist new runs immediately after text or image searches resolve. @client/hooks/useSearchHistory.ts
UI Surfaces
- History Drawer β wraps the hook data in a drawer with filtering, pin/delete affordances, grouped stacks, and an Analytics tab powered by
SearchStatsin compact mode. The drawer guards against disabled history settings and mirrors the hook filtered list in real time. @client/components/Search/History/HistoryDrawer.tsx#35-315 - History Button β lazy-loads the drawer and logs open/close events for observability. @client/components/Search/History/HistoryButton.tsx#18-56
- History Restore β recreates full search state (query string, search results, AI response, and chat transcript) when a user replays an entry. @client/hooks/useHistoryRestore.ts#32-105
Settings Surface
HistorySettings wires Mantine form controls to the settings pub/sub so users can toggle history, adjust retention/max entries, and clear all rows (with confirmation + toast feedback). It relies on the same hook to know when the table is empty before enabling destructive actions. @client/components/Settings/HistorySettings.tsx#24-152
Analytics Integration
The History Drawer Analytics tab renders the compact SearchStats cards scoped to period="all", giving total searches, daily averages, and most active hours pulled from the same IndexedDB data. Keeping analytics co-located ensures the metrics share the hook filtering and cleanup guarantees.
Related Topics
- Overview:
docs/overview.md- System architecture and data flow - UI Components:
docs/ui-components.md- History drawer and components - Conversation Memory:
docs/conversation-memory.md- Chat persistence - Configuration:
docs/configuration.md- History settings