Alur dan logika sistem
Semua aturan di bawah ditegakkan di backend Convex. Tampilan di browser hanya membantu memilih; server tetap memeriksa ulang setiap permintaan. Kode acuannya ada di convex/ dan aturan bersama di convex/lib/.
Gambaran besar
Tiga peran, satu sumber data
Pengguna mengajukan, petugas memutuskan dan menindaklanjuti, admin mengelola data dan akun. Semua membaca data yang sama di Convex, jadi perubahan satu peran langsung terlihat di layar peran lain.
flowchart LR
P([Pengunjung]) -->|lihat katalog dan slot| K[Katalog fasilitas]
U([Pengguna]) -->|ajukan| R[Reservasi]
U -->|lapor + foto| L[Laporan]
T([Petugas]) -->|setujui / tolak / batalkan| R
T -->|tangani / selesaikan| L
T -->|jadwalkan| M[Jadwal perbaikan]
A([Admin]) -->|kelola| F[Fasilitas]
A -->|verifikasi| AK[Akun]
A -->|rekap + CSV| X[Analitik]
R --> DB[(Convex)]
L --> DB
M --> DB
F --> DB
AK --> DB
DB -->|update real-time| K- Pengunjung tanpa akun hanya bisa melihat katalog dan slot yang terisi, tanpa nama pemohon atau tujuan.
- Admin juga bisa melakukan semua tindakan petugas.
- Setiap tindakan penting dicatat di tabel
auditEvents.
Perjalanan satu permintaan
Contoh: pengguna mengirim reservasi. Browser memanggil fungsi Convex langsung dengan token sesi; fungsi itu memeriksa identitas, status akun, peran, dan aturan sebelum menulis apa pun.
sequenceDiagram
actor B as Browser
participant N as Next.js
participant A as Better Auth
participant C as Convex function
participant D as Convex DB
B->>N: Masuk (email + password)
N->>A: Proxy /api/auth
A-->>B: Cookie sesi (HttpOnly)
B->>C: reservations.create + JWT
C->>C: Cek sesi, akun aktif, peran "user"
C->>D: Cek bentrok (index by_facility_status_start)
C->>D: Simpan "pending" + auditEvents
D-->>B: Query berlangganan ikut berubah- Satu mutation = satu transaksi: kalau satu pemeriksaan gagal, tidak ada yang tersimpan.
- Data tidak dihapus destruktif; status yang berubah.
Akun
Status akun
Daftar mandiri menghasilkan akun pending yang belum bisa masuk portal. Admin menyetujui atau menolak (alasan wajib). Akun buatan admin langsung active dengan password sementara.
stateDiagram-v2
[*] --> pending: Daftar mandiri
[*] --> active: Dibuat admin (wajib ganti password)
pending --> active: Admin menyetujui
pending --> rejected: Admin menolak + alasan
active --> disabled: Admin menonaktifkan + alasan
disabled --> active: Admin mengaktifkan lagi
rejected --> [*]- Admin tidak bisa menonaktifkan akunnya sendiri.
- Akun
pending,rejected, dandisableddiarahkan ke halaman status akun, bukan portal.
Masuk ke portal
Setelah login, server membaca profil lalu mengarahkan ke portal sesuai peran. Halaman portal memeriksa ulang di server, jadi URL tidak bisa ditebak untuk masuk.
flowchart TD
L[Login berhasil] --> S{Status akun aktif?}
S -- Tidak --> ST[/Halaman status akun/]
S -- Ya --> R{Peran}
R -- user --> APP[/Portal pengguna /app/]
R -- officer --> STAFF[/Portal petugas /staff/]
R -- admin --> ADM[/Portal admin /admin/]
APP --> G{Halaman butuh peran lain?}
STAFF --> G
ADM --> G
G -- Ya --> F[/403 Forbidden/]
G -- Tidak --> OK[Tampilkan halaman]- Pemeriksaan yang sama diulang di setiap fungsi Convex (
requireRole). - Satu perangkat bisa menyimpan hingga 5 akun dan berpindah tanpa login ulang.
Reservasi
Mengajukan reservasi
Server memeriksa urutan aturan ini. Reservasi yang baru diajukan berstatus pending dan belum memblokir slot bagi pengguna lain.
flowchart TD
A[Pengguna kirim reservasi] --> B{Fasilitas aktif?}
B -- Tidak --> X1[Ditolak: tidak dapat dipesan]
B -- Ya --> C{07.00–20.00 WIB, satu hari, kelipatan 30 menit?}
C -- Tidak --> X2[Ditolak: waktu tidak valid]
C -- Ya --> D{Di masa mendatang?}
D -- Tidak --> X3[Ditolak]
D -- Ya --> E{Bentrok reservasi disetujui?}
E -- Ya --> X4[Ditolak: slot sudah dipakai]
E -- Tidak --> F{Bentrok jadwal perbaikan?}
F -- Ya --> X5[Ditolak: bertepatan dengan perbaikan]
F -- Tidak --> G[Tersimpan sebagai Menunggu]- Beberapa pengajuan menunggu boleh menumpuk di slot yang sama; petugas yang memilih.
- Tujuan penggunaan wajib diisi.
Status reservasi
Begitu petugas menyetujui satu reservasi, semua pengajuan menunggu yang bentrok dengannya otomatis ditolak sistem dengan catatan yang jelas.
stateDiagram-v2
[*] --> pending: Pengguna mengajukan
pending --> approved: Petugas menyetujui
pending --> rejected: Petugas menolak
pending --> rejected: Otomatis, kalah oleh reservasi lain yang disetujui
pending --> cancelled: Pengguna / petugas membatalkan
approved --> cancelled: Pengguna (min. 1 jam sebelum) atau petugas + alasan
approved --> [*]
rejected --> [*]
cancelled --> [*]- Pengguna hanya bisa membatalkan minimal 1 jam sebelum mulai.
- Petugas yang membatalkan wajib menulis alasan.
- Penolakan otomatis dicatat di audit sebagai aktor
system.
Persetujuan dan penolakan otomatis
Saat petugas menekan Setujui, server memeriksa ulang bentrok di dalam transaksi yang sama, jadi dua petugas yang menyetujui bersamaan tidak bisa menghasilkan dua reservasi di slot yang sama.
sequenceDiagram
actor P as Petugas
participant C as reservations.decide
participant D as Convex DB
P->>C: Setujui reservasi R1 (10.00–12.00)
C->>D: Ada reservasi disetujui yang bentrok?
alt Sudah ada
C->>D: R1 ditolak otomatis
else Kosong
C->>D: Ada jadwal perbaikan di waktu itu?
C->>D: R1 = Disetujui
C->>D: R2, R3 (menunggu, bentrok) = Ditolak otomatis
end
D-->>P: Antrean langsung diperbarui- Reservasi yang bersebelahan (10.00–12.00 dan 12.00–13.00) tidak dianggap bentrok.
Laporan fasilitas
Status laporan
Laporan baru berstatus pending. Menyelesaikan atau menolak wajib disertai catatan penanganan, dan status yang sudah ditutup tidak bisa dibuka lagi.
stateDiagram-v2
[*] --> pending: Pengguna melapor (+ foto opsional)
pending --> in_progress: Petugas mulai menangani
pending --> rejected: Petugas menolak + catatan
in_progress --> resolved: Petugas menyelesaikan + catatan
in_progress --> rejected: Petugas menolak + catatan
resolved --> [*]
rejected --> [*]- Foto maksimal 5 MB, hanya JPG, PNG, atau WebP; server memeriksa ulang metadata file.
- Saat laporan ditutup, jadwal perbaikan yang terkait ikut diakhiri.
Dari laporan ke perbaikan
Klik Mulai tangani berarti pekerjaan mulai sekarang. Dialog meminta dampak dan keterangan publik; pekerjaan berbahaya tidak harus menunggu slot kosong.
flowchart LR
A[Laporan masuk] --> B[Petugas: Mulai tangani]
B --> C{Perlu menutup ruang?}
C -- Tidak --> E[Gangguan + notifikasi, slot tetap terbuka]
C -- Ya --> D[Penutupan keselamatan sekarang]
D --> F[Batalkan booking terdampak + notifikasi]
E --> G[Selesaikan laporan + catatan]
F --> G
G --> H{Semua pekerjaan tertutup selesai dan aman?}
H -- Ya --> I[Buka closure penanganan, booking lama tetap batal]
H -- Tidak --> F- Perbaikan yang sudah berjalan diakhiri saat itu juga; yang belum mulai dibatalkan.
- Closure manual memerlukan reopen tersendiri. Estimasi tidak otomatis membuka closure.
Jadwal perbaikan
Aturan utama
Untuk jadwal perbaikan terencana, perbaikan hanya mengambil waktu kosong. Ini berbeda dari penutupan keselamatan pada pekerjaan yang tidak aman.
flowchart TD
S[Petugas pilih fasilitas, tanggal, jam mulai-selesai, alasan] --> V{Kelipatan 30 menit, belum lewat, maks 7 hari?}
V -- Tidak --> XV[Ditolak: waktu tidak valid]
V -- Ya --> K{Bentrok reservasi DISETUJUI?}
K -- Ya --> XK[Ditolak: pilih waktu yang kosong]
K -- Tidak --> P{Bentrok reservasi MENUNGGU?}
P -- Ya --> XP[Ditolak: setujui atau tolak dulu di antrean]
P -- Tidak --> M{Bentrok jadwal perbaikan lain?}
M -- Ya --> XM[Ditolak]
M -- Tidak --> OK[Tersimpan: slot itu tertutup untuk reservasi]- Reservasi yang sudah disetujui tetap berjalan; perbaikan harus mencari waktu lain.
- Pengajuan menunggu tidak ditolak diam-diam oleh sistem; petugas yang memutuskannya dulu.
- Jam lain di hari yang sama tetap bisa dipesan.
Status jadwal perbaikan
Jam selesai wajib diisi sebagai perkiraan. Jadwal berakhir otomatis di jam itu lewat scheduled function Convex, atau lebih cepat kalau petugas menekan Selesai.
stateDiagram-v2
[*] --> scheduled: Dijadwalkan (waktu kosong)
scheduled --> scheduled: Diperpanjang (tambahan waktu juga harus kosong)
scheduled --> completed: Jam selesai tiba (otomatis)
scheduled --> completed: Petugas klik Selesai saat berjalan
scheduled --> cancelled: Dibatalkan sebelum mulai
scheduled --> completed: Laporan terkait ditutup (sudah mulai)
scheduled --> cancelled: Laporan terkait ditutup (belum mulai)
completed --> [*]
cancelled --> [*]- Status "Berlangsung" atau "Terjadwal" dihitung dari jam sekarang terhadap rentang
startAt–endAt. - Satu jadwal maksimal 7 hari; pekerjaan yang memerlukan penutupan tanpa kepastian selesai memakai Penutupan fasilitas, bukan memaksakan estimasi.
Contoh kasus: kelas sudah direservasi lalu perlu diperbaiki
Reservasi yang sudah disetujui tetap jalan. Perbaikan dijadwalkan di waktu kosong berikutnya, dan selama perbaikan slot itu tidak bisa direservasi.
sequenceDiagram
actor U as Pengguna
actor P as Petugas
participant S as Sthana (Convex)
U->>S: Reservasi Aula, Senin 08.00–10.00
P->>S: Setujui
S-->>U: Disetujui
Note over P: Laporan masuk: AC Aula rusak
P->>S: Jadwalkan perbaikan Senin 09.00–12.00
S-->>P: Ditolak: bentrok dengan reservasi 08.00–10.00
P->>S: Jadwalkan perbaikan Senin 10.00–14.00
S-->>P: Tersimpan
U->>S: Reservasi Aula, Senin 13.00
S-->>U: Ditolak: bertepatan dengan perbaikan
Note over U,S: 08.00–10.00 tetap dipakai sesuai reservasi
P->>S: Selesai pukul 12.00
S-->>U: Slot 12.00 dan seterusnya bisa dipesan lagi- Kalau perbaikan butuh lebih lama, petugas memperpanjang; tambahan waktunya juga harus kosong.
Data jadwal perbaikan
Jadwal perbaikan disimpan di tabel sendiri, terhubung ke fasilitas dan, bila dibuat dari laporan, ke laporan itu.
erDiagram
FACILITY ||--o{ RESERVATION : dipesan
FACILITY ||--o{ MAINTENANCE_WINDOW : diperbaiki
REPORT |o--o{ MAINTENANCE_WINDOW : memicu
PROFILE ||--o{ MAINTENANCE_WINDOW : menjadwalkan
MAINTENANCE_WINDOW {
id facilityId
id reportId "opsional"
string reason
number startAt
number endAt
string status "scheduled, completed, cancelled"
id createdBy
}- Index
by_facility_status_startdipakai untuk cek bentrok, sama seperti reservasi. - Status fasilitas lama
maintenance(menutup seluruh fasilitas) tidak bisa dipasang lagi; admin hanya bisa mengaktifkannya kembali.
Hak akses
Siapa boleh melakukan apa
Setiap fungsi Convex memanggil requireRole sebelum membaca atau menulis data. Tombol yang disembunyikan di UI bukan satu-satunya pengaman.
flowchart LR
subgraph Pengguna
U1[Ajukan / batalkan reservasi sendiri]
U2[Buat laporan + foto]
end
subgraph Petugas
O1[Setujui / tolak / batalkan reservasi]
O2[Tangani laporan]
O3[Jadwalkan / perpanjang / akhiri perbaikan]
end
subgraph Admin
A1[Semua tindakan petugas]
A2[Kelola fasilitas]
A3[Verifikasi dan kelola akun]
A4[Rekap + ekspor CSV]
end
Pengunjung[Pengunjung tanpa akun] --> V[Katalog + slot terisi, tanpa data pribadi]- Query pengguna selalu memakai ID profil dari sesi, bukan ID kiriman browser.
- Ekspor CSV memeriksa sesi dan peran admin di server.