feat(payments): payments schema, currency domain and money type #215

Merged
developer merged 2 commits from feature/payments-data-foundation into development 2026-07-07 23:21:43 +00:00
Owner

Payments data foundation — the substrate for the in-game currency, with nothing wired to real money yet.

What

  • payments Postgres schema + a NOLOGIN confinement role (ALL on payments.*, nothing on backend), in migration 00010.
  • Append-only ledger (a BEFORE UPDATE/DELETE trigger + a partial idempotency index), materialised balances/benefits, the catalog (atoms seeded) + products + per-method prices, a typed single-row config, orders, payment_events.
  • No cross-schema FK: account_id is a plain uuid kept consistent in code — the domain stays extractable into its own database. Expand-contract and reversible.
  • Money value type: a bigint in the currency's minor units, exact via math/big, no float ever touching an amount; a whole-unit currency (Vote/Star/chip) cannot hold a fraction.
  • jetgen extended to the payments schema; the service is constructed behind a narrow interface with a boot-time reachability check.

Isolation guarantee

The application connects as a superuser (which bypasses grants), so the runtime wall is an import-boundary test: only internal/payments imports the payments jet code. The DB role + grants are the SET ROLE-tested stepping-stone to a real separate login/process later.

Tests

  • integration: role confinement (SET ROLE), the append-only trigger, CHECK constraints, the idempotency index, and a forward+backward migration.
  • unit: Money (exact round-trip, no-float, rejects fractions for whole-unit currencies) + the import-boundary test.
  • Local gate green: go build/go vet/gofmt clean, go test ./backend/..., and the full -tags=integration suite.

Docs

PLAN.md, docs/PAYMENTS.md (+ _ru mirror) updated to the built model.

Backend jet sync (2nd commit)

jetgen regenerates the whole backend schema and surfaced pre-existing drift in the committed backend jet (robot_blocks, robot_friend_requests, the feedback_messages app_version/browser_tz columns, and UseSchema gaps). Fixed here rather than deferred: jet/backend regenerated to match the migrations — additive only (nullable columns appended + two new tables), with the full build/vet/unit/integration suites green.

Payments data foundation — the substrate for the in-game currency, with nothing wired to real money yet. ## What - `payments` Postgres schema + a NOLOGIN confinement role (ALL on `payments.*`, nothing on `backend`), in migration `00010`. - Append-only ledger (a `BEFORE UPDATE/DELETE` trigger + a partial idempotency index), materialised `balances`/`benefits`, the catalog (atoms seeded) + products + per-method prices, a typed single-row `config`, `orders`, `payment_events`. - **No cross-schema FK**: `account_id` is a plain `uuid` kept consistent in code — the domain stays extractable into its own database. Expand-contract and reversible. - `Money` value type: a `bigint` in the currency's minor units, exact via `math/big`, **no float** ever touching an amount; a whole-unit currency (Vote/Star/chip) cannot hold a fraction. - jetgen extended to the payments schema; the service is constructed behind a narrow interface with a boot-time reachability check. ## Isolation guarantee The application connects as a superuser (which bypasses grants), so the runtime wall is an **import-boundary test**: only `internal/payments` imports the payments jet code. The DB role + grants are the `SET ROLE`-tested stepping-stone to a real separate login/process later. ## Tests - integration: role confinement (`SET ROLE`), the append-only trigger, CHECK constraints, the idempotency index, and a forward+backward migration. - unit: `Money` (exact round-trip, no-float, rejects fractions for whole-unit currencies) + the import-boundary test. - Local gate green: `go build`/`go vet`/`gofmt` clean, `go test ./backend/...`, and the full `-tags=integration` suite. ## Docs `PLAN.md`, `docs/PAYMENTS.md` (+ `_ru` mirror) updated to the built model. ## Backend jet sync (2nd commit) jetgen regenerates the whole `backend` schema and surfaced pre-existing drift in the committed backend jet (`robot_blocks`, `robot_friend_requests`, the `feedback_messages` `app_version`/`browser_tz` columns, and `UseSchema` gaps). Fixed here rather than deferred: `jet/backend` regenerated to match the migrations — additive only (nullable columns appended + two new tables), with the full build/vet/unit/integration suites green.
developer added 1 commit 2026-07-07 23:08:41 +00:00
feat(payments): add the payments schema, currency domain and money type
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 20s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m45s
ce8b5026c1
Stand up the payments data foundation: a self-contained `payments` Postgres
schema for the in-game currency, wallets, benefits, catalog, orders and the
append-only operations ledger, behind a domain package — nothing wired to real
money yet.

- Migration 00010: the `payments` schema and a NOLOGIN confinement role (ALL on
  payments.*, nothing on backend); the ledger with a BEFORE UPDATE/DELETE
  append-only trigger and a partial idempotency index; the materialised
  balances/benefits; the catalog (atoms seeded) + products + per-method prices;
  the typed single-row config; orders and payment_events. There is no
  cross-schema foreign key — account_id is a plain uuid kept consistent in code,
  which keeps the domain extractable. Expand-contract and reversible.
- Money is a bigint in the currency's minor units carried by a `Money` value
  type (exact, math/big): no float ever touches an amount, and a whole-unit
  currency cannot hold a fraction.
- Extend jetgen to generate the payments schema; construct the service in the
  composition root behind a narrow interface with a boot reachability check.
- Tests: integration (role confinement via SET ROLE, the append-only trigger,
  CHECK constraints, the idempotency index, and a forward+backward migration),
  Money unit tests, and an import-boundary test keeping the payments jet code
  private to the domain.
- Docs: PLAN.md, docs/PAYMENTS.md (+ _ru mirror) updated to the built model.
owner approved these changes 2026-07-07 23:12:07 +00:00
Dismissed
developer added 1 commit 2026-07-07 23:18:38 +00:00
chore(jet): regenerate the backend jet to match the migrations
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m43s
bab57343e1
The committed go-jet code had drifted from the schema: robot_blocks and
robot_friend_requests (created in the baseline) had no generated tables, the
feedback_messages model was missing app_version/browser_tz (added in 00003 and
00004), and UseSchema omitted account_best_move and the two robot tables.
Regenerate so the jet layer mirrors the migrations again.

Additive only — two nullable columns appended to feedback_messages plus two new
tables; the full build, vet, unit and integration suites stay green.
developer dismissed owner's review 2026-07-07 23:18:38 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

owner approved these changes 2026-07-07 23:20:25 +00:00
developer merged commit 07815c5a30 into development 2026-07-07 23:21:43 +00:00
developer deleted branch feature/payments-data-foundation 2026-07-07 23:21:43 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#215