specs / 028-Changes-Resto-Spaces-Reservation

028 - Resto: Spaces Reservation, VIP Room Bundling & Table Mapping POS

  • Tanggal: 2026-08-13
  • Chat/topik: Fitur Resto end-to-end — reservasi space (Room/TableArea) by pax, bundling Court VIP dengan Room, mapping meja oleh kasir di POS. QR ordering per meja = app terpisah (fase lain).

Ringkasan perubahan

Fitur Resto lintas 7 aplikasi:

  • Schema (migration 020): spaces (Room = unit eksklusif; TableArea = pool pax, meja fleksibel), space_reservations, space_tables + space_reservation_tables (mapping meja kasir), courts.bundled_space_id, setting durasi/jam resto di store_settings.
  • Member (Android v1.17 → parity iOS v1.6 + Web v0.7): menu Resto → landing space → reservasi by pax (tanggal, jam mulai, guests; durasi fixed dari settings) atau Room VIP eksplisit dengan minimum spend terlihat; History dengan cancel; callout "Includes Private VIP Room" di court detail.
  • Backend (mpc-be v1.7): endpoint spaces/availability/reservations; availability Room eksklusif vs TableArea pool (online_capacity_pax = buffer walk-in, max_party_pax = batas rombongan online); hard block court VIP saat Room bundling terisi; POST /orders auto-create reservasi CourtBundle + cascade cancel/reschedule.
  • Admin (v0.8): halaman Resto (Spaces CRUD + Reservations harian + walk-in manual), picker Bundled VIP Room di form Court.
  • POS (mpc-be-pos v1.7 + mpc-pos v1.4): rutinitas kasir — daftar reservasi harian, assign meja per reservasi (multi-meja), ubah status (Seated/Completed/NoShow), kelola meja per area.

Keputusan desain kunci:

  • Reservasi TIDAK berhubungan dengan meja — availability online murni pax pool / room eksklusif; mapping meja lapisan operasional kasir.
  • Minimum spend display-only — reservasi Rp 0 (tanpa pajak); pemenuhan lewat pembelian FnB yang kena PB1 10% + service 5% di jalur existing; harga court tetap non-PB1.
  • Bundling best-effort (keputusan owner 2026-08-13, menggantikan hard block awal): court VIP tetap bisa dibook saat Room bundling penuh; reservasi CourtBundle hanya dibuat bila Room kosong; response POST /orders menyertakan bundled_room_included (true/false); copy court detail member apps: "Included when the room is available for your slot".
  • QR ordering per meja = app terpisah, fase berikutnya; space_tables sudah kompatibel (nol rework).
  • Order F&B tidak dari landing Resto (feedback owner 2026-08-13): link "Order food & drinks" dihapus dari landing Resto di ketiga member app; aksi order F&B hanya muncul di success state setelah reservasi space berhasil.
  • Flow reservasi berurutan (feedback owner 2026-08-13, revisi lanjutan): tanggal dipilih di landing Resto (bukan di reserve screen) → pilih ruangan/space + pax → pilih jam tersedia → confirm (bottom sheet, bukan dialog usang) → opsional pre-order F&B terikat ke reservasi itu (bukan alur cart court booking yang membingungkan).
  • Order F&B terikat reservasi butuh schema baru: transactions.space_reservation_id (migration 021) — pre-order F&B pasca-reservasi disimpan dengan reference ke reservasi, lalu ditampilkan sebagai orders[] di GET /spaces/reservations/me sehingga History menampilkan reservasi + pesanan menunya sebagai satu kesatuan (bukan dua entri terpisah/hilang).

Impact bisnis

Resto venue jadi bisa direservasi online (positioning premium, cross-sell F&B), Room VIP termonetisasi via minimum spend tanpa komplikasi pajak, Court VIP naik value karena bundling private room, dan operasional kasir tetap sederhana (mapping meja pagi hari, tanpa denah rumit).

Epic / User stories

  • Epic: Reservasi Resto end-to-end (member → admin → kasir POS).
  • US: Sebagai member, saya ingin reservasi meja resto berdasarkan jumlah tamu, agar tempat siap saat saya datang.
  • US: Sebagai member, saya ingin memilih Room VIP dengan minimum spend yang jelas di awal, agar tidak ada kejutan biaya.
  • US: Sebagai member yang booking court VIP, saya ingin private room otomatis termasuk, agar pengalaman VIP utuh.
  • US: Sebagai kasir, saya ingin melihat reservasi hari ini dan menentukan meja yang dipakai, agar penataan siap sebelum tamu datang.
  • US: Sebagai admin, saya ingin mengelola spaces & reservasi (termasuk walk-in), agar operasional terkontrol.

User terdampak

Member (Android/iOS/Web), admin, kasir POS.

Aplikasi terdampak

  • mpc-be: PERLU (selesai, v1.7) — endpoint spaces/reservations, bundling + hard block, api_contract §14.
  • mpc-be-pos: PERLU (selesai, v1.7) — endpoint /resto (spaces, tables CRUD, reservasi harian, status, assign meja), api_contract POS.
  • mpc-admin: PERLU (selesai, v0.8) — Prisma models, halaman Resto, picker bundled room.
  • mpc-android: PERLU (selesai, v1.17) — menu Resto, flow reservasi, History, callout VIP room. APK di Downloads.
  • mpc-ios: PERLU (selesai, v1.6) — parity 1:1.
  • mpc-web: PERLU (selesai, v0.7) — parity 1:1 (/resto, /resto/reserve).
  • mpc-pos: PERLU (selesai, v1.4) — tab Resto (reservasi harian + meja). APK di Downloads.
  • mpc-owner: TIDAK — domain dashboard owner; data resto belum masuk datamart.
  • ksr-sync: TIDAK — belum ada kebutuhan sync tabel resto ke ksrdb (evaluasi menyusul bila owner butuh laporan resto).

Perubahan schema

spaces, space_reservations, space_tables, space_reservation_tables (baru); courts.bundled_space_id; store_settings.space_reservation_duration_minutes + resto_open_time + resto_close_time. Detail + seed + rollback: mpc-dev/docs/schema/migration/020-resto-spaces-reservations.md (sudah diapply ke mpcdb lokal; jalankan di server saat deploy).

Lanjutan (flow reorder + pre-order terikat): transactions.space_reservation_id (nullable FK ke space_reservations, + index) — mpc-dev/docs/schema/migration/021-link-orders-to-space-reservations.md.

Perubahan kode

  • mpc-be: internal/spaces/ baru; internal/courts (bundled_space + hard block), internal/bookings/internal/orders (auto-reserve CourtBundle + cascade), internal/settings; mpc-dev/docs/api/be.md §14.
    • Lanjutan: internal/transactions (SpaceReservationID + GetTransactionsBySpaceReservationIDs), internal/spaces (GetMyReservations enrich orders[], GetReservationForCustomer), internal/orders (CheckoutRequest.space_reservation_id + validasi kepemilikan).
  • mpc-be-pos: internal/resto/ baru + wiring; mpc-dev/docs/api/be.md section Resto.
  • mpc-admin: prisma/schema.prisma, src/actions/resto.ts, src/app/(dashboard)/services/resto/*, form Court + sidebar.
  • mpc-android: feature/resto/* baru; Dtos/Models/Mappers/Api/Repository; Home, History, CourtDetail, nav.
    • Lanjutan: RestoScreen.kt (date picker + "Your reservations"), SpaceReserveScreen.kt (hapus date picker internal, pre-order CTA), FoodDrinksScreen.kt/ProductCatalogScreen.kt (mode pre-order via reservationId), HistoryScreen.kt (ReservationOrdersSummary), CheckoutState.spaceReservationId, MainTabState + goHistory(), Dtos/Models/Mappers untuk orders[].
  • mpc-ios: Features/Resto/* baru; Dtos/Models/Mappers/Api/Repository; Home, History, CourtDetail, Route.
    • Lanjutan: parity 1:1 dari perubahan Android di atas (RestoScreen.swift, SpaceReserveScreen.swift, FoodDrinksScreen.swift/ProductCatalogScreen.swift, HistoryScreen.swift, AppState.swift (CheckoutState.spaceReservationId, MainTabState), Router.goHistory(), Dtos/Models/Mappers).
  • mpc-web: src/app/resto/*, src/lib/resto/space.ts, repo/types, History, courts, header/home.
    • Lanjutan: /resto (date strip + "Your reservations"), /resto/reserve (hapus date picker internal, pre-order CTA + "Maybe later"), /resto/order baru (katalog F&B standalone tertaut reservasi), /history (ReservationOrdersSummary + ?tab=resto), useCheckout (spaceReservationId), /payment (kirim space_reservation_id, guard court-less checkout).

Deploy production (lanjutan, 2026-08-13 malam)

  • Migration 021 diapply ke mpcdb production (docker exec mpc-postgres psql) — kolom + index transactions.space_reservation_id terverifikasi via \d transactions.
  • SKIP_WEB=1 SKIP_POS_WEB=1 ./deploy-mpc.sh — build+kirim mpc-be, mpc-be-pos (tanpa perubahan, ikut restart), member web (mpc-web-cs.glenrh.com); admin & POS Flutter web di-skip (tidak ada perubahan kode yang perlu redeploy sesi ini).
  • Smoke test prod: GET /spaces 200, mpc-web-cs.glenrh.com/resto 200, /resto/order 200, /history 307 (redirect login, expected tanpa sesi) — semua service (mpc-be, mpc-be-pos, mpc-web-cs) active.
  • APK mpc-android-demo-v1.17.apk di-rebuild ulang (overwrite) untuk menyertakan perubahan flow reorder + pre-order; instalasi ke Mi 9 di-skip karena device belum terhubung ke adb saat sesi ini — APK sudah siap di Downloads.
  • iOS: xcodebuild ... buildBUILD SUCCEEDED (simulator).

Deploy production (2026-08-13)

  • Migration 020 diapply ke mpcdb production (mpc-postgres di VPS) — 4 spaces + 10 meja + bundling CRT-03 terverifikasi.
  • deploy-mpc.sh full: mpc-be, mpc-be-pos, mpc-admin (mpc-web.glenrh.com), member web (mpc-web-cs.glenrh.com/resto), POS web (mpc-pos.glenrh.com) — semua smoke test 200; GET /spaces + availability + bundled_space Court 3 terverifikasi di prod.
  • APK demo: mpc-android-demo-v1.17.apk + mpc-pos-demo-v1.4.apk di Downloads (Android di-rebuild setelah copy best-effort).

Catatan terbuka

  1. Fase berikutnya (disepakati, belum dikerjakan): QR ordering per meja sebagai app terpisah (web menu tamu + intake order + seat layout POS + tracking otomatis minimum spend).