4.9 KiB
Event, GL, and test audit
User transaction events
Status: partially correct, not reliable enough yet.
- Good: each transaction insert atomically creates a durable RabbitMQ outbox record; delivery has retries/deadbox; consumption has an idempotent inbox.
- Critical: the event is created only once, at initial insert. Transfers and redeem are inserted as
CREATED; if consumed before confirmation, the handler rejects/retries and can dead-letter. Later status updates do not refresh/re-enqueue it because transaction ID and payload are immutable. - Only
BUY,SELL,INTERNAL_TRANSFER, andREDEEMare executable by the event processor. Other declared topics—including IRT deposit/withdrawal, external transfer, commission, lock, and trustline—cannot be processed by it. - Several user flows still execute synchronously: external Kuknos transfers, Mellat/IPG steps, IRT withdrawal, and ICO/market settlement. The current pipeline therefore does not satisfy “user-side transaction requests are event driven” as a general invariant.
Recommended contract: persist a command/request event only after validation and TFA, use a unique command ID plus state/version, let a worker own side effects, and expose request status to the client. Lifecycle events should be separate facts, not reuse a single immutable command row.
The clarified product flows require separate event-driven process managers for market/ICO settlement, Kuknos ingestion, bank/IPG deposits, IRT withdrawal approval, and third-party collateral locks. Each must persist 2FA and agreement evidence before emitting an executable command.
GL
Status: primary append-only source of truth; current integration still behaves as an asynchronous mirror.
- The feature branch implements double-entry journals, lifecycle events, idempotency, immutable PostgreSQL storage, balance queries, replay, and a localized explorer.
- Required availability policy: fail closed. When GL or its database is unhealthy, reject/pause all new value-changing commands and pause transaction workers until GL recovers. Reads may remain available but
/healthmust reportCRITICAL/not-ready. - Normal mode requires both GL and Kuknos. Kuknos is the secondary settlement/verification truth. Its outage also halts transactions unless an operator explicitly activates
KUKNOS_DISABLEDthrough AdminPanel or configuration. KUKNOS_DISABLEDmust never activate automatically. Mode changes require authorization, immutable audit evidence, OTel telemetry, and reconciliation before/after returning to normal.- Implemented: shared readiness gate at Wallet/Internal/Market mutation RPCs and transaction workers; GL database-aware health; API critical/503 propagation; structured OTel-compatible transition logs; config-only Kuknos switch; local/config wiring.
- Still missing: persisted/AdminPanel mode control, hysteresis, metrics/traces, concrete compose GL deployment, reconciliation tooling, broad outage/concurrency acceptance tests, trustline state, and reservation ownership/reason semantics.
- Health polling alone has a race: GL can fail after the check but before a Wallet commit or external Kuknos/IPG submission. A strict “no transaction commits while GL is unavailable” guarantee requires an acknowledged GL write/prepare step or a formal saga; an asynchronous outbox plus preflight check cannot provide that guarantee by itself.
- Money risk: Wallet stores and maps
float64, then formats only seven decimal places before GL. GL'snumeric(38,18)cannot recover precision already lost upstream. - Lifecycle risk: GL event version is always
1; multiple transaction states may collide at the GL uniqueness boundary. - Append-only verification: PostgreSQL triggers reject journal deletion, entry/account/event update or deletion, and entry insertion after journal sealing. Corrections are exact reversing journals; the original record remains intact.
Tests run on 2026-08-28
- GL feature branch in isolated copy:
go test ./...passed. - Wallet: full
go test ./...passes after replacing the invalid dependency on ignored secret config fixtures with explicit default/override tests. - API: health tests pass in an isolated copy populated with compatible generated stubs; the checkout still needs its normal
buf generatestep. Auth was not changed. - Coverage gap: most
core/walletImpuser flows have no package tests. Existing event tests prove infrastructure mechanics but miss theCREATED -> confirmed -> PENDING_TRXrace described above.
Minimum logical acceptance tests: GL-down admission rejection, workers paused while GL is critical, recovery without duplicate execution, failure between health check and commit, duplicate commands, broker/Kuknos/IPG outage, crash after external submission, state-version ordering, concurrent spend/lock, partial maker fills, whitelist rejection, amount precision, 2FA/agreement evidence, admin approve/deny, reconciliation, and a full request-to-final-status test for every transaction type.