Booking grup & kelas

Terima booking kelas atau sesi grup di Termilo dengan kapasitas resource dan kursi tersisa per jadwal. Satu layanan, banyak peserta per slot — tanpa risiko overbooking.

Lihat .md

Model kapasitas#

Kelas memakai primitif booking yang sama dengan sesi privat — tidak ada tipe khusus. Bedanya hanya kapasitas. Modelkan kelas sebagai layanan yang diikat ke sebuah resource dengan capacity lebih dari 1, lalu mesin ketersediaan menghitung berapa kursi yang masih tersisa di tiap slot.

  • Sumber kapasitas adalah kolom capacity pada tabel resources (bawaan 1). Isi 12 untuk kelas 12 kursi.
  • Tiap slot membawa capacityRemaining — sisa kursi setelah booking aktif dikurangi.
  • Satu booking memesan satu kursi. Peserta berikutnya membuat booking sendiri sampai capacityRemaining mencapai 0.
PARAMETERTIPEWAJIBKETERANGAN
startsAtMsnumberwajibAwal slot — UTC epoch milidetik.
endsAtMsnumberwajibAkhir slot — UTC epoch milidetik.
resourceIdstring | nullopsionalResource (mis. ruang kelas) yang membawa kapasitas slot. null bila kapasitas berasal dari staf.
staffIdstring | nullopsionalStaf yang membawakan sesi, bila kelas diikat ke staf alih-alih resource.
capacityRemainingnumberwajibSisa kursi pada slot itu setelah booking aktif dikurangi. 0 berarti penuh.

Bentuk satu slot dari hasil GET /book/:tenantSlug/availability.

Menyiapkan kelas#

Tiga langkah, semuanya dari dashboard (sesi Google + header CSRF):

  1. Buat resource lewat POST /api/resources dengan capacity > 1 — wajib mengisi type dan name.
  2. Atur jam operasional layanan di Mengatur ketersediaan agar tiap kemunculan kelas menjadi slot tersendiri.
PARAMETERTIPEWAJIBKETERANGAN
typestringwajibJenis resource, mis. "room", "seat", "equipment".
namestringwajibNama yang muncul di dashboard, mis. "Studio Yoga A".
capacitynumberopsionalJumlah peserta yang muat per slot. Bawaan 1 (sesi privat). Isi > 1 untuk kelas.
locationLabelstringopsionalLabel lokasi yang ditampilkan ke pelanggan.

Field POST /api/resources. Endpoint ini butuh peran tulis (tenant_owner / tenant_admin) dan header X-Termilo-CSRF.

Pengikatan layanan ke resource tidak tersedia
Pengikatan layanan ke resource tidak tersedia lewat API atau dashboard. Tanpa pengikatan ini, kelas berkapasitas tidak tersedia — setiap layanan tetap memakai kapasitas bawaan satu kursi per slot.

Membaca kapasitas tersisa#

Endpoint ketersediaan publik (tanpa auth) mengembalikan satu daftar slot, masing-masing dengan capacityRemaining. Saring slot yang masih punya kursi sebelum menampilkannya:

# 1. Buat resource kelas dengan kapasitas 12 (dashboard, sesi + CSRF) curl -X POST https://app.termilo.id/api/resources \ -H "Content-Type: application/json" \ -H "X-Termilo-CSRF: $CSRF" \ --cookie "$SESSION" \ -d '{ "type": "room", "name": "Studio Yoga A", "capacity": 12 }' # 2. Baca slot publik — capacityRemaining ikut per slot curl "https://app.termilo.id/book/studio-anjani/availability\ ?serviceSlug=yoga-pagi&fromMs=1750000000000&toMs=1750600000000"
capacityRemaining adalah perkiraan
Hasil availability menandai dirinya finalAuthority: "booking_create_recheck_under_lock". Angka kursi bisa berubah antara saat dibaca dan saat booking dibuat — otoritas terakhir selalu pengecekan ulang di bawah lock, bukan respons ini.

Jendela query dibatasi maksimum 31 hari (fromMstoMs dalam UTC epoch milidetik).

Menerima booking kelas#

Booking kelas memakai endpoint create yang sama dengan sesi privat. Header Idempotency-Key wajib, dan customer perlu mengisi email atau telepon.

POST /book/studio-anjani/bookings Idempotency-Key: 3f0a… # wajib { "serviceSlug": "yoga-pagi", "startsAtMs": 1750084200000, "source": "public_page", "customer": { "name": "Sari", "primaryEmail": "sari@example.com" } }
201 Createdapplication/json
{
"ok": true,
"data": { "booking": {
"bookingId": "bk_7Qd…",
"status": "held",
"startsAtMs": 1750084200000,
"holdExpiresAtMs": 1750084800000 },
"idempotentReplay": false,
"manageUrl": "https://…/booking/manage/tm_m1…"
} },
"meta": { "requestId": "req_…" }
}

Booking baru lahir dengan status held dan holdExpiresAtMs = sekarang + 10 menit; konfirmasi dari dashboard memindahkannya ke confirmed. Tiap booking aktif mengurangi capacityRemaining satu kursi.

Saat kursi terakhir direbut dua orang sekaligus, slot dicek ulang di bawah Durable Object lock. Yang kalah menerima BOOKING_SLOT_UNAVAILABLE (409) — bukan overbooking.

Waitlist & reminder#

Tidak tersediatidak ada endpoint waitlist

Saat kelas penuh, daftar tunggu otomatis (waitlist) yang menggeser peserta saat ada pembatalan tidak tersedia. Kelas penuh berarti slot menampilkan capacityRemaining: 0 dan booking ditolak. Kelola daftar tunggu secara manual di luar Termilo.

Endpoint waitlist tidak tersedia
Tidak ada endpoint waitlist di Termilo. Reminder terjadwal (H-1, 1 jam sebelum) juga tidak tersedia. Konfirmasi booking terkirim lewat email; WhatsApp bukan kanal kirim — hanya nomornya yang tersimpan di booking. Webhook booking keluar sudah live. Lihat Webhooks untuk event live (mis. booking.created).

Batas MVP#

Termilo mendukung kelas berkapasitas sederhana berbasis kapasitas resource. Yang berikut sengaja di luar MVP:

  • Tidak tersediaWaitlist otomatis dengan promosi saat ada pembatalan
  • Tidak tersediaMemesan beberapa kursi dalam satu booking
  • Tidak tersediaRangkaian kelas berulang yang dikelola sebagai satu kesatuan

Tetap pada pola kelas berbagi-kapasitas sederhana, dan satu booking per kursi, agar perilaku tetap dapat diprediksi dan bebas overbooking.

Pertanyaan umum#

Keduanya bisa. Ikat layanan ke sebuah resource ber-capacity > 1 (mis. ruang dengan 12 kursi), atau gunakan kapasitas staf. Apa pun pembawanya, slot mengembalikan capacityRemaining yang sama.