A desktop restaurant-operations simulator built in C++17 with the SplashKit graphics/windowing library. It models a single restaurant end-to-end — front-of-house seating, guest self-ordering, kitchen fulfilment with staff-capacity constraints, checkout/payment, receipts, and an admin back-office — all inside one application, backed by CSV files instead of a database.
This file is a personal reference for what the program actually does, module by module, so future-me doesn't have to re-read 20k lines to remember.
36361542_FP_main_menu.cpp is the entry point (main()):
- Loads fonts (including an emoji fallback font on Windows), starts background music, and resets
data/sales_totals.csvto zero on every boot (sales are "per session", not cumulative across app restarts). - Drops into a loop that always opens the role chooser (
auth_gui_get_session) until the user quits:- Admin →
run_admin_hub() - Waiter →
run_waiter_hub() - Guests don't log in through this screen — they reach the menu via a QR code a waiter/table shows them (see Guest flow below).
- Admin →
- On exit, stops audio and — via
shutdown_cleanup.cpp's static destructor (registered withstd::atexit) — wipes all transient session state: chef queue, chef timing schedule, served markers, voided items, per-table carts, and seat/occupancy snapshots. So every fresh launch starts with an empty floor and empty kitchen, but the menu, staffing config, store details, and user accounts persist.
Defined in auth_gui.hpp: Waiter, Admin, Guest. Login/sign-up is handled by auth_gui.cpp (modal window, role picker → login/sign-up, Back returns to role chooser, closing the window exits the whole app).
The waiter's home screen, with four actions plus Back:
- Time menu — opens the Day/Night session picker (see Time & Session below). Seat ordering is disabled while the session is "Closed".
- Seat ordering — opens the seating/table screen (
seat_availability.cpp) for the current Day/Night session. - Payment — prompts for a table number, then reopens that table's cart directly in payment mode (skips straight to checkout instead of ordering).
- Customer order queue — opens the kitchen ticket view (chef queue) inside the same window, so a waiter can see prep/serve status without leaving the hub.
The app simulates "Malaysia Standard Time" (UTC+8) rather than using the wall clock directly, so a session can be tested at any hour:
- Reads real system time and converts to MYT, or lets an admin manually step the clock forward/backward via an in-app editor (hour/minute steppers).
- Classifies the current time into three windows: Day (07:00–16:59), Night (17:00–02:59), Closed (03:00–06:59). Trying to "Use this time" while Closed shows a warning and refuses.
- The Day/Night boundary times themselves are also configurable and persisted (
open_time_settings_clock()intime_settings_clock.cpp), independent of the quick session picker. - Everything downstream (menu shown, kitchen prep-time bucketing, seating availability) reads off this simulated session, not the OS clock.
- Table layout (id, seat capacity, active/inactive) is defined in
data/tables.csvand can be edited by an admin (table_layout.cpp). seat_store.cppis the live in-memory store of tables plus their occupancy, with functions to check-can-seat / assign / release a table by party size, and immediately persists occupancy todata/tables_state.csvon every change (so a mid-service crash doesn't lose the floor state — though it's wiped intentionally on clean exit).seat_availability.cpprenders the actual floor-plan-style UI: pick a party size, see which tables can fit it, seat/release tables, track a seating-order history (a stack) per Day/Night session independently.
- Each table can present a QR code (
qr_generator.cppdraws it directly, no external image library) that a customer scans/opens to reach a read-only, single-table guest menu — no login required, no access to other tables, no delete/capacity controls. - Guest mode swaps a global "client mode" flag (
menu_ctx::ClientMode::GuestvsWaiter) so the same cart/menu-overlay code (table_order.cpp/menu_overlay.cpp) renders a restricted UI for guests instead of maintaining a second UI implementation. - Guests can browse the current Day/Night menu, build a cart, and confirm — which enqueues the order to the kitchen exactly like a waiter-placed order.
FileMenuReporeads/writes two CSVs (data/day_menu.csv,data/night_menu.csv);MenuServiceis the in-memory façade the rest of the app calls (list, add/update, remove, reload). Menu items carry name, price, cost, and prep time in seconds.- Dishes are tagged into one of three sections — Hot-Mains, Beverage/Drinks, Desserts/Pastry — which is the same taxonomy the kitchen scheduler uses to route work to the right staff pool.
menu_hub.cppis the admin-facing menu viewer (Total/Day/Night tabs, scrollable price/cost table);admin_gui.cppis the actual editor (add/update/remove a dish, choose which session(s) it serves, optionally mirror a price/cost change into the other session with a confirm dialog, undo-style before/after diff banners).
Two independent integrations with the DeepSeek chat-completions API (both read the API key from the DEEPSEEK_API_KEY environment variable, with a data/deepseek.key file as a fallback path):
deepseek_suggest_dishes()— asks the model for N dishes for a given section + Day/Night, expects a strict CSV reply (name,price_cents,cost_cents,prep_secs), used to bulk-generate menu candidates for the admin to approve.ds_fetch_menu_idea()— asks for a single dish idea as JSON (name,prep,ingredients), used for one-off "give me an idea" prompts.- Both are built directly on
libcurlwith hand-written JSON escaping/construction and hand-written response parsing (no JSON library) — fine for the known DeepSeek response shape, but brittle if the API output format ever changes.
The most involved subsystem. Orders aren't just a FIFO queue — they're scheduled against limited staff capacity per section:
- Staffing levels (chefs, bartenders, pastry crew) are configured in the Admin Hub (
staff_capacity.cpp, persisted todata/staff_capacity.cfg) and treated as the number of parallel "slots" available per section. - When a ticket comes in, its line items are bucketed by inferred section (via a
data/section_map.csvlookup, falling back to a keyword-based guess), and each section's total prep time is computed from a prep-time table (pulled from the Admin Menu database first,data/prep_times.cfgas override/fallback). compute_parallel_schedule()places each ticket's per-section work into the next available slot (respecting how many workers exist for that section), giving every ticket a real start/end time estimate — i.e., an ETA that reflects actual kitchen bottlenecks, not just "first in, first out."- Scheduling results are persisted (
data/chef_times.csv) so ETAs survive redraws/restarts within a session, with logic to invalidate stale timings if a ticket predates its recorded schedule. - The same view renders differently for staff (full queue, mark items served/void, delete) vs. guests (read-only, single-table, no capacity/served/delete controls) — one implementation, mode-gated UI, same pattern as the menu overlay.
- Per-table cart state (items + quantities) is tracked independently per table/session (
table_order.cpp), with overlays for the cart itself, the payment screen, and (guest-only) an ETA display. order_cart.cppis the entry point used by both the waiter ("Payment" button on the hub) and guest flows; apayment_modeflag decides whether confirming the cart just sends it to the kitchen or walks straight into checkout.- Confirming an order calls
confirm_order_to_kitchen(), which is what actually creates the chef ticket consumed bychef_queue.cpp.
checkout_flow::open_from_waiter_hub()— waiter picks a table number, then a Day/Night session, then opens the cart in payment mode.checkout_pay.cpp— a small, decoupled payment module (amount due in,on_paid(due, paid, change)callback out) so the payment UI doesn't need to know about carts/menus directly.- Produces change calculation and hands off to the receipt module.
show_receipt_full()renders an itemized receipt (unlimited line items, not capped) with configurable tax %, service charge %, rounding, payment method/status, order type (Dine-In/etc.), store name/address block, and a receipt ID.- Store identity defaults are hardcoded (
"Gordon Sensay", Monash University Malaysia address) — worth knowing that's a placeholder/branding stub, not pulled fromstore_config.
- Post-meal customer ratings screen: 1–5 stars each for Served Appearance, Served Size, Flavor, Aroma, tied to a specific
receipt_idand written toratings.txt.
The largest single file in the project (~100KB). Admin-only actions:
- Menu Update — the dish editor described above (add/update/remove, Day/Night targeting, AI-assisted suggestions).
- Store Detail — store configuration (
store_config.cpp,data/store.cfg). - Password Change — account credential management.
- Staffing capacity — chefs/bartenders/pastry headcount editor (spinner UI), feeding directly into the kitchen scheduler.
- Also owns the "Admin Menu Database" table view (Total/Day/Night tabs) and the "Ask AI" entry point into the DeepSeek dish generator.
Everything is CSV/plain-text files under data/, no database, no external JSON library:
| File | Purpose |
|---|---|
day_menu.csv / night_menu.csv |
Menu items per session |
menu_sections.csv |
Dish → section tagging |
tables.csv / tables_state.csv |
Table layout / live occupancy |
staff_capacity.cfg |
Chefs/bartenders/pastry headcount |
prep_times.cfg |
Prep-time overrides |
chef_queue.csv / chef_times.csv / chef_served.txt |
Kitchen ticket queue, computed schedule, served markers (all wiped on clean exit) |
voided_items.csv |
Voided kitchen items |
sales_totals.csv |
Session sales (reset every launch) |
store.cfg |
Store details |
users.csv |
Login accounts |
deepseek.key |
Fallback location for the DeepSeek API key |
ratings.txt |
Customer ratings, keyed by receipt ID |
audio_init()(inbgm.cpp) loads three named audio assets once: music"bg"←Resources/sound/bgm_FP.mp3, sound effect"tick"←Resources/sound/change_time.mp3, sound effect"strike"←Resources/sound/use_time.mp3.bgm_start(volume)plays"bg"on an infinite loop (play_music(..., -1));main()calls it with volume0.22right afteraudio_init(), wrapped so it's guaranteed to stop on exit (bgm_stop()+audio_shutdown(), plus aBgmGuardRAII struct as a belt-and-suspenders version of the same start/stop pairing).sfx_play("tick")/sfx_play("strike")are triggered from the Time menu (time_menu.cpp) —"tick"on every hour/minute step and on "Reset to System"/"Change time","strike"when a valid time is confirmed via "Use this time" (a little clock-strike flourish for committing the session change).- Note to self:
Resources/sound/bgm.mp4, plus the wholeTime menu sound effect clock ticking/folder (clock_edit.mp4,tick_sound.mp3), sit in the project but are not referenced bybgm.cppor anywhere else — leftover/unused assets from an earlier iteration, safe to ignore or clean up. - Font loading (
fonts.cpp) with an emoji fallback (Windowsseguiemj.ttf) for icon-style UI text.
Plain make via Makefile.mak: compiles every 36361542_FP_*.cpp file against SplashKit (-lsplashkit), libcurl (AI calls), winmm/ws2_32 (Windows audio/networking), producing build/AdminHub.exe. Uses auto-generated .d dependency files (-MMD -MP) for incremental rebuilds.
Note to self:
36361542_FP_HD_Final.cppalso lives in this folder and matches the Makefile's wildcard — check whether that's a stale monolithic draft before assuming the modular build above is what actually ships.
main() → role picker
├── Admin → Admin Hub → menu editor / staffing / store config / password
└── Waiter → Waiter Hub → time session / seating / payment / kitchen queue
│
Guest (via QR at a table) → read-only menu → cart → kitchen ticket
│
Kitchen scheduler (capacity-aware, per section) → ETA
│
Checkout → payment → receipt → ratings