spend like a wallet, keep like a vault
Top-ups, bonuses, loyalty and referral credit land in separate buckets on one ledger — each with its own rules about spending, expiry, and whether it can ever be withdrawn.
cash
Real money the user put in. The only kind that can ever leave again — and the only kind a withdrawal can draw on.
bonus
Promotional credit with conditions still outstanding. Spends first, never cashes out, and disappears on its own schedule.
loyalty
Value the user earned rather than bought. Its own expiry, its own spend priority, its own rules.
referral
Credit granted for bringing someone in. A module the customer didn't buy has no pod, no schema, no consumer group.
a portfolio project, built like something a bank would buy
Nothing here is a demo shortcut. The decisions are argued in full, the contradictions between them are tracked with IDs, and the part that decides money is under test.
single-tenant
One Kubernetes cluster per customer. Isolation is the cluster boundary, not a query filter.
modular by contract
Seven sellable modules are line items. Unsold means not deployed, not a disabled flag.
running, not described
This page is served from the cluster it describes — RKE2, Argo CD, Gateway API, automatic certificates, secrets in OpenBao.
open about gaps
Twenty-five unresolved items tracked in public, four of them blocking.
the stack, layer by layer
Hover any tile for why it's there. running on this cluster codebuilt, not deployed planneddecided, not built
frontend
what you're looking atbackend
java services and what they sharedata & events
where money is recordedsecurity
secrets, certificates, identityinfrastructure
the machine and the cluster on itdevops
build, test, publishgitops
git is the only way anything changesobservability
decided, not built yetan overdraft isn't a race — it's a row the database refuses
The first decision record specified Redis locking. Reviewed before implementation, the lock turned out to guard a balance read — while the write happened asynchronously, after the lock was released.
| t | request a | request b | ledger |
|---|---|---|---|
| 1 ms | reads balance: €100 | — | €100 |
| 2 ms | €100 ≥ €60 → approve | — | €100 |
| 4 ms | releases lock | — | €100 |
| 51 ms | — | reads balance: €100 | €100 |
| 52 ms | — | €100 ≥ €60 → approve | €100 |
| ~200 ms | ledger consumes a | — | €40 |
| ~250 ms | — | ledger consumes b | −€20 |
CONSTRAINT account_not_overdrawn CHECK (posted_balance - held_total >= 0)
try to overdraw it
cash€100.00bonus€40.00loyalty€12.50
No holds. The full cash balance is available.
built in the open, including the gaps
get in touch
Questions about the architecture, the licence, or the product are all welcome.