Today we built the data foundation for Accelerate Finance. Not features—primitives. The atoms that will compose into every use case we haven't imagined yet.
Why Dexie?
We chose Dexie.js as our local database layer. It's a wrapper around IndexedDB that gives us:
- Reactive queries — liveQuery() returns observables that update when data changes
- Schema versioning — Built-in migrations for evolving data models
- Compound indexes — Complex queries without performance penalty
- Transactions — ACID guarantees for data integrity
The Six Primitives
After much deliberation, we settled on six core primitives. Each is designed to be minimal but complete:
1. Workspace
The container for everything else. One workspace = one financial context (personal, business, project).
2. Account
Bank accounts, credit cards, cash, investments. Where money lives.
3. Transaction
Income, expenses, transfers. The atomic unit of financial activity.
4. Category
Classification for transactions. Hierarchical (parent/child) for flexibility.
5. Rule
Automation primitives. Auto-categorize, split, rename transactions based on conditions.
6. View
Saved perspectives on data. Filters, sorts, columns. Future: shareable via links.
Design Decisions
Soft Delete Everywhere
Every entity has a deletedAt tombstone. Nothing is truly deleted—it's marked. This enables future sync, undo, and audit trails.
Amounts in Cents
All monetary values stored as integers (cents/smallest unit). No floating-point precision issues. $100.50 = 10050.
Metadata Bags
Every entity has a typed metadata object for extensibility. AI can reason over this. Future features can add fields without migrations.
Repository Pattern
Clean abstraction over Dexie. Components never touch the database directly. Makes testing easy, makes swapping storage possible.
The Repository Layer
Each primitive gets a repository with consistent methods:
create(data) → entity getById(id) → entity | undefined getByWorkspace(workspaceId) → entity[] liveByWorkspace(workspaceId) → Observable update(id, changes) → void delete(id) → void // soft delete
What We Built Today
- Schema module — TypeScript interfaces for all six primitives
- Database module — Dexie setup with indexes and versioning
- Repository layer — CRUD + live queries for each entity
- Demo seeding — Sample workspace with accounts, categories, and transactions
- /app route — Workspace creation and ledger view
The Philosophy
We resist the urge to build features. Features are compositions of primitives. If we get the primitives right, features emerge naturally.
Budgeting? Categories with budget metadata + transaction filtering.
Reports? Views with date filters + aggregation.
Automation? Rules matching transactions to actions.
Sharing? Views that serialize to shareable links.
Primitives before features. Always.
With the data layer in place, we can now build anything. The foundation is solid. Tomorrow we'll work on making the ledger view actually useful.
— The Accelerate Finance Team