Web app untuk menemukan biaya perjalanan Umrah mandiri yang termurah: tiket pesawat untuk semua penumpang, hotel Makkah (semua kamar, semua malam), dan hotel Madinah (semua kamar, semua malam), dijumlahkan sebagai satu total biaya dalam IDR.
Aplikasi ini dibangun terbuka untuk membantu tiga kelompok sekaligus: calon jamaah yang ingin berangkat mandiri dengan biaya terkendali, pengusaha travel dan KBIHU yang ingin membandingkan harga komponen untuk menyusun paket yang kompetitif, serta developer yang ingin ikut membangun. Semua diskusi, saran, dan kontribusi silakan lewat repo ini (lihat bagian Berkontribusi di bawah).
Spesifikasi kanonis berada di umrah-fare-watch-spec/. Dokumen tersebut adalah kontrak produk; folder ini adalah implementasinya.
- Mode data: aplikasi otomatis memilih sumber data. Tanpa kredensial ia berjalan di mode demo (mock deterministik, tanpa jaringan); begitu kredensial provider real tersedia di server, ia beralih ke data live.
- Provider live aktif: Google Flights (tiket) dan Google Hotels (hotel Makkah/Madinah) melalui SerpAPI, dengan konversi FX live ke IDR. Provider lain tersedia sebagai adapter (Travelpayouts/Aviasales, Duffel) dan aktif sesuai kondisi pasar masing-masing.
- Fitur inti: pencarian kombinasi, kalender harga, kalender cakupan per kota, watchlist + alert, dan alur lanjut-booking aman (detail di seksi Fitur).
- Kualitas: release gate otomatis (
npm run release-gate) yang menjalankan typecheck, lint, test, build, smoke test, dan validasi spesifikasi. Data provider real hanya ditampilkan setelah smoke test server-side untuk rute Indonesia lulus, demi menjaga keterbukaan data. - Kuota provider: kuota bulanan yang habis dibedakan dari pembatasan permintaan per jam. API dan UI menampilkan respons khusus, menghentikan panggilan provider lanjutan, dan tidak mengganti data live dengan data mock.
- Deployment publik: VPS produksi tersedia melalui
https://103.226.139.211. Nginx mengalihkan HTTP ke HTTPS dan memakai sertifikat IP short-lived Let's Encrypt dengan renewal otomatis. - Keamanan dan responsif (16 Agustus 2026): penguatan API (rate limit, security headers + CSP, sesi ter-hash, lihat seksi Keamanan) dan tata letak yang nyaman dari layar hape 360px sampai desktop lebar: header ringkas tanpa geser horizontal, kartu hasil 2 kolom di desktop, format harga ringkas di kalender, dan kontrol sentuh minimal 44px.
Catatan: angka fitur dan milestone berubah cepat; detail terkini ada di umrah-fare-watch-spec/progress.md, bukan di README ini.
βοΈ Cari kombinasi termurah: tiket pesawat untuk semua penumpang, hotel Makkah, dan hotel Madinah dalam satu total biaya dalam IDR.- π¨ Status hotel per kota: ketersediaan Makkah (MK) dan Madinah (MD) ditampilkan terpisah, sehingga Anda bisa memutuskan lanjut memproses atau menunggu.
- π Kalender harga 365 hari: bandingkan total lengkap untuk setiap tanggal keberangkatan dalam satu pindai.
- π Kalender cakupan berwarna: tiap tanggal menampilkan status flight dan hotel per kota, dengan warna kartu sesuai kondisi data.
- π Pantauan harga: simpan kombinasi perjalanan dan terima alert in-app saat total turun atau mencapai budget Anda.
- π Lanjut-booking aman: harga diverifikasi ulang sebelum membuka situs provider.
npm install
npm run dev # http://localhost:3000 (mode demo tanpa kredensial)
npm run typecheck
npm run lint
npm test
npm run smoke # end-to-end tanpa kredensial
npm run build # tsc + copy UI ke dist
npm run release-gate # semua check berurutan: typecheck, lint, test, build, smoke, spec validator
npm start # jalankan hasil build (dist/api/server.js)Mode live diaktifkan dengan menyediakan kredensial di server (lihat .env.example; token tidak pernah di-commit). Tanpa kredensial, semua fitur tetap bisa dicoba di mode demo.
GitHub Pages hanya menyajikan file statis; aplikasi ini membutuhkan backend Node.js (API Express, SQLite, session auth, dan background worker), sehingga perlu server sendiri:
- PaaS (Railway, Render, Fly.io): push repo GitHub, set
NODE_VERSION>= 22.5, runnpm install && npm run build && npm start. Catatan: disk SQLite di PaaS bersifat ephemeral saat redeploy; gunakan volume persistent atau DB eksternal jika data pantauan harus bertahan. - VPS kecil (DigitalOcean, Hetzner, dan sejenisnya): kontrol penuh; SQLite permanen di disk; jalankan dengan PM2 atau systemd. Direkomendasikan saat provider real aktif karena API key wajib tersimpan server-side.
- HTTPS berbasis IP:
deploy/nginx-umrah-fare-watch.confmemuat terminasi TLS serta jalur HTTP-01. Sertifikat IP Let's Encrypt membutuhkan Certbot 5.4 atau lebih baru, profilshortlived, timer renewal aktif, dan hookdeploy/certbot-reload-nginx.shagar Nginx memuat sertifikat yang diperbarui. - Envvars penting:
PORT,DB_PATH,MOCK_MODE,SESSION_TTL_DAYS,WATCHLIST_WORKER_INTERVAL_MS,COVERAGE_WORKER_INTERVAL_MS, dan kredensial provider. Lihat.env.example. - Kredensial provider real hanya dimuat dari secret manager server-side, tidak pernah dari frontend atau file env yang di-commit.
src/
api/ Express app, routes, error mapping, correlation ID
composer/ Trip Composer: derive city dates, totals, snapshot, summaries
domain/ types, money, dates, horizons, validation, canonical keys,
completeness, ranking, alerts (pure functions)
providers/ contracts, mock flight/hotel, runtime schemas, registry, FX
services/ search orchestration (bounded discovery + verification +
canonical hotel search + composition + ranking)
store/ node:sqlite schema and append-only repositories
ui/public/ index.html, styles.css, app.js (vanilla, no build step)
tests/ Vitest acceptance tests mapped to 09_ACCEPTANCE_TESTS.md IDs
scripts/ smoke tests, copy-ui.mjs, release-gate.ts
- Runtime schema: zod di boundary adapter; payload provider yang invalid ditolak dan tidak disimpan.
- Uang: integer minor units; normalisasi deterministik half-up; nilai hilang tidak pernah menjadi nol.
- Tanggal: local date ISO; datetime Saudi diturunkan dari UTC instant + offset eksplisit.
- Horizon: user 365 hari, technical flight 370, frontier hotel 330.
- Persistensi: node:sqlite bawaan Node (>= 22.5), append-only observasi, dedup key unik, constraint non-negatif dan checkout >= check-in.
Kontrol yang aktif di API dan UI (diaudit ulang 16 Agustus 2026):
- Kata sandi: salted scrypt (64 byte) per pengguna, verifikasi memakai
timingSafeEqual. Panjang email dibatasi 254 karakter dan kata sandi 8 sampai 128 karakter agar hash tidak bisa dipakai untuk membebani server. - Sesi: token acak 32 byte yang dikirim lewat header
X-Session-Token(bukan cookie, jadi bebas CSRF). Di database hanya disimpan SHA-256 dari token, sehingga kebocoran database tidak langsung membuka akun. Sesi kedaluwarsa dibersihkan otomatis tiap jam. - Rate limiting: endpoint auth dibatasi 20 permintaan per 10 menit per IP; endpoint pencarian dan pemindaian (search/trip, search/calendar, coverage/scan) dibatasi 60 per 5 menit per IP. Melebihi itu menghasilkan 429 beserta header
Retry-After. - Security headers: setiap respons memuat Content-Security-Policy. Script aplikasi tetap same-origin tanpa inline event handler, dengan allowlist terbatas ke subdomain
*.histats.comyang dipakai loader dan renderer counter Histats. HTTP dipertahankan pada allowlist untuk local development, sedangkan produksi selalu dialihkan ke HTTPS. Respons juga memuatX-Content-Type-Options,X-Frame-Options: DENY,Referrer-Policy, danPermissions-Policy. - Correlation ID: header
X-Correlation-IDdari klien hanya diterima bila berupa identifier pendek yang aman; selain itu diganti UUID baru agar log dan header tetap bersih. - Tautan booking: frontend hanya merender tautan provider berprotokol http/https (menolak
javascript:dandata:); handoff ke provider nyata juga melewati allowlist host di server sebelum tautan dibuka. - Validasi input: seluruh input pencarian dan pantauan divalidasi ulang di server dengan zod (batas penumpang, kamar, rentang tanggal, radius, dan horizon), apa pun yang dikirim klien.
- Rahasia: token provider hanya lewat environment variable;
.env, database, dan log diabaikan git.
Repo ini terbuka untuk siapa saja yang peduli pada keterbukaan biaya Umrah:
- Developer: buka issue untuk bug/ide, atau kirim pull request. Mulai dari
umrah-fare-watch-spec/10_FREEBUFF_MASTER_PROMPT.mddan12_HANDOFF_TO_FREEBUFF.mduntuk konteks, lalu pastikannpm run release-gatelulus sebelum mengajukan PR. - Pengusaha travel dan KBIHU: Anda tahu kebutuhan nyata jamaah dan seluk-beluk paket. Saran fitur, data, atau koreksi asumsi bisnis sangat berharga - buka issue dengan label diskusi atau tulis di bagian saran.
- Mantan jamaah haji/umrah: ceritakan pengalaman nyata (biaya aktual, muslihat harga, hal yang baru disadari setelah berangkat) lewat issue "Pengalaman Jamaah". Ini membantu aplikasi menampilkan peringatan dan konteks yang jujur.
- Calon jamaah: usulkan hal-hal yang Anda butuhkan saat merencanakan keberangkatan mandiri - fitur, cara tampilan harga, atau pertanyaan yang sering membuat bingung.
Panduan singkat: gunakan bahasa Indonesia, jelaskan masalah dan harapan dengan jelas, dan sertakan contoh data bila relevan (tanpa data pribadi sensitif). Semua saran ditanggapi, tidak semua langsung dikerjakan - prioritas mengikuti spesifikasi dan kebutuhan mayoritas pengguna.
Harga yang ditampilkan hanya mencakup tiket pesawat serta hotel Makkah dan Madinah, belum termasuk berbagai kebutuhan lain dalam perjalanan umrah, antara lain:
- Visa
- Transportasi darat antarkota (bus atau kereta)
- Transportasi dalam kota
- Makanan (misalnya 3x makan sehari)
- Jasa muthawif atau pembimbing ibadah
- Tiket ziarah
- Bagasi atau biaya tambahan yang tidak dinyatakan provider
- Asuransi
- Pengeluaran pribadi
Harga dan ketersediaan dapat berubah. Hasil membandingkan provider yang aktif saat data diambil, bukan seluruh penawaran di internet. Periksa kembali total, syarat refund, detail reservasi hotel, persyaratan visa, dan kebijakan provider sebelum booking. Mode demo memakai data sintetis.