# DIGITRAVEL Partner Portal — arsitektur dan infrastructure plan

21 September 2026 · Target Phase 1 · Bahan meeting IT, bukan konfigurasi yang sudah terpasang.

## Keputusan dasar

**Satu VPS production menampung aplikasi, API, worker, dan PostgreSQL. Staging berada pada VPS berbeda.** Core Ammegatech tetap di server existing; tidak dipindahkan ke VPS portal. BUILD aplikasi tetap lokal dan sedang dijeda menunggu hasil meeting. Dokumen ini tidak mengaktifkan koneksi atau membeli server.

| Lingkungan | Kapasitas awal | Isi | Status |
| --- | --- | --- | --- |
| Lokal | MacBook existing | Next.js, NestJS, PostgreSQL, worker tanpa dispatch | Sudah ada; data simulasi |
| Staging | 4 vCPU, 8 GB RAM, 100 GB NVMe | Seluruh layanan portal + database uji | Rencana; terpisah dari production |
| Production | 4 vCPU, 8 GB RAM, 100 GB NVMe | Seluruh layanan portal + database production | Rencana satu VPS; belum HA |
| Backup di luar VPS | Object storage terenkripsi, kapasitas mengikuti retensi | Base backup/WAL, konfigurasi yang diperlukan untuk pemulihan | Rencana; provider dan retensi belum dipilih |

Sizing adalah perkiraan awal, bukan jaminan jumlah partner/order. Pastikan CPU, RAM, latensi database dan antrean memenuhi uji beban sebelum pilot. Pilih paket yang dapat ditingkatkan. Lokasi Jakarta atau Singapura diputuskan menurut lokasi core, latensi dan kebutuhan penempatan data. Tidak perlu GPU, Kubernetes atau Redis untuk rancangan awal ini; outbox memakai PostgreSQL.

OS usulan Ubuntu Server 24.04 LTS x86-64. Node.js versi LTS yang kompatibel dan PostgreSQL 18 patch terpelihara; versi final dikunci serta diuji saat menyiapkan image rilis. Gunakan container terpisah melalui Docker Compose, volume database persisten dan restart/healthcheck per layanan. Compose deployment belum dibuat; compose existing hanya untuk database lokal.

## Cara membaca diagram

1. `01-services.html`: hubungan layanan target. Panah menunjukkan jalur utama; bukan daftar lengkap seluruh request/response. Hubungan ke layanan eksternal belum membuktikan koneksi aktif.
2. `02-infrastructure.html`: penempatan layanan dalam satu VPS production, staging terpisah, serta backup eksternal. Panah promosi menunjukkan proses rilis yang disetujui, bukan trafik pengguna dari staging ke production. Backup digambar dari database sebagai asal data; pelaksana sebenarnya adalah job backup terbatas.
3. `03-payment-to-esim.html`: contoh pembayaran langsung Midtrans hingga hasil eSIM. Interaksi pengguna menyelesaikan pembayaran diringkas. Return browser tidak menjadi bukti bayar. Koneksi core pada diagram adalah kontrak target; bentuk hasil sinkron/callback/polling ditetapkan IT.

Klik node untuk fokus, gunakan zoom, pencarian, Light/Dark dan Export. Kontrol bawaan Archify berbahasa Inggris; isi diagram berbahasa Indonesia. Setiap diagram HTML berdiri sendiri tanpa server atau koneksi internet untuk melihat diagram. Halaman indeks memakai file diagram di folder yang sama.

## Komponen dan kepemilikan

| Komponen | Tanggung jawab | Kondisi sekarang / keputusan |
| --- | --- | --- |
| Next.js / React | Portal partner dan Admin CMS, ID/EN; menampilkan harga beli akhir | UI lokal tersedia; satu aplikasi dengan akses berbasis role |
| NestJS | Otorisasi partner, validasi input, quote, transaksi, endpoint callback, kontrol admin | Fondasi lokal ada; integrasi nyata belum aktif |
| PostgreSQL portal | Akun/sesi, pengaturan, diskon lokal, snapshot order, audit, outbox | Saat ini data simulasi. Master partner/diskon dan ledger produksi harus disepakati IT |
| Worker | Mengambil pekerjaan persisten, memeriksa izin terbaru, kirim order, rekonsiliasi hasil | Outbox lokal ada; dispatch production belum dibuat/diaktifkan |
| Core Ammegatech / NocoBase | Produk, harga publish retail, proses injection eSIM dan kirim SIM, email eSIM | Kontrak internal, sandbox dan callback perlu jawaban IT |
| Midtrans | Pembayaran order dan top-up; notifikasi/status transaksi | Simulator lokal; callback nyata belum terhubung |
| ZeptoMail US | Email akun: undangan, reset dan notifikasi keamanan | Satu email uji diterima. Pengiriman otomatis aplikasi masih perlu dihubungkan |
| Backup / monitoring | Pemulihan, alarm, log operasional | Konfigurasi, PIC dan pengujian belum selesai |

Harga akhir dihitung **sekali** dari harga retail core, dikurangi diskon partner. Diskon awal berlaku segera; perubahan selanjutnya bulan berikutnya. Persentase dan pilihan diskon hanya untuk admin. Jangan menerapkan diskon kedua pada harga net dari core.

**Usulan owner:** tim aplikasi mengelola web/API/worker; IT Ammegatech mengelola kontrak dan enforcement core; IT/DevOps mengelola VPS, database, backup dan pemulihan; Finance mengelola kebijakan saldo/invoice/rekonsiliasi; Operations menangani pesanan tertahan. Nama PIC dan pembagian tanggung jawab belum ditetapkan.

## Jaringan dan akses

- Internet → HTTPS 443 → Nginx → aplikasi. HTTP 80 hanya untuk pengalihan ke HTTPS/validasi sertifikat bila diperlukan.
- Usulan domain `partner.digitravel.store` dan `staging-partner.digitravel.store`; DNS dan sertifikat belum dikonfigurasi.
- NestJS, PostgreSQL dan worker tidak memiliki port publik. Akses antarlayanan lewat jaringan container internal; database hanya dari layanan yang memerlukan akses.
- SSH menggunakan key melalui VPN atau IP pengelola terbatas. Akses CMS tetap MFA dan otorisasi admin di backend, bukan sekadar menu tersembunyi.
- Outbound HTTPS ke host core, Midtrans, ZeptoMail dan backup yang disetujui. IP keluar tetap untuk allowlist core; perubahan IP harus dikoordinasikan.
- Callback core/Midtrans masuk melalui reverse proxy, diteruskan ke handler khusus. Validasi autentisitas, referensi, jumlah, partner dan status; simpan receipt serta deduplikasi sebelum mengubah transaksi.
- IP allowlist hanyalah lapisan tambahan. Jangan menjadikannya pengganti signature/verifikasi resmi atau otorisasi order.
- Pisahkan secrets, database, key enkripsi, alamat callback dan akun vendor staging/production. Tidak menyalin pelanggan/QR aktif ke staging.
- Akses sensitif dan hasil QR tidak dicache secara publik; log tidak memuat credential atau kode aktivasi. Secret tidak masuk source maupun file diagram.

## Pembayaran, injection dan hasil

1. Backend menerima produk/jumlah/penerima. Ambil harga retail, terapkan diskon aktif, validasi stok dan buat quote berumur terbatas.
2. Saldo: reservasi/debit di ledger otoritatif. Midtrans: verifikasi pembayaran sah lewat callback/status lookup. Invoice: cek fasilitas aktif, exposure, overdue dan izin kredit. Lokasi ledger ditetapkan IT; hindari dua saldo independen.
3. Catat otorisasi pendanaan dan pekerjaan fulfillment secara konsisten. Bila ledger ada di core, tentukan protokol reservasi/konfirmasi/kompensasi; transaksi database lokal tidak otomatis atomik dengan core.
4. Worker mengecek kembali status partner, izin, batas unit/biaya dan emergency stop sebelum mengirim. Gunakan referensi stabil per order/unit, diterima dan dideduplikasi core.
5. Core memproses injection atau kirim SIM. Hasil harus cocok dengan order/unit/partner. Callback harus terautentikasi; bila menggunakan polling, batasi frekuensinya.
6. Simpan hasil per unit: QR/ICCID/APN/panduan untuk eSIM; ICCID/resi/status kirim untuk SIM Card. QR hanya untuk partner pemilik. Detail core tidak boleh bocor lintas partner.
7. Timeout atau hasil tidak pasti → UNKNOWN dan lookup referensi. Jangan menganggap gagal lalu melakukan injection ulang otomatis. Setelah restore database, rekonsiliasi ke gateway/core sebelum membuka dispatch kembali.

Top-up hanya mengkredit saldo, tidak membuat injection. Email eSIM dikirim core ke partner/customer dengan template DIGITRAVEL atau Generic; tidak ada invoice email setiap transaksi. Email akun ZeptoMail terpisah dari email fulfillment.

## API partner: keputusan penting meeting

Satu akun integrasi per partner mengikuti kontrak Apidog. **Jalur final belum diputuskan:** melewati backend portal atau langsung API core. Pilih satu desain yang mempertahankan identitas partner, harga, saldo/invoice, rate limit, suspend, otorisasi injection dan emergency stop di semua jalur. Jangan membuat jalur langsung ke core yang melewati kontrol tersebut. Diagram layanan utama tidak menetapkan endpoint API partner final.

## Backup, monitoring dan kegagalan satu VPS

Production satu VPS merupakan satu titik kegagalan: host rusak dapat menghentikan web dan database sekaligus. Container membantu pengelolaan proses, bukan failover host. Awali pilot terbatas dan sepakati target kehilangan data maksimal (RPO) serta waktu pemulihan (RTO) sebelum rilis.

Backup harus disimpan terenkripsi di luar VPS, dengan base backup dan WAL untuk point-in-time recovery. Usulan retensi awal 30 hari, dikonfirmasi dengan IT dan kebijakan data. Secret/key pemulihan dikelola terpisah; salinan data terenkripsi tanpa key yang dapat dipulihkan tidak cukup. Uji restore ke lingkungan terisolasi, kemudian rekonsiliasi pembayaran/core dan cegah pengulangan order sebelum layanan dibuka.

Monitor CPU/RAM/disk, koneksi dan latensi DB, error/latensi API, umur antrean tertua, UNKNOWN/dead letter, callback gagal, selisih rekonsiliasi, backup tertinggal dan sertifikat. Tetapkan PIC serta kanal alarm yang diuji. Snapshot VPS bukan satu-satunya backup transaksi.

Jika pemakaian melewati hasil uji kapasitas, pisahkan PostgreSQL ke server/layanan terkelola lebih dahulu sesuai profil beban; worker dapat dipisahkan bila antrean mengganggu API. Redundansi aplikasi dan database/failover merupakan langkah tersendiri, bukan otomatis didapat dari dua server.

## Urutan deployment setelah meeting

1. Tetapkan kontrak dan owner data, sandbox, domain, lokasi server, PIC, RPO/RTO serta kebutuhan trafik pilot.
2. Selesaikan integrasi lokal, email akun, ledger dan kontrol keamanan yang belum lengkap.
3. Buat profil staging/production, image rilis, Compose, reverse proxy, secrets, migrasi dan rollback. Config saat ini sengaja hanya mengizinkan localhost dan integrasi disabled; jangan sekadar mengganti nilai env untuk membuka produksi.
4. Deploy staging dengan data sintetis; uji checkout ketiga metode, callback ganda, timeout, partial, suspend, API partner dan kedua produk.
5. Uji beban, keamanan, backup/restore, rekonsiliasi dan UAT bisnis. Tutup temuan yang menghalangi rilis.
6. Persetujuan rilis → deploy versi yang sama ke production dengan konfigurasi production terpisah. Jangan memindahkan database simulasi menjadi ledger production.
7. Pilot partner terbatas, rekonsiliasi transaksi nyata dan monitoring; perlu persetujuan live tersendiri.

## Yang dibutuhkan dari IT

- Server core/sandbox, lokasi, protokol akses, contoh payload/status/error dan PIC.
- Master partner/diskon/ledger, pemetaan ID dan aturan konflik/sinkronisasi.
- Bukti deduplikasi, lookup UNKNOWN, callback, suspend, funding dan stop di core.
- Merchant Midtrans, akun API partner, pemisahan email core/portal.
- Provider/server, DNS, akses pengelola, tujuan backup, target pemulihan serta PIC alarm.

Rincian 49 pertanyaan ada di `project-management/12_MEETING_IT_AMMEGATECH_2026-09-21.md` pada proyek. Hasil meeting belum diterima saat dokumen ini dibuat.

## Bukti, sumber dan batas

Rancangan disusun dari keputusan pengguna dan kode lokal per BUILD 30: `apps/web`, `apps/api/src`, `apps/worker/src/main.ts`, `packages/security/src/config.ts`, migration 017, `project-management/STATUS.json`, serta laporan BUILD 27–30. 138 tes lokal yang sudah tercatat bukan uji deployment atau throughput produksi.

Renderer: [Archify](https://github.com/tt-a1i/archify), commit `29f1ff53814b7b13fa161687e0565e8f596c9257`. Salinan repo hanya di folder kerja lokal; tidak dipasang global dan source portal tidak diunggah ke GitHub. JSON sumber dan receipt validasi tersedia bersama HTML. Validasi diagram membuktikan struktur/geometri artefak, bukan keamanan atau ketersediaan infrastruktur.

Referensi teknis yang ditinjau untuk rencana hosting: [Next.js self-hosting](https://nextjs.org/docs/app/guides/self-hosting), [PostgreSQL 18 PITR](https://www.postgresql.org/docs/18/continuous-archiving.html), [Ubuntu 24.04 LTS](https://documentation.ubuntu.com/release-notes/24.04/). Rincian kapasitas, retensi dan topology di dokumen ini merupakan usulan proyek, bukan minimum resmi vendor.
