Skip to content

Operations

1. Deployment

PropertyValue
Imageregistry/nx-seller-finance:<tag>
Container Port3000
External Port31040
Snowflake ID4
Replicas (default)1 (dev) / 2+ (staging+)
Resources (req/lim)200m / 1 CPU, 512Mi / 2Gi memory
HPA targetCPU 70% (when scaled)
Migration modeRUN_MODE=migrate job before rollout; on-boot for dev
Live probeGET /v1/api/finance/healthz
Ready probeGET /v1/api/finance/readyz

Scaling the consumer past 1 replica spreads partitions across the SVC-00040-FINANCE_CONSUMER_GROUP. Posting stays correct under concurrency because each account row is FOR UPDATE-locked during a voucher post.

Traefik routing labels

yaml
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.finance.rule=PathPrefix(`/v1/api/finance`)"
  - "traefik.http.services.finance.loadbalancer.server.port=3000"

Required infrastructure

DependencyWhy
PostgreSQLPrimary datastore (schema finance)
Kafka brokersMandatory — component throws on boot if APP_ENV_KAFKA_BROKERS empty
RedisAuthorization cache + WebSocket emitter pub/sub
@nx/identity reachableJWKS verification on every JWT
@nx/commerce + DebeziumMerchant CDC stream drives account reconciliation

2. Observability

SignalSourceWhere to look
Logsstdout (IGNIS structured logger, key: %s format)kubectl logs deploy/finance / Loki
HealthGET /v1/api/finance/healthz, GET /readyzGateway portal
OpenAPI live specGET /v1/api/finance/doc/openapi.jsonGateway portal explorer
MetricsTraefik gateway (Prometheus scrape)Grafana — gateway dashboard

Key log fields

FieldSourceNotes
requestIdheader X-Request-IdPropagated cross-service
merchantIdrequest scope / eventTenant key
voucherNumber / voucherIdFinanceVoucherServicePosting audit trail
topic / partition / offsetKafka consume logsReplay coordinates
accountId / postingSequencebalance mathIntegrity alerts

Useful log queries

QuestionQuery
Voucher posting failureslevel=error AND FinanceWorkerService
Payment events skipped (no account on payload)SKIP voucher AND finance.source.id
Idempotent replays (redelivery)finance.voucher.idempotent_replay
Account went negativefinance.account.went_negative
Missing control accountINVENTORY/COGS control account missing

3. Security

ConcernMitigation
AuthNJWT (ES256, JWKS pulled from identity); VerifierApplication
AuthZCasbin; account list/count restricted to merchants the user has a GROUP policy on; single-entity routes call assertMerchantAccess (404 across tenants, not 403)
Credential secrecyPaymentIntegration.credential encrypted at rest; FinanceIntegrationService masks in responses
SecretsK8s Secret mounted as env (APP_ENV_DB_URL, SASL password, etc.)
TLSTerminated at Nginx → Traefik → service plaintext intra-cluster
Network policyCilium — allow only gateway + Kafka + Postgres + Redis + identity
Soft-deletedeletedAt on all finance entities; issued vouchers voided (reversed), never deleted
Posting integrityPer-account FOR UPDATE lock + monotonic postingSequence + DB partial unique index

4. Runbook

4.1 Alert classes

AlertTriggerCheckFixEscalate
FinanceHighErrorRate5xx >5% over 5mkubectl logs deploy/finance | grep level=erroridentify failing route; rollback recent deployon-call backend
FinanceConsumerLaggroup lag risingbroker consumer-group lagcheck handler errors (offset not committed = redelivery loop)on-call SRE
FinancePostingFailureFinanceWorkerService errorsgrep handler + voucherresolve root cause; redelivery replays once fixedon-call backend
FinanceMissingControlAccountcontrol account missing logsconfirm merchant CDC ranre-emit merchant CDC or manually create INVENTORY/COGS accounton-call backend
FinanceAccountNegativewent_negative warningsreview postings for that accountreconcile via ADJUSTMENT voucher (overdraft is allowed, not blocked)finance ops

4.2 Common operations

OperationCommand
Tail logskubectl logs -n <ns> -f deploy/finance
Run migrations manuallykubectl exec -it deploy/finance -- bun run migrate
Replay a Kafka topicreset SVC-00040-FINANCE_CONSUMER_GROUP offset; idempotency dedups replays
Inspect a voucher's ledgerSELECT * FROM finance."FinanceTransaction" WHERE finance_voucher_id = '<id>' ORDER BY line_number
Reconcile a balanceissue a manual ADJUSTMENT voucher (reason correction / cash_count) — never UPDATE balance directly

4.3 Recovery scenarios

ScenarioRecovery
Handler crash mid-postPosting is one DB transaction → rolled back; offset not committed → redelivered, replays cleanly
Duplicate Kafka redeliverytryIdempotentReplay returns the existing voucher; no double posting
Payment event without attempt.finance.source.idINFO-skip by design (no account chosen) — investigate sale-side payload, not finance
Wrong posting issuedvoid the voucher (posts a balanced reversal); COGS / INVENTORY_ADJUSTMENT vouchers are not voidable — correct with a fresh ADJUSTMENT
Merchant missing default accountsconfirm CDC delivered `op c

5. Cross-Service Runbook

For incidents spanning services, see central runbook/:

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.