e-Tempahan: replacing scattered food orders with a real system
A government agency in Sabah was managing meal orders for meetings and events through chat messages and paper. No tracking, no approvals, no records. We built a structured ordering system instead.
Admin portal: statistics, approvals, and the active booking queue.
The problem
Food orders arrived through WhatsApp messages, phone calls, and handwritten notes. Three things broke as a result:
- No single record. When a department asked what was ordered for a meeting three weeks ago, someone had to scroll through chat history.
- No approval step. Anyone could request anything. Budget limits were enforced by memory, not by the system.
- No accountability. If an order was wrong or duplicated, there was no way to trace who approved it or when.
What we built
A public booking form for staff, paired with an admin portal for the officers who handle approvals and suppliers.
Public side
- Booking form with department, pax count, date, time, session, and menu selection
- Server side validation on every field, including rejection of past dates and malformed time values
- Copyable reference number so staff can quote it in follow-up messages
- Live status page so staff can check progress without messaging anyone
Admin side
- Approval queue with approve, reject, and delivered states
- Menu and supplier management, with prices held server side only
- Live timeline showing every state change with the officer who made it
- Audit trail logging every action
- Monthly and per month reporting, including spend, pax totals, and delivered counts
- Session based authentication with forced password change on first login
The parts that were actually hard
Timezone handling. The server runs in UTC. The users are in Malaysia. Every date comparison, including the "cannot book a past date" rule and the "today" statistics, had to be recalculated in Malaysia time. The naive approach silently accepted bookings one day in the past for anyone submitting after midnight local time. We centralised the conversion into a single helper and routed every date operation through it.
Price integrity. The browser sends a menu selection, not a price. The server looks up the current price from the menu record at approval time. If a client tampers with the request body, the price is still correct. This matters because approved bookings feed directly into spend reporting.
Authentication scope. This is a meal ordering system, not a banking application. We deliberately kept the security proportionate: session based login, throttled password reset, forced change on first use, and server side authorisation on every admin endpoint. We did not add multi factor authentication, because the friction would have outweighed the risk for a system holding meal orders.
Architecture choices
The whole system runs on Cloudflare Pages with Workers handling the API and KV for storage. No traditional server, no database to patch, no hosting bill beyond the domain. For an agency without an IT department, that matters more than raw performance: there is nothing to maintain and nothing to go down at 2am.
We deployed behind strict security headers including a content security policy that blocks all external script sources. The trade off is that no third party analytics or tag manager can be added later without an explicit policy change, which is the correct default for a government system.
What I would do differently
The public form has no rate limiting or honeypot field yet. It is behind a government domain with low traffic, so the risk is small, but a bot could still fill the booking table with junk. That is the first thing I would add before the system handles a public launch.
The agency is not named here by request. Details of the internal workflow are summarised, not reproduced.