# Pemasangan dan deployment

## Prasyarat

Gunakan Node.js 22.13 atau lebih baru dan package manager dari lockfile (`pnpm`). Situs ini disiapkan untuk Sites dengan Worker, D1, dan R2. Logical binding berada pada `.openai/hosting.json`: `DB` dan `BUCKET`. Jangan menyalin ID resource Cloudflare dari lingkungan lain.

Database dan bucket adalah penyimpanan persisten. Media publik dan privat berbagi bucket dengan prefix yang berbeda, tetapi akses selalu diperiksa oleh backend. Bucket aplikasi tidak dibuka sebagai bucket publik. Foto/proposal dilayani melalui endpoint publik berdasarkan metadata; bukti dan dokumen internal memerlukan sesi keuangan/pemilik.

## Instalasi lokal

```bash
node scripts/install-ci.mjs
node node_modules/typescript/bin/tsc --noEmit
node tests/run.mjs
node scripts/run-framework.mjs build
```

Setiap migrasi lokal diterapkan sekali, sesuai urutan:

```bash
node --import ./scripts/sites-env.mjs ./node_modules/wrangler/bin/wrangler.js d1 execute DB --local --config dist/server/wrangler.json --persist-to .wrangler/state --file drizzle/0000_cultured_nocturne.sql
node --import ./scripts/sites-env.mjs ./node_modules/wrangler/bin/wrangler.js d1 execute DB --local --config dist/server/wrangler.json --persist-to .wrangler/state --file drizzle/0001_financial_integrity.sql
node --import ./scripts/sites-env.mjs ./node_modules/wrangler/bin/wrangler.js d1 execute DB --local --config dist/server/wrangler.json --persist-to .wrangler/state --file drizzle/0002_luxuriant_stingray.sql
```

Migrasi production dikelola saat deployment Sites. Migrasi yang sudah diterapkan tidak boleh ditulis ulang. Tambahkan migrasi baru untuk perubahan berikutnya. Data awal dimasukkan idempoten pada akses pertama setelah skema tersedia; bukan bagian dari migrasi skema.

Jangan memasukkan data dari `tests/` ke produksi. Test runner menyediakan lingkungan D1/R2 sendiri. Jalankan render setelah build dengan `node tests/render.mjs`.

## Konfigurasi server

Salin nama variabel dari `.env.example`, tetapi pasang nilai produksi melalui runtime settings Sites. Jangan menaruh rahasia di file hosting, Git, browser, atau source code. Kunci enkripsi harus berupa 64 karakter heksadesimal acak (256 bit).

| Variabel | Fungsi |
|---|---|
| `DATA_KEY` | Rahasia untuk mengenkripsi secret authenticator |
| `SITE_ORIGIN` | Origin HTTPS situs yang dikonfirmasi, untuk metadata gambar berbagi |
| `INITIAL_SETUP_ENABLED` | `true` hanya ketika pemilik pertama sedang disiapkan pada situs privat |
| `BOOTSTRAP_OWNER_EMAIL` | Email pemilik yang sudah dikonfirmasi; harus sama dengan identitas login |
| `BACKUP_SERVICE_URL` | Endpoint HTTPS Worker cadangan terpisah |
| `BACKUP_SERVICE_TOKEN` | Rahasia akses penyimpanan cadangan |
| `BACKUP_KEY` | Kunci enkripsi cadangan yang berbeda dari `DATA_KEY` |
| `OPERATIONS_TOKEN` | Rahasia pemanggilan pekerjaan backup |
| `BACKUP_SCHEDULE_ACTIVE` | `false` sampai penjadwal berhasil diverifikasi; bukan tombol yang menyalakan cron |

Penerbitan awal sudah memasang kunci enkripsi acak dan membatasi pendaftaran pemilik pada email pemilik Sites. Cadangkan kunci melalui pengelolaan rahasia sebelum faktor kedua digunakan. Jika hendak memakai kunci milik organisasi, ubah sebelum enrollment pertama. Jangan mengganti `DATA_KEY` setelah admin mengaktifkan authenticator tanpa migrasi secret yang terencana.

## Pemilik pertama dan faktor kedua

1. Buka situs privat dari akun pemilik, kemudian **Admin** di footer.
2. Tekan **Buat akun pemilik**. Identitas harus cocok dengan email bootstrap.
3. Pilih **Aktifkan authenticator**. Tambahkan secret secara manual pada aplikasi authenticator, atau gunakan tautan `otpauth` pada perangkat yang sama. Tidak ada layanan QR eksternal yang menerima secret.
4. Masukkan kode 6 digit. Aplikasi menggunakan HMAC-SHA1, periode 30 detik, sesuai RFC 6238.
5. Simpan delapan kode pemulihan secara privat. Masing-masing hanya dapat dipakai sekali. Server menyimpan hash, bukan teks kode.
6. Setelah akun dibuat, ubah `INITIAL_SETUP_ENABLED=false` pada runtime settings dan terapkan environment revision dengan deployment baru.
7. Tambahkan akun keuangan dan editor pada menu **Akun & aktivitas**, setelah autentikasi ulang. Pengguna masuk dengan email ChatGPT yang diizinkan. Tidak ada email undangan otomatis.

Pemilik dan keuangan tidak dapat mengakses API penuh sebelum faktor kedua. Editor boleh mengaktifkannya. Sesi memakai cookie HttpOnly, Secure, SameSite Strict, dengan masa berlaku delapan jam. Logout menghapus sesi aplikasi dan keluar dari identitas ChatGPT.

## Membuka transfer manual

Unggah proposal atau surat rekening sebagai PDF. Dokumen pendukung rekening dapat tetap privat. Buka **Keamanan akun**, verifikasi ulang, lalu **Pengaturan**. Periksa bank, nomor rekening, nama penerima, dan dokumen sumber. Simpan alasan pemeriksaan dan centang konfirmasi.

Nomor 7211001016 berasal dari data pengguna; penulisan proposal “7 211001016” belum dapat diperiksa karena PDF belum diberikan. Jangan mengaktifkan transfer berdasarkan angka awal saja. Situs tidak menampilkan rekening yang belum dikonfirmasi.

Sesudah konfirmasi, donatur dapat membuat permintaan tanpa akun, menentukan rupiah bulat positif, transfer, dan mengunggah bukti. Batas aplikasi terlihat pada formulir: Rp1 sampai Rp1.000.000.000.000. Bank pengirim dapat memiliki batas dan biaya sendiri; website tidak menambahkan biaya atau kode nominal.

## Deployment dan rilis publik

Deployment Sites mengemas hasil build Worker kompatibel Cloudflare, menerapkan migrasi D1, dan menghubungkan D1/R2. Source disimpan bersama situs. Gunakan workflow Sites untuk deployment berikutnya. Jangan membagikan credential Git sementara.

Sebelum mengubah akses dari privat menjadi publik:

- Pemilik dan semua akun keuangan sudah mengaktifkan faktor kedua.
- Bootstrap sudah dimatikan.
- Rekening sudah diperiksa terhadap dokumen asli.
- Kontak, proposal, foto asli, dan kebijakan telah diperiksa pengelola.
- Backup dan cron terpisah sudah aktif, serta satu backup produksi berhasil dipulihkan ke lingkungan uji.
- Periksa alur browser di ponsel dan desktop, termasuk unggahan, dialog, keyboard, dan cetak bukti. Pemeriksaan browser belum dapat dijalankan dalam lingkungan pembuatan ini.
- Periksa saldo dan pencocokan rekening dengan cakupan yang jelas.

QRIS/VA tetap nonaktif. Integrasi merchant dan webhook belum diimplementasikan. Sebelum menambahkannya, validasi signature, merchant, ID pembayaran, jumlah, IDR, dan lingkungan uji/produksi. Gunakan receipt ledger yang unik untuk idempotensi; jangan menganggap callback sebagai penerimaan tanpa validasi resmi.

Dokumentasi utama: [D1 Worker API](https://developers.cloudflare.com/d1/worker-api/d1-database/), [R2 Worker API](https://developers.cloudflare.com/r2/api/workers/workers-api-reference/), [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/), [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238).
