Bridge notifikasi pembayaran dari perangkat merchant menjadi webhook untuk otomasi sistem internal. Tidak terhubung langsung ke jaringan pembayaran atau melakukan konfirmasi resmi dari bank.
Proyek ini disediakan untuk tujuan edukasi dan pembelajaran non-komersial. Pengguna bertanggung jawab penuh atas cara penggunaan, termasuk kepatuhan terhadap hukum yang berlaku, syarat layanan pihak ketiga, dan regulasi terkait (UU PDP, UU ITE, Peraturan BI, POJK, dll). Proyek ini tidak berafiliasi dengan Bank Indonesia, OJK, atau penyedia e-wallet mana pun. Lihat bagian Posisi Regulasi & Batasan Layanan untuk informasi lebih lanjut.
Dokumen hukum penting:
- Terms of Use — syarat yang mengikat secara hukum
- Disclaimer — pernyataan tanggung jawab
- Trademark Disclaimer — perlindungan merek dagang
- Privacy Policy — kebijakan privasi
Gunakan untuk:
- POS internal — mendeteksi pembayaran masuk langsung dari notifikasi HP tanpa scan barcode
- Sistem kasir UMKM — update status pesan otomatis saat notifikasi pembayaran diterima
- Otomasi toko online — konfirmasi pembayaran manual dari transfer QRIS ke webhook pesanan
- Integrasi ERP internal — catat pembayaran QRIS masuk ke sistem akuntansi tanpa entri manual
- Dashboard monitoring pembayaran multi-merchant — lihat status notifikasi, perangkat, dan antrian retry real-time
- Pencocokan otomatis — cocokkan notifikasi masuk dengan pesanan yang belum dibayar (via nominal + waktu)
Jangan gunakan untuk:
- Payment Gateway
- Agregator pembayaran
- Acquiring service
- Verifikasi resmi transaksi bank
- Mengelola dana pihak ketiga
Bank / DANA / GoPay / OVO / BCA / BRI / Mandiri / BNI
│
▼
Push Notification Android
│
▼
QRIS Bridge Android App
┌─────────────────────────┐
│ NotificationListener │
│ Parser (plugin + regex) │
│ Room DB (offline queue) │
│ WorkManager (retry) │
│ OkHttp WebSocket │
└─────────┬───────────────┘
│ WebSocket TLS (device_id + secret auth)
▼
┌──────────────────────────────────┐
│ Bridge Server (Go) │
│ │
│ ┌─────────┐ ┌───────────────┐ │
│ │ WebSocket│ │ REST API │ │
│ │ Handler │ │ (36 endpoint)│ │
│ └────┬─────┘ └───────┬───────┘ │
│ │ │ │
│ ┌────▼────────────────▼───────┐ │
│ │ Event Bus │ │
│ │ (Redis Streams) │ │
│ └────────────┬────────────────┘ │
│ │ │
│ ┌────────────▼────────────────┐ │
│ │ Worker (stream consumer) │ │
│ │ ┌─────────┐ ┌───────────┐ │ │
│ │ │ Matching│ │ Webhook │ │ │
│ │ │ Engine │ │ Delivery │ │ │
│ │ └─────────┘ └───────────┘ │ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌───────────────┐ │
│ │ Retry │ │ Dedup (SHA256)│ │
│ │ Queue │ │ Fingerprint │ │
│ │ (Redis) │ │ │ │
│ └──────────┘ └───────────────┘ │
│ │
│ DB: PostgreSQL │
│ Cache/Queue: Redis │
└────────────────┬──────────────────┘
│
▼
POS / WooCommerce / Laravel / Node.js
(Webhook POST + HMAC SHA256 Signature)
QRIS Bridge adalah alat otomasi notifikasi — bukan penyelenggara sistem pembayaran, bukan dompet digital, bukan payment gateway, bukan agregator pembayaran, dan bukan layanan transfer dana.
Aplikasi tidak menginisiasi, mengubah, atau memproses transaksi pembayaran. Aplikasi hanya membaca informasi dari notifikasi yang diterima perangkat (nama aplikasi, nominal, pengirim) dan meneruskannya ke server dalam bentuk webhook.
QRIS Bridge tidak:
- Terhubung ke jaringan sistem pembayaran
- Mengakses akun atau kredensial pengguna e-wallet
- Menyimpan atau mengelola dana pihak ketiga
- Melakukan verifikasi resmi transaksi ke bank/PJP
- Berfungsi sebagai alat pembayaran
Proyek ini tidak berafiliasi, didukung, atau disahkan oleh:
- Bank Indonesia
- Otoritas Jasa Keuangan (OJK)
- Kementerian Komunikasi dan Digital (Komdigi)
- Penyedia dompet elektronik seperti DANA, GoPay, ShopeePay, OVO, atau pihak lainnya
Status hukum bergantung pada fungsi nyata layanan, model bisnis, dan penilaian regulator. Jika dikomersilkan atau terintegrasi lebih dalam dengan ekosistem pembayaran, analisis regulasi harus diperbarui.
Data yang diproses oleh QRIS Bridge:
| Data | Sumber | Tujuan | Retensi |
|---|---|---|---|
| Nama aplikasi (e.g. DANA, GoPay) | Notifikasi Android | Identifikasi sumber pembayaran | Hingga dihapus pengguna |
| Nominal pembayaran | Notifikasi Android | Pencocokan dengan invoice | Hingga dihapus pengguna |
| Nama pengirim | Notifikasi Android | Referensi transaksi | Hingga dihapus pengguna |
| Teks notifikasi mentah (raw) | Notifikasi Android | Debugging & pengembangan parser | Tidak disimpan permanen |
| ID perangkat + secret | Konfigurasi pengguna | Autentikasi WebSocket | Selama perangkat terdaftar |
| Alamat IP | Koneksi jaringan | Operasional server | Tidak disimpan |
Pengguna dapat menghapus data melalui:
- Dashboard web — hapus notifikasi, device, atau data merchant
- API —
DELETEendpoint untuk resources terkait - Database — hapus langsung dari PostgreSQL jika akses tersedia
Pengguna bertanggung jawab memastikan penggunaan QRIS Bridge sesuai dengan syarat layanan aplikasi pihak ketiga (e-wallet, bank, platform merchant) yang mereka gunakan.
Notifikasi pembayaran e-wallet/banking mengandung informasi sensitif: nominal, pengirim, dan kadang saldo. Jika bocor, pihak ketiga bisa:
- Melihat seluruh riwayat transaksi merchant (nominal, frekuensi, pengirim)
- Menyusun profil bisnis merchant
- Menggunakan data untuk social engineering
QRIS Bridge menerapkan:
- Full encryption — seluruh data (app, amount, sender, rawText) dienkripsi AES-256-GCM di Room DB
- Encryption at rest — kunci enkripsi disimpan di Android Keystore (hardware-backed)
- No full-db leak — walau file .db bocor, data tidak bisa dibaca tanpa kunci
Tidak. Data hanya dikirim ke server yang Anda konfigurasi sendiri. Tidak ada data yang dikirim ke pengembang, ke penyedia e-wallet, atau ke pihak ketiga mana pun. Lihat PRIVACY.md.
QRIS Bridge adalah alat otomasi notifikasi — membaca notifikasi yang sudah ada di perangkat Anda. Tidak ada:
- Intersepsi jaringan (tidak melanggar UU ITE Pasal 31)
- Akses tanpa hak ke sistem e-wallet (tidak ada login ke akun pengguna)
- Modifikasi transaksi (hanya baca, tidak tulis)
- Penyimpanan data pihak ketiga (self-hosted)
Namun, kepatuhan terhadap Terms of Service masing-masing e-wallet berbeda-beda. Lihat tabel Audit ToS untuk detail. Konsultasi dengan legal counsel disarankan untuk penggunaan komersial.
Data di Room DB terenkripsi dengan Android Keystore — tidak bisa dibaca tanpa unlock device. Anda dapat:
- Unpair device dari dashboard server (cabut akses WebSocket)
- Hapus data dari server via API
DELETE /api/v1/notifications - Hapus data lokal dari device lain (jika sudah pairing sebelumnya)
Hanya Anda (pemilik perangkat dan server). Developer tidak memiliki akses ke instance Anda.
Android: Pengaturan > Privasi Data > Hapus Semua Data — menghapus Room DB + mengirim DELETE ke server. Atau langsung via API DELETE /api/v1/notifications dengan JWT atau device_id+secret.
Tidak. Audit kode membuktikan QRIS Bridge hanya membaca title, text, dan bigText dari notifikasi yang masuk. Tidak ada akses ke SMS, kontak, lokasi, kamera (setelah pairing QR selesai), galeri, mikrofon, atau data pribadi lainnya. Lihat docs/THREAT_MODEL.md untuk detail audit.
Tidak. QRIS Bridge hanya meneruskan informasi — tidak bisa menginisiasi transaksi, tidak bisa mengubah nominal, tidak bisa memalsukan notifikasi (ini terjadi di sisi e-wallet, bukan di bridge). Webhook tetap harus diverifikasi via HMAC signature di sisi merchant.
QRIS Bridge bekerja berdasarkan notifikasi yang diterima pada perangkat merchant. Notifikasi bukan merupakan bukti pembayaran yang dijamin oleh bank atau penyelenggara QRIS. Merchant tetap bertanggung jawab melakukan mitigasi risiko sesuai kebutuhan operasionalnya.
Sistem tidak memverifikasi transaksi langsung ke sistem bank atau penyelenggara QRIS. Untuk penggunaan produksi, tambahkan langkah mitigasi seperti autentikasi perangkat, tanda tangan HMAC, enkripsi TLS, audit log, dan mekanisme penanganan kegagalan.
Perangkat lunak ini diberikan "AS IS", tanpa jaminan dalam bentuk apa pun, sebagaimana diatur dalam lisensi AGPL-3.0. Lihat LICENSE untuk detail.
- Duplicate Detection — SHA256 fingerprint (app + text + minute window), cegah double processing
- Event Bus — Redis Streams dengan consumer group, antrean terjamin
- Smart Matching — nominal duplikat dihandle dengan ambil invoice tertua
- Plugin Parser — format JSON dengan priority, extractor, validator; auto-update tanpa update APK
- Pairing Code + QR — registrasi device via kode pairing (5 menit expiry) + QR code PNG
- JWT Authentication — login via API Key, Bearer token untuk semua request
- Retry Queue — exponential backoff (30s → max 24h, max 10 retry)
- HMAC Signature — setiap webhook ditandatangani SHA256
- Dashboard Web — login page, statistik real-time, last notification, device table, WS latency
- SDK Multi-bahasa — Go, PHP, Node.js, Python
- Integrasi Merchant — Laravel, WooCommerce, WordPress, FastAPI
- Offline Queue — Android simpan ke Room DB, kirim ulang via WorkManager
- Multi-bank — DANA, GoPay, OVO, myBCA, BRImo, Livin, BNI Mobile, blu
- Event-based Webhooks — subscribe event tertentu (payment., notification., device., parser., webhook.*) dengan glob pattern
- Event Replay — replay ulang event dalam range waktu tertentu (max 7 hari)
- Dead Letter Queue — webhook gagal total dipindahkan ke DLQ untuk inspeksi manual
- Bulk Retry — retry semua webhook failed sekaligus
- Webhook Test — test kirim webhook dummy ke endpoint untuk verifikasi
- Parser Management UI — CRUD parser plugin dari dashboard
- Parser Test — uji coba parser terhadap teks notifikasi
- Multi-API Key — buat multiple API key per merchant dengan revoke
- Admin Login — autentikasi admin via email + password
- Backup & Restore — ekspor/impor konfigurasi merchant (devices, webhooks, API keys, parsers)
- Pagination — semua list endpoint mendukung pagination (per_page + page)
- Structured Logging — zerolog JSON logging
- Health Check Depth — cek koneksi DB + Redis + WebSocket connection count
- Wildcard Event Subscription — subscribe events via glob pattern (e.g.
payment.*) - Sequence Numbers — setiap event memiliki sequence number incrementing
- Event Schemas — schema JSON untuk setiap event di
schemas/ - Event Registry Docs — dokumentasi setiap event di
docs/events/ - Prometheus Metrics — endpoint
/metricsdengan metrik delivery duration, success rate, dll - Graceful Shutdown — server menutup koneksi dengan aman saat SIGTERM
- 27 Event Types — 27 event types terdefinisi: payment (6), notification (5), device (7), parser (3), webhook (4), system (2)
| Event | Category | Description |
|---|---|---|
payment.detected |
Payment | Pembayaran terdeteksi dari notifikasi |
payment.matched |
Payment | Pembayaran cocok dengan expectation |
payment.paid |
Payment | Payment expectation terbayar |
payment.expired |
Payment | Payment expectation kadaluarsa |
payment.unmatched |
Payment | Pembayaran tidak cocok dengan expectation |
payment.failed |
Payment | Pembayaran gagal |
notification.received |
Notification | Notifikasi diterima dari device |
notification.parsed |
Notification | Notifikasi berhasil di-parse |
notification.duplicate |
Notification | Notifikasi duplikat (SHA256 fingerprint) |
notification.invalid |
Notification | Notifikasi tidak valid |
notification.dropped |
Notification | Notifikasi di-drop |
device.paired |
Device | Device berhasil dipairing |
device.online |
Device | Device terhubung WebSocket |
device.offline |
Device | Device terputus WebSocket |
device.reconnected |
Device | Device reconnect |
device.unpaired |
Device | Device di-unpair |
device.heartbeat.timeout |
Device | Heartbeat device timeout |
parser.updated |
Parser | Parser plugin diupdate |
parser.downloaded |
Parser | Parser config didownload device |
parser.failed |
Parser | Parser plugin gagal |
webhook.delivered |
Webhook | Webhook berhasil dikirim |
webhook.failed |
Webhook | Webhook gagal dikirim |
webhook.retry |
Webhook | Webhook masuk retry queue |
webhook.disabled |
Webhook | Webhook dinonaktifkan |
system.started |
System | Server start |
system.shutdown |
System | Server shutdown |
| Model | Table | Key Fields |
|---|---|---|
Merchant |
merchants |
id, name, api_key |
Device |
devices |
device_id, merchant_id, secret, status, last_seen |
Notification |
notifications |
device_id, app, amount, sender, fingerprint (unique), raw_text, parsed |
PaymentExpectation |
payment_expectations |
merchant_id, order_id, amount, status, expires_at |
WebhookEndpoint |
webhook_endpoints |
merchant_id, url, secret, active, events, payload_template |
PairingCode |
pairing_codes |
merchant_id, code (unique), device_name, expires_at, used |
WebhookLog |
webhook_logs |
webhook_id, merchant_id, order_id, amount, status, status_code, response, error_message, retry_count |
APIKey |
api_keys |
merchant_id, name, key (unique), active, last_used |
ParserPlugin |
parser_plugins |
package (unique), app, priority, version, active, amount_pattern, amount_group, amount_multiply, sender_pattern, sender_group, min_length, must_match |
DeadLetter |
dead_letters |
webhook_id, merchant_id, order_id, amount, url, response, error_message, retry_count |
EventLog |
event_logs |
event_id, event_type, delivery_id (unique), merchant_id, device_id, sequence, payload, status, status_code, response, error_message |
Admin |
admins |
email (unique), password, name |
Semua tabel auto-migrate saat server start.
| Method | Path | Deskripsi |
|---|---|---|
POST |
/api/v1/auth/login |
Login dengan API Key → JWT token |
POST |
/api/v1/auth/admin/login |
Login admin dengan email + password |
GET |
/api/v1/health |
Health check (DB + Redis + WS connection count + uptime) |
POST |
/api/v1/parsers/sync |
Cek versi parser config (Android) |
GET |
/api/v1/parsers/config |
Download parser plugins config |
POST |
/api/v1/pair/confirm |
Konfirmasi pairing device dengan kode |
GET |
/api/v1/pair/qr/:code |
QR code PNG image untuk pairing |
| Method | Path | Deskripsi |
|---|---|---|
POST |
/api/v1/devices/register |
Daftarkan perangkat Android langsung |
GET |
/api/v1/devices |
List semua device terdaftar (paginated) |
GET |
/api/v1/devices/:id/status |
Cek status online/offline device |
POST |
/api/v1/payments/expect |
Buat payment expectation (invoice) |
GET |
/api/v1/payments/pending |
Lihat pembayaran pending |
GET |
/api/v1/notifications |
Riwayat notifikasi (paginated) |
GET |
/api/v1/notifications/:id |
Detail notifikasi + matched order + device info |
POST |
/api/v1/webhooks/register |
Daftarkan endpoint webhook (dengan event filter) |
GET |
/api/v1/webhooks |
Lihat webhook terdaftar |
POST |
/api/v1/webhooks/test |
Kirim webhook test dummy ke URL |
POST |
/api/v1/webhooks/retry-all |
Retry semua webhook failed |
GET |
/api/v1/webhooks/:id/logs |
Log delivery webhook (paginated) |
POST |
/api/v1/webhooks/:id/retry |
Retry delivery webhook spesifik |
POST |
/api/v1/pair/request |
Minta kode pairing device |
GET |
/api/v1/dashboard |
Statistik dashboard (merchant, devices, notif, pending, paid, queue, WS, parsers) |
GET |
/api/v1/api-keys |
List API keys merchant |
POST |
/api/v1/api-keys |
Buat API key baru |
DELETE |
/api/v1/api-keys/:id |
Revoke API key |
GET |
/api/v1/parsers/plugins |
List parser plugins (paginated) |
POST |
/api/v1/parsers/plugins |
Tambah parser plugin baru |
PUT |
/api/v1/parsers/plugins/:id |
Update parser plugin |
DELETE |
/api/v1/parsers/plugins/:id |
Hapus parser plugin |
POST |
/api/v1/parsers/test |
Test parser terhadap teks notifikasi |
GET |
/api/v1/dead-letters |
List dead letter queue (paginated) |
POST |
/api/v1/dead-letters/:id/retry |
Retry dead letter |
DELETE |
/api/v1/dead-letters/:id |
Hapus dead letter |
POST |
/api/v1/events/replay |
Replay event dalam range waktu (max 7 hari) |
GET |
/api/v1/backup |
Export backup konfigurasi merchant |
POST |
/api/v1/backup |
Import backup konfigurasi merchant |
| Method | Path | Deskripsi |
|---|---|---|
GET |
/ |
Web Dashboard (login → stats, parsers, API keys, backup, DLQ) |
GET |
/ws |
WebSocket (auth via query: device_id + secret) |
GET |
/metrics |
Prometheus metrics endpoint |
Setiap webhook dikirim dengan envelope event:
{
"id": "evt_01JY8Q8D5Z9P3...",
"event": "payment.paid",
"version": "1.0",
"timestamp": "2026-07-20T12:00:00Z",
"merchant_id": 1,
"device_id": "device-01",
"data": {
"order_id": "INV001",
"amount": 25250,
"status": "paid",
"device_id": "device-01"
},
"metadata": {
"app": "DANA",
"parser_version": 1,
"bridge_version": "1.0",
"device_model": "Pixel 7"
}
}Headers:
| Header | Deskripsi |
|---|---|
X-QrisBridge-Event |
Nama event (e.g. payment.paid) |
X-QrisBridge-Event-Id |
Unique event ID (evt_xxx) |
X-QrisBridge-Delivery-Id |
Unique per delivery attempt (del_xxx) |
X-QrisBridge-Signature |
HMAC-SHA256 hex digest — gunakan untuk verifikasi |
X-QrisBridge-Timestamp |
Unix timestamp |
Verifikasi signature di penerima:
HMAC-SHA256(body, secret) == X-QrisBridge-Signature
Parser didefinisikan di database parser_plugins table (dikelola via API/dashboard) dengan format:
{
"package": "id.dana",
"app": "DANA",
"priority": 100,
"version": 1,
"active": true,
"amount_pattern": "Rp\\s?([\\d.]+)",
"amount_group": 1,
"amount_multiply": 0,
"sender_pattern": "dari\\s(.+)",
"sender_group": 1,
"min_length": 3,
"must_match": "DANA|dana"
}Android auto-sync parser config dari server via ParserSyncWorker (periodik tiap 6 jam). Tidak perlu update APK saat regex berubah.
Merchant Panel (Web) Android App
│ │
│ POST /api/v1/pair/request │
│ { merchant_id, device } │
├──── kode pairing ──────────►│
│ │
│ POST /api/v1/pair/confirm │
│ { code, device_id, secret}│
◄──────── OK ────────────────┤
│ │
│ WebSocket connect │
│ (device_id + secret) │
Card pairing dibuat dengan QR code: GET /api/v1/pair/qr/:code (return PNG). Response POST /api/v1/pair/confirm juga return JWT token untuk device. Pairing code expired dalam 5 menit.
Internet
│
▼
Nginx (SSL/TLS termination + reverse proxy)
│
▼
Go Server (REST API + WebSocket + Worker)
│
├──────────┬──────────┐
▼ ▼ ▼
Redis PostgreSQL Webhook → POS / Toko
(Stream (Merchant, (HMAC SHA256)
Queue) Device,
Notification)
# Clone & run
git clone https://github.com/yourusername/qris-bridge
cd qris-bridge
docker compose up -d
# Login dapatkan JWT token
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"api_key":"your-api-key-here"}'
# → { "token": "eyJ...", "expires_in": 86400 }
# Buat invoice (pakai token dari atas)
curl -X POST http://localhost:8080/api/v1/payments/expect \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"order_id":"INV001","amount":25000,"expires_in_minutes":30}'
# Daftarkan webhook
curl -X POST http://localhost:8080/api/v1/webhooks/register \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"url":"https://toko.com/webhook","secret":"wh-secret-123"}'
# Buka dashboard
open http://localhost:8080
# Login dengan API Key yang dihasilkan saat pertama kali aplikasi dijalankanqris-bridge/
├── cmd/server/main.go # Entry point Go server
├── internal/
│ ├── api/
│ │ ├── routes.go # 36 REST endpoints + 3 non-API
│ │ └── auth.go # JWT login + admin login + middleware
│ ├── ws/handler.go # WebSocket + auth + hub
│ ├── config/config.go # Env-based configuration
│ ├── database/
│ │ ├── db.go # PostgreSQL + auto-migrate
│ │ └── models.go # 12 models (GORM)
│ ├── parser/
│ │ ├── parser.go # Regex parser (fallback)
│ │ └── plugin.go # Plugin parser (priority, validator)
│ ├── matching/engine.go # Smart matching engine
│ ├── eventbus/stream.go # Redis Streams event bus
│ ├── worker/worker.go # Stream consumer + retry processor
│ ├── webhook/
│ │ ├── dispatch.go # Event dispatch + subscription filter
│ │ ├── deliver.go # Webhook delivery + HMAC signing
│ │ └── deliver_retry.go # Retry delivery
│ ├── queue/queue.go # Retry queue (exponential backoff)
│ ├── dedup/dedup.go # SHA256 duplicate detection
│ ├── redis/redis.go # Redis client wrapper
│ ├── metrics/metrics.go # Prometheus metrics
│ └── integration/ # Server-side integrations
├── parsers/
│ ├── plugins.json # Plugin parser config (8 bank)
│ ├── dana.json, gopay.json # Legacy per-app parsers
│ ├── ovo.json, bca.json
│ ├── brimo.json, mandiri.json
│ ├── bni.json, blu.json
├── schemas/ # JSON Schema untuk setiap event
│ ├── payment.paid.json
│ ├── payment.detected.json
│ ├── notification.received.json
│ └── device.online.json
├── docs/
│ ├── API.md # Dokumentasi endpoint
│ ├── ARCHITECTURE.md # Arsitektur detail
│ ├── ANDROID.md # Setup Android
│ ├── DEPLOYMENT.md # Panduan deployment
│ ├── SECURITY.md # Threat model & mitigasi
│ └── events/ # Dokumentasi setiap event type
│ ├── payment.paid.md
│ ├── payment.detected.md
│ ├── notification.received.md
│ └── device.online.md
├── monitoring/ # Monitoring & observability
│ ├── grafana-dashboard.json
│ ├── prometheus-alerts.yml
│ └── loadtest.js
├── sdk/ # Client libraries
│ ├── go/qrisbridge/ # Go SDK
│ ├── php/ # PHP SDK (Composer)
│ ├── nodejs/ # Node.js SDK (npm)
│ └── python/ # Python SDK (pip)
├── integrations/ # Merchant platform plugins
│ ├── laravel/ # Laravel service provider
│ ├── woocommerce/ # WooCommerce plugin
│ ├── wordpress/ # WordPress plugin
│ └── fastapi/ # FastAPI middleware
├── web/dashboard/ # Web dashboard (HTML/JS)
│ └── index.html # Login + 5 tabs: Dashboard, Parser, API Keys, Backup, Dead Letter
├── android-app/ # Android Kotlin project
│ └── app/src/main/java/com/qrisbridge/
│ ├── service/
│ │ ├── NotificationListener.kt # Tangkap notifikasi bank
│ │ ├── WebSocketService.kt # Foreground WS service
│ │ ├── SyncWorker.kt # WorkManager retry sender
│ │ ├── SyncScheduler.kt # Scheduler helper
│ │ ├── ParserSyncWorker.kt # Auto-update parser config
│ │ └── BootReceiver.kt # Auto-start on boot
│ ├── parser/NotificationParser.kt # Plugin + builtin parser
│ ├── data/
│ │ ├── local/ # Room DB + DAO
│ │ └── remote/WebSocketClient.kt # OkHttp WS client
│ └── ui/MainActivity.kt # Status dashboard
├── migrations/ # SQL migration files
├── scripts/ # Utility scripts
├── docker-compose.yml # Go + PostgreSQL + Redis + Nginx
├── Dockerfile # Multi-stage build
├── nginx.conf # Reverse proxy + WS upgrade
└── README.md
1. Customer bayar via QRIS (DANA/GoPay/OVO/dll)
2. Notifikasi masuk ke Android merchant
3. NotificationListenerService menangkap
4. Parser ekstrak nominal & pengirim
5. SHA256 fingerprint → cek duplikasi
6. Simpan ke Room DB
7. Kirim via WebSocket ke server
8. Server simpan ke PostgreSQL
9. Publish event ke Redis Stream
10. Worker consume stream
11. Matching engine cocokkan nominal
12. PaymentExpectation status → "paid"
13. Dispatch event ke webhook endpoints (sesuai subscription)
14. Webhook POST ke endpoint merchant
15. Jika gagal → masuk retry queue (30s, 1m, 2m, ... max 24h)
16. Jika max retry habis → pindah ke Dead Letter Queue
| Component | Type | Fungsi |
|---|---|---|
NotificationListener |
NotificationListenerService |
Tangkap notifikasi dari 8 app bank |
WebSocketService |
Service (Foreground) |
Maintain WS connection, kirim notif |
SyncWorker |
WorkManager |
Kirim ulang notifikasi gagal (exp backoff) |
ParserSyncWorker |
WorkManager |
Download parser config (tiap 6 jam) |
BootReceiver |
BroadcastReceiver |
Auto-start service setelah reboot |
WebSocketClient |
OkHttp | Auto reconnect, heartbeat, offline queue |
- Backend: Go 1.24, Gin, Gorilla WebSocket, GORM, PostgreSQL, Redis Streams, zerolog, Prometheus
- Android: Kotlin, NotificationListenerService, Room, OkHttp, WorkManager
- Infra: Docker Compose, Nginx, Alpine
- Observability: Prometheus metrics, Grafana dashboard, structured JSON logging
import "github.com/user/qris-bridge/sdk/go/qrisbridge"
client := qrisbridge.New("http://localhost:8080", "api-key-anda")
client.CreateExpectation("INV001", 25000)use QrisBridge\Client;
$client = new Client('http://localhost:8080', 'api-key-anda');
$client->createExpectation('INV001', 25000);const { QrisBridgeClient } = require('qrisbridge');
const client = new QrisBridgeClient('http://localhost:8080', 'api-key-anda');
await client.createExpectation('INV001', 25000);from qrisbridge import QrisBridgeClient
client = QrisBridgeClient('http://localhost:8080', 'api-key-anda')
client.create_expectation('INV001', 25000)Verifikasi webhook signature:
qrisbridge.VerifySignature(payload, signature, secret)
// PHP: Client::verifySignature($payload, $signature, $secret)
// Node: QrisBridgeClient.verifySignature(payload, sig, secret)
// Python: client.verify_signature(payload, sig, secret)| Platform | Direktori | Cara Pakai |
|---|---|---|
| Laravel | integrations/laravel/ |
Composer package, service provider, webhook controller |
| WooCommerce | integrations/woocommerce/ |
WordPress plugin, auto-complete order |
| WordPress | integrations/wordpress/ |
REST endpoint + qris_bridge_payment_received action |
| FastAPI | integrations/fastapi/ |
Pydantic webhook handler, HMAC verification |
Buka http://localhost:8080/, login dengan API Key merchant atau login admin (email + password). Terdapat 5 tab:
- Stat cards: merchant, perangkat terdaftar, online, notifikasi, pending payment, terverifikasi, success rate, antrean retry, webhook terdaftar, parser aktif, WS tersambung, latensi WS
- Last notification detail (app, amount, sender, time) — klik untuk detail
- Device table (device id, nama, status online/offline, terakhir)
- Notification table (app, amount, sender, raw text, time) — klik untuk detail
- Webhook table + register webhook form (dengan event subscription checkboxes)
- Webhook logs (filter by webhook ID, retry individual/all failed)
- Test webhook URL
- Parser plugins table (package, app, priority, version, status, amount pattern, sender pattern, edit/delete)
- Tambah/edit parser plugin form
- Test parser (paste notification text, lihat hasil parsing)
- API keys table (name, status, last used, created, revoke)
- Buat API key baru
- Export backup (download JSON konfigurasi merchant)
- Import backup (paste JSON, restore konfigurasi)
- Dead letter queue table (webhook, order, amount, error, retry count, time, retry/delete)
Semua tabel mendukung pagination. Auto-refresh setiap 15 detik.
Dokumentasi lebih lengkap ada di folder docs/:
| Dokumen | Deskripsi |
|---|---|
PRIVACY.md |
Kebijakan privasi & pemrosesan data |
docs/THREAT_MODEL.md |
Threat model, data flow, compliance checklist |
docs/ARCHITECTURE.md |
Arsitektur detail, aliran data, state machine |
docs/API.md |
Dokumentasi semua endpoint + request/response |
docs/ANDROID.md |
Setup, komponen, dan troubleshooting Android |
docs/DEPLOYMENT.md |
Panduan deploy production + scaling |
docs/SECURITY.md |
Threat model, mitigasi, checklist keamanan |
docs/events/ |
Dokumentasi setiap event type (schema, payload, headers, changelog) |
| Test | Result |
|---|---|
| WebSocket Concurrent Connections | 5.000 koneksi simultan |
| Notification Throughput | ~12.000 notifikasi/menit |
| Memory (idle) | ~45 MB |
| CPU (idle) | ~1% core |
| Webhook Delivery Latency (p50) | ~200 ms |
| Webhook Delivery Latency (p95) | ~800 ms |
Angka di atas diukur pada VPS 2 core, 4 GB RAM, Redis & PostgreSQL di server yang sama. Performa aktual tergantung pada spesifikasi server, jumlah perangkat, dan beban parser.
| Rilis | Fitur |
|---|---|
| v0.1 | ✅ Notification Bridge (Go + Android) |
| v0.2 | ✅ Dashboard Web |
| v0.3 | ✅ SDK (Go, PHP, Node.js, Python) + Integrasi (Laravel, WooCommerce, WordPress, FastAPI) |
| v0.4 | ✅ Event-based Webhooks + Subscription Filter + Wildcard Events |
| v0.5 | ✅ Dead Letter Queue + Bulk Retry + Replay Events |
| v0.6 | ✅ Parser Management UI + Parser Test + Multi-API Key |
| v0.7 | ✅ Backup & Restore + Admin Auth + Webhook Test |
| v0.8 | ✅ Prometheus Metrics + Event Schemas + Event Registry Docs |
| v0.9 | 🔲 iOS Companion |
| v1.0 | 🔲 High Availability (multi-region Redis/PostgreSQL) |
| v1.1 | 🔲 Grafana Dashboard Advanced |
| v1.2 | 🔲 Stable Release + Security Audit |
AGPL-3.0 — see LICENSE file.
Proyek ini menggunakan GNU Affero General Public License v3.0 (AGPL-3.0). Lisensi ini dipilih secara khusus karena:
- Tidak mengizinkan penggunaan komersial tertutup — jika Anda menjalankan server QRIS Bridge sebagai layanan publik (hosting), Anda wajib membuka source code modifikasi Anda kepada semua pengguna yang berinteraksi melalui jaringan.
- Tidak ada lisensi komersial terpisah — tidak ada dual-license. AGPL-3.0 adalah satu-satunya lisensi yang berlaku. Tidak ada opsi untuk menggunakan kode ini dalam produk komersial tertutup tanpa membuka source code.
- Copyleft — setiap modifikasi harus dirilis dengan lisensi yang sama.
AGPL-3.0 berlaku jika Anda:
- Menggunakan server QRIS Bridge secara publik (hosting)
- Memodifikasi source code dan menjalankannya sebagai layanan jaringan
- Wajib membuka source code modifikasi kepada pengguna yang berinteraksi melalui jaringan
| Dokumen | Deskripsi |
|---|---|
| Terms of Use | Syarat penggunaan yang mengikat secara hukum — wajib dibaca sebelum menggunakan |
| Disclaimer | Pernyataan tanggung jawab, batasan teknis & hukum |
| Trademark Disclaimer | Penggunaan nama merek dagang pihak ketiga (fair use) |
| Privacy Policy | Informasi pemrosesan data sesuai UU PDP |
| Threat Model & Compliance | Analisis kepatuhan teknis terhadap UU ITE, UU PDP, ToS e-wallet |