Konsep Inti
Pahami tenant, layanan, ketersediaan, slot, booking & status, customer, dan deposit di Termilo dengan nama field aslinya. Setiap konsep dipetakan langsung ke kolom yang benar-benar tersimpan di database tenant.
db/migrations/tenant). Yang ditandai Tidak tersedia tidak bisa dipakai lewat API atau dashboard hari ini.Konvensi data#
Sebelum membaca field mana pun, kenali tiga aturan penyimpanan yang berlaku di seluruh Termilo:
- Instant disimpan sebagai UTC epoch milidetik di kolom
INTEGERbersufiks_at_ms— mis.created_at_ms,starts_at_ms,hold_expires_at_ms. Bukan epoch detik. - Waktu-dalam-hari adalah menit sejak tengah malam:
start_minutedanend_minute(mis. 09:00 = 540). - Hari diwakili
weekdaybernilai0–6(0 = Minggu … 6 = Sabtu).
timezone (bawaan Asia/Jakarta). Epoch ms selalu UTC; zona waktu hanya dipakai untuk menampilkan dan menghitung jam operasional.Tenant (bisnis)#
Satu tenant adalah satu bisnis booking. Setiap baris data diisolasi berdasarkan tenant_id dan berada di shard D1 yang dipilih router control-plane (tenant_shard_routes / tenant_registry). Tabel tenants:
Layanan (event type)#
Sebuah layanan adalah hal yang bisa dibooking — sesi 1:1, kelas, meeting, atau konsultasi. Di standar penamaan Termilo istilahnya event type, tetapi di skema dan admin API resource-nya bernama services. Tidak ada tabel event_type terpisah. Tabel services:
Layanan bisa dikaitkan ke staf dan resource lewat tabel join. Detail kolomnya:
staff_id, tenant_id, user_id (boleh null), display_name, email, timezone, status. Dikaitkan ke layanan lewat join service_staff (kolom role, bawaan provider).resource_id, tenant_id, type, name, location_label, capacity (bawaan 1), status. Skema mengaitkannya lewat service_resources (kolom requirement_type, bawaan required) — tidak ada endpoint atau layar dashboard untuk mengisi tabel ini hari ini. capacity > 1 dipakai untuk booking kelas/grup.location_type, provider, external_meeting_id, join_url, display_label — label offline atau URL gabung dari Google Meet/Zoom, ditulis oleh consumer aksi provider. Pelanggan hanya menerima join_url; data khusus host tetap di server.Ketersediaan & jam operasional#
Ketersediaan dibentuk dari tiga sumber. Aturan ketersediaan (availability_rules) adalah jendela mingguan berulang — pemiliknya bisa tenant, staff, atau resource:
Dua sumber lain memotong jam itu:
- Blokir waktu (
blocked_times) — cuti satu kali:block_id,owner_type,owner_id,starts_at_ms,ends_at_ms,reason,status(active | cancelled). - Hari libur (
holidays) — penutupan se-tenant:holiday_id,name,starts_at_ms,ends_at_ms,timezone,status.
Slot#
Slot bukan tabel — ia dihitung. Mesin ketersediaan menghasilkan kandidat slot dari aturan dikurangi hari libur, blokir waktu, dan booking yang sudah ada. Setiap kandidat berbentuk { startsAtMs, endsAtMs, staffId|null, resourceId|null, capacityRemaining }.
finalAuthority: "booking_create_recheck_under_lock". Ketersediaan sebenarnya diuji ulang di bawah lock saat booking dibuat, sehingga dua orang tidak bisa mengambil waktu yang sama.Bentuk respons dari GET /book/:slug/availability (jendela dibatasi 31 hari):
Booking & status#
Sebuah booking (tabel bookings) menautkan layanan, customer, waktu, dan opsional staf/resource. Booking baru selalu dibuat dengan status held dan hold_expires_at_ms = now + 10 menit; jika tidak dikonfirmasi sebelum batas itu, hold kedaluwarsa dan slot dilepas.
Status & transisi
Lima status:heldconfirmedcompletedcancelledno_show
Status terminal — tidak bisa berubah lagi — adalah cancelled, completed, dan no_show. Transisi yang diizinkan:
| Dari | Ke | Aksi |
|---|---|---|
| held | confirmed | Konfirmasi booking |
| held · confirmed | cancelled | Batalkan booking |
| confirmed | completed | Tandai selesai |
| confirmed | no_show | Tandai tidak hadir |
| held · confirmed | (status tetap) | Reschedule — pindahkan waktu |
BOOKING_POLICY_BLOCKED. Reschedule mempertahankan status dan hanya memindahkan waktu.Membuat booking publik (header Idempotency-Key wajib; 201 untuk booking baru, 200 untuk replay idempoten):
Deposit & pembayaran#
AktifPembayaran deposit diproses lewat gateway bisnis (BYOK).
price_amount + price_currency pada services, lalu memilih tanpa deposit, nominal tetap, atau persentase. Pembayarannya masuk langsung ke rekening bisnis lewat gateway yang dihubungkan bisnis, bukan ke Termilo.Pengaturannya ada di editor layanan: persen “Minta deposit” per layanan (20% / 30% / 50%), toggle bawaan di Settings, dan halaman /checkout yang menurunkan default 30% saat layanan tidak menetapkan persentase eksplisit.
Customer#
Customer adalah pemesan, dan tidak perlu login. Saat membuat booking, wajib mengisi email ATAU phone (validasi createBookingSchema). Tabel customers:
customers dibuat implisit saat booking pertama, atau langsung lewat POST /api/customers dari dashboard. Daftar dan baca customer tersedia lewat GET /api/customers dan GET /api/customers/:customerId.