fix(vk): persist settings via VK Bridge storage; hide competing sign-in in Mini App hosts
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m28s
CI / conformance (pull_request) Successful in 16s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m6s

VK moderation follow-ups.

1. Settings (theme, language, board style, reduce-motion, zoom, first-run
   coachmark flags) were lost between reloads in VK's desktop iframe: Firefox
   partitions/blocks IndexedDB and localStorage in a cross-origin iframe, so the
   browser-local store is empty on every reload (a plain tab / PWA keeps them —
   first-party storage — and Telegram has its own CloudStorage sync). Mirror the
   prefs (plus the locale, which has no other durable client home on VK) and the
   coachmark flags to VK Bridge storage (VKWebAppStorageSet/Get), which travels
   over postMessage to vk.com and survives; reconcile them on the VK launch
   before the first paint. The VK identity re-derives from the signed launch
   params each load, so the values reload onto the same account.

2. Inside a proprietary Mini App host (VK or Telegram) the profile now surfaces
   only email linking — both the Telegram and VK link/unlink entries are hidden
   (signInProvidersVisible), so a competing sign-in is never advertised (a
   platform ToS requirement; VK forbids showing a Telegram login, mirrored in
   Telegram for VK). A provider linked earlier on the web stays attached and is
   managed from the web; web/native builds show both.

Tests: vkprefs codec + signInProvidersVisible unit tests. Docs: ARCHITECTURE,
FUNCTIONAL (+_ru). No schema/wire change.
This commit is contained in:
Ilia Denisov
2026-07-15 22:53:58 +02:00
parent b285e27d55
commit 6c0daeb177
10 changed files with 376 additions and 43 deletions
+16 -2
View File
@@ -47,7 +47,16 @@ Three executables plus per-platform side-services:
insets (the bottom/home-indicator strip taking the bottom bar's colour), exposes
Telegram's native **Settings** button into the in-app settings, and syncs the
device-independent display preferences (theme, reduce-motion, board labels — **not** the
interface language) across the user's Telegram devices via **CloudStorage**.
interface language) across the user's Telegram devices via **CloudStorage**. Inside the **VK
Mini App** the same preferences — **plus** the interface language and the first-run coachmark
flags — are instead mirrored to **VK Bridge storage** (`VKWebAppStorageSet`/`Get`,
`lib/vkprefs.ts` + `lib/vk.ts`, reconciled on launch): VK's cross-origin desktop iframe
(notably in Firefox) partitions or blocks the browser's IndexedDB/localStorage, so the local
store is lost across reloads there, while VK Bridge storage travels over the postMessage channel
to vk.com and survives; the VK identity re-derives from the signed launch parameters each load,
so the values reload onto the same account. The locale rides this store because on VK it has no
other durable client home (`preferred_language` is written from the client but never read back).
A plain browser tab / PWA keeps everything in first-party storage.
- **`platform/telegram`** — the Telegram side-service (module
`scrabble/platform/telegram`), split into two binaries that share the bot token
(**one bot**, one optional game channel, §3):
@@ -361,7 +370,12 @@ arrive from a platform rather than completing a mandatory registration).
- **Unlink** detaches a platform identity (`telegram`/`vk`) from the profile. The
backend **refuses removing the last identity** (`ErrLastIdentity`), so an account
never becomes unreachable; the UI mirrors the guard by hiding Unlink when only one
method remains. **Email is never unlinked — it is changed.**
method remains. **Email is never unlinked — it is changed.** **Inside a proprietary Mini App
host (VK or Telegram) the profile surfaces only email linking** — both providers' link and
unlink entries are hidden there (`profileValidation.signInProvidersVisible`), so a competing
sign-in is never advertised: a platform ToS requirement (VK forbids showing a Telegram login,
mirrored in Telegram for VK). A provider linked earlier on the web stays attached and is managed
from the web; the web and native builds show both providers.
- **Change email** mails a confirm-code (`purpose=change`) to the new address on the
authenticated account and, on confirm (code or one-tap deeplink), **atomically
replaces** the account's email identity with the new one, freeing the old address. A
+7 -4
View File
@@ -129,9 +129,10 @@ to finish that shared game before signing in.
The profile lists the account's **sign-in methods**. On the web a player can add
Telegram (a login-widget popup) or VK (VK ID web login — a redirect to VK's sign-in and
back); inside a Mini App the host platform is already linked, and its own sign-in-method
row is hidden — the platform the player is currently signed in through cannot be unlinked
from there, only the other provider's row is shown. Linking a provider that
back); inside a proprietary Mini App host (VK or Telegram) the player is offered **only email
linking**both providers' rows and add buttons are hidden there, so a competing sign-in is
never shown (a platform ToS rule). A provider linked earlier on the web stays attached and is
managed from the web. Linking a provider that
already belongs to another account offers the same irreversible **merge** as email
linking. A linked provider can be **unlinked** — except the last
remaining sign-in method, which is refused so the account stays reachable. **Email is
@@ -425,7 +426,9 @@ an email or Telegram and merging accounts are covered under "Accounts, linking &
merge". Inside the Telegram Mini App, Telegram's own ⋮ menu also offers a **Settings**
entry that opens this screen, and your display preferences (theme, board-label style and
reduce-motion — not the interface language, which follows your account) sync across your
Telegram devices. On a touch device the settings also offer a **Zoom the board** toggle (on by
Telegram devices. Inside the VK Mini App the same preferences — and the interface language —
are remembered between sessions this way too, including VK's desktop web version, where the
browser would otherwise forget them on every reload. On a touch device the settings also offer a **Zoom the board** toggle (on by
default): with it off, dropping a tile no longer auto-magnifies the board toward it. It is a
per-device preference and is hidden on desktop, where the board already fits and never auto-zooms.
+7 -4
View File
@@ -132,9 +132,10 @@ Telegram держит **единого бота**: все игроки поль
В профиле перечислены **способы входа** аккаунта. В вебе игрок может добавить
Telegram (попап логин-виджета) или VK (веб-вход VK ID — редирект на страницу входа VK и
обратно); внутри Mini App платформа-хозяин уже привязана, и её собственная плашка способа
входа скрыта — платформу, через которую игрок сейчас вошёл, отсюда отвязать нельзя,
показывается только плашка другого провайдера. Привязка провайдера, уже
обратно); внутри проприетарного Mini App хоста (VK или Telegram) игроку предлагается **только
привязка email** — плашки обоих провайдеров и кнопки добавления там скрыты, чтобы конкурирующий
способ входа не показывался (требование ToS платформы). Провайдер, привязанный ранее в вебе,
остаётся привязанным и управляется из веба. Привязка провайдера, уже
принадлежащего другому аккаунту, предлагает то же необратимое **слияние**, что и привязка
email. Привязанного провайдера можно **отвязать** — кроме последнего
оставшегося способа входа: он не отвязывается, чтобы аккаунт оставался достижимым.
@@ -431,7 +432,9 @@ UTC; при создании аккаунта она подставляется
Mini App пункт **Settings** в системном меню «⋮» Telegram также открывает этот экран, а
ваши настройки отображения (тема, стиль подписей клеток и reduce-motion — кроме языка
интерфейса, который следует за аккаунтом) синхронизируются между вашими устройствами в
Telegram. На сенсорном устройстве в настройках также есть переключатель **«Приближать
Telegram. Внутри VK Mini App те же настройки — и язык интерфейса — так же запоминаются между
сессиями, в том числе в десктопной веб-версии VK, где браузер иначе забывал бы их при каждой
перезагрузке. На сенсорном устройстве в настройках также есть переключатель **«Приближать
доску»** (по умолчанию включён): если выключить, при кидании фишки доска больше не
приближается к ней автоматически. Это настройка на устройство, и она скрыта на десктопе,
где доска и так помещается целиком и авто-зума нет.