Summer Payment SDK — Shared Event DTOs & Prefix Annotations
Gate: Verify summer-core loaded and io.f8a.summer:summer-platform in build.gradle.
Module: io.f8a.summer:summer-payment-sdk (added 0.2.5)
Package roots: io.f8a.summer.payment.{annotation, domain, event, serialize}
Versioning: Independently versioned. summer-platform BOM pins paymentSdkVersion per Summer release (since 0.3.3 via explicit coordinates); consumers can override independently. Current: paymentSdkVersion=0.3.4 (paired with summer-platform:0.3.5).
Activation: Manual dependency; no Spring auto-config. Jackson registers Ufid/Txid deserializers through summer-core and summer-data-r2dbc.
Tracks LATEST stable (payment-sdk 0.3.4, paired with summer-platform:0.3.5). Older versions: load matching overlay from references/versions/.
Why it exists
Every service publishing or consuming ledger.transfer.posted, bank.notify.transaction, party.*, va.*, or wallet.* events needs the same DTOs and enums. summer-payment-sdk is the shared wire-contract jar — bump it once to propagate record types and JSON shape to all consumers.
Public API
Event DTOs (io.f8a.summer.payment.event.*)
| Sub-package | Events |
|---|---|
event.ledger |
LedgerTransferEvent, EntriesPostedEvent, EntriesRejectedEvent, PostEntriesCommand, LedgerEventType, SagaRejectionCode |
event.bank |
BankNotifyTransaction* and related |
event.party |
Party (customer/account) lifecycle |
event.va |
Virtual-account events |
event.wallet |
Wallet lifecycle / status |
Subpackages added in 0.2.9 — pre-0.2.9 events were flat in io.f8a.summer.payment.event.*. Imports must reflect subpackage; see versions/0.2.9.md.
Domain enums (io.f8a.summer.payment.domain.*)
LedgerAccountCodes, LedgerAccountType, LedgerEntryDirection, LedgerOperation (POST / VOID / REVERSE — CAPTURE renamed POST in 0.2.6), TransactionChannel, TransactionStatus, TransactionType. Single source of truth — never redefine per-service.
Prefix annotations (io.f8a.summer.payment.annotation.*)
Used on Ufid-typed fields to control Jackson serialization. Apply to event DTOs and service-side records needing same display style on wire.
| Annotation | Output format | Used for |
|---|---|---|
@JE |
JE_<Crockford-Base32> (28 chars total) |
Journal entries |
@TX |
TX_<Crockford-Base32> (28 chars) |
Transfers / transactions (replaces @TXN, removed in 0.2.6) |
@SE |
SE_<Crockford-Base32> (28 chars) |
Saga executions |
@Compact |
26-char Crockford Base32, no prefix | Generic compact IDs (replaces @Hex, removed in 0.2.6) |
@UfidPrefix("XX") |
XX_<Crockford-Base32> — custom prefix; meta-annotatable to define new aliases |
Service-specific Ufid kinds |
@UInt128 |
Unsigned 128-bit decimal string (no prefix) | TigerBeetle / BigInteger interop |
Display format: hex → Crockford Base32 in 0.2.6. @Hex and @TXN removed in 0.2.6. @Link removed in 0.3.3 — use @Compact; replace @Link with @Compact on field and update string-side parsing expecting LINK_.
public record LedgerTransferRequest(
@TX Ufid transferId,
@JE Ufid journalEntryId,
@Compact Ufid linkedTransferId, // was @Link Ufid — pre-0.3.3
@UfidPrefix("WAL") Ufid walletId,
LedgerOperation operation,
BigDecimal amount,
Instant occurredAt) {}
Producer-routing vocabulary (0.3.3+)
Six types under io.f8a.summer.payment.domain.producer.* shared between Payment Service and Core-Ledger — both materialize same routing YAML byte-identically:
| Type | Role |
|---|---|
Direction (enum) |
TOPUP, WITHDRAW, TRANSFER, REFUND, CREDIT, DEBIT, FEE — each carries its TigerBeetle transfer code, aligned with TransactionType codes |
ProducerId (record) |
parse(String) enforces <channel>.<partner>.<direction>.v<N> (external) or internal.<flow>.<variant>.v<N> (internal); exposes channel(), partner(), version(), isInternal() |
ProducerStatus (enum) |
ACTIVE, DEPRECATED, SUNSET, ORPHANED, EMERGENCY_DISABLED |
ProducerSpec (record) |
Jackson-deserialized canonical YAML row; @JsonIgnoreProperties(ignoreUnknown = true) lets each service ignore blocks it doesn't consume |
YamlHash |
SHA-256 over YAML bytes; both services hash byte-identically — used to verify both sides loaded the same revision |
ProducerEventFields (constants) |
PRODUCER_ID, FEE_PRODUCER_ID — wire-side field names so producer / consumer never disagree |
Transfer ids are Txid since 0.3.4 (BREAKING)
LedgerTransferEvent.Transfer.id and pendingId are now Txid (was Ufid). Every consumer of ledger.transfer.posted must be on payment-sdk 0.3.4+ to deserialize. Wire JSON is 18-digit zero-padded decimal from Txid.toJsonValue(), not UUID.
Account.id stays Ufid — TigerBeetle accounts may predate Txid cutoff and aren't all from TxidGenerator.
Conversion at the TigerBeetle CDC boundary:
Txid txid = Txid.fromUUID(ufid.toUUID()); // throws if upper 8 bytes != 0
// or
Txid txid = Txid.from16Bytes(raw128); // same guard
Guard throws when upper half is non-zero — transfer wasn't from TxidGenerator; surface immediately rather than silently truncate.
Gradle
// Use whatever paymentSdkVersion the platform BOM pins; the BOM is authoritative.
implementation 'io.f8a.summer:summer-payment-sdk'
BOM pins summer-payment-sdk via explicit coordinates since 0.3.3 — summer-platform:0.3.5 brings payment-sdk:0.3.4 transitively. Override only when adopting newer payment-sdk before platform catches up.
Version Notes
Headline only — full detail: load matching overlay. Payment-SDK uses own version axis (paymentSdkVersion in gradle.properties) — these are payment-sdk versions, not platform versions.
- 0.3.4 —
LedgerTransferEvent.Transfer.{id, pendingId}→Txid(BREAKING). → - 0.3.3 —
@Linkremoved (use@Compact); producer-routing vocabulary added. → - 0.3.1 — minor;
@Linkexisted briefly, removed in 0.3.3. - 0.2.9 — events split into subpackages
event.{ledger,bank,party,va,wallet}(BREAKING imports);CustomerInfoEventexpanded. → - 0.2.8 —
Ufid.toBase32()/fromBase32()/fromUInt128();@JsonCreatoraccepts UUID/Base32/display;UfidUInt128Deserializer. → - 0.2.6 —
@TXN→@TX,@Hex→@Compact(BREAKING);LedgerOperation.CAPTURE→POST. → - 0.2.5 — module introduced;
@JE,@TXN,@SE,@UfidPrefix,@Hex; payment domain enums. →
For full feature × version table see summer-core/references/version-matrix.md.
Rules
- Never redefine
LedgerOperation/TransactionType/TransactionChannel/LedgerAccountType/LedgerEntryDirectionper-service — drift means events won't deserialize on consumer side. - Never use
@Hex,@TXN, or@Link— removed in 0.2.6 (@Hex/@TXN) and 0.3.3 (@Link). Use@Compact/@TX/@Compact. Account.idisUfid, transfer ids areTxid(since 0.3.4). Don't conflate.- Wire JSON for
Txidis 18-digit zero-padded decimal, not UUID. Legacy UUID consumers fail loudly — bump to payment-sdk 0.3.4+. - Platform BOM is authoritative for
paymentSdkVersion. Override only when intentionally adopting newer payment-sdk ahead of platform bump. - Producer-routing YAML hashing (
YamlHash) must match byte-identically between Payment Service and Core-Ledger. Pin samepaymentSdkVersionto avoid hash mismatches at boot.
References
- references/event-types.md — Map of every event DTO, topic, and which fields are
UfidvsTxid. - references/versions/ — Per-version overlays (0.2.5 → 0.3.4).
Related Skills
- summer-core —
UfidandTxidtypes,@TxidConverter,MachineIdResolver. - summer-data — R2DBC
UfidConverter/TxidConverter/TxidUuidConverter(auto-registered). - summer-kafka — consumers apply LSN-watermark idempotency via
OutboxConsumerIdempotency. - summer-rest — controllers hand-craft event payloads via
OutboxService.saveEvent.