feat: add guest booking system and admin slot reservation

Guest flow: CreateGuestUserHandler creates disposable guest accounts on-the-fly.
CreateBookingHandler uses OptionalAuth — accepts authenticated or guest (user_id
in body, validated as account_role='guest'). Guests bypass deposits, patch tests,
and the 24h deposit advance rule.

Admin reserve: AdminReserveSlotHandler supports walk-in (5min TTL) and call-in
(60min TTL) reservations with configurable TTL. Validates against bookings,
blockers, working hours.

Route restructuring: POST /bookings moved to OptionalAuth group. POST /bookings/reserve
added for public reservation. POST /admin/bookings/reserve added for admin.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-30 11:44:39 +01:00
co-authored by Sisyphus
parent 91dbdb199e
commit 70cba5e412
4 changed files with 441 additions and 49 deletions
+7 -1
View File
@@ -140,6 +140,12 @@ func main() {
// Public booking endpoints (optional auth for slot reservation)
r.With(mw.RateLimit(30, time.Minute), mw.OptionalAuth).Post("/bookings/reserve", bookings.ReserveSlotHandler)
// Guest user creation (public, no auth required)
r.With(mw.RateLimit(10, time.Minute)).Post("/users/guest", user.CreateGuestUserHandler)
// Booking creation (accepts both authenticated and guest users)
r.With(mw.RateLimit(30, time.Minute), mw.OptionalAuth).Post("/bookings", bookings.CreateBookingHandler)
// Authenticated users
r.Group(func(r chi.Router) {
r.Use(mw.RequireAuth)
@@ -155,7 +161,6 @@ func main() {
r.Get("/user/loyalty", user.GetLoyaltyHandler)
r.Route("/bookings", func(r chi.Router) {
r.Post("/", bookings.CreateBookingHandler)
r.Get("/", bookings.GetAllUserBookingsHandler)
r.Get("/{id}", bookings.GetBookingHandler)
r.Get("/{id}/calendar", bookings.GetBookingCalendarHandler)
@@ -189,6 +194,7 @@ func main() {
r.Put("/{id}/progress", bookings.ProgressBookingHandler)
r.Post("/{id}/confirm", bookings.ConfirmBookingHandler)
r.Post("/{id}/cancel", bookings.AdminCancelBookingHandler)
r.Post("/reserve", bookings.AdminReserveSlotHandler)
// Edit request endpoints
r.Get("/{id}/edit-requests", bookings.AdminListEditRequestsHandler)
r.Post("/{id}/edit-requests/{request_id}/approve", bookings.AdminApproveEditRequestHandler)