Case study · Coffee Shop Ordering & POS
Lore
An ordering, payment and point-of-sale app for Lore Coffee Station in Jaro, Iloilo. Customers customize drinks, order ahead and pay online, while the cashier rings up walk-ins, confirms payments and moves orders through a live kitchen display.
- Role
- Full-stack Developer
- Year
- 2026
- Type
- Web app
- Status
- Ongoing
Ongoing project. It runs locally while I finish it, so there's no live site yet.
01 — overview
Lore Coffee Station is a coffee shop and mobile espresso bar in Jaro, Iloilo that I like a lot, so I built them a full ordering system. Customers browse the menu, pick the size, milk and sweetness of each drink, then order for dine-in, takeout or a scheduled pickup and pay online. Behind the counter, the cashier rings up walk-ins, confirms QR and bank payments, and moves orders from new to preparing to ready, while the customer's page and a "Now serving" board update on their own.
02 — the problem
Lore takes orders at the counter and through Instagram and Facebook messages, and payments come in through cash, QR, cards and bank transfers. Customers can't see what's ready or how long it will take, and the counter has no single place to see every order and payment.
03 — goals
- Let customers order ahead and pay with the methods Lore already accepts
- Show each order's status live to the customer and the staff
- Give the cashier a fast register for walk-ins, discounts and receipts
- Keep the site looking like Lore, using their own photos and branding
04 — approach
The React app and an Express API share one set of TypeScript types and pricing rules, so the price a customer sees is computed the same way the server charges it. The server recalculates every total, discount and fee on its own and never trusts amounts sent from the browser. Socket.IO pushes order changes to three kinds of listeners: staff screens, the customer's own order page and the counter board, each getting only the data it should see. Orders and the menu live in SQLite through Node's built-in driver, so the app runs with nothing else to install.
05 — stack
- ReactCustomer pages and the staff screens
- TypeScriptTypes and pricing rules shared by the app and the server
- ViteDevelopment server and production build
- Tailwind CSSStyling built around Lore's colors and branding
- ExpressREST API for the menu, orders, payments, reports and promos
- Socket.IOLive order status, kitchen display and queue board
- SQLiteMenu, orders, loyalty points and event inquiries, using Node's built-in driver
- ZustandCart and register state
06 — key features
Drink customization
Hot or iced, 12 or 16 oz, fresh or oat milk, five sweetness levels and add-ons like an extra shot, priced as you choose.
Order ahead
Dine in, takeout or pick a 15-minute pickup slot. While the shop is closed, only scheduled pickup is offered.
Payments
QR Ph (GCash, Maya), card, bank transfer or cash at the counter, with Lore's posted 1% QR and 3% card fees added automatically.
Promo codes and Lore Points
Percent or peso-off codes with a minimum spend, plus points earned per ₱50 and redeemed as pesos off.
Live order tracking
Received, preparing, ready and done, updating on the customer's phone without a refresh.
Cashier register
Walk-in orders with quick cash buttons and change, Senior Citizen and PWD discount, open tabs and printable thermal receipts.
Kitchen display and queue board
Columns for new, preparing and ready orders, a warning after 15 minutes, and a "Now serving" screen with a chime.
Manager tools
Sold-out toggles, menu and price editing, promo codes, event inquiries and a daily sales report by hour, payment method and item.
07 — challenges & solutions
Keeping prices honest
- Problem
- If the browser sent the total, anyone could change it before placing an order.
- Solution
- The browser only sends item IDs and chosen options. The server looks up every price, discount and fee itself, and the checkout shows a quote from the same code before the customer pays.
Payments Lore checks by hand
- Problem
- QR and bank transfers don't confirm themselves, but the cashier needs to know which orders are actually paid.
- Solution
- Customers submit the reference number from their receipt, the order shows as payment pending, and the cashier confirms it was received or rejects it in one tap. The order can't be completed until it's paid.
Live updates without leaking data
- Problem
- Broadcasting every order to every browser would expose customers' names and numbers.
- Solution
- Staff join a channel with their session token, each customer only follows their own order through a random ID, and the public board only receives order numbers.
08 — outcomes
- The full flow works end to end: order, pay, confirm, prepare, ready and complete, with live updates at every step.
- Separate customer, staff and counter-board views that all work on phones and computers.
- Uses Lore's own menu, photos, hours and payment fees.
09 — what I learned
- Sharing types and pricing code between the app and the server removes a whole class of mismatch bugs
- Realtime features need clear rules about who is allowed to hear what
- Designing around a real brand is harder, and more fun, than starting from a template
10 — what I'd improve next
- Connect a real card and QR payment provider
- Deploy it and test it with the Lore team at the counter