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
| Release | Name | Main Modules | Demoable Value |
|---|---|---|---|
| 12.0 | Booking Foundation | Booking, Tenant (settings) | A garage sets hours and capacity and sees free slots and a calendar |
| 12.1 | Customer Booking | Booking, Customer BFF, public page | A customer books from the app or the public page and the garage confirms |
| 12.2 | Booking Lifecycle | Booking, Notification | Reminders, reschedule, cancel, no-show, and conversion to a quote or repair order |
| 12.3 | Booking Resources (optional) | Booking | Bays and technicians on a grid calendar with drag and drop |
| 12.4 | Platform Admin Dashboards | Platform 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) andbookings.- 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→confirmedorrejected→arrived→converted; side exitscancelledandno_show. - Booking is a plan capability (
booking_enabledin 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/:garageSlugand 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 stayspending_verificationand holds its slot for 15 minutes only; verification creates the walk-in customer (FR-CUS-01) and moves it torequested. 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.cancelledandbooking.convertedthrough 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-webwith 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 ofvietgara-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.