One till, many sellers: a market POS that splits every sale by stall

Client
A community market in Thailand (client kept anonymous)
Sector
Retail — point of sale
Period
June–July 2026

At a glance

A point-of-sale system for a physical market where dozens of independent sellers share the same tills. A cashier rings up one basket; the system knows which stall every item belongs to, splits the sale per seller at the moment it happens, and keeps the books each stall settles against. Thai-first interface with a synchronized English translation set, built on Laravel 12 with a Filament v4 admin panel and PostgreSQL underneath.

Every amount is integer satang — a float never touches money
Append-only audit log: till actions are written once, never edited or deleted
Thai-first UI with a synchronized English translation set
Laravel 12 · Filament v4 · PostgreSQL · 19 migrations · PHPUnit suite

The challenge

A shared-till market breaks the assumption almost every off-the-shelf POS makes: that the shop is one business. Here a single basket routinely holds goods from three or four different sellers, and at the end of the month each of them needs to be paid exactly what their stall sold — no more accounting spreadsheet, no arguing with the till roll.

Money software also has two classic self-inflicted wounds waiting: floating-point prices that drift by a satang, and editable transaction tables where a typo "fix" quietly rewrites history. Both had to be impossible by construction, not by discipline.

The solution

A Laravel 12 application with the day-to-day sale screen kept deliberately simple — product grid, basket, charge — and a Filament v4 back office for products, sellers, shifts and reports. Every sale line carries its seller, so per-stall settlement is not a report bolted on top but a property of the data model itself.

Money is stored exclusively as integer satang (฿290 is the integer 29000); no float ever touches an amount. And every till action lands in an append-only audit log — rows are written once and can be neither updated nor deleted, so the history the settlement is based on is the history that actually happened. The interface is Thai-first, with the English translation set kept in lockstep by a sync command rather than by memory.

The results

The system is live and in daily use at the client's market (a private deployment, so it is not linked here). Cashiers work one shared basket per customer regardless of how many stalls it spans, and per-seller settlement falls straight out of the ledger instead of out of an end-of-month spreadsheet session.

The build runs on the same delivery model as the rest of this page: phased Trello cards worked by an AI agent under review, 19 database migrations and a PHPUnit suite grown alongside the features, and the production database covered by the server's nightly dump-and-backup routine from day one.

Review Greg on Google

Greg Nowak Google Reviews

 

Written recommendations from Trafik og Veje, Aarhus Municipality (2011) and AgroTech (2010) — read them on LinkedIn.