PORT=3000
TRUST_PROXY=false
JSON_BODY_LIMIT=1mb
LOG_FORMAT=dev
LOG_LEVEL=info
ADMIN_TOKEN=admin-dev-token
ADMIN_AUTH_ALLOW_LEGACY_TOKEN=true
ADMIN_DEV_LOGIN_ENABLED=true
ADMIN_SESSION_SECRET=change-me-long-random-admin-session-secret
ADMIN_SESSION_TTL_SECONDS=28800
MERCHANT_TOKEN=merchant-dev-token
MERCHANT_PORTAL_PASSWORD=merchant
MERCHANT_AUTH_ALLOW_LEGACY_TOKEN=true
MERCHANT_DEV_LOGIN_ENABLED=true
MERCHANT_SESSION_SECRET=change-me-long-random-merchant-session-secret
MERCHANT_SESSION_TTL_SECONDS=28800
DEVICE_TOKEN=device-dev-token
DEVICE_AUTH_ALLOW_LEGACY_TOKEN=true
TRACE_HEADER=x-request-id
IDEMPOTENCY_TTL_MS=300000
INTEGRATION_WEBHOOK_SECRET=dev-callback-secret
MQTT_PUBLISH_MODE=simulator
MQTT_BROKER_URL=mqtts://broker.bizone.id:8883
MQTT_USERNAME=qris-backend
MQTT_PASSWORD=change-me
MQTT_CLIENT_ID=qris-platform-backend
MQTT_CONNECT_TIMEOUT_MS=5000
MQTT_SUBSCRIBE_ENABLED=false
MQTT_SUBSCRIBE_TOPICS=devices/+/uplink/#
MQTT_PUBLISH_FORCE_FAIL_ALL=false
MQTT_PUBLISH_FORCE_FAIL_DEVICE_IDS=
MQTT_PUBLISH_DEFAULT_RETRY_INTERVAL_MS=15000
QF100_MQTT_BROKER_HOST=
QF100_MQTT_BROKER_PORT=0
QF100_MQTT_USERNAME=
QF100_MQTT_PASSWORD=
QF100_MQTT_KEEP_ALIVE_SECONDS=60
DYNAMIC_QR_EXPIRY_SCHEDULER_ENABLED=true
DYNAMIC_QR_EXPIRY_SWEEP_INTERVAL_MS=60000
DYNAMIC_QR_EXPIRY_SWEEP_LIMIT=100
EXPORT_WORKER_ENABLED=true
EXPORT_WORKER_INTERVAL_MS=2000
EXPORT_WORKER_BATCH_SIZE=2
EXPORT_JOB_STALE_RUNNING_MS=900000
EXPORT_SETTLEMENT_ADJUSTMENT_MAX_ROWS=5000
EXPORT_STORAGE_DIR=./storage/exports
EXPORT_RETENTION_DAYS=7
RATE_LIMIT_ENABLED=true
RATE_LIMIT_LOGIN_WINDOW_MS=60000
RATE_LIMIT_LOGIN_MAX=20
RATE_LIMIT_DEVICE_WINDOW_MS=60000
RATE_LIMIT_DEVICE_MAX=600
RATE_LIMIT_ADMIN_WRITE_WINDOW_MS=60000
RATE_LIMIT_ADMIN_WRITE_MAX=300
FINANCE_PLATFORM_FEE_BPS=70
SETTLEMENT_ADJUSTMENT_REQUIRE_APPROVAL=false

# PostgreSQL settings
PGHOST=127.0.0.1
PGPORT=5432
PGUSER=postgres
PGPASSWORD=postgres
PGDATABASE=qris_soundbox_platform
# Optional alternative:
# DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:5432/qris_soundbox_platform
