Download CV

Cerbiol Gadgets point of sale

A point of sale and inventory system the shop runs on every day, with per-device IMEI tracking, part payments, invoices, debt follow-up and an audit log.

When
Live in production
Context
Cerbiol International Co Ltd, a phone and gadget retailer in Nigeria
Role
Solo build
  • Next.js 16
  • React 19
  • TypeScript
  • Supabase
  • PostgreSQL
  • Row-level security
  • Tailwind CSS v4
  • Vercel

The problem

The shop tracked stock, part payments and debts on paper. Devices are individually identifiable by IMEI, so quantity-based inventory could not say which handset was sold to whom, and no record showed who changed what.

The point of sale dashboard, with customer names, invoice numbers and amounts blurred
Dashboard. Customer names, invoice numbers and amounts are blurred.
The point of sale sign-in screen

What the shop uses it for

  • Devices are tracked one by one by IMEI or serial number; accessories are tracked by quantity.
  • A sale takes full or part payment in cash, transfer or card, and records which business account a transfer landed in.
  • Every sale produces a printable invoice, numbered INV-YYYYMMDD-####, carrying its payment history and outstanding balance.
  • Outstanding debts are tracked with follow-up payments against the original invoice.
  • Staff accounts get a temporary password and a forced change on first login, and can be deactivated and reactivated.

How the money is protected

  • Money is only ever written through two PostgreSQL functions, process_sale and record_payment. Each one locks the rows it touches and updates stock, totals, payments and the audit log in a single transaction, so a half-finished sale cannot exist.
  • Both functions run SECURITY DEFINER with their own checks: only an active, signed-in user can call them, and the seller recorded is always the signed-in user, never a value sent by the browser.
  • Supabase row-level security backs the functions, and the service-role key never leaves the server.
  • An audit log records who did what, which is what makes a discount or a price change answerable.

How it ships

  • Database changes go out as dated migrations, and each function is backed up before it is replaced, so a rollback is one file.
  • Production deploys run from main through Vercel preview builds on every pull request, and merges happen after shop hours.

The result

  • The shop runs its daily trading on it: sales, part payments, debts and staff accounts.
  • Every money-moving action is transactional, attributable and reversible by record.

Private client repository. The screenshots are redacted.

Hire meCV