Inside LiKAR: Distributed Database Design & Cold Storage Architecture
How LiKAR isolates every shop in its own database, keeps a lean master control plane, and tiers ever-growing sales data into cold storage so the live database never bloats.
A liquor ERP looks simple from the counter — scan, bill, print. Underneath, it has to keep every shop’s data completely isolated, stay fast as transaction history piles up year after year, and do it on infrastructure that doesn’t cost more than the shop earns. This is how LiKAR is architected to hit all three at once.
One database per shop, plus a thin control plane
LiKAR is multi-tenant, but it does not pool every shop’s rows into one shared set of tables. Instead it uses a database-per-tenant model:
- The master database (control plane). A small, central database that knows about shops without holding their operational data. It stores platform users, the list of shops, who owns or is a member of each shop, activation keys, and a shared master price/barcode catalogue. It never holds a single sale.
- One shop database per shop (data plane). Every shop gets its own isolated Postgres database — its own products, stock, purchases, sales, ledgers and reports. Shop A physically cannot read Shop B’s rows, because they don’t live in the same database.
When a user logs in, the master database resolves which shop they’re allowed to open and hands back a connection to that shop’s database for the rest of the session. The credential is resolved server-side and never travels to the browser.
The problem: sales data grows forever
Most tables in a shop database are bounded. The product catalogue, categories, parties and stock levels change but don’t endlessly grow. Exactly one thing grows without limit: sales(and its line items). A busy shop can write thousands of sale-item rows a day. On a free-tier database capped at 500 MB, that clock is always ticking — and the irony is that 99% of that data is historical and rarely read.
Deleting old sales isn’t acceptable — they’re legal records. So the answer is to tier the data: keep what’s hot live, and move the rest somewhere cheap but still retrievable.
The cold storage architecture
LiKAR splits sales history into three tiers:
| Tier | Where it lives | What it holds | Grows? |
|---|---|---|---|
| Hot | Shop database | Current + recent quarters of raw sales | Bounded (rolling window) |
| Warm | Shop database | One tiny summary row per month — totals, payment mix, top products | Linear, negligible |
| Cold | Object storage (Vercel Blob) | Full original sale rows as compressed JSON, one file per quarter | Cheap, unbounded |
The dashboard, charts and day-to-day reports only ever read the hot and warm tiers, so they stay fast no matter how many years of history exist. The cold tier is touched only when someone explicitly opens an archived period.
How the quarterly archive runs
A scheduled job runs per shop. For each quarter old enough to be safe (the current and previous quarter always stay hot so rolling 14- and 30-day windows never lose data), it:
- Rolls up the quarter into the monthly summary table — so the stats survive permanently.
- Serialises the raw sales and line items to newline-delimited JSON and gzips it (roughly 10× smaller).
- Uploads the file to object storage at a per-shop, per-quarter path, then verifies it landed intact by checking its size and checksum.
- Records the file in a manifest table (period, row count, byte size, checksum, location).
- Only then deletes the raw rows from the live database.
Reading it back
Browsing archived data is driven by the manifest, which is tiny and lives in the shop database. A listing call reads only the manifest — no object storage hit at all. When a user opens a specific quarter, the server fetches that one compressed file, decompresses it, and returns a single page of results. The object-storage URL stays server-side and is always scoped to the authenticated shop, so one tenant can never read another’s archive.
Why object storage instead of another database
Cold sales data is written once and read rarely. Paying a database to hold it is the wrong shape — you want cheap, durable bytes with occasional reads. Object storage (Vercel Blob in LiKAR’s case) bills a few cents per gigabyte-month, and at quarterly-archive volumes the cost is effectively zero while the live database stays comfortably under its cap.
The takeaway
Distributed, database-per-shop isolation gives every shop a private, independently scalable home. Three-tier cold storage keeps the one table that grows forever from ever filling that home — without losing a single record and without the dashboard ever slowing down. It’s the kind of architecture that’s invisible when it works, which is exactly the point.
Run your liquor shop on LiKAR
AI billing, barcode POS, inventory and multi-state excise compliance — built for Indian liquor retail.
View the live demo