Skip to content

RELEASE PLAN — PHASE 12

VietGara — Scheduling

Version 12.0 — October 9, 2026 · Cloud: Google Cloud Platform (GCP) · Backend: Go

1. Introduction

Today a customer reaches a garage by phone or by walking in. Phase 12 lets them book:

  • Customer: picks a garage, a vehicle, the jobs and a slot, in the Customer App or on a public page without any user.
  • Garage: sets working hours and capacity, sees a calendar, confirms or rejects, and turns a booking into a quote or repair order in one step.
  • VietGara: sees sign-ups and licences per day, month and year.

Channels. The Customer App is the main path and push notifications reach the customer’s phone. The public page is a fallback with e-mail confirmation and reminders. SMS and Zalo come with the integrations in Phase 16, not earlier, because registering the sender brand and templates takes time.

Booking depends on earlier phases: the job catalogue (Release 7.3) to pick services, flexible customers (Release 5.1) so a booking from someone with no user creates a walk-in customer, e-mail (Release 10.1) and push (Release 11.0) for confirmations and reminders, and rate limiting (Release 8.0), because the public page is the first unauthenticated write endpoint a customer uses.

2. Overview of the 5 Releases

ReleaseNameMain ModulesDemoable Value
12.0Booking FoundationBooking, Tenant (settings)A garage sets hours and capacity and sees free slots and a calendar
12.1Customer BookingBooking, Customer BFF, public pageA customer books from the app or the public page and the garage confirms
12.2Booking LifecycleBooking, NotificationReminders, reschedule, cancel, no-show, and conversion to a quote or repair order
12.3Booking Resources (optional)BookingBays and technicians on a grid calendar with drag and drop
12.4Platform Admin DashboardsPlatform Analytics (admin web and admin app)VietGara sees new sign-ups and new licences per day, month and year

3. Release Details

Release 12.0 — Booking Foundation

  • Backend (FR-BKG-01/02/05): a Booking module with booking_settings (working hours per weekday, holidays, blocked_periods, slot length, capacity per slot, lead time, cancellation window, auto-confirm or manual) and bookings.
    • Times are stored in UTC; the garage’s time zone (FR-TEN-05, default Asia/Ho_Chi_Minh) drives hours, holidays and slot generation.
    • Slots are computed on read from the settings and the existing bookings, never stored in advance.
    • Creating a booking runs a capacity check inside the transaction (a lock on the garage and slot), so two requests cannot take the last place.
    • States: pending_verification → requested → confirmed or rejected → arrived → converted; side exits cancelled and no_show.
    • Booking is a plan capability (booking_enabled in the entitlement cache), not metered against the daily transaction limit.
  • Frontend (web console and owner app): booking settings, a day/week calendar with confirm, reject, manual booking and mark arrived or no-show.
  • Definition of Done: an owner sets hours and capacity of 2 per slot; the slot list shows exactly the free places; two concurrent requests for the last place produce one booking and one refusal.
  • Calendar views. Day, week and month list views, plus the grid of Release 12.3. After a booking is converted, its card shows the linked repair order’s progress (waiting, in service, done) next to the booking status, so staff follow the whole visit in one place; the quote or repair order links back to the booking.

Release 12.1 — Customer Booking

  • Customer App (FR-BKG-03, FR-CAPP-06): pick a garage, a vehicle, one or more jobs from the job catalogue and a slot; list, reschedule and cancel own bookings.
  • Reminder channel. The Customer App is the primary channel: a booking made in the app, or by staff for a customer linked to a user, sends push at each step (received, confirmed or rejected, the reminder, a reschedule). Customers who book on the public page without a linked user get e-mail. The staff screen shows each booking’s reminder channel (push, e-mail or none). The confirmation page and e-mail invite the person to install the app and link their profile, so later notices arrive by push.
  • Problem description and photos (FR-BKG-10). The customer describes what is wrong and attaches up to three photos (file registry); they prefill the quote created from the booking.
  • Owner page for chains (FR-BKG-11). An owner-level page lists the owner’s garages and leads to each garage’s booking page.
  • Public booking page (FR-BKG-04): each garage gets /b/:garageSlug and a QR code. A person without a user enters name, contact, vehicle plate and jobs, and verifies their e-mail with an OTP. The booking stays pending_verification and holds its slot for 15 minutes only; verification creates the walk-in customer (FR-CUS-01) and moves it to requested. Phone-only bookings wait for phone OTP (Release 2.4); until then an e-mail is required.
  • Abuse protection (FR-BKG-08):
    • at most 2 open bookings per verified e-mail or phone per garage and 5 across the platform;
    • per-IP rate limits on the public endpoints (Kong, Release 8.0) and per-garage burst limits on slot lookup and booking creation;
    • a captcha (Turnstile or reCAPTCHA) on the public page once a limit trips;
    • after 2 no-shows by the same contact a garage can require manual confirmation (off by default);
    • the public page shows availability only, never other customers’ data.
  • Definition of Done: a customer with the app and another with only the public page each book the same garage; both appear on the garage calendar with the right customer record; an unverified booking frees its slot after 15 minutes; the fourth open booking of one e-mail is refused.

Release 12.2 — Booking Lifecycle

  • Reminders (FR-BKG-06): push to the customer 24 hours before the slot (e-mail when the customer has no linked user), computed from the slot’s UTC time; notices to staff on new requests and cancellations. SMS and Zalo reminders arrive with Phase 16; the sender registrations they need (SMS brand name, Zalo official account and templates) should start early and in parallel because approval takes time.
  • Reschedule and cancel: the customer changes or cancels until the cancellation window closes; staff can always change; every change notifies the other side.
  • No-show handling: marking a no-show updates the contact’s counter used by the abuse rules.
  • Convert (FR-BKG-07): one action creates a quote or a repair order with the customer, vehicle and jobs prefilled (the job catalogue’s labor and suggested parts). The new document counts against the daily limit; the booking does not.
  • Events: booking.requested, booking.confirmed, booking.cancelled and booking.converted through the outbox (Event Design).
  • Definition of Done: a confirmed booking sends a reminder 24 hours before, a reschedule moves it and notifies the garage, an arrived booking converts to a quote with its jobs and parts, and the booking shows as converted.

Release 12.3 — Booking Resources (optional)

  • Resources (FR-BKG-09). Garages that need more than a capacity number define bays (a lift, a wash bay, a paint booth: name, type, active) and mark which jobs need which bay type. A booking can carry an optional bay and an optional technician, with conflict detection on both over the estimated duration (the sum of the jobs’ duration_minutes). Customers never choose the technician.
  • Grid calendar. Day and week grids by bay or technician, with drag and drop to move a booking to another time, bay or technician; drops that would conflict are refused with the reason.
  • Capacity. When bays are defined, free slots are computed from free bays instead of the single capacity number; garages without bays keep the simple model.
  • Definition of Done: a garage with two lifts and one paint booth cannot be double-booked on a lift; dragging a booking to an occupied bay is refused; a booking with an assigned technician shows on that technician’s grid row.

Release 12.4 — Platform Admin Dashboards

  • Backend: a Platform Analytics read path for platform admins only (/api/v1/admin/stats/..., FR-ADM-01..03). It returns aggregate counts only, never garage business data, bucketed by day, month or year over a chosen date range:
    • sign-ups: new users, verified users and new garages;
    • licences: new trials, trial-to-paid conversions, plan changes, subscriptions that became past due, suspended or cancelled, and active subscriptions by plan;
    • activity: active garages (a quote, repair order or settlement in the last 30 days) and platform-wide transactions per day.
  • Frontend: a Dashboard in vietgara-admin-web with KPI cards for today, this month and this year against the previous period, trend charts, period and date-range pickers and CSV export; the same figures on the home screen of vietgara-admin-app (FR-AAPP-03).
  • Definition of Done: registering two test owners and starting one paid plan in staging shows up the same day in the sign-up and licence figures, on the web and in the app. The totals match a direct database count for the same range.

4. Dependency Diagram

flowchart TD
  P11(["Phase 11 complete"]) --> R120["Release 12.0<br/>Booking foundation"]
  R120 --> R121["Release 12.1<br/>Customer booking"]
  R121 --> R122["Release 12.2<br/>Booking lifecycle"]
  R122 --> R123["Release 12.3<br/>Booking resources (optional)"]
  P11 --> R124["Release 12.4<br/>Platform admin dashboards"]
  R122 --> DONE(["Phase 12 complete"])
  R123 --> DONE
  R124 --> DONE

Release 12.4 depends only on data that already exists and can run alongside the booking releases. Release 12.3 is optional and can be postponed without affecting the others.