FRQN®

Work / Spotlight Furnishings, Srinagar

Spotlight Furnishings

A carpet and home furnishings shop in Srinagar, sold cash on delivery and run entirely from the owner's phone. Small enough that nobody would ever notice a bug, which is exactly why the money and the stock are the parts built hardest.

Sole engineer2026Visit live site ↗
Amounts stored as decimals
0
Functions allowed to move stock
2
How passwords are stored
argon2id
Engineer
1
Spotlight Furnishings storefront and the phone-sized owner admin panel
Spotlight Furnishings · as shipped

01 / The problem

A family carpet business does not need a commerce platform. It needs a shop that loads on a slow connection, an admin panel that fits a phone, and numbers that are never wrong, because the stock on the shelf is the only thing anybody can actually check against.

Cash on delivery also takes away the safety net a card payment gives you. Nothing gets reconciled later. If the site sells the last carpet twice, somebody drives to a customer's house to apologise.

02 / What I built

Next.js serves the shop and the owner's panel from one codebase, over Supabase Postgres. Money is stored in whole paise and never as a decimal, so no total is ever a rounding artefact. Sessions live in the database instead of in a signed cookie, which is the difference between logging a device out and hoping it expires.

Every read on the shop side goes through a wrapper that returns something sensible when the query fails. If the database is down the shop still loads, with the phone number and the WhatsApp link on it. Somebody who can ring you is not a lost customer.

03 / Deep dive

Every number can be explained

Stock that can be changed from several places turns into a number nobody trusts. Here exactly two functions may move it, and both write a line in a ledger inside the same transaction as the change. The question is never whether the count is right, it is which movement made it that.

Selling the same item twice is closed off in the database rather than by a check beforehand. Checkout reduces the count only where there is enough left, and if that changes no rows, the whole order is abandoned. Two people buying the last carpet in the same second cannot both win. A constraint refuses a negative count as a second line of defence, coupons are claimed under the same kind of guard, and a status change takes a lock on the row and re-checks itself while holding it.

  • Conditional decrement inside a transaction, zero rows aborts the order
  • Every movement carries a reason, and nothing deletes the ledger
  • Status transitions re-checked under SELECT ... FOR UPDATE
CHECKOUTids and quantitiesTRANSACTIONone, for all of itDECREMENTwhere qty >= orderedCOMMITorder and ledger rowZERO ROWSthe order abortsSTOCK WAS THEREIT WAS NOTTWO PEOPLE BUYING THE LAST CARPET: ONE ORDER, ONE APOLOGY AVOIDEDPRICES ARE RECOMPUTED SERVER-SIDE, THE BROWSER IS ONLY ASKED WHAT IT WANTS
Fig 01 · Conditional decrement in one transaction

04 / Deep dive

The admin panel assumes somebody is trying

One account protects the whole business, on a public address, with nobody watching it. So every guard is written to survive being moved, forgotten, or called from somewhere nobody expected.

Passwords are hashed with argon2id at the settings OWASP recommends. A session is 32 random bytes and only its hash is kept, so a copy of the database hands over nothing usable. Every admin page checks for itself instead of trusting the layout above it, because pages and layouts can render at the same time and an inherited guard disappears the day somebody moves a file. Every server action checks on its first line too, since an action is a public address whether or not a button points at it. A wrong email and a wrong password give the same answer, and a fake check still runs for an account that does not exist, so the time it takes gives nothing away.

  • Sessions in the database, so a device can actually be revoked
  • Login limited per IP address and per email at the same time
  • First-run owner setup serialised behind a Postgres advisory lock
LOGINrate limited twiceARGON2ID19 MiB, 2 passesSESSION ROWsha-256 of 32 bytesPAGE AND ACTIONeach checks for itselfLOOKED UP PER REQUESTUNKNOWN EMAIL STILL RUNS A DUMMY VERIFY, SO TIMING SAYS NOTHINGLOGGING A DEVICE OUT DELETES A ROW, IT DOES NOT HOPE A TOKEN EXPIRESA LAYOUT GUARD IS NOT INHERITED, SO EVERY PAGE REPEATS THE CHECK
Fig 02 · Sessions that can actually be revoked

05 / Outcomes

  • The owner runs the catalogue, the stock, the orders and the coupons from a phone
  • Selling the same last item twice is impossible, not just unlikely
  • If the database goes down the shop still loads and can still be phoned
  • Public database roles are revoked by a script that is re-run after every change

Stack

Frontend
Next.js 16, React 19, TypeScript, server components
Data
Supabase Postgres, Drizzle, whole paise, an inventory ledger
Security
argon2id, hashed sessions in the database, checked input, CSP and HSTS
Ops
Cloudinary, Sentry, a database hardening script, self-tests

Next case study

KOKOMATA