Give customers this public link: https://fixitsukil.github.io/bossman-queue/book.html.
The page shows every listed barber. Available barbers show their live queue and estimated wait; paused barbers and those on a scheduled off day remain visible but cannot be selected. Customers choose a barber, enter their name and phone, and join the live queue from anywhere. They do not choose a service or appointment time. Online joining is open from 11:00 AM through 10:45 PM Malaysia time; the database enforces these hours. After joining, customers see their place and wait on index.html, which refreshes automatically.
The in-shop QR is permanent: qr-display.html shows the fixed shop-qr.png, which links to index.html and can also be printed. The in-shop page asks customers to share their location. QR joining runs from 11:00 AM through 10:45 PM Malaysia time. Outside that window, the page shows a closed message instead of barber choices, and the database rejects any attempted join. Customers already in the queue can still view their place. Both paths enter the same live queue. Staff see remote customers in their existing barber and owner dashboards. The service catalog remains available to the owner for staff reference, and previous appointments remain visible to staff.
For a fresh database, run supabase/schema.sql, then supabase/hardening.sql, then the SQL migrations in supabase/migrations/ in timestamp order. For an existing database, apply only new migrations. The static QR join function is in 20261010102842_static_shop_qr.sql. Publish the site to GitHub Pages, then test both the QR and public links. No owner or barber secret belongs in a public URL.
Estimated waits use each barber's average minutes and the remaining time of any customer currently being served. They are estimates; actual service length and queue changes can affect them.
The owner uses the existing private owner.html?pin=... dashboard to add and edit workers, set names, roles, average service times, display order, and weekly off days, and pause or resume new joins. Off days follow Malaysia time. The owner can hide a worker temporarily, or delete them from the staff list after their active queue and future appointments are resolved. Deletion invalidates their private link and removes them from customer pages, while preserving historical customer records. The owner can also copy or reset each worker's private dashboard link. Barbers can stop or resume new joins on their own private barber.html?pin=... dashboard. Pausing or a scheduled off day leaves current queues intact. Customer pages refresh availability every 10 seconds, and the database checks availability again when someone joins.
Customer names, phone numbers, and booking activity are stored in the production Supabase project's public.queue_entries (live queue) and public.bookings (older appointment flow) tables. The owner portal's Customer database section downloads a unique customer contact list or the complete queue and appointment history as CSV. Both exports require the owner PIN; no customer details are available through the public read views. A customer who has never joined or booked will not appear in either export.
Barbers can cancel a waiting or called customer separately from marking a no-show. The customer's queue page then shows an apology and links to WhatsApp or call Bossman at 011-1165 1608. The page checks for status changes every 10 seconds while open and shows the cancellation again if the customer returns to that queue page on the same device.
The barber's Cancel action asks for explicit No/Yes confirmation before changing the queue. A customer can cancel their own place from the queue status page, including after being called. New queue entries receive a private cancellation token saved on that customer's phone; the public queue ID alone cannot cancel an entry. Entries created before this change need staff help to cancel because their phones never received a token. Both QR and remote joins enforce one active barber place per phone and a 30-minute repeat-join limit on the server, with Malaysian 0 and 60 prefixes treated as the same number. The QR path permits one facial therapist place alongside an active barber place. A completed cut releases the repeat-join limit immediately. The booking page also hides its join form while a saved active entry exists on the device.
The customer pages are installable as a home screen web app. Android Chrome offers an install option; iPhone customers use Safari's Share menu and Add to Home Screen. The live queue still needs an internet connection. The app manifest, service worker, and icons are in the repository root.