Web app pemantau harga tiket pesawat — Duffel API + LCC Scraper + Web Push Notification
Live: https://tiket.andresptr.site
Stack tanpa Docker. Frontend, backend, Postgres, dan Redis semua jalan native untuk hemat RAM di VPS terbatas.
- Node.js 20+
- PostgreSQL 14+ (install lokal atau pakai service)
- Redis 6+ (install lokal atau pakai service)
- PM2 (untuk production):
npm install -g pm2 - Duffel API token (opsional di dev — daftar gratis di https://duffel.com)
cp backend/.env.example backend/.env
# Edit backend/.env: isi DUFFEL_ACCESS_TOKEN (opsional), DATABASE_URL, REDIS_URL# Buat DB lokal
psql -U postgres -c "CREATE USER mytiket WITH PASSWORD 'mytiket_dev_password';"
psql -U postgres -c "CREATE DATABASE mytiket OWNER mytiket;"
# Pastikan redis aktif
redis-cli ping # → PONGcd backend
npm install
npm run vapid:generate
# Copy output ke .envcd backend
npm install
npx prisma generate
npx prisma migrate dev # buat tabel
npx playwright install chromium # untuk scraper LCC (opsional di dev)
npm run dev
# Backend: http://localhost:4000cd frontend
npm install
npm run dev
# Frontend: http://localhost:3000| Variable | Required | Description |
|---|---|---|
DUFFEL_ACCESS_TOKEN |
⚪ | Dari duffel.com → Dashboard → Developer → Access tokens. Format: duffel_test_xxx (sandbox gratis) atau duffel_live_xxx |
DATABASE_URL |
✅ | PostgreSQL: postgresql://user:pass@localhost:5432/mytiket |
REDIS_URL |
✅ | Redis: redis://localhost:6379 |
VAPID_PUBLIC_KEY |
✅ | Generate: npm run vapid:generate |
VAPID_PRIVATE_KEY |
✅ | Generate: npm run vapid:generate |
VAPID_EMAIL |
✅ | Email untuk VAPID |
CHECK_INTERVAL_MIN |
⚪ | Interval scraper (default 120 menit) |
PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH |
⚪ | Path chromium (default /usr/bin/chromium-browser) |
myTiket/
├── frontend/ # Next.js 14 (TypeScript, Tailwind, shadcn/ui)
├── backend/ # Fastify API + BullMQ Workers + Playwright Scrapers
├── nginx/
│ └── nginx.aapanel.conf # Vhost untuk aaPanel / nginx native
├── ecosystem.config.js # PM2 config (frontend + backend)
├── deploy.sh # Deploy script (full native, no Docker)
└── .env.example
| Maskapai | Sumber | Kode |
|---|---|---|
| Garuda Indonesia | Duffel API | GA |
| Batik Air | Duffel API | ID |
| Singapore Airlines | Duffel API | SQ |
| Malaysia Airlines | Duffel API | MH |
| AirAsia (GDS) | Duffel API | QZ |
| Lion Air | Web Scraper | JT |
| Citilink | Web Scraper | QG |
| AirAsia Indonesia | Web Scraper | QZ |
| Super Air Jet | Web Scraper | IU |
- User cari tiket → klik "Set Alert"
- Input harga target (IDR)
- Browser minta izin notifikasi
- Backend cek harga setiap 2 jam via BullMQ (bisa diubah via
CHECK_INTERVAL_MIN) - Saat harga ≤ target → Web Push Notification dikirim ke browser
- Notifikasi muncul meski tab ditutup
- Ubuntu 20.04 / 22.04 / 24.04
- Minimal 2 GB RAM (rekomendasi tambah 2 GB swap —
deploy.sh first-runsetup otomatis) - 2 CPU cores
- Nginx sudah dikelola control panel (aaPanel) atau install manual
# Di VPS Ubuntu (sebagai root)
git clone https://github.com/andresptr/mytiket.git /opt/mytiket
cd /opt/mytiket
bash deploy.sh first-run
# Install: Node.js 20, PM2, PostgreSQL 16, Redis, Chromium, 2GB swap, create DB
# Ganti password DB production
sudo -u postgres psql -c "ALTER USER mytiket WITH PASSWORD 'GANTI_PASSWORD_KUAT';"
# Isi env
cp backend/.env.example backend/.env.prod
nano backend/.env.prod # update DATABASE_URL password sesuai di atas
# Setup nginx vhost lewat aaPanel:
# 1. Add Site: tiket.andresptr.site
# 2. Buka Config → paste isi nginx/nginx.aapanel.conf
# 3. SSL → Let's Encrypt → apply
# Deploy
bash deploy.shcd /opt/mytiket
bash deploy.sh
# Akan: git pull → npm ci → build → prisma migrate → pm2 reload| Service | Max RAM | Catatan |
|---|---|---|
| Frontend (Next.js) | 350 MB | PM2 fork mode, single instance |
| Backend (Fastify + Worker) | 450 MB | Termasuk spike Playwright saat scraping |
| PostgreSQL | ~150 MB | Default config |
| Redis | ~30 MB | AOF on, dataset kecil |
| Nginx | ~20 MB | Shared dengan site lain |
| Total peak | ~1 GB | Sisanya buffer + control panel |
⚠️ Monitor:pm2 monitdanfree -h. Kalau OOM, naikkanCHECK_INTERVAL_MINjadi 180+ atau matikan scraper LCC.
pm2 list # daftar proses
pm2 logs # semua logs
pm2 logs mytiket-backend # logs backend saja
pm2 reload all # zero-downtime reload
pm2 restart mytiket-frontend # restart (singkat downtime)
pm2 monit # CPU & memory monitor real-time
pm2 save # simpan list proses → auto-start saat reboot- Frontend: Next.js 14, TypeScript, Tailwind CSS, TanStack Query, Recharts — PM2
- Backend: Fastify, TypeScript, Prisma, BullMQ, Playwright — PM2
- Database: PostgreSQL 16 — native (apt)
- Cache: Redis 7 — native (apt)
- Scraping: Playwright + Chromium native (
/usr/bin/chromium-browser) - Notifications: Web Push API (VAPID)
- Web server: Nginx (managed by aaPanel) + Let's Encrypt