Skip to main content
The app stores everything in a single SQLite database accessed through Prisma. The schema is privacy-first by construction: no customer names, emails, or addresses exist in any table. Shopper identity is an anonymous, client-generated session UUID.

Tables at a glance

Identity and events Commerce Configuration Operations

Logical relations

The schema declares no database-level foreign keys. Every cross-table link is a string id, and most tables use composite natural keys scoped by shop (for example shop + product id + session id). Store isolation is enforced by every query filtering on the shop column, which is regression-tested.

SQLite specifics that matter to maintainers

  • DateTimes are epoch-millisecond integers. Prisma stores SQLite datetimes as integer milliseconds, and the metrics code relies on it: time buckets are computed with integer division, and raw MAX() results are converted back to dates explicitly.
  • Money is BigInt cents. Order totals, refunds, prices, and rollup revenue are stored as integer cents and surface as JavaScript BigInt.
  • Raw SQL uses tagged templates only ($queryRaw), never string concatenation.
  • SQLite serializes writes, not reads. The view-dedupe check-then-insert is wrapped in a per-key in-process promise chain to close the race; this is one of the single-instance assumptions documented in Security.
  • Dev and production databases are separate files (dev.sqlite locally, /data/prod.sqlite on the deployment volume). Integration tests share the dev database and therefore run sequentially.

Data lifecycle

Deletion matrix

Prune and deletion jobs run inside the scheduler — see Background jobs. The retention window is merchant-configurable under Settings.