← Semua laporan MASJID APP

F0 · v0.1/Keputusan & kontrak/MASJID APP

Kontrak Konten & API

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.

01Keputusan
tak bisa dibatalkan

Struktur URL

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.

PilihanUntungRugi
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.

Aturan bentuk slug

  • 3–40 karakter, hanya a-z, 0-9, dan tanda hubung. Tidak diawali atau diakhiri tanda hubung, tidak ada dua hubung berurutan.
  • Bukan angka semua. 2024 ditolak — akan tabrakan dengan halaman arsip platform di kemudian hari.
  • Ditolak juga jika identik dengan kata terkunci setelah tanda hubung dihapus. mas-jid ditolak karena sama dengan masjid. Tanpa aturan ini daftar terkunci gampang diakali.
  • Boleh diubah, tapi meninggalkan jejak. Slug lama disimpan permanen di tabel riwayat dan selamanya dialihkan permanen ke yang baru. Slug lama tidak pernah bisa diambil masjid lain.

Aturan kanonik

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.

02279 kata
terkunci

Daftar kata yang tidak boleh diambil masjid

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.

Infrastruktur & teknis

apiwwwcdnstaticassetsauthoauthwebhookhealthstatussitemaprobotswell-knownstaging+ 40 lainnya

Halaman platform (Indonesia & Inggris)

masukdaftarhargabantuantentangkontakprivasisyaratloginpricingdocsdashboardterms+ 90 lainnya

Kata produk yang harus tetap milik platform

masjidjamaahtakmirdonasizakatinfaksedekahwakafkajianjadwalsholatadzanquranlaporantvdisplay+ 30 lainnya

Kata umum & sakral

allahmuhammadnabirasulislammuslimumatindonesianasionalpusatresmiofficial

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.

Cadangan merek

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.

03Mekanisme
inti

Satu record, empat kanal

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.

Konsol Konten pengurus masjid simpan Record bertipe Event · Lecture · Program Announcement · Laporan PostgreSQL · tenant_id + RLS /v1/public Web masjid SSR · terindeks mesin pencari TV Display layar di dalam masjid Aplikasi jamaah Flutter · iOS & Android otomatis saat disimpan ContentIndex potongan teks + vektor jawab + sitasi Asisten masjid di halaman publik · fase F3
Jalur bergaris putus berwarna adalah lapisan yang baru dinyalakan di F3 — tapi tabel dan pemicunya dipasang di F0. Memasang indeks setelah ribuan konten masuk berarti memproses ulang seluruh arsip; memasangnya sekarang hanya beberapa baris migrasi.
0412 entitas
publik

Peta entitas

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.

EntitasPeranCatatan rancangan
TenantMasjidAkar isolasi. Menyimpan slug, domain, koordinat, zona waktu, tema.
OrganizationYayasan indukOpsional. Sudah ada sekarang supaya konsolidasi antar-unit di F5 tidak perlu migrasi.
PersonPengurus, imam, penceramahSatu tabel dengan larik peran. Penceramah tamu tercatat tanpa harus jadi pengurus.
FacilityFasilitas masjidKecil, tapi ini yang dicari orang yang belum pernah datang.
AnnouncementPengumumanPunya tingkat kepentingan dan jendela tayang. Yang bertanda darurat langsung naik ke TV display.
EventKegiatan & kajian terjadwalBerulang memakai RRULE. Server yang menguraikannya, bukan klien.
LectureArsip kajianSengaja dipisah dari Event: Event terjadi sekali, Lecture hidup terus dan jadi bahan artikel.
ArticleArtikel & beritaMarkdown, bukan HTML bebas. Punya penanda kalau lahir dari transkrip.
ProgramProgram donasiMembawa rincian rencana penggunaan — ditampilkan sebelum orang menyumbang, bukan sesudah.
DonationKonfirmasi transferCatatan konfirmasi, bukan saldo. Baru menambah jumlah terkumpul setelah diverifikasi pengurus.
FinancialReportLaporan publikBentuknya dibekukan di F4. Diisi manual di F2, dihasilkan modul keuangan di F5 — halaman tidak tahu bedanya.
PrayerTimeJadwal sholatSatu baris per masjid per tanggal, dengan koreksi menit per waktu. Di-cache supaya TV display tidak menghitung ulang.

Pendukung

User, Membership (peran per masjid), MediaAsset, Fund dan BankAccount (dana & rekening — berdiri sejak sekarang meski modul keuangan beku di MVP), SlugHistory, dan ContentIndex.

05Aturan
mengikat

Enam aturan yang berlaku di seluruh kontrak

  • Uang selalu bilangan bulat dalam satuan terkecil, disertai kolom mata uang. Tidak pernah pecahan desimal. Struktur sudah siap multi-mata-uang meski operasional rupiah dulu.
  • Setiap objek publik membawa canonicalUrl. Dipakai tag kanonik halaman sekaligus sitasi jawaban asisten. Tanpa ini, asisten AI menjawab tanpa bisa menunjuk sumbernya.
  • Kejadian berulang diuraikan di server. Klien tidak pernah memproses RRULE sendiri — kalau tidak, web, TV display, dan aplikasi jamaah akan menghasilkan tiga versi kalender yang berbeda.
  • Platform tidak pernah memegang dana. Endpoint donasi mencatat konfirmasi transfer ke rekening masjid. Respons mengembalikan status menunggu, dan halaman dilarang menampilkannya sebagai donasi yang sudah masuk.
  • Menghapus berarti mengarsipkan. Tidak ada baris konten yang benar-benar hilang — jejaknya tetap ada.
  • Alt-text wajib untuk setiap gambar. Boleh dihasilkan AI di F3, tapi kolomnya wajib sejak sekarang. Menambahkannya belakangan berarti menyisir ribuan gambar lama.

Dua endpoint bundel, dan alasannya

/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.

06Batas
v0.1

Yang sengaja belum ada

  • Alur autentikasi rinci — hanya skema bearer yang ditetapkan. Alur masuk, undangan pengelola, dan penyegaran token menyusul di awal F0 setelah penyedia identitas dipilih.
  • Alur unggah media — endpoint donasi sudah merujuk proofUploadId, tapi mekanisme unggah langsung ke penyimpanan objek belum ditulis.
  • Pencarian lintas masjid — direktori sudah ada; pencarian teks penuh lintas tenant menunggu data nyata untuk diuji.
  • Kolom bahasa — struktur sudah siap RTL untuk teks Arab, tapi kontrak masih satu bahasa. Terjemahan menyusul saat ada masjid yang membutuhkannya.
  • Webhook keluar — belum diperlukan sampai ada integrasi pihak ketiga.

Cara memperlakukan versi ini: permukaan /v1/public/** diperlakukan sebagai janji — kalau berubah, semua kanal ikut berubah. Permukaan konsol boleh bergerak bebas sampai F2 selesai.

07Berkas

Tiga berkas yang menyertai halaman ini

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.