# Backup, upgrade, pemulihan dan diagnosis Semua perintah dijalankan dari direktori release yang benar dengan path env privat absolut. Simpan versi source, image tag/ID, hash arsip, konfigurasi, waktu migrasi, hasil smoke dan nama backup dalam receipt privat. Jangan simpan secrets dalam repository atau screenshot/log publik. ## Backup dan restore ```sh sh deploy/staging.sh /private/bereaware-staging/staging.env backup sh deploy/staging.sh /private/bereaware-staging/staging.env restore-check /private/bereaware-staging/backups/bereaware-TIMESTAMP.dump ``` Backup adalah custom-format `pg_dump` konsisten. Dump dan daftar `pg_restore --list` ditulis ke `.dump.tmp` dan `.dump.manifest.tmp`; hasil kosong atau perintah gagal tidak diterbitkan sebagai backup selesai. SHA-256 dibaca streaming dengan buffer 64 KiB, bukan seluruh dump di RAM. Sidecar baru tetap memakai format 64 digit hex satu baris yang kompatibel dengan backup lama. Helper menolak file/symlink yang sudah ada dan menghubungkan manifest/checksum lebih dahulu, lalu dump final terakhir; setelah sukses, nama pending milik operasi itu dihapus dan tiga file final tetap privat 0600, masing-masing satu hard link. Tidak ada backup lama yang ditimpa atau dihapus. Publikasi memerlukan dukungan hard link pada filesystem lokal karena semua nama berada pada direktori yang sama. Gangguan proses dapat meninggalkan `.dump.tmp` serta sebagian sidecar pending/final; ini bukti yang harus direkonsiliasi, bukan paket yang boleh otomatis diulang atau dinyatakan berhasil. Direktori backup harus dipercaya, privat, dan tidak boleh berupa symlink. Jangan mengubah file backup selama hashing, verifikasi atau restore. Media saat ini disimpan bersama database; jika nanti storage eksternal ditambahkan, snapshot storage dan manifest referensi juga wajib dibackup. Salin dump dan env secara terenkripsi ke tempat di luar VM. Jadwalkan backup melalui scheduler operator yang memanggil perintah di atas, periksa exit code, dan tentukan retensi serta penghapusan secara eksplisit. Script tidak menghapus backup lama. Sebelum `createdb`, restore-check memverifikasi isi dump terhadap `.sha256`. Checksum salah, format rusak, nama arsip yang tidak cocok, input bukan file reguler, symlink atau file dengan lebih dari satu hard link ditolak. Helper juga mendeteksi perubahan file saat hashing. Format checksum lama tanpa nama file tetap didukung; format umum `HASH nama-file.dump` juga diterima hanya jika namanya cocok dengan dump yang dipilih. Perintah berikut hanya memeriksa integritas byte lokal dan tidak membuat database: ```sh node deploy/checksum.mjs verify /private/bereaware-staging/backups/bereaware-TIMESTAMP.dump ``` Untuk arsip legacy yang benar-benar tidak mempunyai checksum, operator harus menerima pengecualian secara eksplisit: ```sh sh deploy/staging.sh /private/bereaware-staging/staging.env restore-check /private/legacy.dump --allow-missing-checksum ``` Opsi tersebut hanya mengizinkan sidecar yang tidak ada; checksum yang ada tetapi salah/rusak tetap ditolak. Hash saat ini dihitung dan ditampilkan tanpa menciptakan bukti bahwa backup asli sudah benar. Tidak ada sidecar baru yang dibuat oleh pengecualian ini. Simpan dump dan direktori privat serta tidak berubah sepanjang operasi; verifikasi sebelum restore tidak menggantikan pengujian hasil restore. Restore-check hanya membuat database baru `bereaware_restore__`, menjalankan restore transaksi tunggal dan menghitung organisasi/jemaat/publikasi. Database sumber tidak disentuh. Database pemeriksaan ditahan untuk inspeksi; hapus hanya nama yang tercetak setelah diterima. Keberhasilan `pg_restore --list` saja bukan bukti pemulihan. Catat jumlah data dan uji login/publikasi pada environment disposable sebelum menerima backup sebagai layak. ## Upgrade dan rollback Gunakan tag unik dalam `RELEASE_TAG`, bukan menimpa image rilis terakhir. Persiapkan release baru dari source tervalidasi dengan project/env yang sama dan jadwal maintenance yang sesuai. Jalankan: ```sh sh deploy/staging.sh /private/bereaware-staging/staging.env upgrade node deploy/smoke.mjs /private/bereaware-staging/staging.env ``` Script memvalidasi, membangun image serial, mencatat image sebelumnya, mengambil backup, lalu menjalankan migrasi dan `up --wait`. Build gagal tidak menyentuh container aktif. Compose bukan deployment atomik: sebagian container dapat berpindah sebelum layanan lain gagal. Jangan menyebut rollback otomatis atau zero downtime. Pertahankan source/image lama, backup database, env lama dan konfigurasi Caddy terakhir. Tidak ada prune/down/restore otomatis. Bila gagal, simpan `docker compose --env-file ... -f compose.staging.yaml ps` dan `logs --tail 100`, tinjau perubahan skema, dan tentukan apakah image sebelumnya kompatibel. Restore skema/data lama hanya pada database/volume pengganti yang telah diuji, dengan maintenance dan keputusan operator; jangan menimpa volume sumber atau mengulang migrasi tak pasti. Caddy tidak perlu diubah untuk upgrade image pada port yang sama. Bila harus mengubah proxy, bandingkan hash sumber dengan receipt, buat backup eksak, validasi config kandidat lalu reload. Pada kegagalan validasi/reload, pertahankan config aktif dan periksa status sebelum mencoba lagi. Periksa layanan tetangga sebelum/sesudah deployment. ## Pemantauan dan troubleshooting - Status: `sh deploy/staging.sh /private/bereaware-staging/staging.env status` dan smoke per host. Health container tidak membuktikan DNS/HTTPS, otorisasi atau journey pengguna. - Monitor eksternal HTTPS untuk enam host, masa sertifikat, HTTP 5xx, disk/volume/backup age, OOM/restart dan pool/latensi database. Log container dibatasi 3 × 10 MiB per service; jangan log cookie, secret atau data jemaat. - 421: Host tidak sesuai origin. 403 gateway: header hop dari Caddy hilang atau Origin salah. Jangan memperbaiki dengan membuka wildcard origin atau mempercayai XFF. - 503: periksa health API, migrasi dan koneksi DB. Unknown church/path harus gagal; jangan mengganti scope secara diam-diam. - Asset Flutter 404: verifikasi build web ikut image; gateway tidak memberi index.html untuk asset hilang atau typo API. Deep link member tanpa ekstensi memakai SPA fallback. - Port bentrok: ubah keenam port env secara konsisten, regenerasi fragmen Caddy yang ditinjau dan validasi. Port tetap loopback. - Banyak pengguna Wi-Fi: Caddy mengirim IP koneksi yang sama untuk pengguna NAT; rate limit backend tetap harus sesuai journey. Gateway mencegah seluruh pengguna tereduksi menjadi satu IP container; NAT publik tetap tidak dapat dibedakan sebagai IP unik. Tidak ada uji restore/deployment yang boleh diklaim hanya dari validasi file atau unit test. Jalankan dan simpan bukti runtime pada instalasi terisolasi. ## Jadwal backup opsional Template `deploy/bereaware-backup.service` dan `.timer` tersedia untuk ditinjau operator. Service membaca `/etc/bereaware-staging/backup-paths.env` berisi hanya dua path absolut `BEREAWARE_RELEASE` dan `BEREAWARE_ENV`. Operator menginstal unit setelah mencoba backup manual, memeriksa isi path dan akses Docker, lalu mengaktifkan timer. Jadwal default 19:00 UTC (02:00 WIB) dengan jitter 10 menit dan catch-up saat host kembali hidup. Panggilan systemd gagal terlihat pada exit code/journal; hubungkan alert yang dimiliki operator. Tidak ada unit diaktifkan otomatis oleh source package. Rotasi/retensi backup harus ditentukan terpisah setelah salinan off-host dan restore diperiksa. ## Batas bukti restore-check Helper saat ini memakai `--no-owner --no-privileges` untuk restore pemeriksaan. Ia memverifikasi struktur/data dan jumlah organisasi/jemaat/publikasi melalui akun postgres di database baru, bukan hak akses runtime `mychurch_app`. Untuk menerima pemulihan aplikasi, operator juga perlu memulihkan ACL asli hanya pada database disposable yang sama dan menguji koneksi/journey aplikasi di environment terisolasi. Jangan mengubah password atau role cluster bersama untuk pemeriksaan ini. Dump PostgreSQL tidak mencakup role global; backup konfigurasi/secrets dikelola terpisah secara privat. Pilih dump tepat dari hasil perintah backup, bukan file 'terbaru' yang belum direkonsiliasi. `pg_restore --list` dan pemeriksaan data bukan uji login atau media dari browser. Bila backup/restore terinterupsi, pertahankan `.tmp`, manifest dan nama database pemeriksaan sebagai bukti; jangan otomatis mengulang operasi atau menjatuhkan database sumber. ## Pemeriksaan layanan berkala Template `deploy/bereaware-health.service` dan `.timer` memakai file path operator yang sama dengan backup. Unit menjalankan `deploy/smoke.mjs` setiap lima menit dan mencatat status/penolakan endpoint Backoffice dari host publik ke journal systemd. `ExecStartPost` memanggil `deploy/ops-health.mjs` untuk pemeriksaan baca-saja: ruang disk bebas minimal 2 GiB, backup selesai terbaru berumur maksimal 30 jam, dan pending `.dump.tmp` yang belum selesai maksimal satu jam. Helper memeriksa file reguler/satu link/permission privat serta keberadaan manifest nonkosong dan format checksum, tanpa membaca ulang seluruh isi dump setiap lima menit. Ambang operator tersedia melalui `--min-free-mib`, `--max-backup-age-hours`, dan `--max-partial-age-hours`; konfigurasi serta penerimaan hasil dilakukan operator. Pemeriksaan metadata ini bukan verifikasi SHA-256 isi dump, bukan uji restore, dan bukan bukti pemulihan aplikasi. Jalankan verifikasi checksum penuh/restore pada proses pemeriksaan backup yang sesuai. Timer tidak menghapus backup, mengekspor data, melakukan restart atau memulihkan database otomatis. Operator memeriksa unit dengan `systemd-analyze verify` dan menjalankan service manual sebelum aktivasi. Pemantauan eksternal serta jalur notifikasi mengikuti konfigurasi yang benar-benar tersedia; tidak ada provider SMTP/alert baru yang diasumsikan. Batas default jaringan bersama: tindakan anggota memakai identitas akun terverifikasi, 15 tindakan per akun per menit dengan batas agregat 600 per IP per tindakan. Login jemaat dibatasi 120 per IP dan 15 per gereja/email per menit lintas IP. Tindakan anonim, pendaftaran dan pemulihan tetap dibatasi 15 per IP per tindakan. Form publik pada acara dengan banyak peserta anonim perlu kapasitas/rencana jaringan yang ditinjau; jangan menonaktifkan pembatasan tanpa perlindungan pengganti.