S
ACTIVEFull-stack EngineerProfessionalProduction

FUMAK Inventory

Production inventory and point-of-sale system for a retail operation: a phone barcode scanner feeds a web app that manages products, stock, sales, and revenue analytics over the shop's local network.

KotlinJetpack ComposeNext.jsNeon PostgreSQLPrismaCloudflare R2

[ 01 ] · Context

Problem

  • A single-shop retail business kept inventory and revenue on paper and in memory: stock counts drifted, and nobody could say how much revenue a given period actually produced.
  • The products already carry manufacturer barcodes, so generating new labels was never the answer: the shop just had no way to read those barcodes at the counter and tie a scan to a stock count or a sale.
  • A general-purpose POS or accounting suite was the wrong size of solution: the shop needed a narrow inventory + point-of-sale companion where a phone scans while a desktop or tablet runs the shop, without adopting a full accounting system.

[ 02 ] · Response

Solution

The system is two-part, talking over the shop's local network. The Android app is a thin barcode-scanner remote: CameraX + Google ML Kit decode barcodes on-device, and the app POSTs each value to the desktop web app, which holds no database of its own.

The Next.js web app is the actual inventory, POS, and analytics application. It owns all data in a Neon PostgreSQL database (via Prisma), stores product photos in Cloudflare R2, and is where a staff member runs the shop from a browser while a phone on the counter feeds it scanned barcodes in real time.

The product catalog covers name, category, color, size/variant, buying and selling prices, stock, barcode, and photo. Every stock change (add, remove, adjust-to-counted-value, and automatic deductions from a sale) is written to a full inventory-transaction audit log with the resulting stock level snapshotted on each entry.

The POS checkout builds a multi-item cart (with per-line discounts), computes total / amount due / change live, then completes in one atomic database transaction: sale header + line items inserted, stock decremented, and a SALE inventory transaction logged per item. Dashboard KPIs and period-filtered revenue analytics (Today / Month / 3M / 6M / Year / custom) aggregate over the same ledger.

[ 03 ] · My work

My contribution

  • I designed and built the system end-to-end as the sole developer: the Android scanner remote (CameraX + ML Kit on-device decoding, saved desktop connection profiles, LAN heartbeat) and the Next.js web app (Prisma schema, inventory audit log, atomic POS checkout, dashboard and revenue analytics).
  • I owned the LAN integration contract between the two apps: the /api/scanner/events short-polling feed that turns a phone scan into a live product lookup at the counter, including the connected/disconnected heartbeat state shown in the POS.
  • I defined the data model (products, inventory transactions, sales, sale items, settings) with money stored as integer poisha, and the checkout/analytics logic over it.

[ 04 ] · Structure

Architecture

┌──────────────────────────┐      LAN Wi-Fi (HTTP POST)      ┌─────────────────────────────────┐
│ Scanner Remote (Android) │  /api/scanner/events              │  Web App (Next.js 16)            │
│  CameraX + ML Kit        │ ────────────────────▶  { type:   │  In-memory scan queue            │
│  on-device barcode decode│     "scan", barcode, format }   │  /sales live scan feed → cart →  │
│  connection profiles     │    + periodic heartbeat          │  checkout                        │
│  (name, IP, port)        │                                   │  Prisma ORM                      │
└──────────────────────────┘                                   │       │                          │
                                                               │       ▼                          │
                                                               │  Neon PostgreSQL                 │
                                                               │  (products, inventory txns,      │
                                                               │   sales, sale items, settings)   │
                                                               │  Cloudflare R2 (product photos)  │
                                                               └─────────────────────────────────┘

[ 05 ] · Trade-offs

Key engineering decisions

  1. 01

    Data lives in the web app, not the phone

    The scanner is deliberately stateless: it only decodes a barcode and POSTs it to the desktop's LAN IP and port. All business logic, validation, and persistence live in the Next.js API routes, so the phone never touches the database or object storage directly.

  2. 02

    Stock is an audit ledger, not a number

    Every stock-affecting event (ADD, REMOVE, ADJUST, or the automatic SALE deduction) is an InventoryTransaction row with the resulting stock level snapshotted on each entry, so the current count is provable from history rather than a mutable field.

  3. 03

    Atomic checkout

    Completing a sale inserts the header and line items, decrements stock, and logs the SALE inventory transactions in a single database transaction. Prices are snapshotted at sale time, so historical gross-profit figures stay correct even after a product's prices later change.

  4. 04

    Integer poisha, never floats

    Monetary fields are stored as integer poisha (1/100 BDT) rather than floating point, so summing sales can never drift into rounding error.

  5. 05

    Soft-delete products only

    Products are archived, never hard-deleted, so historical sales stay intact and the ledger remains fully reconcilable.

[ 06 ] · Under the hood

Engineering highlights

The LAN scan contract
// Android scanner → desktop web app, one fire-and-forget POST:
POST http://<desktop-ip>:<port>/api/scanner/events
  { type: "scan", barcode: "1234567890123", format: "EAN_13" }
  { type: "heartbeat" }   // keeps the POS "Connected" badge alive

// /sales page short-polls GET /api/scanner/events?since=<id>
// and resolves each arriving barcode against the product catalog.
Decoding is on-device (ML Kit) and needs no network; only the decoded value is sent onward, so the scan feed works entirely over the shop's LAN.
One transaction per sale
Checkout, in a single DB transaction:
  insert Sale        (header: total, paid, due, change, payment type)
  insert SaleItem ×N (selling price / buying cost / discount snapshotted)
  decrement Product.stock ×N
  insert InventoryTransaction(SALE, signed delta, resulting stock) ×N

receipt.invoiceNumber = `INV-${year}-${saleId}`
A sale and its inventory effect can never diverge: the commit that writes the sale also deducts stock and logs the ledger entries.
Scan-to-sale pipeline
Phone Camera
   │
   ▼
CameraX (image analysis stream)
   │
   ▼
Google ML Kit Barcode Scanning (on-device decode)
   │
   ▼
BarcodeSender ── POST /api/scanner/events ──▶ /sales live scan panel
   │
   ▼
Product Lookup ── not found ──▶ Register New Product
   │ found
   ▼
Add to Cart ──▶ qty / discount ──▶ Checkout ──▶ Dashboard + Analytics
One continuous path from a physical barcode to a recorded sale and its revenue figures.

[ 07 ] · Outcomes

Results

2
apps: Android scanner + web
8
barcode formats (EAN/UPC/CODE/QR)
5
Prisma data models
4
stock event types
5
areas: dashboard, products, inventory, POS, analytics
LAN
phone ↔ desktop pairing

[ 08 ] · Where it's going

Status & next steps

  • Authentication and user roles (currently any device on the LAN can operate the app).
  • An automated test suite; verification is currently manual and on-device.
  • Supplier management and partial-payment / credit (debtor) tracking.
  • Remote (non-LAN) scanner pairing and multi-shop / multi-location support.

[ 09 ] · Keep exploring

More projects

InvoicePilot: AI-powered invoice processing platform that extracts, validates, and analyzes invoices while detecting duplicates and anomalies to streamline financial document workflows.
ProfessionalProduction
Featured

AI-powered invoice processing platform that extracts, validates, and analyzes invoices while detecting duplicates and anomalies to streamline financial document workflows.

FastAPIPythonMindee OCRPostgreSQLRedis StreamsCloudflare R2
Back to all projects