Lewati ke konten utama

Dashboard API Architecture

services/dashboard_api adalah dedicated backend untuk apps/merchant_dashboard (Flutter web admin). Production-grade Go service yang melayani operator/admin Kesles — terpisah dari merchant_core_api yang melayani mobile_user dan OLTP money-path.

Status: 🟢 LIVE production — ~130 file Go, ~44.000 LOC, monolitik package app.

Lihat services/dashboard_api/README.md untuk dokumentasi operasional lengkap.

Boundary

dashboard_api owns

  • Admin/operator dashboard session & auth (facade ke auth_service + core_api)
  • Master data CRUD: partners, reps, credentials, merchants, devices, terminal stock
  • Sales workflow: quotations, sales orders, shipping orders
  • Purchasing: vendors, PO, GRN, invoices, landed cost, WAC
  • Settings: shipping origins/rates/fee, company profile, bank accounts, system settings, QRIS config, payment policy
  • Reports & planning: device WAC, growth projection, deployment ramp, revenue by merchant/partner
  • Internal dashboard KPI & summary (native query sejak 2026-05-18)
  • Users-access: dashboard users, sessions, devices, platform access, roles, permissions, RBAC, audit logs
  • Marketing: promo content (native) + promo schedules (proxy marketing_service) + broadcasts (proxy firebase_service)
  • PSP integration: inbound HMAC webhook dari payment.kesles.com + outbound dispatch
  • Dev tools: WA/FCM/partner/phone-auth tester, email bulk, beta testers (super-admin + ENABLE_DEV_TOOLS)

dashboard_api does NOT own

  • Mobile user auth (OTP, JWT) — milik merchant_core_api
  • Transaction write path (QRIS, payment callback) — milik payment_service
  • Order lifecycle state machine — milik order_service
  • Product catalog mutations — milik inventory_service
  • Push notification / WA / email queue — milik masing-masing notification service
  • Partner domain mutations (cutover 2026-06-02) — milik partner_service
  • PSP tester + PSP External tester (cutover 2026-06-16) — dipindah ke integration_api :8092; handler dashboard_dev_psp_tester.go sudah dihapus

Service Structure (aktual)

services/dashboard_api/
├── cmd/
│ ├── server/ — HTTP server entry point (main.go)
│ ├── psp-encrypt/ — CLI: enkripsi PSP API secret ke "enc:v1:..." format
│ └── psp-sign-post/ — CLI: test HMAC signature untuk PSP integration
├── internal/app/ — Seluruh business logic, monolitik package app (~130 file)
├── .env.example
├── .env.development
├── .env.production
├── README.md
├── go.mod
└── go.sum

Tidak ada sub-package di internal/ — semua flat di internal/app/. Ini desain eksplisit (bukan hutang teknis).

Lihat README.md §Code organization di services/dashboard_api/README.md untuk daftar lengkap file per-kategori.

Service Clients

dashboard_api memanggil service lain via HTTP (bukan direct DB ke domain milik service lain):

ClientField di ServerServicePortKapan nil
authAdminClients.authAdminauth_service8081AUTH_SERVICE_BASE_URL kosong
corePSPClients.corePSPClientmerchant_core_api8080CORE_API_BASE_URL kosong
inventoryClients.inventoryClientinventory_service8084INVENTORY_SERVICE_BASE_URL kosong
orderClients.orderClientorder_service8083ORDER_SERVICE_BASE_URL kosong
partnerServiceClients.partnerClientpartner_service8086PARTNER_SERVICE_BASE_URL kosong
paymentServiceClients.paymentClientpayment_service8085PAYMENT_SERVICE_BASE_URL kosong

Semua client nil-safe — kalau nil, handler fallback ke SQL path lokal (untuk domain yang masih punya SQL fallback) atau return error/503.

Auth header: X-Internal-API-Key untuk semua internal call.

Data Flow

apps/merchant_dashboard (Flutter Web, operator Kesles)

│ HTTPS (JWT dashboard session)

services/dashboard_api (:8082)

├─► merchant_core_api (:8080) via s.httpClient + s.corePSPClient
│ /dashboard/auth/* ← auth facade (login, OTP, me, logout)
│ /internal/dashboard/txn-trend ← OUT-OF-SCOPE forwarder (blocked daily_agg)
│ /internal/dashboard/merchant-ranking ← OUT-OF-SCOPE forwarder

├─► auth_service (:8081) via s.authAdmin (authAdminClient)
│ /internal/admin/users/* ← admin user lookup, staff management

├─► order_service (:8083) via s.orderClient
│ /internal/quotations/* ← quotation dual-write ke order domain

├─► inventory_service (:8084) via s.inventoryClient
│ /internal/* ← product catalog reads (Phase 7C)

├─► payment_service (:8085) via s.paymentClient
│ /internal/transactions ← recent transactions (Phase 3 reader)
│ + /api/dashboard/transactions (Transaction History)
│ → enrich merchant_name+merchant_code via merchant.merchants

├─► partner_service (:8086) via s.partnerClient (partnerServiceClient)
│ /internal/partners/* ← partner CRUD + reps + credentials + webhooks
│ (cutover 2026-06-02; SQL fallback masih ada)

├─► firebase_service (:8093) via s.httpClient + INTERNAL_NOTIFICATION_API_KEY
│ /internal/broadcasts/* ← broadcast pengumuman (proxy)

├─► marketing_service (:8095) via s.httpClient
│ /internal/promo-schedules/* ← jadwal kirim promo (proxy)

├─► db_kesles_merchant (direct SQL via s.db)
│ merchant.* ← merchants, devices, sales, purchasing, settings
│ psp.* ← PSP merchant data + HMAC keys
│ dashboard.* ← dashboard users, sessions, RBAC
│ partner.* ← SQL fallback (jika partnerClient nil)
│ (+ db_reference via s.referenceDB — opsional)

└─► db_kesles_merchant_planning (direct SQL via s.planningDB — PLANNING_POSTGRES_DSN)
planning.* ← planning defaults, scenarios (sole writer; mirror code removed 2026-06-16)

Auth & Middleware

Dashboard auth endpoints (/dashboard/auth/*) — prefix tanpa /api/, proxied ke merchant_core_api:

POST /dashboard/auth/login
POST /dashboard/auth/verify-otp
POST /dashboard/auth/forgot-password
POST /dashboard/auth/reset-password
GET /dashboard/auth/me
POST /dashboard/auth/logout

Nginx strip /merchant/dashboard-api/ prefix sebelum forward ke :8082. Jadi browser kirim /merchant/dashboard-api/dashboard/auth/login → Go menerima /dashboard/auth/login.

Middleware chain: withSecurityHeaders → withCORS → mux

Dashboard RBAC: withDashboardAuth middleware validate JWT + inject profile ke context. Handler-handler tertentu panggil requirePermission() untuk RBAC fine-grained.

PSP Integration

dashboard_api adalah satu-satunya entry point untuk event dari payment.kesles.com:

payment.kesles.com
│ HMAC-SHA256 + IP allowlist

/api/psp/v1/* (psp_auth_middleware.go — verifikasi HMAC per tenant)
├── psp_merchants.go — lookup merchant data
├── psp_event_receiver.go — terima payment event + dispatch notifikasi
└── psp_push_notifier.go — forward FCM push ke mobile_user

Outbound (kesles → payment.kesles.com) dikontrol via PSP_OUTBOUND_MODE (default disabled).

Internal Dashboard KPI / Summary

8 dari 10 endpoint /internal/dashboard/* sudah native (langsung query s.db) sejak Phase 3 extraction selesai 2026-05-18. 2 endpoint tetap forwarder ke merchant_core_api:

EndpointStatusAlasan
/internal/dashboard/kpi✅ Direct
/internal/dashboard/summary✅ Direct
/internal/dashboard/overview✅ Direct
/internal/dashboard/pending-merchants✅ Direct
/internal/dashboard/recent-transactions✅ Direct
/internal/dashboard/device-summary✅ Direct
/internal/dashboard/reports/revenue-by-merchant✅ Direct
/internal/dashboard/reports/merchant-transactions✅ Direct
/internal/dashboard/reports/revenue-by-partner✅ Directendpoint baru, post-extraction
/internal/dashboard/txn-trend⏸ Forward ke core_apiblocked transactions_daily_agg
/internal/dashboard/merchant-ranking⏸ Forward ke core_apiblocked transactions_daily_agg

Transport dikontrol via env INTERNAL_DASHBOARD_TRANSPORT=direct (production).

Transaction History — /api/dashboard/transactions

Endpoint terpisah dari /internal/dashboard/* — melayani panel Transaction History di Flutter dashboard. Sumber data: payment_service via paymentClient, diperkaya (enrichTxnMerchantNames) dengan merchant_name + merchant_code dari merchant.merchants (db_kesles_merchant).

Filter merchant_id, bukan outlet_id: transaksi sandbox/PSP tester tidak memiliki outlet_id (kolom NULL), sehingga filter outlet_id menghasilkan 0 baris. Outlet selector di Flutter mengirim merchant_id dari outlet yang dipilih — bukan outlet_id outlet itu sendiri. Detail: services/dashboard_api/README.md §Transaction History.

Chart KPI hanya hitung transaksi sukses: tiga widget visualisasi di dashboard_sections.dart — daily bar chart, channel donut, dan top merchants — sudah difilter transactionStatus == 'success'.

Deployment

ItemNilai
Systemd unitmerchant-dashboard-api.service
Folder VMmerchant_dashboard_api/
Port8082
Binary path VMmerchant_dashboard_api/dashboard-api
EnvironmentAPP_ENV=production (wajib di .env line 1)
Nginx upstream (kesles.com)proxy_pass http://localhost:8082/; via /merchant/dashboard-api/
Nginx upstream (api-merchant)proxy_pass http://localhost:8082; via /api/psp/v1/ (tanpa trailing slash — path preserved)

Nginx Security Hardening (Audit #4 — 2026-06-11)

Tiga file nginx aktual di VM:

File VMScope
/etc/nginx/nginx.conflimit_req_zone — 3 zone: api_general (10r/s), api_auth (5r/s), psp_hook (30r/s)
/etc/nginx/sites-available/kesles.com.conf7 security headers (HSTS, X-Frame, X-Content, XSS, Referrer, Permissions, CSP) + limit_req di 8 location block
/etc/nginx/sites-available/api-merchant.kesles.com.conf6 security headers (HSTS, X-Frame, X-Content, XSS, Referrer, CSP default-src 'none') + limit_req + client_max_body_size di 2 location

Local ref: deploy/nginx/kesles.com.conf, deploy/nginx/api-merchant.kesles.com.conf, deploy/nginx/kesles-merchant.conf (combined view).

Dokumen Terkait

  • services/dashboard_api/README.md — dokumentasi operasional lengkap
  • docs/services/dashboard/cleanup-plan.md — cleanup plan aktif (Tier 2.3–4.5 masih pending)
  • docs/services/dashboard/extraction-plan.md — internal dashboard extraction (Phase 0–3 DONE 2026-05-18)
  • docs/architecture/whatsapp-dual-dispatch.md — WA dual-channel pattern
  • runbooks/setup-api-merchant-subdomain.md — api-merchant.kesles.com setup + status LIVE 2026-06-11