20 KiB
20 KiB
Codex Handoff - QRIS Soundbox Platform
Tanggal update: 2026-06-08, Asia/Jakarta.
Dokumen ini adalah snapshot kerja terakhir untuk melanjutkan project tanpa perlu membaca ulang seluruh chat.
Update Terbaru - 2026-06-08
soundbox-backend-mqtt-spec.mdsekarang mendokumentasikan device command QF100 category5untukrebootdanpoweroff.- Backend sudah sinkron dengan spec command tersebut:
POST /admin/devices/{id}/commandsmenerimadevice.poweroff;- publisher MQTT membuat payload QF100 category
5dengandata.command = "poweroff"; - downlink tercatat sebagai
poweroff_commanddimqtt_messages.
scripts/smoke-qf100-adapter.mjssudah menambahkan assertion untuk commanddevice.poweroff.- Dashboard
/ui/soundbox-opsdirapikan untuk operator:- KPI warning sekarang menunjukkan breakdown stale vs degraded;
- KPI card bisa dipakai sebagai quick filter;
- tabel Fleet Status menampilkan health bar, reason, signal, dan battery;
- Device ID menjadi link langsung ke technical detail;
- Remote Actions menambahkan tombol
Power Off Device; - layout mobile header/filter dibuat full-width agar tidak overflow.
- Registry
/ui/device-registry-monitoringsekarang mendukung koreksi device metadata:- menu row punya
Edit Device; - modal edit bisa koreksi
serial_number/dev-sn, vendor, model, communication mode, status, dan firmware version; - perubahan model ikut memperbarui
capability_profile_jsondari katalog model aktif; - backend menolak duplicate
serial_numbersupaya config pull/MQTT lookup tidak ambigu.
- menu row punya
- Search UI yang sebelumnya dekoratif sudah mulai difungsikan:
- Admin Dashboard global search route ke Device Registry, Merchant List, atau Transaction History dengan
?q=; - Transaction History dan Merchant List membaca
?q=sebagai initial search; - Admin Reconciliation top search route ke Transaction History;
- Settlement Batch search live-filter batch table;
- Merchant Settlement History search live-filter disbursement table dan membaca
?q=; - Merchant Dashboard search route ke Merchant Settlement History;
- Fee Pricing search route ke Audit Logs, dan Audit Logs membaca
?q=; - Merchant Detail search route ke Merchant List;
- Device QR Payment Display search live-filter transaction rows.
- Admin Dashboard global search route ke Device Registry, Merchant List, atau Transaction History dengan
- Verifikasi lokal update ini:
npm run typecheck: pass;node --check scripts/smoke-qf100-adapter.mjs: pass.node scripts/ui-qa-check.mjs: pass;- direct script parse
ui/device-registry-monitoring/index.html: pass; - headless Chrome screenshot desktop/mobile
/ui/soundbox-ops/?preview=1: pass visual sanity.
Update Terbaru - 2026-06-07
- Production saat ini fokus ke portal Soundbox Ops di
sms.bizone.id, dengan MQTT brokerbroker.bizone.id. - Commit terakhir yang sudah dipush sebelum update handoff ini:
1e0f36f Split MQTT trace and commands pagesef23b09 Parse QF100 heartbeat time as WIBe3d7e60 Complete QF100 ops commands and detail UI
- Perubahan UI/ops terbaru:
- menu
MQTT Tracesekarang halaman sendiri:/ui/mqtt-trace; - menu
Config & Commandssekarang halaman sendiri:/ui/config-commands; - sidebar tidak lagi lompat ke anchor dashboard untuk dua menu tersebut;
- dashboard tetap ada summary ringkas, tetapi menu operasional utama pindah ke screen masing-masing.
- menu
- Halaman
/ui/mqtt-trace:- menampilkan trail uplink/downlink ala audit trail;
- filter direction
uplink/downlink; - filter message type;
- search topic/device/type/payload;
- limit 100/250/500;
- auto refresh 10 detik;
- klik event untuk lihat full payload JSON.
- Endpoint
/admin/mqtt/statussekarang mendukung:limitsampai 500;direction;message_type;device_id.
- Halaman
/ui/config-commands:- menampilkan status database, pending/failed notification, export worker;
- menampilkan MQTT publisher/subscriber runtime;
- dropdown device dengan SN, model, connection, last seen;
- tombol
Reboot Device; - tombol
Open Device Detail.
- Fix dashboard terbaru:
- kolom
Last Seendi/ui/soundbox-opstidak lagi menampilkan[object Object]; - formatter sekarang membaca
latest_heartbeat.received_at,latest_heartbeat.timestamp, lalu fallbacklast_seen_at.
- kolom
- QF100 firmware categories yang sudah disiapkan:
- category
1: payment sound, payloaddata.pay-amount; - category
3: heartbeat dari device; - category
4: dynamic QR display, payloaddata.qr-url,data.amount,data.expire-seconds; - category
5: reboot command, payloaddata.command = "reboot".
- category
- Dynamic QR:
- modal preview di Device Technical Detail sudah generate QR dari
data["qr-url"]; - tombol
Send Test QRmengirim commanddynamic_qr.display; - backend menerima payload nested
header/datadan publish category4kesoundbox/{serial_number}/down.
- modal preview di Device Technical Detail sudah generate QR dari
- Reboot:
- command
device.rebootpublish category5kesoundbox/{serial_number}/down; - bisa dikirim dari Device Technical Detail, Device Registry drawer, dan
/ui/config-commands.
- command
- Heartbeat:
- QF100 mengirim
data.timesebagai WIB/UTC+7; - backend sekarang parse waktu itu sebagai WIB lalu simpan UTC;
- contoh
20260607023400disimpan menjadi2026-06-06T19:34:00.000Z.
- QF100 mengirim
- Device Registry dan Device Detail:
- SN ditampilkan di tabel Device Registry;
- SN ditampilkan di drawer Device Detail;
- SN ditampilkan di header Device Technical Detail.
- Verifikasi lokal terakhir:
npm run typecheck: pass;node scripts/ui-qa-check.mjs: pass;node --check scripts/smoke-qf100-adapter.mjs: pass pada patch QF100 sebelumnya;git diff --check: pass.
Update Terbaru - 2026-06-06
- Fokus produk sekarang:
sms.bizone.idmenjadi portal utama Soundbox Ops / Monitoring, bukan katalog UI atau dashboard admin campuran. - Default route sudah disesuaikan:
GET /redirect ke/ui/soundbox-ops;GET /uiredirect ke/ui/soundbox-ops;- halaman Soundbox Ops tetap berada di
/ui/soundbox-ops.
- Server target deploy diganti menjadi Debian 13, memakai user khusus
qrisapp. - Dokumen deploy:
DEBIAN12_APP_SERVER_SETUP.mddiganti menjadiDEBIAN13_APP_SERVER_SETUP.md;- README sudah menunjuk ke dokumen Debian 13;
- install dari server kosong mencakup package dasar, Node.js 22, PostgreSQL, Nginx, Certbot, UFW, env production, migration, systemd, TLS, dan verification;
- semua proses app/repo/build/migration/service dijalankan sebagai
qrisapp; - root/sudo hanya untuk install package, direktori, env, Nginx, systemd.
- Env deploy sekarang mencantumkan
DATABASE_URLselainPGHOST/PGPORT/PGUSER/PGPASSWORD/PGDATABASE, supayanpm run deploy:check-envtidak gagal dengan errorDATABASE_URL is required. - Endpoint config device sudah men-support:
GET /speaker/dev-config;POST /speaker/dev-config;- lookup device berdasarkan
dev-snkedevices.serial_number; - device tidak dikunci model tertentu, sehingga tipe device asli bisa diinput lewat master data/model dan matching tetap berdasarkan SN.
- Response config device tetap vendor-compatible:
error-code;mqtt.broker-ip;mqtt.broker-port;mqtt.client-id;mqtt.user-name;mqtt.password;mqtt.subscribe-topic;mqtt.keep-alive.
- Production target:
- HTTP config URL device:
https://sms.bizone.id/speaker/dev-config; - MQTT broker:
broker.bizone.id; - MQTT TLS default:
mqtts://broker.bizone.id:8883; - jika firmware belum support TLS, siapkan listener non-TLS terbatas atau patch firmware.
- HTTP config URL device:
- Dashboard Soundbox Ops sudah dirapikan untuk fokus operasional:
- sidebar hanya menu ops: Monitoring, Registry, MQTT Trace, Config & Commands, Catalog;
- menu Register Device dihapus dari sidebar, action register ada di Device Registry;
- Technical Detail dihapus dari sidebar, akses detail lewat row action di Device Registry;
- footer/dev nav UI katalog dihapus dari halaman ops yang relevan.
- Master data
Catalogsudah ditambahkan:- vendor create/edit/delete;
- model create/edit/delete;
- model code generated backend;
- model thumbnail upload;
- country dropdown searchable dengan Palestine/Palestina masuk list;
- structured vendor contact: PIC name, phone/WhatsApp, email, notes.
- Device Registry sudah dibuat live dari API, bukan dummy:
- KPI dari data device;
- search berfungsi;
- pagination nyata;
- filter reset page;
- row action 3-dot untuk View Device Detail / Quick Inspect.
- Device Detail sudah dibuat lebih operasional:
- tombol refresh, retry push, test QR, copy payload, clear console, reboot, firmware update, unbind, rotate MQTT credential, decommission punya action;
- Dynamic QR preview dibuka sebagai modal inline, bukan pindah ke dashboard lain.
- Verifikasi terakhir lokal:
npm run typecheck: pass.
Status Terakhir
- Fokus sebelumnya bergeser dari production readiness umum ke integrasi device soundbox QF100.
- Folder SDK lokal
QF100-60s-l511-SecondApp-260107/ditemukan dan dianalisis. Folder ini sengaja tidak dimasukkan git. - Backend sekarang sudah punya adapter awal untuk firmware QF100 sample:
- config server vendor-compatible;
- payload MQTT payment success format QF100;
- smoke script backend untuk static + dynamic QF100.
- Target milestone berikutnya: dua soundbox real, satu static dan satu dynamic, bisa ambil config dari backend, connect MQTT, lalu static payment test bunyi dan tercatat di dashboard.
- Worktree aktif/dirty karena perubahan backend QF100 dan update handoff. Jangan revert perubahan yang tidak eksplisit diminta.
Verifikasi Terakhir
npm run typecheck: pass setelah perubahan QF100.npm install: sudah dijalankan untuk memasang dependency lokal; perubahan lockfile accidental sudah dibalik.npm run smoke:qf100: script sudah dibuat, belum dijalankan end-to-end di DB/server lokal pada turn ini.- Verifikasi lama yang masih relevan:
npm run db:migrate: sebelumnya pass dan idempotent sampai migration003_export_job_storage.sql.npm audit --json: sebelumnya pass, 0 vulnerability.npm run ui:qa: sebelumnya pass.npm run smoke:e2e: sebelumnya pass.- Real MQTT smoke sebelumnya pernah pass terhadap
mqtts://broker.bizone.id:8883.
SDK QF100 Yang Ditemukan
- Folder lokal:
QF100-60s-l511-SecondApp-260107/. - Sudah ditambahkan ke
.gitignore:QF100-60s-l511-SecondApp-260107/
- Struktur penting:
docs/Config Server.docx: kontrak config server vendor.docs/Cloud Speaker API Spec V2.8.7.pdf: API spec cloud speaker.app/source/MainApp/globalDefine.h: device model, demo mode,CONFIG_ADDR.app/source/MainApp/demo.c: alur config server, MQTT connect/subscribe, parse payment payload.app/source/MainApp/demo.h: MQTT TLS/QoS/clean session/cert config.app/source/MainApp/main.c: boot flow dan monitor network/MQTT.app/inc/MercuryMqtt.h: header MQTT SDK.app/release/user_app.bin: firmware build existing.
Kesimpulan SDK QF100
- SDK ini memungkinkan develop/patch aplikasi firmware sendiri, tetapi bentuknya embedded C firmware app, bukan SDK backend.
- Strategi dipilih: firmware hanya hardcode URL config server backend kita, bukan hardcode broker MQTT.
- Firmware sample boot lalu call
CONFIG_ADDRke endpoint vendor/speaker/dev-config. - Request config berisi field seperti:
dev-modelitem-numberdev-snfw-versionfw-buildapp-config-versionimeiimsiiccid
- Response yang firmware cari memiliki blok:
mqtt.broker-ipmqtt.broker-portmqtt.client-idmqtt.user-namemqtt.passwordmqtt.subscribe-topicmqtt.keep-alive
- Payment success payload yang firmware sample bisa bunyikan:
{ "header": { "category": 1 }, "data": { "pay-amount": 15000 } } MQTT_TLS_ENABLEdi SDK sample masih0. Jika broker production memakaimqtts://...:8883, firmware perlu patch TLS atau pilot perlu listener non-TLS terbatas.
Implementasi QF100 Backend Hari Ini
1. Config Server Vendor-Compatible
- Route baru:
GET /speaker/dev-config
- File:
src/routes/speaker.ts- mounted di
src/app.ts
- Perilaku:
- menerima query/body vendor;
- lookup device memakai
dev-sn->devices.serial_number; - jika device aktif, update:
vendormodelcommunication_modelast_seen_atfirmware_version
- mencatat heartbeat
state: config_pull; - balas JSON vendor top-level, bukan wrapper internal
successResponse.
- Error vendor style:
1001:dev-snkosong;1002: device tidak terdaftar atau inactive;1003: broker MQTT belum dikonfigurasi.
2. Env QF100
- Env baru di
src/config/env.tsdan.env.example:QF100_MQTT_BROKER_HOSTQF100_MQTT_BROKER_PORTQF100_MQTT_USERNAMEQF100_MQTT_PASSWORDQF100_MQTT_KEEP_ALIVE_SECONDS
- Jika host/port QF100 kosong, endpoint mencoba parse dari
MQTT_BROKER_URL. - Catatan penting: password MQTT yang dikirim ke QF100 diambil dari
QF100_MQTT_PASSWORDatau fallbackMQTT_PASSWORD. Sistem saat ini menyimpan credential device sebagai fingerprint, jadi plaintext per-device tidak bisa dibaca ulang dari DB.
3. Payload MQTT QF100
- File:
src/shared/services/mqttPublisher.tssrc/shared/orchestrators/notificationOrchestrator.ts
- Topic QF100:
soundbox/{dev-sn}/down
- Adapter memilih format QF100 jika:
device.modelmengandungQF100; ataucapability_profile_json.mqtt_payload_profile,protocol_profile, atauvendor_protocolbernilaiqf100.
- Downlink payment sekarang juga dicatat ke
mqtt_messages, sehingga dashboard device detail bisa melihat topic/payload yang dikirim.
4. Device Store dan Schema
- Lookup baru:
getDeviceBySerialNumber(serialNumber)disrc/shared/store/deviceStore.ts.
- Schema bootstrap menambahkan index:
idx_devices_serial_number.
5. Smoke QF100
- Script baru:
scripts/smoke-qf100-adapter.mjs
- Package script baru:
npm run smoke:qf100
- Script ini:
- create merchant/outlet/terminal/device static;
- create merchant/outlet/terminal/device dynamic MQTT;
- set
model: QF100dancapability_profile_json.mqtt_payload_profile: qf100; - hit
/speaker/dev-configuntuk dua SN; - validasi MQTT config vendor;
- trigger static QRIS paid callback;
- validasi
mqtt_messagesdownlink QF100 payloadcategory: 1; - trigger backend dynamic QR MQTT flow untuk device dynamic.
- Untuk memakai SN real:
QF100_STATIC_SN=<sn-static> \ QF100_DYNAMIC_SN=<sn-dynamic> \ BASE_URL=http://127.0.0.1:3000 \ npm run smoke:qf100
Device Flow Yang Disepakati
Static Soundbox
- Device boot.
- Firmware call backend
/speaker/dev-config. - Backend balas MQTT config.
- Device connect MQTT dan subscribe
soundbox/{dev-sn}/down. - QRIS callback paid masuk backend.
- Backend publish payload QF100
category: 1. - Device bunyi nominal.
- Dashboard melihat transaction, notification, mqtt message, last seen/config pull.
Dynamic Soundbox
- Prinsip: trigger tetap via MQTT, bukan polling terus-menerus.
- HTTP polling dynamic QR dianggap tidak cocok untuk skala 20 ribu device karena
gap=30sberarti sekitar 40 ribu request/menit. - Desain lanjutan:
- Backend/admin/merchant membuat dynamic QR request.
- Backend publish MQTT command ke device.
- Device menampilkan QR langsung atau HTTP fetch QR detail dari URL.
- Payment callback tetap jadi source of truth.
- Payment success tetap via MQTT
category: 1.
- Firmware dynamic handler belum dipatch. Perlu tambah handler misalnya
category == 10didemo.c.
Dashboard Yang Perlu Disiapkan Berikutnya
Prioritas UI/dashboard untuk test dua soundbox real:
- Device detail QF100 panel:
- SN;
- model/profile;
- config pull terakhir;
- broker host/port yang dikirim;
- client-id;
- subscribe-topic;
- keepalive.
- Test payment button:
- nominal quick actions, misalnya Rp1.000 dan Rp15.000;
- create dummy tx/callback internal;
- tampilkan notification dan MQTT payload result.
- MQTT timeline:
- direction;
- topic;
- message_type;
- payload JSON;
- publish_status/reason;
- timestamp.
- Dynamic QR panel:
- input nominal;
- create dynamic QR;
- tampilkan QR payload/status;
- nanti
Send to Soundboxvia MQTT command setelah firmware handler siap.
- Ops summary:
- total soundbox;
- online/stale/offline;
- config pull terbaru;
- payment notification sent/failed;
- dynamic QR active/paid/expired.
Endpoint Penting Saat Ini
- Health:
GET /healthGET /health/deep
- QF100 vendor config:
GET /speaker/dev-config
- Admin auth/session:
POST /admin/loginPOST /admin/logoutGET /admin/me
- Admin device:
POST /admin/devicesGET /admin/devicesGET /admin/devices/{id}POST /admin/devices/{id}/credentials/rotatePOST /admin/devices/{id}/bindPOST /admin/devices/{id}/unbindGET /admin/devices/{id}/mqtt-messagesGET /admin/devices/{id}/notifications
- Device API:
POST /device/heartbeatPOST /device/transactions/dynamic-qrPOST /device/mqtt/uplink/dynamic-qr/requestGET /device/configPOST /device/config/ack
- Integrations:
POST /integrations/qris/callback
- Observability:
GET /admin/observability/summaryGET /admin/observability/mqtt-status
Package Scripts Penting
npm run typechecknpm run db:migratenpm run smoke:qf100npm run smoke:e2enpm run smoke:mqtt-realnpm run smoke:mqtt-aclnpm run ui:qanpm run deploy:check-envnpm run load:testnpm run load:test:stagingnpm run mqtt:provision-devicenpm run mqtt:check-aclnpm run admin:create-usernpm run merchant:create-user
File Kunci Yang Sering Disentuh
- App bootstrap:
src/app.ts - Env config:
src/config/env.ts - QF100 config route:
src/routes/speaker.ts - Device route:
src/routes/device.ts - Admin route:
src/routes/admin.ts - MQTT publisher:
src/shared/services/mqttPublisher.ts - MQTT subscriber:
src/shared/services/mqttSubscriber.ts - Notification orchestrator:
src/shared/orchestrators/notificationOrchestrator.ts - Device store:
src/shared/store/deviceStore.ts - MQTT message store:
src/shared/store/mqttMessageStore.ts - Heartbeat store:
src/shared/store/heartbeatStore.ts - Schema bootstrap:
src/shared/db/pool.ts - QF100 smoke:
scripts/smoke-qf100-adapter.mjs - Env sample:
.env.example
Sisa Gap Utama
- Jalankan
npm run smoke:qf100terhadap backend + DB lokal/staging. - Register dua device real:
- static SN -> device static;
- dynamic SN -> device dynamic.
- Patch firmware QF100:
CONFIG_ADDRke backend kita;- TLS setting sesuai broker.
- Test static device real:
- config pull;
- MQTT connect;
- payment success bunyi;
- dashboard melihat downlink.
- Patch firmware dynamic:
- tambah handler command dynamic QR, kemungkinan
category == 10; - pilih direct QR payload vs HTTP fetch detail.
- tambah handler command dynamic QR, kemungkinan
- Siapkan dashboard QF100 detail/test panel.
- Putuskan credential strategy production:
- shared pilot password saat ini cukup untuk lab;
- production sebaiknya credential per-device yang bisa diprovisioning aman.
- Tetap perlu staging rehearsal, restore drill, export storage strategy, dan manual visual QA dari handoff lama.
Catatan Penting
- Folder SDK QF100 adalah artefak lokal dan jangan dimasukkan git.
- Jangan hardcode broker credential production di firmware.
- Firmware cukup hardcode config server URL; broker/topic/credential dikirim dari backend.
- Jangan gunakan wildcard MQTT subscribe di production kecuali maintenance terkontrol.
- Jika memakai MQTT TLS (
mqtts://...:8883), firmware QF100 perluMQTT_TLS_ENABLE=1dan sertifikat yang sesuai. - Rate limiting aktif default;
/speakermemakai limiter device. CODEX_HANDOFF.mdini adalah snapshot operasional terbaru; untuk detail historis keputusan, bacaDECISIONS_LOG.md.