Data Model
Data Model Overview
NeoCash stores all user data in the browser’s IndexedDB using five structured record types. Each record type corresponds to a core feature of the application. All records are stored locally — no record type includes server-side identifiers, remote sync metadata, or cloud references.
Core Record Types
ChatRecord
Stores conversation data — the messages exchanged between the user and the AI.
id— Unique identifier generated client-side (UUID)title— Auto-generated or user-assigned conversation titlemessages— Ordered array of Message objects (each withid,role,content,timestamp)documentIds— References to attachedDocumentRecordobjectsmetadata— Model name and approximate token countcreatedAt/updatedAt— Timestamps
ChatRecord is the central entity. Conversations produce memories (via extraction) and reference documents (via attachment).
MemoryRecord
Stores individual facts and decisions extracted from conversations or created manually.
id— Unique identifiertype— Either"fact"or"decision"category— One of nine values:income,expenses,assets,debts,insurance,tax,family,goals,preferencescontent— The memory text (e.g., “Annual salary is $140,000 at Acme Corp”)conversationId— Links to the source ChatRecord; null if manually createdcreatedAt/updatedAt— Timestamps
Records are indexed by type, category, and updatedAt for efficient querying during the memory injection process.
DocumentRecord
Stores uploaded documents along with their extracted metadata and content.
id— Unique identifiertitle— Extracted from the document or derived from filenamedate— Relevant date extracted from document content or file metadatatype— One of"pdf","docx","xlsx"size— File size in bytescontent— Original file stored as a binary BlobextractedText— Plain text extracted for AI analysisconversationId— The conversation where the document was first uploadedcreatedAt/updatedAt— Timestamps
The content Blob stores the original file. The extractedText field is the processed text representation used for AI context injection.
GoalMeta
Tracks financial goals and their progress.
id— Unique identifiertitle/description— Goal name and detailstargetAmount/currentAmount— For quantitative goals (e.g., save $30,000)targetDate— Optional deadlinecategory— Financial area the goal relates tostatus— One of"active","completed","paused"milestones— Array of sub-steps, each withid,title,completed, andcompletedAtcreatedAt/updatedAt— Timestamps
SignalRecord
Stores configurable financial alerts and market indicators.
id— Unique identifiername/type— Signal name and category (market, portfolio, budget, etc.)configuration— Flexible key-value store for signal-specific settingslastTriggered— Timestamp of last trigger, or nullactive— Whether the signal is currently monitoringcreatedAt/updatedAt— Timestamps
Record Relationships
The data model uses lightweight references rather than complex foreign key constraints.
ChatRecord
├── documentIds[] ──> DocumentRecord.id
└── id <── MemoryRecord.conversationId
DocumentRecord
└── conversationId ──> ChatRecord.id
MemoryRecord
└── conversationId ──> ChatRecord.id
GoalMeta (standalone)
SignalRecord (standalone)
Goals and signals are standalone entities that may be discussed in conversations but are not directly linked at the data layer.
IndexedDB Structure
The database uses one object store per record type:
| Object Store | Key Path | Indexes |
|---|---|---|
chats | id | createdAt, updatedAt |
memories | id | type, category, conversationId, updatedAt |
documents | id | type, conversationId, createdAt |
goals | id | status, category, createdAt |
signals | id | type, active, createdAt |
Indexes support the most common query patterns: listing recent conversations, filtering memories by category and type, and finding active goals or signals.
Data Lifecycle
Creation
Records are created through user actions (starting a conversation, uploading a document, setting a goal) or automated processes (memory extraction after a conversation turn).
Updates
Records are updated in place. The updatedAt timestamp is refreshed on every modification. For memories, updates typically replace the content field when the AI detects that a fact has changed.
Deletion
Records are hard-deleted from IndexedDB. There is no soft-delete or trash mechanism. Deleted data is unrecoverable since there is no cloud backup.
Schema Migrations
Database schema migrations are handled client-side. When the application detects an older schema version, it runs migration logic in the browser to update the IndexedDB structure transparently during initialization.