IndexedDB Schema
IndexedDB is a low-level, client-side browser database designed for storing large amounts of structured data, including files and blobs. It enables high-performance searches through indexed objects, operates asynchronously to prevent blocking the UI, and is crucial for creating offline-capable Progressive Web Apps (PWAs).
External Schema Dependencies
Before we can discuss the IndexedDB model in the client application, first we need to examine the application's external data dependency.
This document assumes that a backend API will provide the client application with some form of user object after the user has been authenticated and it will provide data about the user and what entities the account is entitled to see and with what permissions.
For example, a user API could provide the client application an object like:
{
"id": "dccjvzhrmc28o3ojgrf6j5km",
"name": "Bob Bidnasonah",
"email": "bob@bobshotdogs.com",
"entities": [
{
"id": "pqyanhnj8o9m6t9m75hrlh7j",
"name": "Bob's Burgers LLC",
"baseCurrency": "USD",
"ein": "36-4201234",
"taxType": "Form 1065",
"role": "owner"
}
]
}
A backend model that supports this example user JSON could be defined as:
| Table | Key Fields |
|---|---|
| User | id (CUID2), email (Varchar), name (Varchar) |
| User Entities | userId (CUID2), entityId (CUID2), role (owner, admin, cpa, audit, etc.) |
| Entity | id (CUID2), name (Varchar) |
IndexedDB Object Stores
entities
Stores entities the user is able to edit or view.
Store Definition
{
"name": "entities",
"id": { "keyPath": "id", "autoIncrement": false },
"indices": [
{ "name": "name", "keyPath": "name", "options": { "unique": false } }
]
}
Model
interface Entity {
id: string;
name: string;
ein?: string;
address?: Address;
phone?: string;
baseCurrency?: Currency;
taxType?: TaxType;
createdAt: number;
createdBy: string;
updatedAt?: number;
updatedBy?: string;
}
Example
{
"id": "pqyanhnj8o9m6t9m75hrlh7j",
"name": "Bob's Burgers LLC",
"role": "owner",
"baseCurrency": "USD",
"ein": "36-4201234",
"taxType": "Form 1065"
}
accounts
Stores accounts for each entity that can be built into a hierarchical chart of accounts tree.
Accounts with an entityId of "template" are used to create charts of accounts for new entities.
Store Definition
{
"name": "accounts",
"id": { "keyPath": "id", "autoIncrement": false },
"indices": [
{ "name": "entityId", "keyPath": "entityId", "options": { "unique": false } }
]
}
Model
interface Account {
id: string;
entityId: string;
code: string;
name: string;
parent?: string;
offset?: string;
normalBalance?: string;
balance?: number;
closed?: boolean;
sort: number;
description?: string;
taxCode?: string;
is1099?: boolean;
currencyCode?: Currency;
department?: string;
color?: string;
createdAt: number;
createdBy: string;
updatedAt?: number;
updatedBy?: string;
}
Example
{
"id": "dmkjvzhrmc28o3ojgrf6j4km",
"code": "1110",
"name": "Checking Account",
"createdBy": "jim@jimsaccounting.com",
"createdAt": 1773660314820,
"entityId": "dccjvzhrmc28o3ojgrf6j5km",
"parent": "1100"
}
Note that createdBy and updatedBy fields use the email address. If a user ID was used instead, an additional round trip to look up the user display name would be required.
journal-entries
Stores journal entries for the entity.
Store Definition
{
"name": "journal-entries",
"id": { "keyPath": "id", "autoIncrement": false },
"indices": [
{ "name": "entityId", "keyPath": "entityId", "options": { "unique": false } },
{ "name": "date", "keyPath": "date", "options": { "unique": false } },
{ "name": "accounts", "keyPath": "accounts", "options": { "unique": false, "multiEntry": true } }
]
}
Model
interface JournalEntry {
id: string;
date: string;
reference?: string;
memo?: string;
status: JournalEntryStatus;
accounts: string[];
balance?: number | undefined | null;
deposit?: number | undefined | null;
payment?: number | undefined | null;
lines: JournalEntryLine[];
byAccounts: string[];
createdAt: string;
updatedAt: string;
createdBy?: string;
voidedAt?: string;
voidedBy?: string;
voidReason?: string;
}
Example
{
"id": "cld4d5e6f7g8h9i0j1k2l3m4",
"date": "2026-03-04",
"reference": "CHK-2026-0102",
"memo": "Payroll - biweekly",
"status": "posted",
"accounts": ["1110", "6110", "6120"],
"lines": [
{
"id": "l007",
"accountCode": "6110",
"description": "Wages & salaries",
"type": "debit",
"amount": 4200
},
{
"id": "l008",
"accountCode": "6120",
"description": "Employer payroll tax",
"type": "debit",
"amount": 321.3
},
{
"id": "l009",
"accountCode": "1110",
"description": "Paid from checking",
"type": "credit",
"amount": 4521.3
}
],
"createdAt": "1740920400000",
"createdBy": "bob@bobshotdogs.com",
"payment": 4521.3,
"balance": 1878.7
}