Skip to content

Architecture

Modular monolith

Runne Pass is a single Hono service with clear module boundaries:

apps/api/src/
├── auth/           # registration, login, JWT sessions, revocation
├── workspace/      # workspace CRUD + ownership
├── api-key/        # key generation/verification (HMAC-SHA256)
├── gateway/        # apiKeyAuth, rate limiting, CSRF
├── chat/           # /v1/chat/completions (mock provider in beta)
├── payment/        # YooKassa payments + webhook
├── receipt/        # 54-ФЗ receipts
├── ledger/         # credit/debit/reservation/settlement/refund/adjustment
├── usage/          # cost estimation + usage report
├── quota/          # quota CRUD + enforcement
├── admin/          # dashboard + customer management
└── cron/           # reconciliation, orphan cleanup, receipt retry, monthly reset

Each module exposes a createXxxRouter() and service layer. Beta ships as one process; modules are extracted to services later if scaling signals appear (post-beta).

Stack

LayerTechnology
RuntimeBun 1.x
FrameworkHono 4.x
DatabasePostgreSQL 18+ (uses uuidv7())
ORMDrizzle
CacheRedis 7+ (rate limiting, session denylist)
ValidationZod
MonorepoBun workspaces + Turborepo
TestsBun test runner

Atomic financial operations

All money movements run inside db.transaction with conditional UPDATE … WHERE statements. The balance is updated and the ledger row inserted in the same transaction, so the balance and its history can never diverge.

  • ReservationUPDATE workspaces SET balance = balance - tokens WHERE balance >= tokens. No row → 402 insufficient_balance.
  • Credit — unconditional balance + tokens (from a verified payment).
  • Settlement — reserve was already made; settle recomputes actual vs. estimated.
  • Deficit path — if actual cost exceeds the reservation, the difference is debited; if that fails, the workspace is suspended.

The ledger

transactions is an append-only audit trail. Every balance change writes a row with:

FieldMeaning
typecredit, debit, reservation, settlement, refund, adjustment
amountSigned delta (negative for debits/reservations/settlements)
balance_afterSnapshot of the balance after the operation
metadataOperation-specific context (payment id, usage record id, admin id)

Because balance_after is captured on every row, the ledger reconstructs the balance history independently of the current balance.

Idempotency

Idempotency matters where an external actor can retry:

  • Payment webhook — status check + conditional update + unique index on transactions.payment_id.
  • Receipt send — stable idempotence key (payment id) + atomic claim (pending/sending/succeeded won't re-send).
  • Quota usage increment — conditional increment with a NOT EXISTS guard, race-safe.
  • Monthly quota reset cron — idempotent per period.

Reconciliation

A cron job periodically recomputes each workspace's balance from its ledger rows and flags mismatches. It is a safety net: the atomic operations should never diverge, but reconciliation detects any corruption or manual edit.

  • Security — how the atomicity is protected from abuse.
  • Errors — the 402/429 paths.
  • Roadmap — planned extractions.