Back to Projects
WebSaaSFull-Stack

Barcodum — Market & Greengrocer POS

Live Preview

Tech Stack

Next.jsTypeScriptSupabasePostgreSQLRow Level SecurityTailwind CSS v4shadcn/uiRechartsJsBarcodeVercel

Overview

Barcodum is a production POS (point-of-sale) web app built for the daily flow of Turkish markets and greengrocers. A cashier scans a barcode, the item drops into the cart, and the sale is collected in one keystroke — cash (F1), card (F2), or store credit (F3). Everything a small shop needs lives on one screen: barcoded checkout, optional stock tracking, a store-credit (veresiye) ledger, weighed products, USD/EUR rate snapshots, 80mm thermal receipts, and barcode label printing.

Built on Next.js App Router with server components, Supabase (Postgres + Auth), and a Turkish UI. Access is split into admin and cashier roles enforced with Postgres Row Level Security — the first user to sign up becomes admin via an auth trigger. Sales, stock decrements, and credit debt are written atomically inside a single Postgres function (create_sale), so a receipt can never be half-recorded. Barcode labels (EAN-13 / EAN-8 / Code128, auto-detected) are generated client-side with JsBarcode and printed through a hidden iframe sized for a Zebra GC420t thermal printer, kept fully separate from the receipt print styles. Deployed on Vercel.

Challenges

  • Keeping a sale, its line items, stock decrements, and any store-credit debt perfectly consistent — a receipt must never be half-recorded
  • Enforcing admin vs cashier access safely on the server so a cashier can never reach reports or settings
  • Printing 80mm thermal receipts and 40×25–60×40mm barcode labels from the same app without the two print styles colliding
  • Making the cashier flow fast enough to keep up with a barcode scanner that types like a keyboard

Solutions

  • Wrapped the whole checkout in an atomic Postgres function (create_sale) that writes the sale, items, stock movements, and veresiye debt in one transaction, snapshotting the live USD/EUR rate onto the sale
  • Modeled roles in the database and enforced them with Postgres RLS via an is_admin() check, with an auth trigger auto-promoting the first user to admin
  • Isolated label printing in a hidden iframe with its own @page size so it never clashes with the 80mm receipt @media print block
  • Added a global keydown capture on the POS screen that refocuses the barcode field, plus F-key shortcuts for cash, card, and store-credit payment
1