- Shipped
- September 8, 2026 at 7:10 AM UTC
- Author
- Kamo
- Commit
- 0396bfb
HOLDEM (36) joins KAMO_UNIVERSE and CHESS under GAMES, with PLAY_HOLDEM (319). Both ids were the next free ones; nothing is renamed and nothing moves, because ORG_FEATURES persists a ServiceType id and **************** persists a RoleRightType NAME. COMPLETED + enabled, like its siblings: AppCatalogService derives availability from the stage and FeatureController's auto-provision loop skips an unavailable app, so a lower stage would ship an app no organization could be given. The six entities: HOLDEM_TABLES the room, which outlives every hand played in it HOLDEM_SEATS one occupied chair and the chips in front of it HOLDEM_HANDS one hand, deck and all HOLDEM_HAND_SEATS a player's part in one hand, as a snapshot HOLDEM_ACTIONS append-only: everything anybody did, in order HOLDEM_TABLE_MEMBERS who may open this table — invitation list and rail roster Three shapes worth reading the javadoc for: * HOLDEM_SEATS.STACK is CHIPS, not cheddar. The wallet moves exactly twice per seat; everything between is a local transaction. BUY_IN_SEQ exists because the wallet's idempotency key is DERIVED from the row, so a retry after a crash is a no-op rather than a second $20. * HOLDEM_HANDS stores the WHOLE shuffled deck. Storing only the board would mean re-shuffling to deal the turn, and a player all-in on the flop is entitled to have that card already exist. * ACTION_DEADLINE and NEXT_DEAL_AT are COLUMNS. A timer in one pod's heap dies with that pod and takes nine colleagues' evening with it. Every enum column is @Enumerated(STRING): an ordinal column freezes a CHECK constraint at today's size and fails the day a value is appended. NotificationKind gains HOLDEM_INVITE — its own kind because the kind is the unit a member mutes, and "stop inviting me to card games" should not also silence everything else.