Portfolio / System Ops / floural

The recipe lives in the system,
not in the owner's head.

Floural is a small bakery and cake studio that grew faster than its workflow. The owner was the recipe book, the trainer, the late-staff judge and the shelf-life monitor — all at once. We built her a POS that absorbed every one of those jobs, plus a few she didn't know she wanted, so a brand-new baker could run a shift solo on day one.

ClientFloural Bakery
ScopePOS · Production · Inventory · Staff
Onboarding2 weeks → 1 shift
ChannelsDine-in · GoFood · ShopeeFood · Pre-order
Year2026
The owner's pains

Six things that lived in her head — and shouldn't have.

Every one of these failed in the same way: the bakery worked when the owner was on the floor, and stalled when she wasn't. The brief was simple — get them out of her head and into a system the staff already trusts.

Pain 01

The recipe lived in three places. None of them agreed.

WhatsApp pictures, a battered notebook, and the owner's memory. Every new baker meant re-teaching the same chiffon from scratch — and getting it slightly wrong each time.

"I was the recipe book. If I was at a wedding-cake delivery, the bakery stopped baking."
Pain 02

Stuff sat on the shelf. Nobody knew when it got there.

Staff would shrug and say "looks fresh." Customers eventually didn't. One bad cream pull took out a Saturday's reviews.

Pain 03

Components are batched. Tracking them as "stock" loses the batch.

Sponge, mango cream, ganache — made in batches with their own expiry. The old POS counted them as a single number. A 6-day cream got pulled before a 2-day one. FIFO was a vibe.

Pain 04

A new cashier needed two weeks of shadowing.

The POS was a spreadsheet wearing a hat. Categories weren't colour-coded, items had no short codes, the screen had no rhythm. New hires learned by mistake — at the customer's expense.

Pain 05

Bonus calc was a vibe. Late staff got argued about every month.

Owner remembered who was late. Sometimes. Bonuses turned into negotiations. Fairness was perceived, not measured.

"Some months I felt like the bad guy. Other months I felt like a pushover."
Pain 06

GoFood, ShopeeFood, dine-in, pre-orders — four ledgers, no roll-up.

End of day was four reconciliations done by hand. P&L per channel was a rumour, not a number.

● Pain 01

Production starts with the recipe. Not a question to the owner.

Every product is built from components (sponge, cream, ganache) which are built from ingredients. The owner's recipes live in the database — one for each component, one for each finished product — and a production task is just "pick a component, hit start."

The system shows the baker the exact quantities for the chosen batch size, deducts ingredients on completion at weighted-average HPP, and writes a new component batch with its production date and expiry. The recipe is the source of truth. The owner is no longer the bottleneck.

"First week the new baker ran a full shift without messaging me once. I cried a little, in a good way." — Owner, Floural
floural / production / start batch
Baker · Tika
Mango Cream component · 3 day life
TARGET BATCH 2,000 g
Whipping cream 1,200 g in stock
Mango purée 600 g in stock
Caster sugar 160 g in stock
Lemon juice 40 g in stock
On complete → deducts ingredients at avg HPP, writes batch MC-260422-A, expiry 25 Apr 2026 21:00, location Chiller 2.
● Pain 02

Green, yellow, red. The shelf tells you, not your nose.

Each finished product on display has its own shelf-life threshold (cakes ≠ pastries ≠ bread). When a unit is moved to the shelf, the clock starts. The display shows a coloured bar ticking from green to yellow to red — staff and the owner see the same picture from anywhere in the room.

Hit red? The unit goes into the waste log with a categorised reason — never just "discarded" — so the owner can see whether it's overproduction, mishandling, or contamination across the month.

floural / shelf / live
14:32
Cheesecake Slice CH · on shelf 2h ago ● Fresh · 22h left
Mango Tart MT · on shelf since 09:14 ▲ Sell soon · 4h left
Choco Chiffon CC · on shelf since yesterday ■ Pull & log waste
Croissant CR · on shelf 1h ago ● Fresh · 7h left
● Pain 03

Every batch has an ID. The system pulls the oldest one first.

When a baker assembles a finished cake, the POS doesn't ask "is there cream?" — it picks the cream batch with the soonest expiry that still has enough left, deducts from it, and snapshots which batch the cake came from on the order line.

If the assembling baker overrides FIFO (rare, sometimes legitimate) it gets logged with a reason. Spoilage of an entire batch lands in the waste table at HPP, not at retail — owner sees the real cost.

floural / components / mango cream batches
FIFO · auto
BatchMadeExpiresLeftLocStatus
MC-260420-B 20 Apr 06:30 23 Apr 06:30 340 g Chiller 1 PULL NEXT
MC-260421-A 21 Apr 14:10 24 Apr 14:10 1,820 g Chiller 2 QUEUED
MC-260422-A 22 Apr 09:05 25 Apr 09:05 2,000 g Chiller 2 QUEUED
● Pain 04

The POS designed so a new cashier ships day one.

Every product has a 2–4 letter short code, a category colour, and a fixed grid position the owner pins. New cashiers learn the layout in an hour because the layout doesn't change. Search is by short code or by name — fast for regulars, forgiving for trainees.

Checkout is one screen: items, customer (optional, with loyalty points), payment method (cash, QRIS, transfer, GoFood, ShopeeFood, DP), done. Cash drawer auto-opens on cash; tendered + change calculated; receipt prints; order ID is the date + sequence.

floural / pos / order #260422-014
Cashier · day 1
Cake Cheesecake
Slice
CH 38k
Cake Mango Tart
MT 42k
Cake Choco
Chiffon
CC 35k
Pastry Croissant
CR 22k
Pastry Pain au
Chocolat
PC 26k
Drinkz Iced Latte
IL 28k
Onboarding script · day 1: "Tap colour. Tap item. Tap pay. Tap cash. Done." Five taps, every order. New hires take orders in the first hour.
● Pain 05

Every late minute is a number. Every bonus has an audit trail.

Staff check in by selfie at the start of their shift (Pagi 07:00, Siang 15:00, Malam 21:00). The system reads the timestamp, applies the configured grace (5 min), and converts every minute over into "late points" at the rate the owner sets — 1 point per 5 late minutes, Rp 3,000 per point.

End of month, bonus = base − (late points × penalty). The owner approves once. Disputes drop to zero because the math is on the screen, with photos.

floural / attendance / april 22
shift · Pagi
RT
Rina Tania
cashier · pagi · 07:00
06:58 ON TIME
DH
Dimas Hartono
baker · pagi · 07:00
07:13 LATE 8m · 1 pt
TK
Tika Kurnia
baker · pagi · 07:00
06:51 ON TIME
BONUS · DIMAS H · APR BASE 500k 4 pt × 3k = 488k
● Pain 06 + show-off

Four sales channels, one ledger. Plus the things she didn't ask for.

Every channel — dine-in, takeaway, GoFood, ShopeeFood, pre-order with downpayment — books into the same orders table with a channel tag. End-of-day reconciliation is one screen, not four. P&L per channel is a filter, not a project.

And the show-off layer: customer loyalty points (1 per Rp 1,000 spent, expiring per the owner's rule), categorised waste log with estimated Rp loss, packaging stock that auto-decrements per sale, and a system-wide audit log so any number on any screen can be traced back to a person and a moment.

floural / day close · 22 apr
1 ledger · 4 channels
Dine-in
42
Rp 1.84m
GoFood
31
Rp 1.22m
ShopeeFood
18
Rp 0.71m
Pre-order
07
Rp 2.95m
▸ Waste log · today Rp 84k
Mango Tart · 2 pcs kadaluarsa Rp 38k
Whipping cream · 220 g terkontaminasi Rp 28k
Croissant · 1 pc jatuh Rp 18k
How we built it

Six weeks. Modelled on her actual workflow, not a generic POS.

We didn't fork a POS. We sat in the bakery for the first three days and watched. The data model — three tiers, batches, FIFO, shelf life — was on whiteboard before any code shipped.

01

Week 1 — Watch and write recipes down

Sat in the bakery. Wrote every recipe — for sponge, cream, ganache, every product — into structured component & product schemas. The data model became the recipe book.

02

Week 2 — Three-tier inventory

Built ingredientscomponentsproductsshelf_items with batch tables for components and shelf instances. Weighted-avg HPP on every receive and every production task.

03

Week 3 — Production + shelf life

Production task screen with the recipe-as-checklist. Shelf-life thresholds per product (green/yellow/red hours) wired to live colour bars. Waste log with categorised reasons.

04

Week 4 — Onboarding-first POS

Tile grid with short codes, channel-tagged orders, single-screen checkout, downpayment + remaining flow for pre-orders. Cashier trained in 90 minutes from a 1-page script.

05

Week 5 — Staff & finance loop

Selfie attendance, late-points config, monthly bonus draft → approve flow. Cash drawer with opening / sales / payouts / closing reconciliation. Audit log on every mutation.

06

Week 6 — Two new bakers, live

Hired two fresh bakers as the trial. Both ran a full shift solo by end of week — recipes from the screen, FIFO from the screen, shelf calls from the screen. Owner stayed home a Saturday.

What's working now

Six things the owner doesn't carry in her head anymore.

No fabricated month-over-month deltas — the system is in early ops. These are the workflows that have moved off the owner's shoulders and into the screen.

1

Source of truth for recipes

Every recipe in the database, versioned. New bakers read the screen, not the owner.

90m

Cashier onboarding

Tile grid + short codes + one-screen checkout. New hire takes real orders inside the first hour.

3

Tiers of inventory, FIFO-honest

Ingredients → components → products. Component batches pulled oldest-first, automatic.

G/Y/R

Shelf life, visible

Every shelf unit has a live colour bar. "Looks fresh?" is replaced with "is it green?"

0

Bonus arguments

Late minutes → late points → Rp deduction. Photos and timestamps. Owner approves once.

4

Channels, one ledger

Dine-in, GoFood, ShopeeFood, pre-order all book into the same orders table. Day-close is one screen.

The stack

Built to be owned, hosted, and edited by the operator.

▸ Frontend

Vanilla JS PWA

Installable on the staff Android tablet. No framework — every screen is a single JS module the owner's nephew (a CS student) can read. Service worker keeps the POS alive when wi-fi blinks.

PWA · ES modules · service worker · printer.js
▸ Backend

PHP + MySQL · one file per domain

Action-based routing (?action=), raw PDO, JWT. 25-table schema covers settings, users, products/components/ingredients with recipes, batches, shelf, attendance, bonuses, packaging, waste, audit.

PHP · MySQL · PDO · JWT · transactional integrity
▸ Inventory model

Three-tier with batches

Ingredients (raw) → components (semi-finished, batched, expiry-tracked) → products (finished, recipe-bound) → shelf items (timestamped on display). Weighted-avg HPP threaded through every layer.

component_recipes · product_components · shelf_items · waste_records
▸ Ops loop

Attendance, bonus, cash drawer, audit

Selfie check-in with shift detection, configurable grace + penalty, monthly bonus drafts. Cash drawer per day with opening / sales / payouts / closing. Every mutation in audit log keyed to user + IP.

attendance · bonuses · cash_drawer · daily_reconciliation · audit_log
Back to → All projects

Your bakery, kitchen
or studio still in your head?

Free scope-out call. We'll tell you what's worth building and what isn't.