← All work

Work 01 / 05

Central Plafon

Online store, ERP console, and offline point-of-sale for an interior-materials business — one API, one monorepo.

Role
Founder & engineer
Year
2026
Stack
NestJS, Next.js, React, PostgreSQL, Electron
Website
centralplafon.com ↗

Context

Central Plafon sells interior materials — PVC ceilings, wall panels, PVC marble, vinyl flooring, light-steel frames — and installs them. It serves two kinds of customer: retail buyers, and contractors who buy in bulk on credit.

A business like this usually lives in three disconnected places: an online catalog, a warehouse spreadsheet, and the till in the shop. I wanted one source of truth for all of it.

What I built

One monorepo (Turborepo + Bun) with one API and three apps:

shopNext.js consoleReact + TanStack kasirElectron + PouchDB core-apiNestJS + Drizzle ORM PostgreSQL+ pgvector Redis sync
Three apps, one API. Dashed line: kasir stores sales locally and syncs when online.

Decisions that mattered

Money is always an integer. Prices are stored in the currency's smallest unit, never as floats, so an invoice total is never off by a rupiah.

/** Money is stored as an integer minor unit (whole rupiah for IDR). */
export interface Money {
  amount: number;
  currency: CurrencyCode;
}

The till never turns a customer away. Offline sales go into a local queue and sync when the connection returns. If a sync would push stock below zero, the order isn't dropped — it's flagged for a person to review.

Search that understands intent. Every product has an embedding (pgvector), so a search for "moisture-proof bathroom ceiling" still finds the right product even when the words differ.