Referensi Developer E-Pondok
Sisi teknis E-Pondok — konsep, model data, pipeline kios, keamanan internal, arsitektur, dan HTTP API lengkap. Untuk setup produk langkah demi langkah, lihat Panduan Setup.
Pengenalan
E-Pondok adalah sistem kehadiran & relasi untuk pondok modern. Satu kios wajah di gerbang mencatat siapa yang datang dan pergi, buku tamu digital mengelola kunjungan, dan dashboard merangkai data itu jadi laporan serta peta relasi institusi yang hidup.
Dirancang untuk realitas pondok: bekerja di lokasi dengan jaringan tidak stabil (offline-first), tumbuh bersama banyak pondok (multi-tenancy), dan menjaga keamanan tanpa beban operasional yang berat.
Apa yang didapat
- Kehadiran wajah tanpa sentuh dengan deteksi arah masuk/keluar otomatis.
- Anti-spoofing — menolak foto, video, dan masker wajah palsu.
- Buku tamu digital dengan kategori, tujuan, dan kontribusi kunjungan.
- Manajemen relasi institusi: kontak, lembaga mitra, tag, dan tindak lanjut.
- Dashboard ringkasan + analitik kehadiran.
- Magic-link login tanpa password; setiap kios menandatangani permintaan.
Konsep inti
Pondok = tenan
Satu pondok adalah satu tenan (tenant) yang terisolasi. Setiap pondok mendapat subdomain sendiri — misal pondokabc.epondok.id — dan datanya tidak pernah bercampur dengan pondok lain meski berbagi satu basis data.
Tiga permukaan (surfaces)
- Apex — domain induk
epondok.id. Landing publik, pendaftaran, checkout, dan dokumentasi ini. - Platform — subdomain
platform.epondok.id. Admin super: kelola akun, berlangganan, dan menyediakan pondok baru. - Tenant — subdomain
*.epondok.id. Aplikasi admin per pondok (dashboard, kehadiran, pengunjung, relasi, perangkat).
Di lokal, localhost dan *.workers.dev dianggap tenant. Tambahkan ?surface=platform pada URL untuk memaksa permukaan platform saat pengembangan.
Peran (roles)
Person di pondok mempunyai salah satu peran berikut:
| santri | Pelajar/santri pondok |
| ustadz | Pengajar |
| staff | Staf operasional |
| pengurus | Pengurus pondok |
Peran admin di sisi aplikasi: admin (akses penuh termasuk Perangkat), pengurus, dan platform (super-admin di apex).
Kios
Kios adalah perangkat di gerbang — aplikasi desktop yang menjalankan pipeline wajah dan mencatat kehadiran/pengunjung. Setiap kios terdaftar dengan kunci publiknya sendiri dan menandatangani setiap permintaan.
Alur cepat
Dari nol hingga kehadiran otomatis dalam lima langkah.
Panduan produk lima langkah (daftar → langganan → buat pondok → pasang kios → daftar wajah → live), dengan pratinjau langsung tiap form, kini ada di Panduan Setup. Halaman ini menyimpan referensi teknis.
Dashboard
Halaman utama tenant. Ringkasan real-time dari seluruh modul. Sumber data: GET /api/dashboard.
Kartu ringkasan
- Kehadiran — hadir hari ini, absen, terlambat, total populasi, tren harian.
- Pengunjung — kunjungan hari ini, bulan ini, kunjungan dosen 3 tahun.
- Relasi — baru, mitra aktif, potensial, strategis, jaringan alumni.
- Follow-up — jumlah yang jatuh tempo.
Persons & enrollmen
Person = setiap individu di pondok (santri, ustadz, staff, pengurus). CRUD penuh lewat /api/persons.
Enrollmen wajah
Enrollmen menangkap wajah, mengubahnya menjadi embedding 512-dimensi, lalu menyimpannya di Vectorize. Saat enroll, opsi checkDuplicates mencegah wajah yang sama terdaftar dua kali, dan qualityScore mencatat kualitas tangkapan.
capture frame
→ anti-spoofing (MiniFASNet) // tolak foto/video/masker
→ embedding 512-d (InsightFace)
→ POST /api/persons/:id/enrollments
{ embedding, deviceId, qualityScore, checkDuplicates: true } -
POST /api/persons/:id/verify-face— mencocokkan embedding baru vs enrollmen person. -
DELETE /api/persons/:id/enrollments/:eid— nonaktifkan enrollmen lama (bukan hapus permanen).
Pipeline wajah asli butuh fitur cargo —features real-face. Tanpa fitur itu, kios memakai embedding mock di pengembangan.
Kehadiran
Inti produk. Kios menangkap wajah di gerbang → mencocokkan ke Vectorize → arah masuk/keluar dideteksi otomatis → event disimpan dengan skor kepercayaan (confidence) dan id perangkat (device_id).
Offline-first
Kios mencatat kehadiran meski jaringan putus, mengantrekannya secara lokal, lalu menyinkronkan otomatis saat online. Tidak ada absensi yang hilang karena gangguan jaringan.
Query
-
GET /api/attendance— daftar event (Paged), filterpersonId,role,from,to. -
GET /api/attendance/presence— siapa yang sedang di dalam. -
GET /api/attendance/analytics— daily entries/exits, top late, most punctual, filter window & role.
Pengunjung
Buku tamu digital. Setiap kunjungan dapat kategori, tujuan, check-in/out, dan nomor pengunjung (visitor_no).
Kategori
parent_guardianlecturerteachergovernment_officialcommunity_leaderalumnivendorgeneralother
Kontribusi kunjungan
Tiap kunjungan dapat mencatat kontribusi untuk pelaporan: workshop, guest_lecture, training, mentoring, community_service, research_collaboration, recruitment_opportunity, other — dengan topik, audiens, peserta, dan hasil.
Relasi institusi
Peta jejaring pondok agar tetap hidup dan terlacak.
Kontak
RelationshipContact menyimpan nama, lembaga, jabatan, keahlian, status (new / active / potential / alumni / strategic), dan catatan.
Tag kolaborasi
CollaborationTag (slug + label) bebas dilampir/lepas pada kontak untuk mengelompokkan mitra — mis. pengajar-tamu, beasiswa.
Follow-up
Tindak lanjut terjadwal: contact_id, due_date, assigned_to, status (open / in_progress / completed / cancelled). Filter overdue menyoroti yang sudah lewat jatuh tempo.
Perangkat
Halaman Perangkat (admin saja) mengelola kios. Setiap kios terdaftar dengan device_uid unik global, kunci publik Ed25519, dan opsional bound_network.
-
POST /api/devices/register— daftarkan kios baru. -
POST /api/devices/:id/revoke— cabut akses (kios tidak bisa sync lagi). -
POST /api/devices/:id/activate— aktifkan ulang. -
last_seen_atmelacak sinkronisasi terakhir.
device_uid unik lintas seluruh pondok (bukan per-pondok). Jangan gunakan UID yang sama untuk dua kios.
Kios desktop
Aplikasi desktop (Tauri) yang dipasang di perangkat gerbang. Menjalankan seluruh pipeline wajah secara lokal: tangkap frame → anti-spoofing → embedding → cocokkan → kirim event ke backend.
- UI layar-penuh untuk check-in cepat di gerbang.
- Daftar person & perangkat dimuat dari backend dengan token kios.
- Umpan balik visual (flash) & suara (TTS) saat wajah dikenali.
- Build
aarch64untuk Android layaknya (eksperimental).
Offline-first & sinkronisasi
Karena koneksi di pondok sering tidak stabil, kios tidak bergantung pada internet untuk mencatat. Antrian event lokal disinkronkan lewat rute device-authed (sync) saat koneksi pulih. Backend menerima idempotently — tidak ada ganda saat retry.
1. event dicatat lokal (kios offline)
2. masuk ke antrian sinkron
3. saat online → POST ke rute sync (ditandatangani Ed25519)
4. backend verifikasi tanda tangan + dedup
5. dashboard langsung memperbarui Anti-spoofing wajah
Sebelum embedding dibuat, frame diperiksa oleh MiniFASNet untuk membedakan wajah asli dari foto, video, atau masker. Hanya wajah asli (class index 1) yang diproses lebih lanjut.
Model anti-spoofing butuh input BGR mentah pada rentang [0, 255] — bukan tensor ternormalisasi. Pipeline kios menyiapkan frame sesuai itu.
Pembaruan otomatis
Kios memeriksa /kiosk/update.json untuk versi baru. Rilis disimpan di bucket R2 epondok-kiosk-releases dan dicatat di tabel kiosk_release. Updater bawaan Tauri mengunduh & memasang pembaruan, ditandatangani dengan kunci Tauri. Akun kios dipasangkan dengan pin b7e6.
Admin platform
Permukaan platform (platform.epondok.id) adalah ruang super-admin: menyediakan pondok baru, mengelola langganan, dan mengubah status pondok (active / suspended). Token platform terpisah dari token tenant — keduanya origin berbeda.
Multi-pondok
Satu sistem, banyak pondok. Setiap pondok mendapat subdomain & data terisolasi. Secara teknis: kolom pondok_id pada semua tabel tenan, resolver subdomain→pondok, dan JWT membawa pondokId sehingga setiap query terbatas pada pondok pemilik token.
Saat menambah tabel tenan baru, pondok_id + foreign key harus ikut sejak awal. Constraint global & FK di D1 tidak bisa diubah secara arbitrer pasca-fakta.
Harga & kursi
Tagihan berbasis kursi (seats) via Polar. Pembayaran bulanan, minimal 10 kursi.
| Rentang kursi | Per kursi / bln |
|---|---|
| 10–29 | $0.90 |
| 30–59 | $0.50 |
| 60–99 | $0.42 |
| 100 | $0.50 |
| 101+ | $0.30 |
Webhook Polar memakai spesifikasi Standard Webhooks (Svix) — tiga header + base64 signature, bukan polar-*. cancel = masa tenggat, revoke = segera. POLAR_WEBHOOK_SECRET wajib di produksi.
Login magic-link
Login tanpa password: minta link lewat email, klik untuk masuk. Link dikirim lewat Cloudflare Email binding. Password tetap disimpan (PBKDF2) sebagai jalur cadangan dan untuk admin platform.
PBKDF2 dibatasi 100.000 iterasi di Cloudflare Workers. PASSWORD_ITERATIONS default sudah menyesuaikan — jangan naikkan di atas batas itu.
Penandatanganan perangkat
Setiap kios memegang kunci privat Ed25519 dan mengirim kunci publiknya saat registrasi. Setiap permintaan sync/kehadiran ditandatangani; middleware deviceAuth memverifikasi tanda tangan sebelum memproses. Kios yang dicabut (revoked) ditolak mentah.
Isolasi tenan
Isolasi pondok dijaga berlapis: subdomain → pondok (resolver), pondok_id pada tiap baris, dan pondokId di JWT. Tidak ada titik akhir tenant yang bisa membaca data pondok lain. Semua lalu lintas terenkripsi saat transit (TLS).
Arsitektur
- Cloudflare Workers — edge API, serverless, global.
- D1 — basis data SQLite, multi-tenant via
pondok_id. - Vectorize — indeks embedding wajah 512-d untuk pencocokan cepat.
- Polar — langganan & checkout; Standard Webhooks untuk status.
- R2 — rilis kios (
epondok-kiosk-releases).
Backend pernah berjalan di Bun + Postgres + pgvector, lalu dimigrasikan ke Workers + D1 + Vectorize. Jejak lama mungkin terlihat di komentar atau skema — yang berjalan sekarang adalah versi Cloudflare.
Routing
epondok.id → apex (landing, /docs)
platform.epondok.id → platform (super-admin: provisioning, billing)
*.epondok.id → tenant (aplikasi admin per pondok)
localhost / *.workers.dev → tenant (dev) Model data
Entitas inti dan field kuncinya:
| Entitas | Field penting |
|---|---|
| Person | id, full_name, role, phone, active |
| EnrollmentRow | person_id, device_id, quality_score, active |
| AttendanceEvent | person_id, ts, event_type(entry/exit), confidence, device_id |
| Visitor | visitor_no, name, category, purpose, arrival_ts, departure_ts |
| VisitContribution | type, topic, audience, participants, outcomes |
| RelationshipContact | name, institution, status, tags |
| CollaborationTag | slug, label |
| FollowUp | contact_id, due_date, assigned_to, status |
| Device | device_uid, public_key, status, bound_network, last_seen_at |
| Pondok | id, slug, name, status |
Semua entitas tenan juga membawa pondok_id untuk isolasi.
Referensi API
API JSON di balik aplikasi. Semua rute daftar mengembalikan amplop terpaginasi:
{
"items": T[],
"total": number,
"limit": number,
"offset": number
} Contoh request dengan token:
curl -H "Authorization: Bearer [REDACTED:Authorization header] header] \
"https://pondokabc.epondok.id/api/attendance?from=2026-01-01&limit=50" Rute tenant
Autentikasi
/api/auth/loginPhone + password → { token, user }/api/auth/magic/requestSend a magic-link to email/api/auth/magic/verifyExchange magic-link token → { token, user }/api/auth/meCurrent admin sessionDashboard
/api/dashboardAttendance, visitor, relation, follow-up summaryPondok (publik)
/api/pondoksPondok list for the landing directoryPersons
/api/personsList (Paged<Person>) — role, active, q/api/persons/:idPerson detail/api/personsCreate person (full_name, role, phone)/api/persons/:idUpdate/api/persons/:idDelete (soft delete)Enrollmen wajah
/api/persons/:id/enrollmentsPerson's enrollment history/api/persons/:id/enrollmentsEnroll embedding (+ deviceId, qualityScore, checkDuplicates)/api/persons/:id/enrollments/:eidDeactivate enrollment/api/persons/:id/verify-faceMatch embedding vs person's enrollmentsKehadiran
/api/attendanceEvent list (Paged) — personId, role, from, to/api/attendance/presenceWho is currently inside/api/attendance/analyticsWindow analytics — daily, top late, most punctualPengunjung
/api/visitorsList (Paged) — category, from, to, open, q/api/visitors/:idVisit detail/api/visitorsCheck-in (name, phone, category, purpose, …)/api/visitors/:id/checkoutCheck-out/api/visitors/:id/contributionsVisit contributions/api/visitors/:id/contributionsRecord contribution (type, topic)Relasi
/api/contactsContact list (Paged) — q, status, institution, tag/api/contacts/:idContact detail/api/contactsCreate contact (name, phone)/api/contacts/:idUpdate/api/contacts/:id/tagsAttach tag (slug)/api/contacts/:id/tags/:slugDetach tag/api/contacts/:id/follow-upsContact follow-upsFollow-up
/api/follow-upsList (Paged) — status, overdue/api/follow-upsCreate (contact_id, due_date, assigned_to)/api/follow-ups/:idUpdate status / due dateTag
/api/tagsList collaboration tags/api/tagsCreate tag (slug, label)Perangkat
/api/devicesList (Paged) — q, status (admin)/api/devices/registerRegister kiosk (device_uid, public_key, bound_network)/api/devices/:id/revokeRevoke access/api/devices/:id/activateReactivateRute platform (apex)
Platform (apex)
/api/platform/registerRegister platform account (name, email, password)/api/platform/loginPlatform login/api/platform/magic/requestPlatform magic-link/api/platform/magic/verifyVerify platform magic-link/api/platform/meCurrent platform session/api/platform/slug/checkCheck pondok slug availability/api/platform/checkoutCreate Polar checkout session (seats)/api/platform/pondokList pondok owned by the account/api/platform/pondokCreate a new pondok (slug, name)/api/platform/pondok/:idUpdate pondok name / statusRute kiosk & sync dipakai kios dan dilindungi tanda tangan Ed25519, bukan token admin. Tidak didokumentasikan untuk pemakaian langsung.