Store Router Architecture
Store Router adalah backend yang berjalan di setiap toko. Ditulis dalam Go dengan database SQLite (WAL mode), Store Router dirancang untuk operasi offline-first -- toko tetap beroperasi normal tanpa koneksi internet.
Overview
Entry Point
Store Router di-bootstrap dari cmd/store-router/main.go:
- Baca konfigurasi dari
store.yamlatau environment - Buka SQLite database (WAL mode,
_journal=wal&_busy_timeout=5000) - Jalankan migrasi dari
migrations/store/*.sql - Instantiate semua engine/manager
- Rakit
Dependenciesstruct - Start Sync Agent goroutine
- Start MQTT broker (optional)
- Serve HTTP pada port yang dikonfigurasi
Dependencies Struct
go
type Dependencies struct {
DB *sql.DB
StoreID string
EventLog *eventlog.EventLog
SequenceTracker *sequence.Tracker
Inventory *inventory.Manager
HealthChecker *health.Checker
PromoEvaluator *promo.Evaluator
LoyaltyEngine *loyalty.Engine
PricingEngine *pricing.Engine
SyncAgent *syncagent.Agent
APIKeys map[string]bool
PrivateOnly bool // restrict ke private/loopback IPs
// POS engines
POSSession *pos.SessionManager
POSTransaction *pos.TransactionManager
POSDiscount *pos.DiscountEngine
POSPayment *pos.PaymentManager
POSMember *pos.MemberManager
POSReturn *pos.ReturnManager
POSAuth *pos.AuthManager
// Operations
CashOps *cashops.Manager
Reconciliation *reconciliation.Engine
Transfer *transfer.Manager
Receiving *receiving.Manager
StoreSession *storesession.Manager
Opname *opname.Manager
DailyRecon *dailyrecon.Manager
Dashboard *dashboard.Manager
// Optional
MQTTBroker *mqttbroker.Broker
AuditDB *sql.DB
JWTValidator *JWTValidator
}Endpoint Structure
/ → Landing page (HTML dashboard)
/health → Health check
/metrics → Prometheus metrics
/api/
├── auth/ → Login, WebAuthn, session management
├── pos/
│ ├── sessions/ → Shift open/close
│ ├── transactions/ → Create, pay, void transactions
│ ├── holds/ → Hold & recall transactions
│ └── returns/ → Process returns
├── members/ → Search, register, points
├── stock/ → Current stock levels
├── receiving/ → Goods receiving
├── transfers/ → Inter-location transfers
├── adjustments/ → Stock adjustments
├── opname/ → Stock opname (cycle count)
├── cashops/ → Petty cash, deposits, vouchers
├── reconciliation/ → 3-way recon (POS vs cash vs EDC)
├── store-session/ → Open/close store day
├── daily-recon/ → End-of-day reconciliation
├── dashboard/ → Store manager dashboard data
├── sync/ → Sync status, force sync
└── catalog/ → SKU cache, price lookupMiddleware Stack
- CORS -- Allow cross-origin dari POS Electron dan mobile apps
- Request ID -- UUIDv7 per request (
X-Request-IDheader) - RealIP -- Extract IP dari proxy
- PrivateOnly (production) -- Reject requests dari public IP
- Logger -- Request/response logging
- Recoverer -- Panic recovery
- Rate Limiter -- 100 req/min per IP (token bucket)
- JWT Auth (optional) -- RS256 JWT dari central identity provider
- Idempotency -- Idempotency key tracking untuk mutation endpoints
Offline-First Design
Event Log
Setiap perubahan data di Store Router dicatat ke tabel event_log:
sql
CREATE TABLE event_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_id TEXT UNIQUE NOT NULL,
origin TEXT NOT NULL, -- 'pos-01', 'store-admin'
store_id TEXT NOT NULL,
type TEXT NOT NULL, -- 'sale.completed', 'stock.adjusted'
payload TEXT NOT NULL, -- JSON event data
crc32 INTEGER NOT NULL, -- integrity check
synced INTEGER NOT NULL DEFAULT 0,
sync_batch_id TEXT,
created_at TEXT NOT NULL
);Sync Agent
Sync Agent berjalan sebagai goroutine background dengan dua loop:
Upload Loop (setiap 30 detik):
- Claim batch event yang belum synced
- POST ke Cloud Hub
/stores/{id}/events - Mark events sebagai synced jika accepted
- Circuit breaker melindungi dari cloud downtime
Command Loop (setiap 30 detik):
- GET commands dari Cloud Hub
/stores/{id}/commands - Process command (update harga, push promo, dll)
- ACK command setelah berhasil diproses
- GET commands dari Cloud Hub
Circuit Breaker
Sync Agent menggunakan circuit breaker untuk menghindari hammering Cloud Hub saat down:
- Threshold: 5 failures berturut-turut
- Timeout: 30 detik dalam state open
- Half-open: Coba 1 request, jika sukses reset ke closed
MQTT Broker
Store Router meng-embed MQTT broker untuk push notifications ke mobile apps:
- Topic pattern:
store/{store_id}/{event_type} - Use case: Real-time stock updates, new transaction alerts
- QoS: At-most-once (QoS 0) untuk performance
Konfigurasi
File store.yaml:
yaml
store:
id: "STORE-001"
name: "RetailMart Sudirman"
cloud_url: "https://cloud.retailos.internal"
api_key: "sk_store_xxxxx"
database:
path: "./store.db"
sync:
interval: 30 # detik
batch_size: 100 # max events per batch
server:
port: 8081
private_only: true # reject non-private IPs
mqtt:
enabled: true
port: 1883