release v1.13.0: payments wallet mechanics + database point-in-time recovery #220

Merged
developer merged 16 commits from development into master 2026-07-08 23:42:15 +00:00
Owner

Promotes development to master for a production release.

Included

  • Payments Release 1 — chip wallet mechanics, no real money. The payments schema +
    the currency/Money domain, the trusted platform signal on the session, chip balances +
    benefit application behind the store-compliance gate, and the Wallet screen (balances,
    active benefits, storefront). Funding rails (real money) come later; balances are
    exercised via admin grant for now.
  • Database point-in-time recovery. Continuous WAL archiving (pgBackRest -> S3), shipped
    disarmed — armed on the main host immediately after this deploy.

Deploy notes

  • Carries the payments schema migration (expand, backward-compatible) -> the prod deploy
    opens a maintenance window + a whole-database pre-migration dump.
  • PITR archiving stays inert until armed (stanza-create + PGBACKREST_ARCHIVE_MODE=on).
  • Tag v1.13.0 after merge.
Promotes `development` to `master` for a production release. ## Included - **Payments Release 1 — chip wallet mechanics, no real money.** The `payments` schema + the currency/Money domain, the trusted platform signal on the session, chip balances + benefit application behind the store-compliance gate, and the Wallet screen (balances, active benefits, storefront). Funding rails (real money) come later; balances are exercised via admin grant for now. - **Database point-in-time recovery.** Continuous WAL archiving (pgBackRest -> S3), shipped disarmed — armed on the main host immediately after this deploy. ## Deploy notes - Carries the `payments` schema migration (expand, backward-compatible) -> the prod deploy opens a maintenance window + a whole-database pre-migration dump. - PITR archiving stays inert until armed (`stanza-create` + `PGBACKREST_ARCHIVE_MODE=on`). - Tag `v1.13.0` after merge.
developer added 16 commits 2026-07-08 23:36:05 +00:00
docs(payments): add monetization spec and implementation plan
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Has been skipped
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m45s
4c7bc7baa9
Add docs/PAYMENTS.md (+ docs/PAYMENTS_ru.md mirror) — the monetization
mechanics specification: two-tier «Фишка» currency, per-source wallet
segments, per-origin benefits with the one-directional store-compliance
gate, order-flow payment intake, VK ads, configurable catalog,
append-only ledger, taxes, and native-Android distribution.

Add PLAN.md — the staged technical implementation plan with per-step
touch-points, tests, and done-criteria.
ci: skip the test-contour deploy on a no-code change
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 15s
CI / ui (pull_request) Successful in 1m6s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m44s
4d1f389cf1
The deploy job gated only on the event/ref, so a docs-only PR into
development (where unit/integration/ui/conformance path-skip) still
redeployed the test contour for nothing. Gate it on the `changes` job
too: deploy only when the Go or UI side changed. `changes` still
defaults both true when the diff is uncomputable, and a workflow/deploy
edit forces both true, so ambiguous or infra changes still deploy.
Merge pull request 'ci: skip the test-contour deploy on a no-code change' (#214) from feature/ci-skip-deploy-on-docs into development
CI / changes (push) Successful in 1s
CI / unit (push) Successful in 9s
CI / integration (push) Successful in 15s
CI / ui (push) Successful in 1m6s
CI / conformance (push) Successful in 10s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m39s
3ad3b1dd7f
Merge pull request 'docs(payments): monetization spec and implementation plan' (#213) from feature/payments-docs into development
CI / changes (push) Successful in 1s
CI / unit (push) Has been skipped
CI / integration (push) Has been skipped
CI / ui (push) Has been skipped
CI / conformance (push) Has been skipped
CI / gate (push) Successful in 0s
CI / deploy (push) Has been skipped
d9bc7596c6
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.
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.
Merge pull request 'feat(payments): payments schema, currency domain and money type' (#215) from feature/payments-data-foundation into development
CI / changes (push) Successful in 2s
CI / unit (push) Successful in 10s
CI / integration (push) Successful in 18s
CI / ui (push) Has been skipped
CI / conformance (push) Successful in 9s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m44s
07815c5a30
feat(payments): trusted platform signal on the session
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 18s
CI / ui (pull_request) Successful in 1m7s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m42s
92633f935e
Record the execution platform (kind vk|telegram|direct + device subtype
ios|android|web) on each session, captured at creation and carried
gateway->backend as a trusted X-Platform header, so the upcoming
store-compliance gate has an unforgeable execution context.

- backend.sessions gains nullable platform_kind/platform_subtype columns
  (migration 00011, CHECK-constrained, jet regenerated); session.Platform
  captures them at mint, resolve returns them, middleware exposes platform(c).
  kind is derived from the establish endpoint, never a client field; the
  account-merge session mint inherits the caller's platform.
- gateway derives the platform (VK subtype from the signed vk_platform via
  vkauth, Telegram/direct best-effort from the client) and injects X-Platform
  on every authenticated backend call through the request context.
- ui submits a best-effort device subtype on the telegram/guest/email login
  requests (new FBS subtype field); VK is server-derived from the signed params.
- an unattributed session is untrusted (view-only); VK/TG self-heal on the next
  cold-start re-mint, direct/email on re-login.

Signal plumbing only, no user-visible change; X-Platform is inert until the
gate consumes it.
Merge pull request 'feat(payments): trusted platform signal on the session' (#216) from feature/trusted-platform-signal into development
CI / changes (push) Successful in 1s
CI / unit (push) Successful in 10s
CI / integration (push) Successful in 21s
CI / ui (push) Successful in 1m7s
CI / conformance (push) Successful in 10s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m44s
711fabe9cc
feat(payments): chip wallet, store-compliance gate and benefit application
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 22s
CI / ui (pull_request) Successful in 1m7s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m41s
1c06d1d0d1
Stand up the internal chip/benefit mechanic behind the narrow payments interface:
context-aware balances and benefits, an atomic chip spend, admin grants as
zero-price value sales, the one-directional store-compliance gate (VK/TG same-
origin only, web draws direct→vk→tg, VK-iOS frozen, untrusted fail-closed), and
per-origin hint and no-ads application with term stacking. Reads are served from
an in-process, account-keyed write-through cache (mirroring the suspension gate),
so hot paths issue no query to the payments schema.

Flip the online-game hint wallet and the ad-banner suppression from the deprecated
accounts.hint_balance / paid_account columns to the payments benefit (a hint
balance no longer suppresses the banner — only a no-ads benefit does), and fold
chip segments and benefits by origin on account merge, inside the merge tx. Add
the GET/POST /api/v1/user/wallet edge chain (REST → Connect → FlatBuffers) plus
its codec unit test; no wallet UI yet.

Bring the frozen owner decisions log into the repo at
docs/PAYMENTS_DECISIONS_ru.md (it was untracked under .vscode) and reference it
from PLAN.md; record the read-cache design and the present-sources interface in
PLAN.md and docs/PAYMENTS.md (+ RU mirror).
Merge pull request 'feat(payments): chip wallet, store-compliance gate and benefit application' (#217) from feature/payments-currency-benefit-core into development
CI / changes (push) Successful in 2s
CI / unit (push) Successful in 10s
CI / integration (push) Successful in 21s
CI / ui (push) Successful in 1m7s
CI / conformance (push) Successful in 9s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m45s
41f4fd3497
feat(payments): wallet screen with balances, benefits and storefront
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m8s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m39s
4aa6174968
Add the "Кошелёк" section to the settings hub: context-visible chip
balances, active benefits (no-ads term/forever, hints) and a storefront of
chip-priced values and money-priced chip packs. Guests have no wallet; the
Google Play build hides the money purchases behind a RuStore stub; a web
purchase that would draw VK/Telegram chips warns first.

Add the catalog read path the storefront needs — a context-projected
GET /api/v1/user/wallet/catalog (payments service + store, gateway op
wallet.catalog, FBS Catalog/CatalogProduct/CatalogAtom, client decode) —
plus the client leg for the existing wallet.get/buy ops. Value spends reuse
the existing spend path; the chip-pack purchase (money order flow) arrives
with payment intake, so its action is a disabled placeholder for now.

Covered by Go unit (catalog projection) + integration (/wallet/catalog over
Postgres), vitest (formatting, spendable selection, web-spend warning, GP
flag, codec + gateway encode round-trips) and Playwright mock e2e (render,
guest-hidden, GP stub, warning) on Chromium + WebKit.
Merge pull request 'feat(payments): wallet screen with balances, benefits and storefront' (#218) from feature/payments-wallet-ui into development
CI / changes (push) Successful in 3s
CI / unit (push) Successful in 10s
CI / integration (push) Successful in 19s
CI / ui (push) Successful in 1m8s
CI / conformance (push) Successful in 9s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m40s
04976a64e8
feat(deploy): continuous WAL archiving to S3 for point-in-time recovery
CI / changes (pull_request) Successful in 4s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 24s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m41s
e922f5f3b9
Add pgBackRest-based PITR for the production database, shipped disarmed
(archive_mode and the base-backup timer gated off) so it stays inert until the
operator arms it before real payments — an un-armed deploy cannot pile WAL onto
the disk.

- Postgres now builds from a thin image carrying pgBackRest (archive_command runs
  in-process); the prod overlay wires an encrypted (AES-256-CBC), path-style S3
  repository with 30-day retention and a daily full base-backup systemd timer.
- Repository config/secrets flow through the PROD_PGBACKREST_* Gitea set and
  write-prod-env.sh; prod-rollback re-renders the same env so a rollback cannot
  disarm archiving.
- Grafana alerts watch pg_stat_archiver (failing / stalled), absent-safe on the
  test contour, which never archives.
- Fix the pre-migration pg_dump to snapshot the whole database (was backend-only,
  silently excluding payments).
- Document the PITR runbook, the arming sequence and the restore drill in
  deploy/README.md; record the measured cost/perf assessment.
fix(deploy): support a non-standard S3 port for the pgBackRest endpoint
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) Successful in 1m8s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 1s
CI / deploy (pull_request) Successful in 1m43s
a58f2ce0e4
The S3 endpoint is a host only; some providers publish a separate, non-443
port. Add an optional PGBACKREST_S3_PORT (default 443) alongside the endpoint
host, wired through the prod overlay, write-prod-env.sh and both prod workflows,
and clarify in the docs that the endpoint variable takes the host alone.
Merge pull request 'feat(deploy): continuous WAL archiving to S3 for point-in-time recovery' (#219) from feature/postgres-pitr-archiving into development
CI / changes (push) Successful in 2s
CI / unit (push) Successful in 10s
CI / integration (push) Successful in 21s
CI / ui (push) Successful in 1m9s
CI / conformance (push) Successful in 10s
CI / changes (pull_request) Successful in 1s
CI / gate (push) Successful in 0s
CI / deploy (push) Successful in 1m42s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 18s
CI / ui (pull_request) Successful in 1m8s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Has been skipped
850884d077
owner approved these changes 2026-07-08 23:40:58 +00:00
developer merged commit 18785efc8c into master 2026-07-08 23:42:15 +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#220