Logo Doa & Tahlil Bersama
Masuk

Petunjuk Implementasi

PETUNJUK IMPLEMENTASI
Aplikasi Doa & Tahlil Bersama — doa.wasiat.org

=====================================================================
1. PRASYARAT
=====================================================================
- PHP 8.1 atau lebih baru, dengan ekstensi: pdo_pgsql, mbstring, fileinfo,
  openssl, json
- PostgreSQL 13 atau lebih baru
- Apache dengan mod_rewrite dan mod_headers aktif
- Sertifikat HTTPS aktif untuk doa.wasiat.org
  (kamera, geolokasi, service worker, dan Web Push hanya berfungsi di HTTPS)

=====================================================================
2. BERKAS KONFIGURASI DI LUAR WEB ROOT
=====================================================================
Buat berkas kredensial basis data. Aplikasi mencari pada urutan berikut
dan memakai yang pertama ditemukan:

  /home/wasiator/configdb/dbtopdoa.php
  /home/wasiator/configdb/topdbdoa.php
  /home/wasiator.configdb/dbtopdoa.php
  /home/wasiator.configdb/topdbdoa.php

CATATAN: dokumen sumber menyebut dua nama berkas yang berbeda
(topdbdoa.php dan dbtopdoa.php) serta dua ejaan folder yang berbeda.
Aplikasi mendukung keempatnya, tetapi sebaiknya ditetapkan satu saja.

Isi berkas:

  <?php
  return [
      'host' => '127.0.0.1',
      'port' => 5432,
      'name' => 'wasiator_misc007',
      'user' => 'NAMA_USER_POSTGRES',
      'pass' => 'KATA_SANDI_POSTGRES',

      'superadmin_user'     => 'superadmin',
      'superadmin_email'    => 'alamat@email.anda',
      'superadmin_password' => 'KATA_SANDI_AWAL_MINIMAL_12_KARAKTER',

      'google_client_id'    => 'xxxxx.apps.googleusercontent.com',
  ];

Lalu berkas email pada folder yang sama, bernama emaildoa.php:

  <?php
  return [
      'method'     => 'smtp',            // atau 'mail'
      'host'       => 'smtp.domain.com',
      'port'       => 587,
      'encryption' => 'tls',
      'username'   => 'no-reply@doa.wasiat.org',
      'password'   => 'KATA_SANDI_SMTP',
      'from'       => 'no-reply@doa.wasiat.org',
      'from_name'  => 'Doa & Tahlil Bersama',
  ];

Atur hak akses agar hanya pemilik yang dapat membaca:

  chmod 600 /home/wasiator/configdb/*.php

=====================================================================
3. PEMASANGAN — DUA CARA
=====================================================================
PENGHAPUSAN TABEL DILAKUKAN MANUAL OLEH ADMINISTRATOR.
Tidak ada satu pun berkas dalam paket ini yang menghapus tabel.
Tidak ada DROP TABLE, DROP SCHEMA, maupun TRUNCATE.

Urutan langkahnya sama pada kedua cara:
  1. Pasang skema  (47 tabel, trigger, indeks)
  2. Isi data awal (peran, otorisasi, konfigurasi, template notifikasi)
  3. Semai Superadmin

---------------------------------------------------------------------
CARA A — LEWAT PHP DI BARIS PERINTAH  (dianjurkan)
---------------------------------------------------------------------
Tidak memerlukan psql sama sekali. Berkas SQL dijalankan melalui PDO.

  cd /home/wasiator/doa.wasiat.org

  php cli/install.php --status       # periksa keadaan, tidak mengubah apa pun
  php cli/install.php --all          # skema + data awal + superadmin

Atau satu per satu bila ingin bertahap:

  php cli/install.php --schema
  php cli/install.php --trigger
  php cli/install.php --seed
  php cli/install.php --superadmin

Perintah --status menampilkan versi PostgreSQL, versi PHP, jumlah tabel,
kelengkapan ekstensi PHP, hak tulis folder storage, dan langkah
berikutnya yang perlu dijalankan.

PENGAMAN: bila tabel aplikasi sudah ada, langkah skema berhenti dengan
pesan jelas dan tidak mengubah apa pun. Begitu pula data awal bila peran
sudah terisi. Menjalankan ulang perintah tidak merusak data.

---------------------------------------------------------------------
CARA B — LEWAT PERAMBAN  (bila hosting tanpa akses SSH)
---------------------------------------------------------------------
Berkas install.php menyediakan pemasang bergambar. Pemasang ini MATI
secara bawaan dan hanya menyala melalui langkah berikut.

  1. Tambahkan kunci berikut pada berkas konfigurasi di luar web root,
     berisi untaian acak yang panjang:

        'install_token' => 'untaian-acak-minimal-32-karakter',

  2. Buka di peramban:

        https://doa.wasiat.org/install.php?token=untaian-acak-minimal-32-karakter

  3. Tekan tombol pada setiap langkah secara berurutan.

  4. Setelah selesai, tekan "Kunci pemasang", lalu HAPUS berkas
     install.php dari server, dan hapus install_token dari konfigurasi.

Lapisan pengaman pemasang web:
  - Mati bila install_token belum diisi (mengembalikan 404)
  - Token dibandingkan dengan hash_equals, salah token ditolak 403
  - Perlindungan CSRF pada setiap tombol
  - Mengunci diri melalui storage/.installed setelah dipakai
  - Tidak pernah menghapus tabel
  - Setiap percobaan akses tercatat pada log galat

Bila Anda memiliki akses SSH, hapus saja install.php sejak awal dan
pakai Cara A.

---------------------------------------------------------------------
CARA C — LEWAT psql  (bila Anda lebih terbiasa)
---------------------------------------------------------------------
  psql -U <user> -d wasiator_misc007 -f sql/000_cek.sql     # baca saja
  psql -U <user> -d wasiator_misc007 -f sql/001_schema.sql
  psql -U <user> -d wasiator_misc007 -f sql/003_trigger.sql
  psql -U <user> -d wasiator_misc007 -f sql/002_seed.sql
  php  cli/install.php --superadmin

---------------------------------------------------------------------
KUNCI WAJIB PADA BERKAS KONFIGURASI
---------------------------------------------------------------------
Langkah "Semai akun Superadmin" membaca tiga kunci berikut dari berkas
konfigurasi di luar web root. Bila belum ada, langkah tersebut gagal
dengan pesan "Berkas konfigurasi harus memuat superadmin_email dan
superadmin_password".

    'superadmin_user'     => 'superadmin',
    'superadmin_email'    => 'alamat@email.anda',
    'superadmin_password' => 'minimal 12 karakter',

Tidak ada kata sandi bawaan pada aplikasi ini. Nilainya Anda tentukan
sendiri, disimpan sebagai hash, dan wajib diganti pada login pertama.
Setelah berhasil masuk, hapus superadmin_password dari berkas
konfigurasi.

---------------------------------------------------------------------
KOMPATIBILITAS VERSI POSTGRESQL
---------------------------------------------------------------------
Skema memakai sintaks EXECUTE PROCEDURE pada trigger sehingga dapat
dipasang pada PostgreSQL 9.x sampai 16.

Bila 47 tabel sudah terbentuk tetapi trigger belum ada, jalankan:

    php cli/install.php --trigger

Perintah ini aman dijalankan berulang dan tidak menyentuh data.
Periksa hasilnya dengan php cli/install.php --status, jumlah trigger
seharusnya 21.

Perlu diketahui, PostgreSQL 9.6 sudah berakhir masa dukungannya sejak
November 2021 dan tidak lagi menerima perbaikan keamanan. Aplikasi ini
berjalan di atasnya, tetapi peningkatan versi sebaiknya direncanakan.

---------------------------------------------------------------------
CATATAN OPCACHE
---------------------------------------------------------------------
Bila Anda mengubah berkas konfigurasi tetapi perubahannya belum terasa
(misalnya install_token baru ditambahkan namun pemasang tetap menolak),
kemungkinan besar opcache masih memegang versi lama. Muat ulang PHP-FPM
atau tunggu sampai opcache menyegarkan diri.

=====================================================================
4. PEMASANGAN BERKAS APLIKASI
=====================================================================
Ekstrak isi arsip langsung ke /home/wasiator/doa.wasiat.org sehingga
index.php berada tepat di akar folder tersebut.

  chown -R wasiator:wasiator /home/wasiator/doa.wasiat.org
  find /home/wasiator/doa.wasiat.org -type d -exec chmod 755 {} \;
  find /home/wasiator/doa.wasiat.org -type f -exec chmod 644 {} \;
  chmod -R 770 /home/wasiator/doa.wasiat.org/storage

CATATAN KEAMANAN: susunan ini menempatkan seluruh kode PHP di dalam web
root, mengikuti permintaan agar arsip dapat diekstrak langsung. Akses
langsung ke folder app, storage, sql, cli, dan lang sudah ditutup melalui
.htaccess. Bila di kemudian hari memungkinkan, arahkan document root ke
subfolder public dan pindahkan sisanya ke luar jangkauan web server.

=====================================================================
5. SUPERADMIN
=====================================================================
  php cli/install.php --create-superadmin

Kata sandi diambil dari berkas konfigurasi, disimpan sebagai hash, dan
ditandai wajib diganti pada login pertama. Setelah masuk, segera:
  a. Ganti kata sandi
  b. Aktifkan MFA
  c. Hapus nilai superadmin_password dari berkas konfigurasi

=====================================================================
6. PENJADWALAN
=====================================================================
Cukup satu baris pada crontab. Sisanya diatur dari menu CRON.

  * * * * * /usr/bin/php /home/wasiator/doa.wasiat.org/cli/cron.php >> /home/wasiator/doa.wasiat.org/storage/logs/cron.log 2>&1

=====================================================================
7. LOGIN GOOGLE
=====================================================================
Pada Google Cloud Console, tambahkan pada OAuth Client:
  Authorized JavaScript origins : https://doa.wasiat.org
  Authorized redirect URIs      : https://doa.wasiat.org/login

Token ID diverifikasi di sisi server terhadap kunci publik Google,
mencakup pemeriksaan tanda tangan RS256, issuer, audience, dan masa
berlaku. Tidak memerlukan Composer.

=====================================================================
8. PEMERIKSAAN SETELAH PEMASANGAN
=====================================================================
  [ ] https://doa.wasiat.org membuka halaman depan
  [ ] /assets/css/style.css termuat
  [ ] https://doa.wasiat.org/app/bootstrap.php mengembalikan 404
  [ ] https://doa.wasiat.org/sql/002_seed.sql mengembalikan 404
  [ ] Login superadmin berhasil dan memaksa penggantian kata sandi
  [ ] Menu Otorisasi menampilkan matriks CRUD
  [ ] Audit Trail mencatat login dan verifikasi rantai menyatakan utuh
  [ ] Menu CRON menampilkan waktu jalan terakhir setelah satu menit
  [ ] Manifest terbaca dan PWA dapat dipasang ke layar utama

=====================================================================
9. BILA LOGIN GOOGLE GAGAL
=====================================================================
Langkah pertama, jalankan diagnosis:

    php cli/install.php --status

Bagian LOGIN GOOGLE akan menampilkan tiga hal: Client ID yang terpasang,
status allow_url_fopen, dan apakah kunci publik Google benar-benar dapat
diambil dari server.

Pesan yang mungkin muncul dan artinya:

  "Sesi halaman kedaluwarsa"
      Halaman dibiarkan terbuka terlalu lama. Muat ulang lalu ulangi.

  "Login Google belum dikonfigurasi di server"
      Kunci google.client_id kosong. Isikan melalui Konfigurasi Global,
      atau letakkan google_client_id pada berkas konfigurasi lalu
      jalankan php cli/install.php --superadmin.

  "Server tidak dapat menghubungi Google untuk memverifikasi"
      Hosting memblokir sambungan keluar HTTPS, atau allow_url_fopen
      dimatikan. Aplikasi memverifikasi token langsung ke kunci publik
      Google, jadi sambungan keluar itu wajib terbuka.
      Minta penyedia hosting mengizinkan www.googleapis.com.

  "Client ID Google di server berbeda dengan yang dipakai halaman ini"
      Nilai pada Konfigurasi Global tidak sama dengan yang dipakai
      tombol Google. Samakan keduanya, lalu muat ulang PHP-FPM karena
      opcache mungkin masih memegang nilai lama.

  "Token Google tidak sah"
      Barulah ini masalah token yang sesungguhnya. Periksa apakah
      origin https://doa.wasiat.org sudah terdaftar pada Authorized
      JavaScript origins di Google Cloud Console.

Catatan tambahan: aplikasi ini tidak memakai Client Secret sama sekali.
Bila panduan lain meminta Anda mengisinya, panduan itu memakai alur
redirect, bukan alur token yang dipakai di sini.

=====================================================================
10. MEMASTIKAN VERSI MANA YANG BENAR-BENAR BERJALAN
=====================================================================
Sebelum menyimpulkan sebuah perbaikan tidak bekerja, pastikan lebih
dulu bahwa berkas barunya memang sudah sampai ke peramban. Ada tiga
lapis penyimpanan sementara yang bisa menyajikan berkas lama.

Langkah 1 — periksa versi di server

    Buka https://doa.wasiat.org/api/ping

    Jawabannya memuat nomor versi aplikasi dan penanda isi berkas
    JavaScript. Bila nomor versinya masih lama, berkas di server memang
    belum tergantikan, atau opcache masih memegang kode lama. Muat ulang
    PHP-FPM.

Langkah 2 — bandingkan dengan yang dipakai peramban

    Buka halaman login, tekan Ctrl+U, cari app.js. Penanda ?v= di sana
    harus sama dengan yang tampil pada /api/ping. Bila berbeda,
    peramban Anda masih memakai berkas lama.

Langkah 3 — bersihkan bila memang berbeda

    a. Muat ulang paksa: Ctrl+Shift+R
    b. Bila aplikasi pernah dipasang sebagai PWA, service worker juga
       menyimpan salinannya. Buka DevTools > Application > Service
       Workers > Unregister, lalu muat ulang.
    c. Pada ponsel, tutup aplikasi dari layar utama lalu buka kembali.

Sejak versi 6.1, penanda ?v= dihitung dari isi berkas sehingga berubah
sendiri setiap kali berkasnya berubah, dan service worker mengambil
skrip dari jaringan lebih dulu. Masalah berkas basi seharusnya tidak
terulang, tetapi salinan lama yang sudah terlanjur tersimpan di
peramban tetap perlu dibersihkan satu kali.

=====================================================================
11. GEJALA "HTTP 200" PADA KEGAGALAN
=====================================================================
Bila sebuah kegagalan justru dilaporkan sebagai HTTP 200, hampir selalu
penyebabnya sama: ada keluaran terkirim sebelum header.

Mengapa berakibat fatal
  Begitu satu byte tercetak, PHP menganggap header sudah dikirim.
  Panggilan header() dan http_response_code() sesudahnya diabaikan
  tanpa pesan apa pun, sehingga setiap galat tetap berstatus 200.
  Pada saat yang sama, byte itu ikut mendahului JSON sehingga peramban
  gagal menguraikannya.

Penyebab paling sering
  a. Berkas konfigurasi tersimpan dengan BOM UTF-8. Notepad Windows
     melakukannya secara bawaan. BOM adalah tiga byte tak terlihat
     (EF BB BF) di awal berkas.
  b. Ada baris kosong atau spasi sesudah tanda tutup ?> pada berkas
     konfigurasi.

Cara memastikan

    php cli/install.php --status

  Bagian BERKAS KONFIGURASI akan menyebut berkas mana yang mencetak
  byte liar beserta awalan byte-nya. Awalan efbbbf berarti BOM.

Cara memperbaiki
  a. Buka berkas dengan editor yang mendukung penyimpanan tanpa BOM.
     Notepad++: Encoding > Convert to UTF-8 (tanpa BOM), lalu simpan.
     VS Code: klik "UTF-8 with BOM" di kanan bawah, pilih "Save with
     Encoding" > "UTF-8".
  b. Hapus tanda tutup ?> di akhir berkas konfigurasi. Tanda itu tidak
     wajib pada berkas yang seluruhnya berisi PHP, dan menghapusnya
     menghilangkan kemungkinan spasi tercecer di belakangnya.
  c. Dari baris perintah, BOM dapat dibuang dengan:

         sed -i '1s/^\xEF\xBB\xBF//' /home/wasiator/configdb/dbtopdoa.php

Sejak versi 6.2 aplikasi menahan keluaran liar semacam itu sehingga
tidak lagi merusak header maupun JSON. Meski begitu, berkas konfigurasi
tetap sebaiknya dibersihkan, karena byte liar juga akan merusak
keluaran berkas unduhan seperti CSV, .ics, dan tanda terima.

=====================================================================
12l. MEMERIKSA KONSISTENSI DESAIN
=====================================================================
    python3 cli/cek-desain.py

Melaporkan warna yang ditulis mentah, kelas yang dipakai tanpa gaya,
selektor ganda, gaya sebaris yang berulang, label bahasa yang timpang,
dan gambar tanpa atribut alt.

Sebagian keluarannya memang catatan, bukan kesalahan. Contohnya label
yang tampak tidak terpakai: kelompok menu dipanggil lewat kunci
dinamis sehingga tidak terlihat oleh pemindai. Bacalah sebagai daftar
hal yang perlu diperiksa, bukan daftar yang harus dinolkan.

=====================================================================
12k. MENGATUR BATAS JUMLAH EVENT
=====================================================================
Sistem > Konfigurasi, kelompok event:

    max_active_events_per_user   1   event aktif bersamaan
    max_events_per_30d           2   event per pengguna dalam 30 hari
    max_active_limited_events    3   event terbatas bersamaan

Isi 0 pada salah satunya untuk menghilangkan batas itu sama sekali.

Pertimbangan sebelum melonggarkan: batas ini menahan seseorang
mengunci banyak slot lalu meninggalkannya, sementara slot yang sama
tidak dapat dipakai jamaah lain. Bila dilonggarkan, andalkan sanksi
tidak hadir sebagai penggantinya:

    event.no_show_ban_days
    event.no_show_close_hours

Bila batasnya tampak tidak berubah setelah disimpan, periksa
Konfigurasi Site; nilai di sana menimpa nilai Global.

=====================================================================
12j. PERUBAHAN KONFIGURASI YANG TIDAK BERPENGARUH
=====================================================================
Gejala: Anda mengubah sebuah nilai pada Sistem > Konfigurasi, menyimpan,
tetapi aplikasi tetap memakai nilai lama.

Sebabnya hampir selalu sama. Konfigurasi memiliki dua tingkat, dan
nilai tingkat SITE selalu menang atas nilai GLOBAL untuk kunci dengan
nama yang sama. Bila sebuah kunci ada di kedua tingkat, mengubahnya di
Global tidak berpengaruh apa pun.

Sejak versi 7.12 keadaan itu ditampilkan. Buka Sistem > Konfigurasi,
tab Global. Bila ada nilai yang ditimpa, muncul peringatan di atas
beserta tanda pada barisnya, lengkap dengan nilai site yang sebenarnya
berlaku.

Dua jalan keluarnya:
  1. Tekan tombol "Pakai nilai ini" pada baris tersebut. Nilai site
     akan disamakan dengan nilai global yang baru saja Anda isi.
  2. Buka tab Site aktif, lalu ubah nilainya langsung di sana.

Kunci yang paling sering terkena: event.session_pagi_start,
session_pagi_end, session_sore_start, dan session_sore_end.

=====================================================================
12i. BILA PEMERIKSAAN RANTAI AUDIT MELAPORKAN KERUSAKAN
=====================================================================
Berkas 006_otorisasi_peserta.sql versi awal menyisipkan satu baris ke
audit_logs dengan hash buatan. Setiap baris audit menautkan dirinya ke
hash baris sebelumnya, sehingga baris itu memutus rantai dan membuat
pemeriksaan keutuhan melaporkan kerusakan padahal tidak ada manipulasi.

Jalankan sekali melalui Sistem > Migrasi Basis Data:

    012_perbaiki_rantai_audit.sql

Baris penyebabnya TIDAK dihapus. Audit trail bersifat append-only dan
dilindungi trigger; menghapusnya adalah pelanggaran yang lebih besar
daripada masalah yang hendak diperbaiki, dan menghilangkan jejak bahwa
peristiwa itu pernah terjadi. Yang dilakukan hanyalah menandainya
sebagai titik putus yang diketahui, beserta alasannya.

Baris sesudah titik putus tetap diperiksa dengan ketat, sehingga
manipulasi yang sesungguhnya tetap akan terdeteksi.

=====================================================================
12h. BILA TEKS BACAAN TIDAK MUNCUL
=====================================================================
Gejala: halaman pembaca atau layar pelaksanaan terbuka, tetapi teks
Arab tidak pernah tampil.

Penyebab paling sering: berkas paket teks pada folder assets/content
tidak ada, sementara basis data masih mencatat jalurnya. Ini terjadi
bila folder itu tidak ikut tersalin saat memperbarui berkas aplikasi.

Cara memastikan: buka Sistem > Diagnostik Server, lihat baris
Paket teks bacaan. Bila ada versi yang berkasnya hilang, namanya
disebutkan di situ.

Cara memperbaiki: buka Konten > Versi Liturgi, masuk ke halaman segmen
versi tersebut, lalu tekan Terbitkan sekali lagi. Berkas ditulis ulang
dari isi basis data, sehingga tidak ada teks yang hilang.

Pencegahan: pastikan folder assets/content ikut tersalin setiap kali
memperbarui berkas aplikasi, atau terbitkan ulang setelah pembaruan.

=====================================================================
12g. MENGIZINKAN PENDAFTARAN EVENT HARI YANG SAMA
=====================================================================
Jalankan migrasi 011_event_hari_sama.sql melalui Sistem > Migrasi Basis
Data, lalu setel pada Konfigurasi kelompok event:

    booking_close_days   0    batas terdekat dalam HARI
                              nol berarti hari ini pun boleh
    min_lead_minutes    60    tenggang persiapan dalam MENIT
    booking_open_days   30    batas terjauh dalam hari

Kedua angka pertama bekerja bersama dan keduanya diperlukan. Jendela
pemesanan bekerja pada tingkat tanggal, sehingga bila hari ini
diizinkan tanpa tenggang menit, seseorang dapat membuat event yang
mulai dua menit lagi dan tidak seorang pun sempat bersiap.

Pilihan jam pada formulir untuk hari ini otomatis disaring, dan
penolakannya juga diperiksa ulang di server saat penyimpanan.

PENTING saat menelusuri: rentang sesi dapat ditimpa pada Konfigurasi
Site. Bila sebuah jam ditolak padahal Konfigurasi Global tampak benar,
periksa session_pagi_end dan session_sore_end pada tingkat site.

=====================================================================
12f. MENGATUR DATA YANG WAJIB DIISI
=====================================================================
Sistem > Konfigurasi, kelompok onboarding:

    require_name             1   nama lengkap
    require_city             1   kota
    require_phone            1   nomor ponsel
    require_phone_verified   1   nomor ponsel terverifikasi lewat kode
    require_location         1   titik lokasi untuk peta sebaran

Isi 0 untuk mematikan salah satunya. Halaman Lengkapi Data langsung
menyesuaikan diri, termasuk penomoran langkahnya.

Pertimbangan sebelum mematikan kewajiban nomor ponsel: kewajiban itu
adalah pengaman utama terhadap penguncian slot yang lalu ditinggalkan
(F-G-01). Bila dimatikan, yang tersisa hanya batas event aktif, batas
per 30 hari, dan sanksi tidak hadir. Pertimbangkan mengetatkan
ketiganya sebagai gantinya:

    event.max_active_events_per_user
    event.max_events_per_30d
    event.no_show_ban_days

Bila basis data belum memiliki kunci onboarding, jalankan migrasi
009_setelan_kelengkapan.sql melalui Sistem > Migrasi Basis Data.

=====================================================================
12e. BILA JEJAK GALAT TAMPIL DI LAYAR
=====================================================================
Sejak versi 7.0.1 hal itu tidak lagi terjadi. Aplikasi memasang jaring
pengaman yang mencegat galat fatal, membuang keluarannya, lalu
menampilkan halaman kesalahan yang wajar berstatus 500.

Meski begitu, sebaiknya display_errors tetap dimatikan di sisi hosting.
Buka Diagnostik Server; bila baris display_errors ditandai AKTIF,
berarti hosting menimpa pengaturan aplikasi. Minta penyedia hosting
menyetel pada php.ini:

    display_errors = Off
    log_errors = On

Rincian galat selalu tercatat pada storage/logs/php-error.log dan dapat
dibaca melalui Diagnostik Server, bagian Catatan Galat Terakhir.

=====================================================================
12d. MENJALANKAN MIGRASI TANPA AKSES BARIS PERINTAH
=====================================================================
Masuk sebagai Superadmin, lalu buka:

    Sistem > Migrasi Basis Data

Halaman itu menampilkan berkas migrasi mana yang sudah dan belum
diterapkan, beserta ringkasan tujuan masing-masing. Tekan
"Jalankan semua yang belum" untuk menerapkan seluruhnya berurutan.

Mengapa ini penting: berkas aplikasi yang baru saja disalin tidak
mengubah isi basis data. Bila migrasi tidak dijalankan, perubahan
seperti menu baru atau perbaikan tampilan pesan akan tampak seolah
tidak berfungsi, padahal berkasnya sudah benar.

Berkas pemasangan awal, yaitu 000 sampai 004, sengaja tidak dapat
dijalankan dari sini. Keduanya hanya melalui pemasang atau psql.

Seluruh migrasi tetap dapat dijalankan lewat baris perintah bila
tersedia:

    psql -U <user> -d wasiator_misc007 -f sql/005_perbaikan_baris_baru.sql

=====================================================================
12c. MEMBUKA PEMBUATAN EVENT UNTUK UMUM
=====================================================================
    psql -U <user> -d wasiator_misc007 -f sql/007_event_publik.sql

Setelah dijalankan, setiap peserta yang sudah masuk dapat mendaftarkan
event global melalui menu Buat Event.

Yang dapat disetel lewat Konfigurasi Global:

    event.booking_open_days      30   batas terjauh, dalam hari
    event.booking_close_days      2   batas terdekat, dalam hari
                                      isi 0 untuk mengizinkan hari ini
    event.max_active_events_per_user  1
    event.max_events_per_30d          2
    event.no_show_ban_days           60

Periksa keempat angka terakhir sebelum rilis. Angka yang terlalu longgar
membuat slot mudah dikunci lalu ditinggalkan.

Event terbatas berbasis undangan TIDAK ikut terbuka. Kewenangannya
berupa objek tersendiri bernama event_private, yang dapat diberikan
kepada peran mana pun melalui menu Otorisasi.

=====================================================================
12b. MEMPERSEMPIT KEWENANGAN PESERTA
=====================================================================
Bila Peserta masih melihat menu Liturgi, Donasi Masuk, atau Feedback
Masuk, jalankan sekali:

    psql -U <user> -d wasiator_misc007 -f sql/006_otorisasi_peserta.sql

Penyebabnya: seed versi awal memberi Peserta hak BACA pada objek
liturgy, donation, dan feedback. Hak bacalah yang menentukan tampilnya
menu admin.

Aman dijalankan berulang dan tercatat pada audit trail. Perubahan
serupa juga dapat dilakukan lewat menu Otorisasi tanpa menyentuh SQL.

=====================================================================
12a. MEMPERBAIKI PESAN YANG MENAMPILKAN TULISAN \n
=====================================================================
Bila isi pesan pada menu Pesan tampil sebagai satu paragraf panjang
berisi tulisan \n, jalankan sekali:

    psql -U <user> -d wasiator_misc007 -f sql/005_perbaikan_baris_baru.sql

Penyebabnya: template notifikasi versi awal ditulis dengan '\n' di
dalam kutip tunggal biasa. Pada PostgreSQL itu bukan baris baru,
melainkan dua karakter apa adanya. Baris baru sungguhan memerlukan
awalan E, yaitu E'\n'.

Skrip di atas memperbaiki template, pesan yang sudah terkirim, dan
antrean notifikasi yang belum terkirim. Aman dijalankan berulang.

Catatan bagi yang memeriksa sendiri: jangan memakai LIKE '%\n%' untuk
menghitung sisanya. Pada PostgreSQL, garis miring terbalik di dalam
pola LIKE adalah karakter pelarian, sehingga pola itu justru cocok
dengan huruf n biasa dan memberi angka yang menyesatkan. Pakai
position('\n' in kolom) > 0.

=====================================================================
12. HALAMAN DIAGNOSTIK
=====================================================================
Untuk hosting tanpa akses baris perintah, seluruh pemeriksaan pada
bagian sebelumnya tersedia melalui peramban.

Ada dua cara membukanya.

  Cara 1, paling mudah bila login masih berfungsi:
      Masuk sebagai Superadmin, lalu buka
      https://doa.wasiat.org/diagnostik
      Tersedia juga sebagai menu Diagnostik Server pada kelompok Sistem.

  Cara 2, bila login justru yang bermasalah:
      Tambahkan 'install_token' => 'untaian-acak', pada berkas
      konfigurasi di luar web root, lalu buka
      https://doa.wasiat.org/diagnostik?token=untaian-acak
      Ganti untaian-acak dengan nilai sebenarnya, bukan tulisan itu.
      Hapus kembali barisnya setelah selesai.

Bila halaman terkunci, ia tidak sekadar menolak. Halaman penolakannya
menunjukkan berkas konfigurasi mana yang terdeteksi di server Anda dan
menyediakan baris siap salin beserta nilai acak yang sudah dibuatkan.

Isinya:

  Aplikasi   : versi yang benar-benar berjalan, status opcache, waktu
               ubah app.js, dan penanda versinya. Bandingkan penanda
               itu dengan yang tampil pada kode sumber halaman login;
               bila berbeda, peramban Anda masih memakai berkas lama.
  Keluaran   : apakah ada byte tercetak sebelum header, lengkap dengan
               nama berkas dan awalan byte-nya.
  Google     : Client ID, allow_url_fopen, dan apakah kunci publik
               Google benar-benar terambil.
  Basis Data : koneksi, jumlah tabel, jumlah pengguna Google.
  Catatan galat terakhir, serta tombol untuk menguji /api/ping,
  /api/csrf, dan /google-login langsung dari peramban Anda. Hasil uji
  itu menyebutkan apakah jawaban memuat BOM dan apakah JSON-nya dapat
  diurai.

Setelah masalah selesai, hapus install_token dari berkas konfigurasi
agar halaman ini kembali mati.