Prepare QF100 pilot and Debian app deploy
This commit is contained in:
459
CODEX_HANDOFF.md
459
CODEX_HANDOFF.md
@ -1,251 +1,316 @@
|
||||
# Codex Handoff - QRIS Soundbox Platform
|
||||
|
||||
Tanggal update: 2026-05-29, Asia/Jakarta.
|
||||
Tanggal update: 2026-06-03, Asia/Jakarta.
|
||||
|
||||
Dokumen ini adalah snapshot kerja terakhir untuk melanjutkan project tanpa perlu membaca ulang seluruh chat.
|
||||
|
||||
## Status Terakhir
|
||||
|
||||
- Estimasi MVP / early pilot: 92-94%.
|
||||
- Estimasi production-ready penuh: 82-85%.
|
||||
- Platform sudah bukan prototype docs-only. Backend, UI operasional, migration, smoke test, rate limiting, audit logging, async export, runbook, dan script deployment sudah tersedia.
|
||||
- Fokus terakhir yang selesai: rate limiting + security polish, login audit, admin audit UI real-data, placeholder nav cleanup, dan runbook/checklist produksi.
|
||||
- Worktree kemungkinan masih dirty karena banyak perubahan aktif. Jangan revert perubahan yang tidak eksplisit diminta.
|
||||
- Fokus hari ini 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.
|
||||
- `npm run db:migrate`: pass dan idempotent sampai migration `003_export_job_storage.sql`.
|
||||
- `npm audit --json`: pass, 0 vulnerability.
|
||||
- `npm run ui:qa`: pass setelah cleanup placeholder navigation.
|
||||
- `npm run smoke:e2e`: pass setelah rate limiting dan login audit.
|
||||
- Quick rate limit test: pass. Login admin salah pertama menghasilkan `401` dengan `RateLimit-Remaining: 0`, request berikutnya menghasilkan `429 RATE_LIMITED`.
|
||||
- Quick login audit test: pass. Event `admin.login.success`, `admin.login.failed`, `merchant.login.success`, dan `merchant.login.failed` tercatat.
|
||||
- Quick audit UI API test: pass. `GET /admin/audit-logs?action_contains=.login.&limit=10` mengembalikan event login.
|
||||
- Production-like env check dummy: pass via `npm run deploy:check-env`, hanya warning opsional untuk `MQTT_SUBSCRIBE`.
|
||||
- Staging/load/MQTT real sebelumnya sudah pernah diverifikasi: load level 2 1610 requests 0 errors, MQTT broker `mqtts://mqtt.iptek.co:8883` publish/subscribe OK.
|
||||
- `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 migration `003_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`.
|
||||
|
||||
## Implementasi Selesai
|
||||
## SDK QF100 Yang Ditemukan
|
||||
|
||||
### 1. Auth, RBAC, dan Security
|
||||
- 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.
|
||||
|
||||
- Admin session login tersedia lewat `/admin/login`, `/admin/logout`, `/admin/me`.
|
||||
- Merchant session login tersedia lewat `/merchant/login`, `/merchant/logout`, `/merchant/me`.
|
||||
- Legacy dev auth bisa dimatikan via env dan production check memblokir konfigurasi yang tidak aman.
|
||||
- Admin dan merchant bootstrap script tersedia:
|
||||
- `scripts/create-admin-user.mjs`
|
||||
- `scripts/create-merchant-user.mjs`
|
||||
- Password policy bootstrap diperketat:
|
||||
- minimal 14 karakter;
|
||||
- wajib lowercase, uppercase, angka, dan simbol;
|
||||
- menolak kata mudah ditebak seperti product/default/password/admin/merchant/qris/soundbox.
|
||||
- Rate limiting middleware baru:
|
||||
- [src/shared/middleware/rateLimit.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/middleware/rateLimit.ts)
|
||||
- dipasang ke `/admin/login`, `/merchant/login`, admin write routes, `/device`, dan `/integrations`.
|
||||
- Env security baru:
|
||||
- `TRUST_PROXY`
|
||||
- `JSON_BODY_LIMIT`
|
||||
- `RATE_LIMIT_ENABLED`
|
||||
- `RATE_LIMIT_AUTH_WINDOW_MS`
|
||||
- `RATE_LIMIT_AUTH_MAX`
|
||||
- `RATE_LIMIT_ADMIN_WRITE_WINDOW_MS`
|
||||
- `RATE_LIMIT_ADMIN_WRITE_MAX`
|
||||
- `RATE_LIMIT_WRITE_WINDOW_MS`
|
||||
- `RATE_LIMIT_WRITE_MAX`
|
||||
- Error code baru `RATE_LIMITED` di [src/shared/errors/index.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/errors/index.ts).
|
||||
## Kesimpulan SDK QF100
|
||||
|
||||
### 2. Audit, Monitoring, dan Logging
|
||||
- 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_ADDR` ke endpoint vendor `/speaker/dev-config`.
|
||||
- Request config berisi field seperti:
|
||||
- `dev-model`
|
||||
- `item-number`
|
||||
- `dev-sn`
|
||||
- `fw-version`
|
||||
- `fw-build`
|
||||
- `app-config-version`
|
||||
- `imei`
|
||||
- `imsi`
|
||||
- `iccid`
|
||||
- Response yang firmware cari memiliki blok:
|
||||
- `mqtt.broker-ip`
|
||||
- `mqtt.broker-port`
|
||||
- `mqtt.client-id`
|
||||
- `mqtt.user-name`
|
||||
- `mqtt.password`
|
||||
- `mqtt.subscribe-topic`
|
||||
- `mqtt.keep-alive`
|
||||
- Payment success payload yang firmware sample bisa bunyikan:
|
||||
```json
|
||||
{
|
||||
"header": {
|
||||
"category": 1
|
||||
},
|
||||
"data": {
|
||||
"pay-amount": 15000
|
||||
}
|
||||
}
|
||||
```
|
||||
- `MQTT_TLS_ENABLE` di SDK sample masih `0`. Jika broker production memakai `mqtts://...:8883`, firmware perlu patch TLS atau pilot perlu listener non-TLS terbatas.
|
||||
|
||||
- Audit logging login admin:
|
||||
- `admin.login.success`
|
||||
- `admin.login.failed`
|
||||
- Audit logging login merchant:
|
||||
- `merchant.login.success`
|
||||
- `merchant.login.failed`
|
||||
- `auditLogStore` mendukung `actor_type: merchant`.
|
||||
- Filter audit baru `action_contains` tersedia di:
|
||||
- [src/shared/store/auditLogStore.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/store/auditLogStore.ts)
|
||||
- [src/routes/admin.ts](/home/wira/work/codex/qris-soundbox-platform/src/routes/admin.ts)
|
||||
- Admin audit UI sudah memakai real API, bukan mock:
|
||||
- [ui/admin-system-audit-logs/index.html](/home/wira/work/codex/qris-soundbox-platform/ui/admin-system-audit-logs/index.html)
|
||||
- Audit UI memiliki filter action/entity/date/search, preset login events, KPI count, dan drawer JSON detail.
|
||||
- Observability/health sebelumnya sudah tersedia:
|
||||
- `/health`
|
||||
- `/health/ready`
|
||||
- `/admin/observability/summary`
|
||||
- `/admin/observability/dead-letter-replays`
|
||||
- `/admin/observability/mqtt-status`
|
||||
## Implementasi QF100 Backend Hari Ini
|
||||
|
||||
### 3. MQTT dan Device Operations
|
||||
### 1. Config Server Vendor-Compatible
|
||||
|
||||
- MQTT worker dan policy production sudah diperketat.
|
||||
- Wildcard subscribe default production dicegah oleh env check.
|
||||
- MQTT ACL tooling tersedia:
|
||||
- `scripts/check-mqtt-acl.mjs`
|
||||
- `scripts/smoke-mqtt-acl.mjs`
|
||||
- `scripts/provision-mqtt-device.mjs`
|
||||
- Package scripts:
|
||||
- `npm run mqtt:provision-device`
|
||||
- `npm run mqtt:check-acl`
|
||||
- `npm run smoke:mqtt-acl`
|
||||
- `npm run smoke:mqtt-real`
|
||||
- Real MQTT smoke pernah pass dengan broker `mqtts://mqtt.iptek.co:8883`.
|
||||
- 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:
|
||||
- `vendor`
|
||||
- `model`
|
||||
- `communication_mode`
|
||||
- `last_seen_at`
|
||||
- `firmware_version`
|
||||
- mencatat heartbeat `state: config_pull`;
|
||||
- balas JSON vendor top-level, bukan wrapper internal `successResponse`.
|
||||
- Error vendor style:
|
||||
- `1001`: `dev-sn` kosong;
|
||||
- `1002`: device tidak terdaftar atau inactive;
|
||||
- `1003`: broker MQTT belum dikonfigurasi.
|
||||
|
||||
### 4. Settlement, Reconciliation, dan Finance Ops
|
||||
### 2. Env QF100
|
||||
|
||||
- Settlement batch, merchant settlement history, reconciliation management, adjustment approval, dan device technical detail UI sudah tersedia.
|
||||
- Admin reconciliation UI sudah menggunakan async export flow dan export history.
|
||||
- Key UI pages:
|
||||
- [ui/admin-reconciliation-management/index.html](/home/wira/work/codex/qris-soundbox-platform/ui/admin-reconciliation-management/index.html)
|
||||
- [ui/settlement-batch-management/index.html](/home/wira/work/codex/qris-soundbox-platform/ui/settlement-batch-management/index.html)
|
||||
- [ui/merchant-settlement-history/index.html](/home/wira/work/codex/qris-soundbox-platform/ui/merchant-settlement-history/index.html)
|
||||
- [ui/device-technical-detail/index.html](/home/wira/work/codex/qris-soundbox-platform/ui/device-technical-detail/index.html)
|
||||
- Placeholder `href="#"` sudah dibersihkan dari UI yang masuk QA.
|
||||
- Env baru di `src/config/env.ts` dan `.env.example`:
|
||||
- `QF100_MQTT_BROKER_HOST`
|
||||
- `QF100_MQTT_BROKER_PORT`
|
||||
- `QF100_MQTT_USERNAME`
|
||||
- `QF100_MQTT_PASSWORD`
|
||||
- `QF100_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_PASSWORD` atau fallback `MQTT_PASSWORD`. Sistem saat ini menyimpan credential device sebagai fingerprint, jadi plaintext per-device tidak bisa dibaca ulang dari DB.
|
||||
|
||||
### 5. Async Export dan Storage
|
||||
### 3. Payload MQTT QF100
|
||||
|
||||
- Async export job sudah tersedia untuk settlement adjustment export.
|
||||
- Export job worker:
|
||||
- [src/shared/services/exportJobWorker.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/services/exportJobWorker.ts)
|
||||
- Export job store:
|
||||
- [src/shared/store/exportJobStore.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/store/exportJobStore.ts)
|
||||
- Migration:
|
||||
- [migrations/002_export_jobs.sql](/home/wira/work/codex/qris-soundbox-platform/migrations/002_export_jobs.sql)
|
||||
- [migrations/003_export_job_storage.sql](/home/wira/work/codex/qris-soundbox-platform/migrations/003_export_job_storage.sql)
|
||||
- Export file storage memakai `EXPORT_STORAGE_DIR`, dengan metadata path/size/expiry.
|
||||
- Export retention cleanup tersedia via worker.
|
||||
- Admin endpoints:
|
||||
- `POST /admin/exports/settlement-adjustments`
|
||||
- `GET /admin/exports`
|
||||
- `GET /admin/exports/:jobId`
|
||||
- `GET /admin/exports/:jobId/download`
|
||||
- File:
|
||||
- `src/shared/services/mqttPublisher.ts`
|
||||
- `src/shared/orchestrators/notificationOrchestrator.ts`
|
||||
- Topic QF100:
|
||||
- `devices/{deviceId}/downlink/qf100`
|
||||
- Adapter memilih format QF100 jika:
|
||||
- `device.model` mengandung `QF100`; atau
|
||||
- `capability_profile_json.mqtt_payload_profile`, `protocol_profile`, atau `vendor_protocol` bernilai `qf100`.
|
||||
- Downlink payment sekarang juga dicatat ke `mqtt_messages`, sehingga dashboard device detail bisa melihat topic/payload yang dikirim.
|
||||
|
||||
### 6. Deployment, Backup, Restore, dan Runbook
|
||||
### 4. Device Store dan Schema
|
||||
|
||||
- Production env checker diperketat:
|
||||
- [scripts/check-production-env.mjs](/home/wira/work/codex/qris-soundbox-platform/scripts/check-production-env.mjs)
|
||||
- Backup/restore tooling:
|
||||
- [scripts/backup-production.mjs](/home/wira/work/codex/qris-soundbox-platform/scripts/backup-production.mjs)
|
||||
- [scripts/restore-plan.mjs](/home/wira/work/codex/qris-soundbox-platform/scripts/restore-plan.mjs)
|
||||
- [scripts/restore-drill-validate.mjs](/home/wira/work/codex/qris-soundbox-platform/scripts/restore-drill-validate.mjs)
|
||||
- Load testing/report tooling:
|
||||
- [scripts/load-test.mjs](/home/wira/work/codex/qris-soundbox-platform/scripts/load-test.mjs)
|
||||
- [scripts/run-staging-load-report.mjs](/home/wira/work/codex/qris-soundbox-platform/scripts/run-staging-load-report.mjs)
|
||||
- Operational docs baru:
|
||||
- [OPERATIONAL_RUNBOOK.md](/home/wira/work/codex/qris-soundbox-platform/OPERATIONAL_RUNBOOK.md)
|
||||
- [PILOT_EXECUTION_CHECKLIST.md](/home/wira/work/codex/qris-soundbox-platform/PILOT_EXECUTION_CHECKLIST.md)
|
||||
- [EXPORT_STORAGE_READINESS.md](/home/wira/work/codex/qris-soundbox-platform/EXPORT_STORAGE_READINESS.md)
|
||||
- README dan deployment readiness docs sudah direferensikan ke runbook/checklist tersebut.
|
||||
- Lookup baru:
|
||||
- `getDeviceBySerialNumber(serialNumber)` di `src/shared/store/deviceStore.ts`.
|
||||
- Schema bootstrap menambahkan index:
|
||||
- `idx_devices_serial_number`.
|
||||
|
||||
## Endpoint Penting
|
||||
### 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: QF100` dan `capability_profile_json.mqtt_payload_profile: qf100`;
|
||||
- hit `/speaker/dev-config` untuk dua SN;
|
||||
- validasi MQTT config vendor;
|
||||
- trigger static QRIS paid callback;
|
||||
- validasi `mqtt_messages` downlink QF100 payload `category: 1`;
|
||||
- trigger backend dynamic QR MQTT flow untuk device dynamic.
|
||||
- Untuk memakai SN real:
|
||||
```bash
|
||||
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
|
||||
|
||||
1. Device boot.
|
||||
2. Firmware call backend `/speaker/dev-config`.
|
||||
3. Backend balas MQTT config.
|
||||
4. Device connect MQTT dan subscribe `devices/{deviceId}/downlink/qf100`.
|
||||
5. QRIS callback paid masuk backend.
|
||||
6. Backend publish payload QF100 `category: 1`.
|
||||
7. Device bunyi nominal.
|
||||
8. 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=30s` berarti sekitar 40 ribu request/menit.
|
||||
- Desain lanjutan:
|
||||
1. Backend/admin/merchant membuat dynamic QR request.
|
||||
2. Backend publish MQTT command ke device.
|
||||
3. Device menampilkan QR langsung atau HTTP fetch QR detail dari URL.
|
||||
4. Payment callback tetap jadi source of truth.
|
||||
5. Payment success tetap via MQTT `category: 1`.
|
||||
- Firmware dynamic handler belum dipatch. Perlu tambah handler misalnya `category == 10` di `demo.c`.
|
||||
|
||||
## Dashboard Yang Perlu Disiapkan Berikutnya
|
||||
|
||||
Prioritas UI/dashboard untuk test dua soundbox real:
|
||||
|
||||
1. Device detail QF100 panel:
|
||||
- SN;
|
||||
- model/profile;
|
||||
- config pull terakhir;
|
||||
- broker host/port yang dikirim;
|
||||
- client-id;
|
||||
- subscribe-topic;
|
||||
- keepalive.
|
||||
2. Test payment button:
|
||||
- nominal quick actions, misalnya Rp1.000 dan Rp15.000;
|
||||
- create dummy tx/callback internal;
|
||||
- tampilkan notification dan MQTT payload result.
|
||||
3. MQTT timeline:
|
||||
- direction;
|
||||
- topic;
|
||||
- message_type;
|
||||
- payload JSON;
|
||||
- publish_status/reason;
|
||||
- timestamp.
|
||||
4. Dynamic QR panel:
|
||||
- input nominal;
|
||||
- create dynamic QR;
|
||||
- tampilkan QR payload/status;
|
||||
- nanti `Send to Soundbox` via MQTT command setelah firmware handler siap.
|
||||
5. 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 /health`
|
||||
- `GET /health/ready`
|
||||
- `GET /health/deep`
|
||||
- QF100 vendor config:
|
||||
- `GET /speaker/dev-config`
|
||||
- Admin auth/session:
|
||||
- `POST /admin/login`
|
||||
- `POST /admin/logout`
|
||||
- `GET /admin/me`
|
||||
- Admin audit/observability:
|
||||
- `GET /admin/audit-logs`
|
||||
- Admin device:
|
||||
- `POST /admin/devices`
|
||||
- `GET /admin/devices`
|
||||
- `GET /admin/devices/{id}`
|
||||
- `POST /admin/devices/{id}/credentials/rotate`
|
||||
- `POST /admin/devices/{id}/bind`
|
||||
- `POST /admin/devices/{id}/unbind`
|
||||
- `GET /admin/devices/{id}/mqtt-messages`
|
||||
- `GET /admin/devices/{id}/notifications`
|
||||
- Device API:
|
||||
- `POST /device/heartbeat`
|
||||
- `POST /device/transactions/dynamic-qr`
|
||||
- `POST /device/mqtt/uplink/dynamic-qr/request`
|
||||
- `GET /device/config`
|
||||
- `POST /device/config/ack`
|
||||
- Integrations:
|
||||
- `POST /integrations/qris/callback`
|
||||
- Observability:
|
||||
- `GET /admin/observability/summary`
|
||||
- `GET /admin/observability/dead-letter-replays`
|
||||
- `GET /admin/observability/mqtt-status`
|
||||
- Admin export:
|
||||
- `POST /admin/exports/settlement-adjustments`
|
||||
- `GET /admin/exports`
|
||||
- `GET /admin/exports/:jobId`
|
||||
- `GET /admin/exports/:jobId/download`
|
||||
- Merchant auth/session:
|
||||
- `POST /merchant/login`
|
||||
- `POST /merchant/logout`
|
||||
- `GET /merchant/me`
|
||||
- Device and integration routes remain rate-limited for write-heavy paths:
|
||||
- `/device`
|
||||
- `/integrations`
|
||||
|
||||
## Package Scripts Penting
|
||||
|
||||
- `npm run typecheck`
|
||||
- `npm run db:migrate`
|
||||
- `npm run smoke:qf100`
|
||||
- `npm run smoke:e2e`
|
||||
- `npm run smoke:mqtt-real`
|
||||
- `npm run smoke:mqtt-acl`
|
||||
- `npm run ui:qa`
|
||||
- `npm run deploy:check-env`
|
||||
- `npm run load:test`
|
||||
- `npm run load:test:staging`
|
||||
- `npm run backup:production`
|
||||
- `npm run restore:plan`
|
||||
- `npm run restore:validate`
|
||||
- `npm run admin:create-user`
|
||||
- `npm run merchant:create-user`
|
||||
- `npm run mqtt:provision-device`
|
||||
- `npm run mqtt:check-acl`
|
||||
- `npm run smoke:mqtt-acl`
|
||||
- `npm run smoke:mqtt-real`
|
||||
- `npm run admin:create-user`
|
||||
- `npm run merchant:create-user`
|
||||
|
||||
## File Kunci yang Sering Disentuh
|
||||
## File Kunci Yang Sering Disentuh
|
||||
|
||||
- App bootstrap: [src/app.ts](/home/wira/work/codex/qris-soundbox-platform/src/app.ts)
|
||||
- Env config: [src/config/env.ts](/home/wira/work/codex/qris-soundbox-platform/src/config/env.ts)
|
||||
- Admin routes: [src/routes/admin.ts](/home/wira/work/codex/qris-soundbox-platform/src/routes/admin.ts)
|
||||
- Merchant routes: [src/routes/merchant.ts](/home/wira/work/codex/qris-soundbox-platform/src/routes/merchant.ts)
|
||||
- Audit store: [src/shared/store/auditLogStore.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/store/auditLogStore.ts)
|
||||
- Export worker: [src/shared/services/exportJobWorker.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/services/exportJobWorker.ts)
|
||||
- Export store: [src/shared/store/exportJobStore.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/store/exportJobStore.ts)
|
||||
- Rate limit middleware: [src/shared/middleware/rateLimit.ts](/home/wira/work/codex/qris-soundbox-platform/src/shared/middleware/rateLimit.ts)
|
||||
- UI QA script: [scripts/ui-qa-check.mjs](/home/wira/work/codex/qris-soundbox-platform/scripts/ui-qa-check.mjs)
|
||||
- Admin audit UI: [ui/admin-system-audit-logs/index.html](/home/wira/work/codex/qris-soundbox-platform/ui/admin-system-audit-logs/index.html)
|
||||
- Env sample: [.env.example](/home/wira/work/codex/qris-soundbox-platform/.env.example)
|
||||
|
||||
## Decision Log Ringkas
|
||||
|
||||
- D-026 sampai D-049: dasar auth, merchant/admin flows, migration, UI awal, dan smoke testing.
|
||||
- D-050 sampai D-059: production hardening awal, MQTT policy, finance/reconciliation UI, settlement flows.
|
||||
- D-060 sampai D-069: merchant auth productionization, DB migration idempotent, monitoring/logging, load test, async export.
|
||||
- D-070 sampai D-074: export storage/history, MQTT ACL, backup/restore, staging load report.
|
||||
- D-075 sampai D-080: rate limiting/security polish, login audit, audit UI real data, UI QA cleanup, runbook/checklist produksi.
|
||||
|
||||
Rujukan utama: [DECISIONS_LOG.md](/home/wira/work/codex/qris-soundbox-platform/DECISIONS_LOG.md).
|
||||
- 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
|
||||
|
||||
1. Eksekusi staging nyata dari checklist:
|
||||
- deploy dengan env final;
|
||||
- jalankan `deploy:check-env`, migration, smoke, UI QA, load report;
|
||||
- simpan artefak hasil staging.
|
||||
2. Pilot real device:
|
||||
- provisioning device real;
|
||||
- validasi MQTT ACL per device;
|
||||
- transaksi QRIS test end-to-end;
|
||||
- validasi soundbox delivery dan dead-letter handling.
|
||||
3. Restore drill nyata:
|
||||
- backup production/staging;
|
||||
- restore ke database disposable;
|
||||
- jalankan `restore:validate`;
|
||||
- dokumentasikan RTO/RPO aktual.
|
||||
4. Export storage production topology:
|
||||
- pastikan `EXPORT_STORAGE_DIR` durable, absolute, writable, dan di-backup;
|
||||
- jika multi-node, perlu shared filesystem/object storage strategy.
|
||||
5. Manual visual QA:
|
||||
- buka halaman admin utama di browser;
|
||||
- cek layout mobile/desktop;
|
||||
- cek login/session expiry state;
|
||||
- cek empty/error/loading state.
|
||||
6. Operational readiness:
|
||||
- isi PIC, escalation contact, broker credential, backup location, dan pilot merchant list di runbook/checklist.
|
||||
|
||||
## Prioritas Lanjutan Disarankan
|
||||
|
||||
1. Jalankan full staging rehearsal dari `PILOT_EXECUTION_CHECKLIST.md`.
|
||||
2. Lakukan manual visual QA admin UI dengan browser.
|
||||
3. Jalankan restore drill sungguhan pada database disposable.
|
||||
4. Finalisasi export storage production strategy.
|
||||
5. Siapkan pilot real merchant/device dan rekam hasilnya di runbook.
|
||||
1. Jalankan `npm run smoke:qf100` terhadap backend + DB lokal/staging.
|
||||
2. Register dua device real:
|
||||
- static SN -> device static;
|
||||
- dynamic SN -> device dynamic.
|
||||
3. Patch firmware QF100:
|
||||
- `CONFIG_ADDR` ke backend kita;
|
||||
- TLS setting sesuai broker.
|
||||
4. Test static device real:
|
||||
- config pull;
|
||||
- MQTT connect;
|
||||
- payment success bunyi;
|
||||
- dashboard melihat downlink.
|
||||
5. Patch firmware dynamic:
|
||||
- tambah handler command dynamic QR, kemungkinan `category == 10`;
|
||||
- pilih direct QR payload vs HTTP fetch detail.
|
||||
6. Siapkan dashboard QF100 detail/test panel.
|
||||
7. Putuskan credential strategy production:
|
||||
- shared pilot password saat ini cukup untuk lab;
|
||||
- production sebaiknya credential per-device yang bisa diprovisioning aman.
|
||||
8. Tetap perlu staging rehearsal, restore drill, export storage strategy, dan manual visual QA dari handoff lama.
|
||||
|
||||
## Catatan Penting
|
||||
|
||||
- Jangan hidupkan legacy auth di production.
|
||||
- Jangan gunakan wildcard MQTT subscribe di production kecuali sedang maintenance terkontrol.
|
||||
- `EXPORT_STORAGE_DIR` harus absolute path dan durable untuk production.
|
||||
- Rate limiting sekarang aktif secara default jika `RATE_LIMIT_ENABLED=true`; hati-hati saat smoke test berulang pada login endpoint.
|
||||
- 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 perlu `MQTT_TLS_ENABLE=1` dan sertifikat yang sesuai.
|
||||
- Rate limiting aktif default; `/speaker` memakai limiter device.
|
||||
- `CODEX_HANDOFF.md` ini adalah snapshot operasional terbaru; untuk detail historis keputusan, baca `DECISIONS_LOG.md`.
|
||||
|
||||
Reference in New Issue
Block a user