feat(variants): default a registered account to Erudit + Russian Scrabble
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 22s
CI / ui (pull_request) Successful in 1m16s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m53s

New Game opened on a single variant for everyone, which reads poorly on VK
where Russian Scrabble is the familiar game. A registered account now starts
with both Russian-alphabet games, so the picker offers a real choice with no
pre-selection.

A guest stays on Erudit alone and is invited to register for the rest: the
device-local guest has no profile at all, so the client-side fallback has to
keep matching the server. Registering promotes the set, but only while the
guest still carries the untouched guest default. Existing accounts are not
backfilled — the set they carry may be a deliberate choice.

The Telegram promo start-param becomes additive rather than a replacement,
with English Scrabble withheld from a Russian-speaking arrival; otherwise the
English campaign link would have taken Russian Scrabble away from every
account it onboarded.
This commit is contained in:
Ilia Denisov
2026-07-27 20:38:09 +02:00
parent 69b1a50644
commit b6d88da78c
19 changed files with 338 additions and 56 deletions
+11 -4
View File
@@ -18,6 +18,7 @@ import (
"github.com/go-jet/jet/v2/qrm"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgconn"
"github.com/lib/pq"
"scrabble/backend/internal/postgres/jet/backend/model"
"scrabble/backend/internal/postgres/jet/backend/table"
@@ -57,8 +58,9 @@ type Account struct {
// VariantPreferences is the set of game variants (engine.Variant stable labels:
// "scrabble_en", "scrabble_ru", "erudit_ru") the player is willing to be matched
// into. It gates the New Game picker, the matchmaker and the friend-invite the
// player creates; an invited friend may still accept any variant. A new account
// defaults to Erudit only. Never empty — enforced on update and by a DB check.
// player creates; an invited friend may still accept any variant. A newly registered
// account defaults to DefaultVariantPreferences and a guest to
// GuestVariantPreferences. Never empty — enforced on update and by a DB check.
VariantPreferences []string
// IsGuest marks an ephemeral guest account: a durable row with no identity,
// excluded from statistics, friends and history.
@@ -562,9 +564,14 @@ func (s *Store) ProvisionGuest(ctx context.Context, browserTZ, language string)
if lang == "" {
lang = "en"
}
// A guest is narrower than a registered player: Эрудит alone, where the column default
// gives a registered account both Russian-alphabet games (DefaultVariantPreferences).
// The set is written explicitly for exactly that reason, and ClearGuest widens it to the
// default when the guest later registers.
stmt := table.Accounts.
INSERT(table.Accounts.AccountID, table.Accounts.DisplayName, table.Accounts.IsGuest, table.Accounts.TimeZone, table.Accounts.PreferredLanguage).
VALUES(accountID, guestDisplayName(), true, tz, lang).
INSERT(table.Accounts.AccountID, table.Accounts.DisplayName, table.Accounts.IsGuest, table.Accounts.TimeZone, table.Accounts.PreferredLanguage, table.Accounts.VariantPreferences).
VALUES(accountID, guestDisplayName(), true, tz, lang,
postgres.Raw("#guest_variants::text[]", map[string]interface{}{"#guest_variants": pq.StringArray(GuestVariantPreferences)})).
RETURNING(table.Accounts.AllColumns)
var row model.Accounts