F0 · v0.1/Keputusan & kontrak/MASJID APP
Ini artefak yang saya sebut paling berharga di seluruh proyek: bentuk data dan bentuk permukaan API, ditulis sebelum satu baris kode. Selama dokumen ini berdiri, web masjid, TV display, aplikasi jamaah, dan asisten AI tidak bisa lagi berkembang ke arah yang berbeda-beda.
Isinya dua keputusan yang tidak bisa dibatalkan setelah masjid pertama membagikan tautannya — struktur URL dan daftar kata terkunci — serta dua belas entitas publik dan dua puluh delapan operasi API yang menyusun seluruh lapisan web.
Alamat masjid akan dicetak di spanduk, dibacakan lewat pengeras suara, dan ditempel di grup WhatsApp. Bentuknya menentukan seberapa mudah ia menyebar — dan tidak bisa diubah setelah menyebar.
| Pilihan | Untung | Rugi |
|---|---|---|
| domain.id/<slug> DIPILIH |
Sependek mungkin. Bisa diucapkan lisan tanpa dieja. Otoritas pencarian menumpuk di satu domain dan mengangkat semua masjid di dalamnya. | Namespace berbagi dengan halaman platform. Setiap halaman baru harus mengambil dari daftar terkunci. |
| domain.id/m/<slug> | Namespace bersih. Platform bebas menambah halaman kapan pun tanpa risiko bentrok. | Dua karakter yang harus dijelaskan setiap kali alamatnya diucapkan. Untuk produk yang menyebar dari mulut ke mulut, ini bukan biaya kecil. |
| <slug>.domain.id | Isolasi paling bersih, cookie terpisah per masjid. | Otoritas pencarian terpecah ke ratusan subdomain — justru membuang keunggulan terbesar model terpusat. |
Diputuskan: path langsung domain.id/<slug>, dengan konsekuensi yang diterima sadar — daftar kata terkunci dibekukan sekarang dan hanya boleh bertambah, tidak pernah berkurang.
a-z, 0-9, dan tanda hubung. Tidak diawali atau diakhiri tanda hubung, tidak ada dua hubung berurutan.2024 ditolak — akan tabrakan dengan halaman arsip platform di kemudian hari.mas-jid ditolak karena sama dengan masjid. Tanpa aturan ini daftar terkunci gampang diakali.Selama masjid memakai alamat platform, halaman kanoniknya domain.id/<slug>. Begitu domain sendiri aktif dan terverifikasi, kanonik pindah ke sana dan alamat lama dialihkan permanen. Ini pilihan sadar: menumpuk otoritas dulu di domain induk, menyerahkannya kemudian — dan itulah kenapa custom domain sebaiknya jadi fitur berbayar di fase akhir, bukan janji di awal.
Enam kelompok. Aturannya satu: daftar ini hanya boleh bertambah. Menghapus satu kata berarti membuka kemungkinan bentrok dengan halaman platform di masa depan — dan pada saat itu masjid yang terlanjur memakainya sudah mencetak alamatnya.
Kenapa kelompok terakhir ada. Bukan soal teknis. Satu masjid yang memegang domain.id/islam atau domain.id/nabi akan terbaca seolah platform mengafiliasi diri pada satu pihak, dan istilah yang dipakai bersama jadi milik satu pemakai pertama. Lebih baik ditutup sejak awal daripada dicabut dari masjid yang sudah memakainya.
Nama merek platform dan variannya wajib ditambahkan ke daftar ini pada hari nama itu diputuskan — termasuk support-<merek>, <merek>-id, dan sejenisnya. Ini butir yang paling sering terlupa dan paling mahal saat terlupa.
Ini alasan teknis di balik prinsip "konten itu record, bukan halaman". Pengurus menambah satu kajian sekali; empat kanal membacanya dari sumber yang sama. Kalau konten disimpan sebagai HTML bebas, tiga panah di sebelah kanan putus.
Setiap baris di bawah ini adalah tabel dengan tenantId yang dijaga Row-Level Security PostgreSQL — bukan hanya filter di kode. Satu where yang lupa ditulis tidak boleh bisa membocorkan data masjid lain.
| Entitas | Peran | Catatan rancangan |
|---|---|---|
| Tenant | Masjid | Akar isolasi. Menyimpan slug, domain, koordinat, zona waktu, tema. |
| Organization | Yayasan induk | Opsional. Sudah ada sekarang supaya konsolidasi antar-unit di F5 tidak perlu migrasi. |
| Person | Pengurus, imam, penceramah | Satu tabel dengan larik peran. Penceramah tamu tercatat tanpa harus jadi pengurus. |
| Facility | Fasilitas masjid | Kecil, tapi ini yang dicari orang yang belum pernah datang. |
| Announcement | Pengumuman | Punya tingkat kepentingan dan jendela tayang. Yang bertanda darurat langsung naik ke TV display. |
| Event | Kegiatan & kajian terjadwal | Berulang memakai RRULE. Server yang menguraikannya, bukan klien. |
| Lecture | Arsip kajian | Sengaja dipisah dari Event: Event terjadi sekali, Lecture hidup terus dan jadi bahan artikel. |
| Article | Artikel & berita | Markdown, bukan HTML bebas. Punya penanda kalau lahir dari transkrip. |
| Program | Program donasi | Membawa rincian rencana penggunaan — ditampilkan sebelum orang menyumbang, bukan sesudah. |
| Donation | Konfirmasi transfer | Catatan konfirmasi, bukan saldo. Baru menambah jumlah terkumpul setelah diverifikasi pengurus. |
| FinancialReport | Laporan publik | Bentuknya dibekukan di F4. Diisi manual di F2, dihasilkan modul keuangan di F5 — halaman tidak tahu bedanya. |
| PrayerTime | Jadwal sholat | Satu baris per masjid per tanggal, dengan koreksi menit per waktu. Di-cache supaya TV display tidak menghitung ulang. |
User, Membership (peran per masjid), MediaAsset, Fund dan BankAccount (dana & rekening — berdiri sejak sekarang meski modul keuangan beku di MVP), SlugHistory, dan ContentIndex.
canonicalUrl. Dipakai tag kanonik halaman sekaligus sitasi jawaban asisten. Tanpa ini, asisten AI menjawab tanpa bisa menunjuk sumbernya./home dan /display mengembalikan seluruh isi satu layar dalam satu permintaan. Ini terlihat seperti pelanggaran kerapian REST, dan memang disengaja: beranda yang dirender di server tidak boleh menunggu enam permintaan berantai, dan TV display di jaringan masjid yang lambat lebih baik gagal atau berhasil sekali daripada setengah-setengah. Keputusan performa, bukan kenyamanan.
proofUploadId, tapi mekanisme unggah langsung ke penyimpanan objek belum ditulis.Cara memperlakukan versi ini: permukaan /v1/public/** diperlakukan sebagai janji — kalau berubah, semua kanal ikut berubah. Permukaan konsol boleh bergerak bebas sampai F2 selesai.
openapi.yaml
25 jalur, 28 operasi, 35 skema. Sudah divalidasi — seluruh rujukan internal terselesaikan, tidak ada skema menganggur. Bisa langsung dibangkitkan jadi tipe untuk SvelteKit dan Flutter.
schema.prisma
Model data lengkap dengan indeks, enum, dan komentar alasan di tiap keputusan yang tidak jelas dari namanya.
reserved-slugs.txt
279 kata terkunci dalam enam kelompok, plus aturan pola yang ditolak. Tinggal dibaca program validasi slug.