# Профиль по почте и будущие покупки

Статус на10.11.2026: профиль поemail с одноразовым кодом, именем/паролем, восстановлением и сессиями реализован локально. Настоящая почтовая доставка и публичный сервер ещё не подключены. Магазина и списания денег нет. Ниже — целевая спецификация.

## 1. Регистрация, вход и гость

Требование пользователя трактуется так: **числовой код приходит на email**, телефон не нужен. Экран 1: почта и «Получить код». Экран 2: ввод кода с возможностью исправить адрес/повторить отправку. Экран 3: игровое имя и пароль. После завершения пользователь возвращается к игре; повторная регистрация при каждом входе не нужна.

Обычный последующий вход — email+пароль, восстановление — подтверждение владения почтой и новый пароль. Можно позже добавить passwordless-вход кодом как отдельный способ, но не смешивать его незаметно с созданием нового аккаунта. Почтовая проверка не является вторым фактором для уже существующего passwordless-входа.

Сохранить «попробовать без регистрации» для offline/casual. При создании профиля предложить привязать локальную тренировочную историю и настройки: проверенные серверные матчи сохраняются, произвольные клиентские рекорды помечаются `unverified` и не идут в рейтинг. Регистрация не должна прерывать текущий локальный бой. Для ranked и оплаты email должен быть подтверждён.

## 2. Состояния, безопасность и почта

Аккаунт: pendingVerification → pendingOnboarding → active; отдельные suspended/deletionRequested/deleted. Email хранить приватно, publicId отдельно. Исходный адрес и каноническое сравнение не путать: не удалять точки/плюс по догадке и не склеивать разных людей по особенностям одного провайдера. Политику одинаково применять к signup/login/reset/change-email. Проверка письма и ограничения повторов опираются на [OWASP Email Verification](https://cheatsheetseries.owasp.org/cheatsheets/Email_Validation_and_Verification_Cheat_Sheet.html).

Предлагаемые исходные лимиты:6-значный криптографически случайный код, TTL10 мин,5 попыток на challenge, повтор отправки не чаще 60 сек и до 5/час на адрес; отдельные IP/device/global limits против спама. Значения конфигурируемые и проверяются на доставляемости. Код привязан кpurpose, email, challengeId; старый код аннулируется при повторе, успешный consume атомарен. Сохранять HMAC кода с серверным секретом и challengeId, не открытый код и не простой быстрый hash шестизначного пространства. Не логировать код, пароль, session cookie и email целиком.

Ответ на запрос регистрации/сброса нейтральный, не выдаёт наличие аккаунта постороннему. Проверенный signup challenge может завершить только создание своего нового профиля; существующему аккаунту нельзя сменить пароль через этот маршрут. Recovery имеет отдельныйpurpose и отзывает предыдущие сессии согласно политике.

Пароли: поддержка менеджеров и вставки, без обязательных спецсимволов/периодической смены; минимум 15 символов при одном факторе, разрешить длинные фразы и как минимум 64 символа, проверять известные скомпрометированные пароли. Хранение — проверенная библиотека Argon2id или управляемый identity provider с подходящим контрактом; параметры выбрать и измерить по актуальным рекомендациям. Не писать собственную криптографию. Базовые требования к ошибкам, TLS, повторной аутентификации и паролям: [OWASP Authentication](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html), [Password Storage](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html).

Сессия в Secure+HttpOnly+SameSite cookie, CSRF/Origin-проверки для изменений; срок, rotation и отзыв хранятся серверно. Не держать долгоживущий bearer в localStorage. Короткоживущий join ticket привязан к конкретной комнате и слоту. Сменаemail/пароля/платёжных настроек требует повторного подтверждения. Экран «Устройства и выход со всех»; админ-доступ отдельно от игрока, с усиленной защитой.

Письма: отдельный отправляющий домен, SPF/DKIM/DMARC и bounce/complaint обработки через выбранный сервис. Очередь отправки не блокирует HTTP и игру. Статус доставки/недоступности показан честно; запасной resend без потери введённого адреса. В dev — локальный тестовый почтовый ящик, в production никакого вывода кода на экран. Проверить iOS/Android autofill `one-time-code`, русские/латинские имена и медленную сеть.

## 3. Данные профиля и API

Таблицы: `users`, `email_identities`, `auth_challenges`, `credentials`, `sessions`, `profiles`, `profile_settings`, `guest_links`, `account_audit`, `consents`. Пароль/почта изолированы от публичной статистики. Public profile: publicId, displayName, avatarCosmeticId, createdAt, privacy, selectedBadges; игровые lifetime/season данные запрашиваются из 22.

Никнейм — отображаемое имя, не ключ владения покупками/матчами. Сервер нормализуетUnicode, ограничивает длину, удаляет управляющие символы и опасную разметку; вывод всегда экранирован. Нужны жалоба/смена нарушающего имени и защита от выдачи себя за администратора. Уникальный короткий тег можно добавить отдельно; не раскрыватьemail ради различения одинаковых имён.

Настройки: звук/движение/графика/язык/доступность, приватность профиля, согласие на необязательные письма, косметика и избранные лабиринты. Графическое качество по устройству не синхронизировать слепо с мощногоПК на телефон. Игровая схема лабиринта — отдельный объект и не выдаёт сами башни бесплатно.

API-предложение: `POST /auth/email/start`, `/auth/email/verify`, `/auth/onboard`, `/auth/login`, `/auth/logout`, `/auth/recovery/start`, `/auth/recovery/complete`, `/auth/password/change`; `GET /me`, `PATCH /me/profile`, `PATCH /me/settings`, `GET/DELETE /me/sessions`, `POST /me/export`, `/me/deletion-request`. Все изменяющие операции имеют validation/rate limit/audit. Регистрацию аккаунта и перенос гостевой истории выполнять идемпотентно, повтор onboarding не создаёт второйuser.

Экспорт/удаление/восстановление, длительность хранения и правила несовершеннолетних зависят от стран запуска. До запуска подготовить политику приватности и условия; финансовые записи не обещать стирать вопреки обязательному хранению. Эти юридические настройки — отдельный этап перед публичной оплатой, не повод задерживать графическую работу.

## 4. Что в оригинале продавалось или усиливалось

Подтверждённые факты и цены **внутри матча**:

| Возможность | Что найдено | Что не подтверждено |
| --- | --- | --- |
| Swap/yixinghuanwei |Обмен двух позиций, золото 300/225/175/150 за каст по уровню способности | Квота бесплатных переносов и докупка за реальные деньги |
| Adja-Swap/qingyi |Обмен башни с соседним обычным камнем, золото 200/140/100/80 | Безошибочность всех owner-проверок в runtime |
| xuanfeng |Круговой сдвиг восьми соседних объектов, золото 200/125/75/50 | Прямая денежная цена |
| huidaoguoqu |Повторить незавершённую текущую пятёрку, золото 600/500/400/300 | Это не перенос оставленного камня и не бесплатныйreroll |
| Герои/способности/эффекты/игрушки/курьеры/коробки |Purchase handlers → внешний `/game/.../buy`, товар поGoodsId | Ассортиментные цены, возвраты, реальный платёжный оператор |
| Питомцы |Есть влияющий на уронpet_buff: ранги до суммарных 12 дают 2–50%; co-op складывает бонусы игроков | Нельзя считать магазин исключительно косметическим |
| Профиль |Steam/session, shell/ice/candy, сохранение героя и схем лабиринтов | Наш email-вход не готовое свойство оригинала |

В старом приложении обычный камень мог давать возврат ценыSwap; в 2.0 найденный обработчик этого не делает. Справка старого UI о месячных сезонах/коробках/наградах — свидетельство текста, а не доказанная работа нынешнего backend. Полный аудит — `future-audit/economy-stats.md`; не публиковать чужие серверные URL/секреты в приложении.

## 5. Что можно сделать платным

Рекомендация первой монетизации: косметика и удобство вне боевого преимущества. Это предложение, а не уже принятое ограничение пользователя.

| Вариант | Польза | Рекомендация |
| --- | --- | --- |
| Оболочки строителя-шара, шлейфы, эмоции | Личная выразительность без нового скелета | Первый набор; лимит частиц и reduced motion |
| Темы внешнего острова/воды/пьедесталов | Новый облик утверждённого мира | Хорошо; не менять коллизию, обзор врагов и контраст |
| Альтернативные косметические огранки/снаряды | Приятная кастомизация | Сохранять family/grade читаемыми; не закрывать путь |
| Аватары, рамки, профильные витрины/титулы | Ценность вне боя | Подходит, рейтинг не продаётся |
| Дополнительные слоты сохранённых схем | Удобство организации | Бесплатных слотов достаточно для обычной игры; в ranked схема лишьподсказка |
| Косметический сезонный пропуск | Тематические награды | Фиксированный список, без усиления урона/удачи |
| Поддержка проекта/комплект основателя | Понятная добровольная покупка | Чёткая выдача, без скрытых игровых бонусов |
| Дополнительные переносы/переброски | Сильное влияние на лабиринт и удачу | Только отдельный явно casual/custom режим; для ranked одинаковые лимиты и стоимость для всех |
| Платный урон, качество выпадения, жизни, питомцы с боевым бонусом | Прямое преимущество | Не рекомендую для общего рейтинга и первого магазина |

Если пользователь позже выбирает боевые покупки, включать их только в отдельный ruleset и таблицу, раскрывать условия лобби и co-op-команде до старта. Купленный перенос не должен изменять уже начатую ranked-партию. Бесплатная внутриигровая возможность перемещения за золото доступна всем по одинаковым правилам; выбор точного лимита/цены — баланс после аудита, не платёжная механика.

Не начинать с платных случайных коробок: фиксированные наборы проще объяснить, тестировать и поддерживать. Редкие визуальные предметы не должны стоить дополнительных draw calls без лимита. Не назначать реальные цены до выбора страны, валюты, аудитории и стоимости обслуживания.

## 6. Платёжный контур, который подготовить заранее

Изолировать **три экономики**: золото текущей партии, мета-прогресс аккаунта, реальные денежные заказы. Их балансы не являются одним полемgold. Сначала можно продавать фиксированныеSKU напрямую без виртуального кошелька.

Таблицы: `products`, `prices`, `orders`, `order_lines`, `payment_attempts`, `provider_events`, `entitlement_grants`, `entitlement_revocations`, `refunds`, `commerce_audit`. SKU/версияцены/валюта/налоговыйконтекст и snapshot описания фиксируются в заказе. `Entitlement` содержит itemId, accountId, sourceOrderId, validFrom/until, rulesetRestrictions, status; сервер проверяет доступность, клиент не выдаёт себе предмет флагом.

Поток: клиент выбираетSKU → сервер создаёт заказ по своей цене → hosted checkout провайдера → webhook с проверкой подлинности → транзакционное сохранение события/выдачи → клиент получает обновлённый профиль. Страница «оплачено» и redirect сами по себе не выдают предмет. Повтор webhook/вызова/таймаута не создаёт вторую выдачу: unique(provider,eventId) и unique(orderLine,grantType). Обрабатывать out-of-order сообщения через актуальное состояние заказа.

Проверка подписи по исходному телу, повторы и тестовый контур документированы, например, в [официальной документации Stripe webhooks](https://docs.stripe.com/webhooks). Это архитектурный пример, а не выбранный оператор или утверждение о его доступности пользователю. Провайдера выбирать по стране юридического лица, валютам и способу запуска; подключениеsandbox предшествует любым реальным списаниям.

Возврат/chargeback создаёт revoke соответствующей косметики; история матча и честно заработанный рейтинг не переписываются. Расходуемые платные действия требуют отдельной политики возврата/неиспользованного остатка и поэтому не входят в первый магазин. Для подписки предусмотреть отмену/истечение/grace/неуспешное продление, не хранить карты на нашем сервере. Панель поддержки показывает заказ/выдачу/возврат без доступа к игровым паролям.

## 7. Пакеты работ и критерии

| ID | Работа | Приёмка |
| --- | --- | --- |
| P1 |Identity schema и тестовая почта | Один код нельзя применить дважды; адрес/назначение не подменяются |
| P2 |Регистрация/вход/recovery | Просроченный код, 5 ошибок, resend, существующая почта, потеря сети, повтор формы |
| P3 |Сессии и безопасность | Logout-all, смена пароля, CSRF, чужой профиль, join-ticket replay |
| P4 |Профиль и guest-link | Перенос не создаёт ranked-рекорд из localStorage; покупки не привязаны к nickname |
| P5 |Entitlements без оплаты | Тестовый grant/revoke, разрешённые режимы, совместимость устройств |
| P6 |Провайдер sandbox | Верная/неверная подпись, дубликат, неупорядоченные события, таймаут, возврат |
| P7 |Готовность запуска магазина | Выбраны оператор, страны, цены и правила возврата; работает поддержка; нет купленной силы в общем ranked |

ДоP7 не запрашивать у игрока реальные платёжные данные и не выдавать тестовый checkout за действующий магазин.
