VanguardReMaster/DEVELOPMENT_CHECKLIST.md

622 lines
84 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CF!! Vanguard Re:Master — чеклист разработки
> Составлен на основе `plan.md` (283 строки). Версия 1.2 — темп сетов учтён, экономика пыли пересчитана под цикл 1–2 месяца.
> Легенда приоритетов: **P0** — без этого нет продукта, **P1** — нужно к релизу, **P2** — после релиза.
> Метки объёма: `[MVP]` — первая играбельная версия, `[v1]` — публичный релиз, `[later]` — развитие.
---
## 0.0 Зафиксированные решения (ADR)
| # | Вопрос | Решение | Следствия |
|---|---|---|---|
| 1 | Сетевой транспорт | **Свой протокол: TCP/WebSocket + MessagePack** | `Netcode for GameObjects` **исключён** из стека. Общие DTO в `/shared`, генератор кода для клиента. Сервер — чистый .NET 8. |
| 2 | Объём MVP | **1-й бустер + 2 триальные колоды** | MVP = ядро правил + один сет (94 карты) + две готовые колоды + коллекция + **полный декбилдер** + бустеры. Турниры, команды, территории, косметика, баттлпасс, Draft — после MVP. |
| 3 | Описание карт | **C#-скрипты + статы в YAML** | 1 карта = 1 файл-скрипт + запись в YAML-сете. Контент-мейкер без C# не добавляет карты — учитываем в планировании. |
| 3a | Версия .NET | **.NET 10 LTS** вместо .NET 8 из плана | .NET 8 выходит из поддержки 10.11.2026. .NET 10 — до ноября 2028. |
| 4 | Игровой сервер | **Microsoft Orleans** | GeekServer **исключён**. 1 матч = 1 grain, состояние в Redis/PostgreSQL через persistence-провайдер. |
| 5 | Платформа | **ПК (Windows) first**, мобилка после релиза | MVP-клиент — Windows + WPF-лаунчер. Тач-ввод, Addressables-доставка и сторы — веха после v1. |
| 6 | Сайд-дек / BO3 | **Убрать сайд-дек, BO1** | §13 плана правим: сайд-дек и «main + side ≤ 4 копий» удаляются. Валидация колоды проще. |
| 7 | Контент MVP | **TD01 «Blaster Blade», TD02 «Dragonic Overlord», BT01 «Descent of the King of Knights»** | Это **базовая эра 2011 г.**, а не D-серия. Меняет список механик, зон и триггеров. |
| 8 | Декбилдер | **Полный** | Поиск/фильтры, валидация, сохранение, шаринг — всё в MVP. |
| 9 | Онбординг | **Туториал → выбор триал-колоды + 5 токенов** | **1 токен = 1 бустер.** Токены универсальные, не только Draft. Новичок сразу собирает колоду из бустера. |
| 10 | Арты | **Официальные** | Юридический риск максимальный. Нужен план на takedown и правило «не храним арты на своём CDN без нужды». |
| 11 | Ride Deck / Persona Ride | **Нет в Classic** | Подтверждает базовую эру. Движок проектируется без них. |
| 12 | Локализация | **EN + RU** | Оба языка с первого дня, не «потом переведём». |
| 13 | Листы TD01/TD02 | **Получены** (вики + архив) | 50 карт каждая, 17/14/12/7 по грейдам. См. `content/cards-mvp.md`. |
| 14 | Бан-лист | **Банов в MVP нет** | Barcgal играется. Механизм `CardLegality` проектируем, но список пустой. |
| 15 | Параллельные арты | **Отдельные принты в коллекции**, привязка к базовому номеру карты (S02 → BT01/002) | Коллекция различает арты и **не имеет лимитов**. Лимит 4 копий — только при сборке колоды. |
| 16 | Название формата | **Classic** вместо «Standard» | Однозначно отделяет базовую эру от современного Standard. Переименовать в плане, коде и UI. |
| 17 | Лимиты коллекции | **Нет** — любое число копий и артов | 4 копии по имени — правило **декбилдера**, а не инвентаря. Duplicate protection — мягкий приоритет, а не жёсткий кап. |
| 18 | Правило дублей | Ключ — **`printingId`** (номер + арт), порог **4**; замена **внутри редкости**; иначе карта в коллекцию | Дубль разбирается в пыль **вручную** игроком, не автоматически. |
| 19 | Веса слота R+ | **R 70 % / RR 22 % / RRR 7 % / SP 1 %** | ~21 R, ~6,6 RR, ~2,1 RRR, ~0,3 SP на коробку из 30 бустеров. Крутится в `pack_odds.yaml`. |
| 20 | Пыль | **Сквозная валюта крафта**, не привязана к сету | Накопленное тратится на карты нового сета в день выхода. При цикле 1–2 месяца инфляция в норме (13–27 % сета за цикл). |
| 21 | Темп сетов | **1–2 месяца на сет** (80 карт) | Требует 1,3–1,8 карты в день **через приёмку**. Контент, а не движок, становится критическим путём проекта. |
### 0.0.1 Контент MVP — точный объём
Проверено по официальному карт-листу:
| Продукт | Уникальных карт | Принтов | Особенности |
|---|---|---|---|
| **BT01** Descent of the King of Knights | 80 (BT01/001–080) | 92 | +12 параллельных артов (BT01/S01–S12) |
| **TD01** Blaster Blade (Royal Paladin) | 16 | 16 | 7 карт **только** в TD01 (Brigitte, Bors, Tristan, Starlight Unicorn, Morgana, Stardust Trumpeter, Epona) |
| **TD02** Dragonic Overlord (Kagero) | 16 | 16 | 7 карт **только** в TD02 (Goku, Yaksha, Berserk Dragon, Aermo, Joka, Undeux, Rakshasa) |
| **Итого** | **94 уникальные карты** | **124 принта** | 10 кланов |
**Полный каталог с триггерами, редкостями и точными листами триал-дек — `content/cards-mvp.md`.**
Новые факты из вики:
- Редкости BT01: **RRR ×8, RR ×12, R ×20, C ×40** + **SP ×12**.
- В сете ровно **по 4 триггера каждого типа**: Critical, Draw, Stand, Heal.
- **Стартовый вэнгард — grade 0 без триггера** (Stardust Trumpeter в TD01, Undeux в TD02).
- **Draw-триггеры имеют 5000 щита, остальные триггеры — 10000.** Даёт бесплатный инвариант для валидатора.
**Кланы BT01:** Royal Paladin, Oracle Think Tank, Kagero, Nubatama, Tachikaze, Nova Grappler, Spike Brothers, Dark Irregulars, Granblue, Megacolony.
**Два вывода для модели данных:**
1. **`printingId` ≠ `nameId`.** BT01/002EN, TD01/005EN и BT01/S02EN — один и тот же «Blaster Blade». В коллекции это три разные записи без ограничений по количеству, а в деке лимит 4 копии **по имени** — иначе игрок соберёт 4 обычных + 4 параллельных = 8.
2. **Параллельные арты уже есть в первом сете** — вопрос §26 плана «нужны ли альтернативные арты» закрыт. 12 штук, каждый привязан к базовому номеру (`S02 → BT01/002`). Коллекция хранит арты раздельно, лимиты — по базовой карте.
### 0.0.2 Дельта правил: план писался под современный Vanguard
Это главная содержательная правка. Для базовой эры §4 плана даёт лишнее и не даёт нужного.
**Убрать из MVP:**
- Триггеры **Front** и **Over** — появились в V- и D-эре. В этом сете только **Critical, Draw, Stand, Heal**.
- Зоны **G Zone** и **Bind** — в 2011 их нет.
- Состояние **Lock** — появилось в 2013 (Link Joker).
- Понятие **Nation** — в 2011 только **Clan**. Поле `nation` оставить пустым/на будущее.
- **Ride Deck, Persona Ride** — подтверждено вами.
- **Limit Break, Break Ride, Legion, Stride, Imaginary Gift** — всё после MVP.
**Добавить в MVP (в плане отсутствует):**
- **Маллиган** в начале партии. В плане его нет вообще.
- **Стартовый вэнгард**: игрок выбирает grade 0 из колоды и выставляет его в начале игры.
- **Урон лицом вниз.** Damage-карты лежат рубашкой вверх; **Counter Blast** переворачивает одну лицом вверх. Значит, у damage-карты есть флаг `faceUp`, а не только счётчик. Плюс эффекты «turn all cards in your damage zone face up» (Embodiment of Victory, Aleph).
- **Twin Drive!!** — количество drive-чеков это модифицируемое свойство вэнгарда, а не константа: Dragonic Overlord умеет его терять.
- **Событие «атака попала»** отдельно от «атака объявлена»: половина карт сета триггерится на hit.
- **Boost как событие** с источником и целью: «when this unit boosts…» — массовая формулировка в сете.
- **События фаз**: начало main phase, начало close step боя, начало end phase — на них завязаны конкретные карты.
- **Sentinel** как ключевое слово с лимитом **4 карты в колоде** (не 4 копии по имени).
- **Heal-триггер** с лимитом **4 карты в колоде**.
- **Restraint** (не может атаковать) и «cannot [Stand] during next stand phase».
- **Атака в задний ряд той же колонки** (Wyvern Strike, Tejas) — нестандартная цель атаки.
**Ловушка контента — решена.** В официальном карт-листе тип триггера не виден в тексте (только иконка на арте), но в вики-таблицах есть отдельная колонка «Trigger». Все 16 триггеров BT01 и раскладка по триал-декам уже выгружены в `content/cards-mvp.md`. OCR не нужен.
**Что это дало проекту:** минус одна параллельная сетевая технология, минус один серверный фреймворк, минус неопределённость по объёму контента. Оценка MVP сократилась с «3–4 года» до реалистичного среза.
---
## 0. Результаты анализа плана
### 0.1 Что в плане хорошо
- Есть ясная базовая установка: авторитарный сервер, тонкий клиент, скрытая информация. Это правильный фундамент для ККИ.
- Экономика просчитана и внутренне непротиворечива: баттлпасс 2 500 + 21 000 + 35 000 = **58 500 XP**, «15 бустеров каждый 5-й уровень» = 15 бустеров. Совпадает.
- Разделение мета-сервера и игрового сервера, Redis для сессий, PostgreSQL для durable-данных — здоровая схема.
- Явно зафиксирован отказ от монетизации, голосового чата, ботов — меньше поверхности атаки и меньше работы.
- Есть раздел «что не обговорено» — редкость для дизайн-документов.
### 0.2 Противоречия и блокеры (решать до кода)
| # | Где | Проблема | Что делать |
|---|---|---|---|
| 1 | §2 | Игровой сервер — «TCP, MessagePack», но клиент — «Netcode for GameObjects». NGO — это Unity-рантайм (NetworkObject/NetworkBehaviour/Unity Transport). Он **не может** работать против standalone .NET 8 сервера. | ✅ **Решено:** свой протокол TCP/WebSocket + MessagePack, NGO убран. |
| 2 | §2 | «MessagePack / MemoryPack» — не выбрано. MemoryPack быстрее, но генерирует код и хуже дружит с межъязыковыми клиентами. | ✅ **Решено:** MessagePack. |
| 3 | §2 vs §1, §14 | «ScriptableObject (данные карт)» при том, что карты живут в БД, а логика — на сервере. Два источника истины. | SO — только визуал (префаб, арт, звук, VFX) по ключу `cardId`. Статы и текст — только с сервера. |
| 4 | §4 | «Все механики заложены сразу» (Limit Break → Break Ride → Legion → Stride → V → D) при объёме остальных разделов. | ✅ **Решено:** MVP = ядро + базовая D-эра на одном сете. Остальные эры — модули после MVP. |
| 5 | §3 | Редкости «Common/Uncommon/Rare/**Legendary**/RRR» — смешаны две разные таксономии (западная и официальная Vanguard). | Ввести официальную шкалу (C/R/RR/RRR/SP/…), «Legendary» убрать или явно определить как внутренний класс. |
| 6 | §13 | «Сайд-дек 5 карт» — в Vanguard сайд-деков нет, матчи BO1. | ✅ **Решено:** сайд-дек убран, формат BO1. |
| 7 | §21 | Тестовый матч «локальный, без сервера» → второй экземпляр движка правил на клиенте → неизбежное расхождение. | Туториал гонять через тот же серверный движок (локальный инстанс/ offline-режим сервера), либо принять риск и покрыть golden-тестами. |
| 8 | §21 | `TutorialStep`/`TutorialGameManager` — скриптованный туториал, а не «матч». | Решить: скрипт-события поверх реального движка или фейковая сцена. Рекомендую первое. |
| 9 | §2, §24 | Redis — единственное хранилище состояния матча. Потеря/эвикция = потерянный матч. | Redis с AOF + периодический снапшот матча в PostgreSQL + идемпотентное восстановление. |
| 10 | §11 vs §6 | «Casual — матчмейкинг просто по онлайну, без критериев» → новичок против топ-1. | Минимальный скрытый MMR даже в казуале (широкий диапазон), иначе отток новичков. |
| 11 | §24 | Реконнект 0/2/10/30 с, и что дальше — не сказано. | Политика: после N минут отсутствия — авто-поражение/пауза. См. блок 12. |
| 12 | §7 vs весь план | Тайм-контроль есть только в турнирах (35 мин). В обычном матче — нет. | Ввести таймер хода (rope) для всех матчей. |
| 13 | §13 | Нет правил конструирования колоды: размер, лимит копий по имени, лимит Heal-триггеров, Ride Deck (D). | Отдельный артефакт «Deck Construction Rules» на каждый формат. |
| 14 | §4 | В списке механик нет: Sentinel/Perfect Guard, Counter Charge, Soul Charge, Retire, Resist, Quintet Wall, Ultimate Stride, Persona Ride (есть только в D), Imaginary Gift-маркеров как объектов и т. д. | Полная инвентаризация механик по официальным правилам → Rules Reference. |
| 15 | §11 | Draft Run: 10 бустеров → колода. Правила сборки драфт-колоды (размер, триггеры, базовые карты) не заданы. | Определить формат (Sealed vs Draft), размер колоды, выдачу базовых триггеров. |
| 16 | §12 | «Готовые колоды за Gold» — легальны ли они в ранкеде, можно ли их менять. | Зафиксировать: это продукт-набор карт, колода собирается декбилдером. |
| 17 | §16 | Права модераторов описаны, инструментов — нет. | Нужна веб-админ-панель (блок 23). |
| 18 | весь план | Нет RNG-аудита (шаффл, drive/damage check) и реплеев. Без этого невозможны разбор жалоб, баланс и баг-репорты. | Server-side seeded RNG + журнал интентов + реплей (блок 8). |
| 19 | §10 | «Сброс 1-го числа» — таймзона не указана. | Зафиксировать UTC + отображать локально. |
| 20 | §15 | «Гайды… если нет лайков за неделю — удаляется» — неясно, чей лайк и зачем. | Переформулировать (например, авто-скрытие в «непопулярное»). |
| 21 | §4 | Триггеры перечислены как Critical/Draw/Stand/Heal/**Front/Over** — двух последних в 2011 не существует. | Только Critical, Draw, Stand, Heal (см. §0.0.2). |
| 22 | §4, §24 | Нет **маллигана**, **стартового вэнгарда** и **урона лицом вниз**. | Добавлено в блок 6. |
| 23 | §3 | Один `CardData.id` — не различает принт и имя карты. | Ввести `printingId` + `nameId` (см. §0.0.1). |
### 0.3 Крупные пробелы, которых в плане нет вообще
1. **Реплеи и детерминизм** — без них нет ни модерации, ни балансной аналитики, ни отладки.
2. **Админ-панель** (баны, муты, тикеты, бан-листы, выдача валюты, просмотр логов).
3. **Античит и мультиаккаунты** — только упомянуто в «не обговорено».
4. **Тайм-контроль обычных матчей.**
5. **Правила конструирования колод по форматам.**
6. **Пайплайн контента** — откуда берутся карты, как валидируются, как выкатываются сеты.
7. **Версионирование протокола и совместимость клиент/сервер.**
8. **Rate limiting / защита API / DDoS.**
9. **Наблюдаемость** (метрики, трейсы, алерты) — упомянута только как «мониторинг».
10. **Юридический риск** — фан-проект с чужими артами; нужен план на случай takedown и правила по ассетам.
### 0.4 Главные риски
- **R1. Правила.** Vanguard — это не «магия с реаргардами». Check Timing, одновременные триггеры, «may»-эффекты, порядок разрешения — самая дорогая часть проекта. Недооценка = переписывание ядра.
- **R2. Объём.** Раздел «все механики сразу» + 6 очередей + турниры + команды + территории — это 3–4 года для команды из 1–3 человек.
- **R3. Контент.** Карты надо не только описать данными, но и **заскриптовать**. 1 карта со сложным эффектом = 0,5–2 дня.
- **R4. Пустой онлайн.** 6 ранкед-очередей при маленькой аудитории = никто ни с кем не играет. Нужен план консолидации очередей.
- **R5. Юридический.** Bushiroad может потребовать прекратить использование артов/названий.
---
## 1. Дорожная карта (вехи и гейты)
| Веха | Содержание | Гейт (Definition of Done) |
|---|---|---|
| **M0. Решения и каркас** | ADR (уже готовы), Rules Reference v0, схема карт, репозиторий, docker, auth | `docker compose up` поднимает API + PostgreSQL + Redis + Orleans silo; логин/регистрация работают |
| **M1. Ядро правил (headless)** | Состояние, зоны, фазы, боевой цикл, Check Timing, RNG, реплеи | **Все 94 карты** (BT01 + TD01 + TD02) доигрывают матч в консольном раннере; реплей воспроизводится бит-в-бит |
| **M2. Сетевой матч** | Протокол, Orleans grain, скрытие информации, Unity-клиент с серым UI, реконнект | Два игрока по сети играют полный матч триал-колодами; убийство клиента на любом шаге восстанавливается |
| **M3. MVP-продукт** | Пайплайн контента, коллекция, минимальный декбилдер, триал-колоды, бустеры, Gold, XP, 1–2 очереди, базовый туториал | Новый игрок: логин → триал-дека → матч → бустер → собрал колоду из своих карт → сыграл ранкед |
| **M4. Мета и соцслой `[v1]`** | Ранкед/MMR/сезоны, баттлпасс, квесты, достижения, профиль, друзья, чат, лаунчер | Сезон отрабатывает полный цикл: старт → матчи → награды → сброс |
| **M5. Турниры и команды `[v1]`** | Турнирный движок, 3×3, снимки колод, архив, команды, территории, админка | Турнир на 8 человек проходит автоматически от регистрации до публикации архива |
| **M6. Мобилка и полировка `[later]`** | Тач-UI, Addressables-доставка, производительность, сторы, полный туториал | Билд проходит чеклист релиза (блок 26) |
> Рекомендация: **не начинать с UI**. Серый Unity-клиент на M2 — нормально. Красота — на M6.
---
## 2. Блоки
### Блок 1. Проектные артефакты и решения `[MVP]`
- [x] **P0** ADR-0001: сетевой транспорт — **TCP/WebSocket + MessagePack**, NGO исключён.
- [x] **P0** ADR-0002: игровой сервер — **Microsoft Orleans**, GeekServer исключён.
- [x] **P0** ADR-0003: способности карт — **C#-скрипты + статы в YAML**.
- [x] **P0** ADR-0004: объём MVP — **1-й бустер + 2 триальные колоды**.
- [ ] **P0** ADR-0005: архитектура презентации на клиенте (серверный event-stream → очередь анимаций).
- [ ] **P0** ADR-0006: схема идентификаторов карт и версионирование контента.
- [ ] **P0** ADR-0007: где живёт истина по правилам (сервер) и как клиент валидирует ввод «мягко».
- [ ] **P0** Написать **Rules Reference v0**: зоны, фазы, шаги боя, окна Check Timing, порядок разрешения. Источник — официальные Comprehensive Rules, с указанием версии.
- [ ] **P0** Инвентаризация механик: таблица «механика → эра → нужна ли в MVP → модуль».
- [ ] **P0** Правила конструирования колоды: ровно 50 карт, ≤4 копий по имени, ≤4 Sentinel, ≤4 Heal. Ride Deck отсутствует.
- [ ] **P1** Глоссарий-артефакт: ключевые слова RU/EN + плейсхолдеры (`{cb}`, `{sb}`, `{cc}`, `{sc}`) с точным описанием подстановки.
- [ ] **P1** Дизайн-док по UX-флоу: главное меню → коллекция → декбилдер → очередь → матч → результат.
- [ ] **P1** Реестр рисков с владельцами (R1–R5).
- [ ] **P1** Правила ассетов: что можно использовать, что рисуем сами, что плейсхолдер. План на случай takedown.
### Блок 2. Инфраструктура, окружения, CI/CD `[MVP]`
- [ ] **P0** Структура репозитория: `/server` (solution), `/client` (Unity), `/launcher`, `/shared` (контракты), `/content` (данные карт), `/docs`, `/ops`.
- [ ] **P0** `Directory.Build.props` + `global.json` (.NET 10, `LangVersion`, nullable, analyzers).
- [ ] **P0** `docker-compose.yml`: postgres:16-alpine, redis:7-alpine (+ AOF), nginx, meta-api (ASP.NET Core), game-silo (Orleans).
- [ ] **P0** Сети `backend`/`frontend`, volumes `postgres_data`/`redis_data`, `.env.example` без секретов.
- [ ] **P0** Healthcheck-эндпоинты и `depends_on: condition: service_healthy`.
- [ ] **P0** CI: сборка, `dotnet test`, линтеры, сборка Unity-клиента (хотя бы ночью), сборка лаунчера.
- [ ] **P0** Три окружения: `dev` (локально), `staging`, `prod`; разные секреты, одинаковые образы.
- [ ] **P1** Миграции EF Core: только через `dotnet ef migrations`, применять в CI-шаге, а не руками.
- [ ] **P1** Версионирование образов по git SHA, теги `latest` только в dev.
- [ ] **P1** Наблюдаемость: Serilog (структурные логи) + OpenTelemetry (трейсы/метрики) + Prometheus/Grafana.
- [ ] **P1** Алерты: падение сервиса, рост 5xx, лаг матч-акторов, заполнение диска.
- [ ] **P1** Бэкапы Postgres: ежедневный полный + WAL-архив, проверка восстановления раз в месяц.
- [ ] **P1** Секреты: не в git, в `.env` на сервере / Vault, ротация паролей БД.
- [ ] **P2** Load-test сценарий (k6) на 500 одновременных матчей.
### Блок 3. Аккаунты, аутентификация, безопасность `[MVP]`
- [ ] **P0** Модель `User`: id (uuid), login, email (опц.), password hash (BCrypt, cost ≥ 12), created_at, status, roles.
- [ ] **P0** Регистрация/логин/refresh. JWT: короткий access (15 мин) + refresh (30 дней) в Redis с ротацией.
- [ ] **P0** Отдельный короткоживущий **game ticket** для подключения к игровому серверу (не переиспользовать access-токен).
- [ ] **P0** Единая авторизация для HTTP API, SignalR-хаба и TCP-игрового соединения.
- [ ] **P0** Валидация ввода, нормализация логина, защита от перебора (rate limit + lockout).
- [ ] **P0** Роли и политики: `Player`, `Moderator`, `Admin`; авторизация на уровне эндпоинтов **и** сервисов.
- [ ] **P1** Восстановление пароля (email) или явное решение «без email» (тогда — только смена по старому паролю).
- [ ] **P1** 2FA (TOTP) для админов — обязательно, для игроков — опционально.
- [ ] **P1** Привязка устройств/сессий, список активных сессий, «выйти везде».
- [ ] **P1** Анти-мультиаккаунт: эвристики по IP/устройству, флаги для админа (не автобан).
- [ ] **P1** Аудит-лог действий админов/модераторов (кто, что, когда, над кем).
- [ ] **P2** OAuth (Discord/Steam) — если нужен вход без пароля.
### Блок 4. Данные карт и контент-пайплайн `[MVP]`
- [x] **P0** Полный каталог на 94 карты / 124 принта составлен — `content/cards-mvp.md` (BT01 + TD01 + TD02, с триггерами и редкостями).
- [ ] **P0** Точные листы TD01 и TD02 **получены** (50 карт, 17/14/12/7 по грейдам) — см. `content/cards-mvp.md`. Сверить с официальным продуктом при первой возможности.
- [ ] **P1** `CardLegality` с датами действия — таблица проектируется сразу, но в MVP пустая (банов нет).
- [ ] **P1** Зафиксировать раскладку редкостей BT01 (C / R / RR / RRR / SP) — на ней держатся бустер и duplicate protection.
- [ ] **P0** Разделить `printingId` (`BT01/002EN`, `TD01/005EN`, `BT01/S02EN`) и `nameId` (стабильный слаг имени). Лимит копий и поиск «по имени» считаются по `nameId`, арт и цена — по `printingId`.
- [ ] **P0** `CardData` под базовую эру: `printingId`, `nameId`, `setId` (BT01/TD01/TD02), `cardType` (Normal Unit | Trigger Unit), `grade`, `power`, `shield`, `critical`, `triggerType` (null | Critical | Draw | Stand | Heal), `clan`, `nation` (nullable, на будущее), `rarity`, `isParallel` + `artVariant` (для S01–S12), `isSentinel`, `isRestraint`, `name_en/ru`, `text_en/ru`, `flavor_en/ru`, `imageKey`, `artist`, `errataVersion`.
- [ ] **P0** **Не выводить `shield` из грейда или триггера** — в сете встречаются триггерные юниты и с 5000, и с 10000 щита. Значение всегда из данных.
- [ ] **P0** Триггеры и редкости выгружены из вики-таблиц — см. `content/cards-mvp.md`. Сверить выборочно 8–10 карт с иконками на артах.
- [ ] **P0** Добрать силу и щит для 14 карт, которых нет в BT01 (только TD01/TD02) — с карточных страниц.
- [ ] **P0** Нормализация текстов: в официальной БД есть опечатки (`Soul-Chage`, `begininng`, `cannnot`, `Own(VC/RC)`). Хранить `text_source` (как в источнике) и `text_normalized` (после правки), показывать игроку нормализованный.
- [ ] **P0** Структура способностей: `AbilityData { id, type, triggerEvent, conditionIds[], costIds[], effectIds[], targetSpec, optional, source }` + ссылки на скрипт.
- [ ] **P0** Разделить «статы» (в БД, сервер) и «визуал» (Addressables-ключ на клиенте). Клиент получает метаданные по API, арт — по `cardId`.
- [ ] **P0** Источник истины для контента: YAML/CSV в git (`/content/sets/BT01/…`, `/content/sets/TD01/…`), а не ручное редактирование БД.
- [ ] **P1** Валидатор контента: обязательные поля, корректность `legionMateId`, ссылки на существующие скрипты, дубликаты `cardId`, парность `_ru/_en`.
- [ ] **P1** Импортёр: `content → БД` (идемпотентный, с версией сета и откатом).
- [ ] **P1** Экспортёр для клиента: каталог карт + манифест Addressables-ключей.
- [ ] **P1** Легальность: таблица `CardLegality { cardId, format, eraId, banned, limit, condition }` с датами действия.
- [ ] **P2** Версионирование сетов и «снимок меты» на дату (для архива турниров).
### Блок 5. Локализация `[MVP]`
- [ ] **P0** Unity Localization: String Tables `en`/`ru`, ключи по схеме `ui.menu.play`, runtime-переключение без перезагрузки сцены.
- [ ] **P0** Сервер: параметр `lang` в запросах карт/глоссария, fallback `en`.
- [ ] **P1** Текстовый шаблонизатор карт: `{cb}`, `{sb}`, `{cc}`, `{sc}` → локализованный термин из глоссария; поддержка `<b>`, `<i>`, переносов.
- [ ] **P1** Проверка шрифтов TMP: кириллица, fallback-атлас, авто-фит текста на карте.
- [ ] **P1** Псевдолокализация (длинные строки) для проверки вёрстки.
- [ ] **P1** Лаунчер: RESX `ru`/`en`, общий глоссарий с сервером (единый CSV как источник).
- [ ] **P2** Экспорт строк для внешних переводчиков (CSV/XLIFF) и импорт обратно.
### Блок 6. Игровое ядро: состояние, фазы, базовые действия `[MVP]` — **критический путь**
- [ ] **P0** `GameState`: игроки, зоны, флаги хода, счётчики, RNG-состояние, версия/sequence.
- [ ] **P0** Зоны MVP: Vanguard Circle, Rear-Guard (3 колонки × 2 ряда; VG занимает центр переднего ряда, остальные 5 слотов — RC), Guardian, Soul, Damage, Drop, Trigger, Deck, Hand. **Без** G Zone, Bind и Ride Deck — в этой эре их нет.
- [ ] **P0** Модель юнита: `instanceId`, `printingId`, состояние (Stand/Rest), модификаторы силы/крита, временные эффекты с длительностью. **Без** Lock — появился позже.
- [ ] **P0** Модель Damage: карты лежат **лицом вниз**. Флаг `faceUp` у каждой карты, а не просто счётчик урона. Counter Blast = перевернуть одну лицом вверх; отдельные эффекты переворачивают весь damage-зон.
- [ ] **P0** Фазы: Mulligan → Stand → Draw → Ride → Main → Battle → End. Явные шаги внутри Battle: attack declare → guard → drive check → damage check → close step.
- [ ] **P0** Старт партии: выбор стартового grade 0 из колоды → выставление в Vanguard Circle → **маллиган** (замена любого числа карт из руки) → начало первого хода.
- [ ] **P0** Базовые действия: Ride, Call, Move, Attack, Intercept, Guard, Boost, Drive Check, Damage Check, Stand/Rest, Retire, Draw, Discard, Shuffle.
- [ ] **P0** `driveCheckCount` — изменяемое свойство вэнгарда (Twin Drive!! = 2), а не константа: Dragonic Overlord умеет его терять.
- [ ] **P0** Результат боя как явное событие: `Hit` / `Guarded` / `Missed`. Триггеры «when this unit's attack hits» — массовая формулировка сета.
- [ ] **P0** Boost как событие с источником и целью (нужно для «when this unit boosts…» и для модификаторов «boosted unit gets +N»).
- [ ] **P0** Counter Blast / Soul Blast / Soul Charge как первоклассные операции (с проверкой доступности). Counter Charge — позже, в сете его нет.
- [ ] **P0** Валидация действий: сервер отвечает `Rejected(reason)` на нелегальный интент, состояние не меняется.
- [ ] **P0** Машина состояний «чей сейчас ввод»: явный список легальных интентов для каждого игрока (нужен и для UI, и для античита).
- [ ] **P0** Юнит-тесты на каждое правило из Rules Reference (не на карты — на механику).
- [ ] **P1** Тайм-контроль хода (rope): 90 с на ход, 5 мин банк, авто-end.
- [ ] **P1** Обработка «нет легальных действий» (принудительный пас), защита от дедлоков.
- [ ] **P1** Лимит глубины рекурсии эффектов и защита от бесконечных циклов.
### Блок 7. Игровое ядро: способности и Check Timing `[MVP]` — **критический путь**
- [ ] **P0** Шина событий в `GameActor`: типизированные события (`UnitRode`, `UnitCalled`, `AttackDeclared`, `TriggerRevealed`, `DamageTaken`, `UnitRetired`, …).
- [ ] **P0** Три обработчика: `Continuous` (пересчёт слоёв модификаторов), `Activated` (по действию игрока), `Triggered` (по событию).
- [ ] **P0** **Check Timing**: собрать сработавшие триггеры → отсортировать по правилам (обязательные/опциональные, владелец, порядок выбора) → разрешить по одному → повторить, пока очередь не пуста.
- [ ] **P0** Модель стоимости (`costs[]`): CB, SB, discard, rest self, retire self, put into soul, return to deck, «pay if you want» — с откатом, если оплата невозможна.
- [ ] **P0** Модель целей (`targetSpec`): авто-выбор по фильтру, выбор игроком, «до N», «ровно N», валидация на сервере.
- [ ] **P0** Модификаторы силы/крита как слои с длительностью (до конца боя / хода / пока на поле) — без ручного пересчёта в скриптах карт.
- [ ] **P0** Golden-тесты Check Timing: сценарии с 3+ одновременными триггерами и порядком разрешения.
- [ ] **P1** «Resist» и запрет выбора — как фильтр в `targetSpec`, а не как спецкод в картах.
- [ ] **P1** Логирование цепочки разрешения (для отладки и реплеев): «событие → сработавшие → порядок → результат».
- [ ] **P2** Инструмент-визуализатор цепочки для отладки карт.
### Блок 8. Детерминизм, RNG, реплеи `[MVP]` — **критический путь**
- [ ] **P0** Серверный PRNG с явным seed на матч; шаффл детерминированный (Fisher–Yates поверх seeded-потока).
- [ ] **P0** Разделить потоки RNG: шаффл / drive check / damage check / случайные эффекты карт — независимые счётчики (иначе правка одной карты ломает реплеи).
- [ ] **P0** Журнал интентов: `[seq, playerId, intent, timestamp]` + итоговый seed → матч воспроизводим.
- [ ] **P0** Реплей-раннер: `GameState + intents + seed → финальное состояние`, сравнение хешей. В CI на каждый коммит ядра.
- [ ] **P1** Хранение реплеев: последние N матчей в горячем хранилище, остальное — в S3/файлах с сжатием.
- [ ] **P1** Проверяемая честность бустеров: публикация хеша сида до открытия, раскрытие после (опционально, но дёшево и снимает много жалоб).
- [ ] **P1** Лог «почему действие отклонено» для саппорта.
- [ ] **P2** Просмотр реплея в клиенте (шаг вперёд/назад) — сильный инструмент для комьюнити.
### Блок 9. Механики по эрам `[MVP → later]`
Порядок реализации = порядок возрастания сложности, не порядок выхода сетов.
> **Правило MVP:** в первую версию входят **только** механики из 94 карт MVP. Сначала матрица «карта → механика», из неё — список модулей. Ванильных карт без текста много, они не тянут за собой новых модулей.
- [ ] **P0** Ядро (Ride/Call/Boost/Intercept/Guard/Drive/Damage, Stand/Rest, Counter Blast, Soul Blast, Soul Charge, Retire).
- [ ] **P0** Триггеры: **только Critical, Draw, Stand, Heal**. Front и Over появятся в V/D-эре — не реализуем сейчас.
- [ ] **P0** Sentinel (Perfect Guard): нуллификация атаки, лимит **4 карты в колоде** — отдельно от лимита копий по имени.
- [ ] **P0** Heal-триггер: лимит **4 карты в колоде**, отдельная проверка в валидаторе.
- [ ] **P0** Ключевые слова и ограничения: Restraint (не может атаковать), «cannot [Stand] during next stand phase», «cannot be hit», «cannot boost this unit».
- [ ] **P0** Атака в задний ряд той же колонки (Wyvern Strike, Tejas) — нестандартная цель атаки, ломает наивную модель «атакую только передний ряд».
- [ ] **P1** Каждая механика — отдельный модуль с фича-флагом по формату (включение/выключение на уровне матча).
- [ ] **P2** `[later]` Limit Break (4+ урона) + Break Ride (+10000, тот же клан).
- [ ] **P2** `[later]` Legion (Leader + Mate, Seek Mate).
- [ ] **P2** `[later]` G-эра: Stride, Heart Card, G Guardian, G Zone.
- [ ] **P2** `[later]` V-эра: Imaginary Gift Force/Accel/Protect, Front-триггер.
- [ ] **P2** `[later]` D-эра: Ride Deck, Persona Ride, Over Trigger.
- [ ] **P1** Тесты: один и тот же набор базовых тестов прогоняется для каждого формата.
### Блок 10. Скрипты карт и тестирование контента `[MVP]`
- [ ] **P0** Шаблон новой карты для зафиксированного формата (**C#-скрипт + запись в YAML**): 1 файл = 1 карта, обязательные `// rule:` комментарии со ссылкой на официальный текст.
- [ ] **P0** Глоссарий примитивов, собранный из фактических текстов сета: `Draw`, `Retire` (одна/все/до N), `Search→call`, `Search→hand`, `Search→ride`, `Stand` (себя/выбранного/всех), `Soul-Charge`, `Soul-Blast`, `Counter-Blast`, `Flip damage face-up`, `Put into soul`, `Deck→drop`, `Return to deck + shuffle`, `Hand→deck`, `Discard as cost`, `Opponent discards`, `Look top & reorder`, `Power/Crit modifier`, `Gain/lose keyword`, `Attack back row`, `Cannot stand`, `Cannot be hit`. Всё остальное — комбинации этих примитивов.
- [ ] **P0** Хелперы «поиск по имени» (`nameId`) — в сете много карт, которые ищут/проверяют конкретные имена (Blaster Blade, Llew, Flogal, Tejas, Blue Dust, King of Sword).
- [ ] **P0** План скриптования: сначала обе триал-колоды (играбельно сразу), затем остальные карты BT01 — от простых к сложным. Ванильных карт с «–» в сете много — они закрываются одной строкой данных.
- [ ] **P0** Пропускная способность под темп **1–2 месяца на сет**: 80 карт / 45–60 дней = **1,3–1,8 карты в день**, каждый день, без пауз. Это узкое место проекта, а не движок. Варианты: второй контент-мейкер или буфер из двух готовых сетов до публичного запуска.
- [ ] **P1** Мерить «карты, прошедшие приёмку», а не «карты, написанные»: скрипт + тест + RU/EN + воспроизводимый реплей.
- [ ] **P0** Базовые «кирпичики» (helpers): `DrawCard`, `RetireUnit`, `AddPower`, `ChooseTarget`, `LookTopDeck`, `CallFromDeck` — чтобы 80 % карт были однострочными.
- [ ] **P1** Тест-харнесс для карт: «дано состояние → сыграй карту → ожидай состояние» на DSL/YAML.
- [ ] **P1** Чеклист приёмки карты: текст совпадает с официальным, все ветки эффекта покрыты тестом, RU/EN синхронны, работает в реплее.
- [ ] **P1** Метрика покрытия: сколько карт из сета заскриптовано/протестировано (дашборд).
- [ ] **P1** Fuzz-тест: случайные легальные матчи на 1000 партий, проверка инвариантов (нет отрицательных счётчиков, зоны не теряют карты, total cards = const).
- [ ] **P2** Визуальный редактор/валидатор карт.
### Блок 11. Игровой сервер и сетевой протокол `[MVP]`
- [ ] **P0** Спецификация протокола (транспорт выбран: TCP/WebSocket + MessagePack): handshake, auth, версия, ping/pong, реконнект.
- [ ] **P0** Конверт сообщения: `{type, seq, payload}`, типизированные DTO в `/shared`, генерация кода для C#-клиента.
- [ ] **P0** Orleans-модель: `IMatchGrain` (1 матч = 1 grain), `IQueueGrain` на формат, `IUserGrain` (сессия/presence). Последовательная обработка интентов — гонки исключены архитектурно.
- [ ] **P0** Кластеризация: dev — один silo, prod — 2+, Redis как clustering/persistence provider; readiness-проба на silo.
- [ ] **P0** **Проекция состояния под клиента** (fog of war): каждый игрок получает свою руку, свой trigger zone и открытый урон. Никогда не отправлять: порядок колоды, руку противника, **лицом вниз лежащий урон (даже владельцу)**, seed.
- [ ] **P0** Авторитет: клиент отправляет только намерения (`PlayCard`, `Attack`, `PassGuard`), сервер валидирует и рассылает события.
- [ ] **P0** Последовательность событий (`eventSeq`) — клиент просит `resync` при разрыве.
- [ ] **P1** Пауза/возобновление матча при `OnApplicationPause` (мобилка) с лимитом.
- [ ] **P1** Версионирование протокола: `minClientVersion`, вежливый отказ с сообщением «обновите клиент».
- [ ] **P1** Rate limiting на интенты (античит: не больше N действий/сек).
- [ ] **P1** Graceful shutdown: активные матчи дописываются в снапшот, игроки получают «сервер перезагружается».
### Блок 12. Реконнект и устойчивость матча `[MVP]`
- [ ] **P0** Политика: 0 / 2 / 10 / 30 с → затем экран «не удалось», матч живёт ещё N минут.
- [ ] **P0** Явные правила: сколько ждём (например, 5 мин), что происходит по истечении (авто-поражение / ничья), как это влияет на XP и рейтинг.
- [ ] **P0** Сессия в Redis с TTL ≥ длительности матча + запас; продление на каждом интенте.
- [ ] **P0** Снапшот матча в PostgreSQL при завершении и раз в N интентов; восстановление актора после рестарта.
- [ ] **P0** Индикатор «Переподключение…», кнопка «Отменить» (добровольная сдача с подтверждением).
- [ ] **P1** Реконнект **только** при неожиданном обрыве: явный выход = сдача, без «сохранения» матча.
- [ ] **P1** Тест: убить соединение на 20 разных шагах матча, проверить восстановление.
- [ ] **P1** Обработка дублирующихся интентов (idempotency по `intentId`).
### Блок 13. Матчмейкинг, очереди `[MVP]`
- [ ] **P0** MVP: **2 очереди** — Classic Ranked и Classic Casual. Остальные 4 (V/D) включаются конфигом без правки кода — реестр очередей data-driven, не копипаста.
- [ ] **P0** Приватные матчи через приглашение — отдельный путь, минуя очередь.
- [ ] **P0** Алгоритм: скрытый MMR, расширяющееся окно (например, ±100 → ±600 за 60 с), регион/пинг.
- [ ] **P0** Консолидация: если очередь пуста N секунд — предложить «играть в другой формат» (иначе 6 очередей убьют онлайн).
- [ ] **P0** Проверка легальности колоды перед постановкой в очередь; выбор колоды (не «последняя»).
- [ ] **P1** Казуал: широкое окно MMR + защита первых 10 матчей новичка.
- [ ] **P1** «Вес колоды» для матчмейкинга — **пересмотреть**: влияет на мету и воспринимается как несправедливость. Сделать опциональным/выключенным.
- [ ] **P1** Приватные матчи: приглашение → принятие → выбор колоды → матч; без XP, но с записью в историю.
- [ ] **P2** Региональные шарды и межрегиональный матчмейкинг.
### Блок 14. Клиент: каркас `[MVP]`
- [ ] **P0** Unity 2022 LTS **или** Unity 6 — зафиксировать отдельным решением (в 6 закрытых вопросов не входило); render pipeline — URP.
- [ ] **P0** Слои: `Core` (сеть, состояние), `Meta` (меню/коллекция), `Battle` (сцена боя), `UI`, `Audio`, `Localization`.
- [ ] **P0** **State-машина приложения** + DI (VContainer/Zenject или ручной composition root) — без синглтонов-свалок.
- [ ] **P0** Клиентское зеркало состояния: `ClientGameState` собирается **только** из событий сервера; никаких локальных правок правил.
- [ ] **P0** Очередь презентации: события → анимации строго последовательно; скип/ускорение; корректный «догон» после реконнекта.
- [ ] **P0** Addressables: каталог карт, арт, звук; ключ = `cardId`; загрузка/выгрузка по требованию.
- [ ] **P1** Input System: одна схема, два набора привязок (тач / мышь+клавиатура).
- [ ] **P1** Настройки: громкость, язык, качество, лимит FPS, мьют эмоций, приватность.
- [ ] **P1** Экран ошибок/офлайна, повтор запросов, таймауты API.
- [ ] **P1** Логи клиента с отправкой в саппорт (кнопка «отправить лог»).
### Блок 15. Клиент: боевая сцена и UX `[MVP]`
- [ ] **P0** Экран старта партии: выбор стартового grade 0 из колоды → **маллиган** (отметить любые карты, подтвердить) → превью руки противника без содержимого.
- [ ] **P0** Раскладка поля: Vanguard Circle, 2 колонки × (front/back), Guardian, рука, Damage (лицом вниз), Soul, Drop, Trigger.
- [ ] **P0** Отображение силы/крита с модификаторами (подсветка баффов), доступных действий, «почему нельзя».
- [ ] **P0** Ввод: тап/клик на карту → контекстное меню действий → выбор цели (подсветка валидных целей).
- [ ] **P0** Анимации: ride, call, attack, drive check (раскрытие), damage check, retire, boost, guard. DOTween + очередь.
- [ ] **P0** Ход противника: таймлайн «что произошло» + лог боя (текстовый), чтобы не терять контекст.
- [ ] **P0** Таймер хода, индикатор «переподключение», кнопка сдачи с подтверждением.
- [ ] **P1** Эмоции: панель, ID → ассет, кулдаун 2–3 с, локальный мьют per-match.
- [ ] **P1** Экран результата: победа/поражение, XP, прогресс заданий, рейтинг ±, кнопка «ещё матч».
- [ ] **P2** Настройка скорости анимаций, «пропустить всё».
- [ ] **P2** Режим наблюдателя / просмотр реплея.
### Блок 16. Колоды и коллекция `[MVP]`
- [ ] **P0** Декбилдер: поиск/фильтры (клан, грейд, редкость, тип Normal/Trigger, наличие арта), счётчики, валидация в реальном времени.
- [ ] **P0** Валидация на **сервере** (клиентская — только подсказка): ровно 50 карт, ≤4 копий **по `nameId`** (не по принту!), ≤4 карт с Sentinel, ≤4 карт с Heal-триггером, формат, бан-лист.
- [ ] **P0** **Разделить инвентарь и колоду:** коллекция не ограничивает количество копий и артов вообще; лимит 4 по имени действует только в момент сборки/сохранения колоды.
- [ ] **P0** Отдельный тест-кейс: 4× обычный Blaster Blade + 4× параллельный (S02) должен отклоняться валидатором, при этом обе карты спокойно лежат в коллекции в любом количестве.
- [ ] **P0** Коллекция: каждый арт — отдельная запись (BT01/002 и BT01/S02 видны раздельно), привязка к базовому номеру, счётчик копий без верхней границы, «сколько в колодах», блокировка разбора.
- [ ] **P0** Лимиты: 30 колод на формат + 10 турнирных; понятные ошибки при превышении.
- [ ] **P1** Инвариант данных: у grade 0 щит 5000 **только** у Draw-триггеров, у остальных 10000. Автопроверка на всех 94 картах ловит ошибки разметки.
- [ ] **P1** Импорт/экспорт по коду колоды + ссылка; шаринг.
- [ ] **P1** Публичные колоды: просмотры, лайки, «гайд» (описание).
- [ ] **P1** Защита от разбора: карта в колоде/турнирном снимке заблокирована; снятие после турнира.
- [x] ~~Сайд-дек~~ — **решение: убран**, формат BO1. Пункт «main + side ≤ 4 копий» из §13 плана удалить.
- [ ] **P2** «Вес колоды», статистика колоды (winrate), рекомендации.
### Блок 17. Экономика `[MVP]`
> **MVP-объём:** Gold, пыль, бустеры, duplicate protection, покупка триал-колод. Баттлпасс, квесты и Draft Run — после MVP. XP всё равно пишем с первого дня, иначе прогресс не восстановить задним числом.
- [ ] **P0** **Журнал транзакций** (double-entry): каждая операция — запись с `idempotencyKey`, баланс — вычисляемый, не хранимый «на честном слове».
- [ ] **P0** Валюты: Gold, пыль, **токены** (универсальные — обмениваются на любой бустер). Все изменения — только через сервис экономики.
- [ ] **P0** Структура бустера: **5 карт** = 4 карты редкости **C** + 1 слот **«R и выше»**. Генерация слотовая, а не «5 случайных по редкости» — иначе гарантия не выполняется.
- [ ] **P0** Веса слота R+: **R 70 % / RR 22 % / RRR 7 % / SP 1 %** → в `pack_odds.yaml`, с валидацией «сумма = 100 %» и «строгое убывание».
- [ ] **P0** SP-принты (12 шт.) — отдельный исход в слоте R+, заменяет базовую карту. Для duplicate protection это отдельный принт.
- [ ] **P0** Бустеры: серверный рандом по весам, лог открытий (кто/когда/что/сид).
- [ ] **P0** Duplicate protection: ключ — **`printingId`** (номер + арт), порог **4 копии**. Слот выбирается только из принтов, которых у игрока меньше 4.
- [ ] **P0** Замена — **внутри той же редкости**, иначе поедут шансы слота.
- [ ] **P0** Если **вся редкость** насыщена (все принты по 4), а другие ещё нет — перебрасываем редкость с перенормировкой весов. Иначе все 20 R собираются раньше, чем RRR, и дальше каждый R-бросок становится «мёртвым».
- [ ] **P0** Если насыщен весь слот R+ — карта выдаётся как дубль и уходит в коллекцию.
> **Что дают веса** (коробка = 30 бустеров):
> | Редкость | Вес | На коробку | Копий до 4× | Бустеров, если добирать только эту редкость |
> |---|---|---|---|---|
> | R | 70 % | ~21 | 80 | ~114 |
> | RR | 22 % | ~6,6 | 48 | ~218 |
> | RRR | 7 % | ~2,1 | 32 | ~457 |
> | SP | 1 % | ~0,3 | — | вне прогресса сета |
>
> Защита от дублей не ускоряет добор **редкой** редкости: она лишь убирает повторы внутри неё. Поэтому хвост сета — это RRR.
> Точечно нужная карта добывается **пылью**, а не открытием: после насыщения C каждый бустер даёт ~20 пыли, крафт RRR = 400 → 20 бустеров на одну. Это и есть надёжный путь к турнирной колоде.
- [ ] **P0** Дубль **не разбирается автоматически**: игрок сам превращает его в пыль, с предупреждением, если карта стоит в колоде. Коллекция при этом не ограничена.
- [ ] **P0** SP **не учитывать** в прогрессе «собрано X/Y карт сета» и в достижениях за коллекцию — иначе сет не закрывается никогда. SP — косметический параллельный принт.
- [ ] **P0** Пыль под реальные редкости: разбор **C 5 / R 10 / RR 25 / RRR 100**, крафт ×4 — **20 / 40 / 100 / 400**. SP не крафтится (только из бустеров). В плане был «Uncommon» — в BT01 это R.
- [ ] **P0** Пыль — **сквозная валюта, не привязана к сету**: накопленное тратится на крафт карт нового сета в день его выхода. При смене сета пыль не сгорает и не конвертируется.
- [ ] **P1** Инфляция пыли при темпе сетов 1–2 месяца: за цикл накапливается ~800–1600 пыли против 6 000 на полный плейсет, то есть **13–27 %**. Это здоровый диапазон — крафт нового сета можно открывать сразу, задержка не нужна.
- [ ] **P2** Если темп сетов замедлится до 4+ месяцев, вернуться к вопросу задержки крафта: тогда доля доходит до 50 %+ и новинки теряют смысл.
- [ ] **P0** Цены MVP: бустер 100 Gold, 1 токен = 1 бустер. Draft Run 1000 Gold — после MVP.
- [ ] **P1** `[v1]` Баттлпасс: 75 уровней / 30 дней, XP-пороги 250/700/1000, награды каждые 5 уровней, Draft-пропуск на 40 и 75, переполнение 50 Gold/уровень.
- [ ] **P0** XP за матчи: 150/75/100, Draft 200/100, турниры 500/250/1000/2000 (начисление писать с первого дня).
- [ ] **P0** Gold за матчи: **30 / 15 / 20** (победа / поражение / ничья). Мнемоника — **Gold = XP / 5**: одна константа в конфиге, а не два независимых баланса.
- [ ] **P0** Gold **не** начисляется: за сдачу, АФК, приватные матчи. Только после подтверждённого сервером завершения.
- [ ] **P1** Бонус первой победы дня: **+20 Gold**. Компенсирует то, что квесты дают только XP, и держит ежедневный вход осмысленным.
- [x] **P0** Размер бустера подтверждён: **5 карт**, из них 1 гарантированно R или выше.
> **Проверка темпа** (5 карт в бустере = 4 C + 1 R+, 50 % побед, 5 матчей в день):
> - средний доход за матч — 22,5 Gold, то есть ~22 % бустера;
> - день — ~132 Gold (с бонусом первой победы) ≈ **1,3 бустера**;
> - неделя — ~9 бустеров = 36 C + 9 R+;
> - месяц — ~40 бустеров = **~160 C** (ровно 40 карт × 4 — полный C-сет) и **~40 R+**;
> - **узкое место — не коммоны, а R+:** 40 карт × 4 = 160 копий, то есть полный R+ закрывается за ~160 бустеров ≈ **4 месяца**;
> - **на один сет при темпе 1,5 месяца (~60 бустеров):** ~100 % C и ~37 % R+. Новинка ощущается свежей, но R+ остаётся хвостом.
- [ ] **P1** `[v1]` Квесты: 3 ежедневных (1/3/5 матчей → 300 XP), 1 недельный (20 матчей → 2000 XP), сброс по UTC.
- [ ] **P0** Засчитывание матча: доигран, без сдачи, без АФК; приватные — не засчитываются.
- [ ] **P2** `[later]` Draft Run: вход 1000 Gold → 10 бустеров, 5 побед → +5 бустеров, 10 побед → +5 токенов, без пыли, без лимита поражений.
- [ ] **P2** `[later]` Правила драфт-колоды (размер, триггеры, базовые карты) — **сейчас не определены**.
- [ ] **P0** Онбординг: после туториала игрок выбирает **одну из двух триал-колод** (бесплатно) и получает **5 токенов**; токен обменивается на любой бустер. Выбор нельзя отменить — предусмотреть подтверждение.
- [ ] **P0** Покупка второй триал-колоды за Gold.
- [ ] **P1** Анти-дюп и защита от повторного применения `idempotencyKey`; лимит операций в секунду.
- [ ] **P1** Открытые вопросы: сгорает ли пыль в конце сезона, есть ли лимит на токены, есть ли лимит Gold.
- [ ] **P2** «Инфляция Gold»: что ещё продавать, чтобы валюта не обесценивалась.
### Блок 18. Рейтинг, сезоны, прогрессия, достижения `[v1]`
- [ ] **P0** MMR: скрытый, Elo/Glicko-2, отдельный на каждый формат (3 значения), K-фактор с учётом новичков.
- [ ] **P0** Ранги: 6 тиров × 5 дивизионов, Master без дивизионов; звёзды ±1, 5 звёзд = +1 дивизион.
- [ ] **P0** Защита от падения: Bronze/Silver — нет, Gold/Platinum/Diamond — до пола тира, Master — свободно.
- [ ] **P0** Сброс сезона 1-го числа (UTC): Master→Platinum 1, Diamond→Gold 1, Platinum→Silver 1, Gold→Bronze 1.
- [ ] **P1** Награды за ранг (Gold, пыль, Master — рубашка + титул).
- [ ] **P1** Бонусные звёзды при высоком MMR.
- [ ] **P1** Грейды аккаунта 0–5, XP аккаунта, награды (Gold, пыль, слоты колод, косметика, доступ к режимам).
- [ ] **P1** Достижения: категории, разовые/прогрессивные/скрытые, условия — данными, а не кодом.
- [ ] **P2** Сезонные лидерборды с античитом (ручная проверка топ-100).
### Блок 19. Турниры `[v1]`
- [ ] **P0** Турнирный движок: создание, регистрация, фиксация колод, Swiss-пары, Top Cut, тай-брейкеры (OMW%, GW% и т. п.).
- [ ] **P0** Таймер раунда 35 мин — **на сервере**; при истечении Double Loss; синхронизация часов клиента.
- [ ] **P0** Снимок колоды при регистрации (immutable), защита карт от разбора до конца турнира.
- [ ] **P0** Автоматический репорт результата, ручной репорт с подтверждением соперником, разрешение конфликтов админом.
- [ ] **P0** 3×3: капитаны видят **кланы** колод соперников, выбирают порядок скрыто (commit-reveal или одновременная блокировка выбора).
- [ ] **P0** 3×3: счёт по парам 2:1/3:0, техническое поражение только в конкретной паре, а не всей команде.
- [ ] **P1** История: архив всех турниров, публикация снимков колод после завершения, архив меты.
- [ ] **P1** «Эра как модификатор пула» — отдельный флаг турнира поверх формата.
- [ ] **P1** Промо-события: турниры к сету, награды по местам, «Неделя клана», «Двойной опыт», «Легендарный Draft», «Ретро-турнир» — как конфигурируемые модификаторы.
- [ ] **P2** Наблюдение за турниром (spectator), стрим-оверлей.
### Блок 20. Социалка и присутствие `[v1]`
- [ ] **P0** SignalR-хаб: аутентификация, presence (Redis `online:{userId}` с TTL), подписка на каналы.
- [ ] **P0** Друзья: заявки, принятие, удаление, чёрный список, онлайн-статус.
- [ ] **P0** Чат: общий, командный, личный; история в БД (удалённые сообщения **не удаляются физически**).
- [ ] **P0** Модерация чата: мут (15 мин / 1 ч / 24 ч / 7 дней / навсегда), удаление сообщения, лог.
- [ ] **P1** Эмоции: ID вместо текста, кулдаун, глобальный мьют в настройках; отправка своих не блокируется.
- [ ] **P1** Приглашение в матч из чата/списка друзей.
- [ ] **P1** Rate limiting и антиспам (флуд, капс, ссылки).
- [ ] **P2** Фидбек-вкладка: отзывы о мете и предложения, маршрутизация в тикеты.
### Блок 21. Команды и территории `[v1]`
- [ ] **P0** Команда: полное название, тег 2–5 символов (уникальный), иконка; префикс `[TAG]` в нике везде (чат, матч, профиль, лидерборд).
- [ ] **P0** Типы: открытая (заявки) / закрытая (приглашения); роли Leader/Officer(1–3)/Member; матрица прав.
- [ ] **P0** Передача лидерства только офицеру, кулдаун 30 дней от последней передачи.
- [ ] **P0** Лимит участников по уровню команды (1–10), XP команды.
- [ ] **P1** Территории: 6 регионов, точки (столица/ключевая/аутпост), очки контроля за командные победы.
- [ ] **P1** Недельный цикл: расчёт владельца, награды (Gold, пыль, командный XP, рейтинг), лимит 3 территории, убывающая отдача.
- [ ] **P1** Планировщик (Hangfire/Quartz): недельный и месячный джобы, идемпотентные, с восстановлением после падения.
- [ ] **P1** Командный лидерборд.
- [ ] **P2** Визуальная карта наций в клиенте.
### Блок 22. Профиль, косметика, обучение `[v1]`
- [ ] **P0** Профиль: ник + префикс, аватар, рамка, титул; статистика по режимам, любимый клан, рейтинг, история турниров, достижения, публичные колоды.
- [ ] **P0** Приватность: скрыть статистику/историю/достижения/колоды (проверка на сервере, а не в UI).
- [ ] **P0** Косметика: типы (карт-бэки, аватары, рамки, эмоции, эффекты поля, титулы, музыка/звуки), источники, инвентарь, экипировка.
- [ ] **P0** Косметика **не влияет на геймплей** — зафиксировать тестом (никаких статов из косметики).
- [ ] **P1** Обучение: `TutorialGameManager` + `TutorialStep` (SO) поверх реального движка; шаги Ride → Call → Boost → Attack → Drive/Damage Check; «Пропустить».
- [ ] **P1** Экскурсия по клиенту: подсветка меню, коллекции, декбилдера, бустеров, заданий, баттлпасса, настроек, друзей; повторный запуск из настроек.
- [ ] **P1** Продвинутые туториалы по механикам — формат каждого пока не определён.
- [ ] **P2** Обучение старым эрам (LB, Legion, Stride, V, D).
### Блок 23. Модерация и админ-панель `[v1]`
- [ ] **P0** Роли: Admin (логи чата/матчей/транзакций/IP, баны, назначение модераторов, тикеты) / Moderator (только чат).
- [ ] **P0** Веб-админка: список пользователей, поиск, бан/разбан, мут, история действий.
- [ ] **P0** Тикеты: жалобы, апелляции, баг-репорты, пожелания; маршрутизация по типу, SLA, статусы.
- [ ] **P0** Просмотр логов: чат (включая удалённые), транзакции, матчи (+реплей), IP — **с аудитом доступа**.
- [ ] **P1** Управление контентом: бан-лист, лимиты карт, условные баны (`нельзя X если есть Y`), патчноуты.
- [ ] **P1** Выдача валюты/косметики вручную (компенсации) — с обязательным логом.
- [ ] **P1** Инструменты баланса: winrate по картам, популярность, статистика матчей, голосования.
- [ ] **P2** Автоматические детекторы абуза (слив матчей, win-trading, мультиаккаунт).
### Блок 24. Лаунчер и доставка клиента `[v1]`
- [ ] **P0** WPF-лаунчер: логин, проверка версии, прогресс загрузки, кнопка «Играть», новости, настройки (язык, папка).
- [ ] **P0** Манифест версий: `clientVersion → files{hash,size,url}`; дифф-патчи (Game Launcher Asset Store).
- [ ] **P0** CDN/S3 для патчей, подпись манифеста, проверка хешей после загрузки, откат при повреждении.
- [ ] **P1** Принудительное обновление при `minClientVersion`; сообщение «обновитесь».
- [ ] **P1** Самообновление лаунчера.
- [ ] **P1** Установщик (Inno Setup/MSIX), юзер-специфичная установка без прав админа.
- [ ] **P2** Каналы `stable`/`beta`, возможность откатить версию.
### Блок 25. Мобильная адаптация и производительность `[v1]`
- [ ] **P0** Canvas Scaler + Safe Area на всех экранах, проверка на вырезах и планшетах.
- [ ] **P0** Input System: тап, долгое нажатие, drag, свайп — одна схема, два набора привязок.
- [ ] **P0** ASTC-сжатие текстур, атласы UI, стриминг аудио, Addressables-группы по сценам.
- [ ] **P0** Target FPS: 30 (мобилка) / 60 (десктоп); Adaptive Performance.
- [ ] **P0** `OnApplicationPause` → пауза матча (с серверной валидацией, чтобы не абузили).
- [ ] **P1** Мониторинг connectivity, UI офлайн-состояния, повтор запросов.
- [ ] **P1** Бюджеты: draw calls, память, размер билда; профилирование на минимальном устройстве.
- [ ] **P1** Мобильная доставка контента через Addressables + CDN (вместо лаунчера).
- [ ] **P2** Настройки батареи/тепла (лимит FPS, качество эффектов).
### Блок 26. QA, релиз, эксплуатация `[v1]`
- [ ] **P0** Тест-план: юнит (правила), интеграционные (API), e2e (полный матч), нагрузочные (матчмейкинг).
- [ ] **P0** Набор «золотых матчей»: 50 реплеев, которые обязаны воспроизводиться после каждого изменения ядра.
- [ ] **P0** Тестовые аккаунты и «песочница» с бесконечной валютой для QA.
- [ ] **P1** Чеклист релиза: миграции применены, бэкап снят, версия клиента в манифесте, патчноут опубликован, алерты включены.
- [ ] **P1** Rollback-план: как откатить сервер и клиент (клиент — только вперёд, поэтому сервер обязан поддерживать N-1 версию клиента).
- [ ] **P1** Поддержка: шаблоны ответов, форма баг-репорта с логами, публичная страница статуса.
- [ ] **P1** Метрики продукта: DAU, retention D1/D7, среднее число матчей, конверсия в платные валюты (внутренние), длина очередей.
- [ ] **P1** Релизный цикл сета под темп 1–2 месяца: контент заморожен за 2 недели до релиза, плейтест, патчноут, архив меты, пересмотр бан-листа.
---
## 3. Открытые вопросы
### 3.1 Закрыто
1. ~~Сетевой стек~~ → TCP/WebSocket + MessagePack.
2. ~~Формат описания карт~~ → C#-скрипты + YAML.
3. ~~Серверный фреймворк~~ → Orleans.
4. ~~Платформа~~ → ПК-first.
5. ~~Сайд-дек~~ → убран, BO1.
6. ~~Объём MVP~~ → 94 карты: BT01 + TD01 + TD02.
7. ~~Декбилдер~~ → полный, в MVP.
8. ~~Онбординг~~ → туториал → триал-колода на выбор + 5 токенов.
9. ~~Арты~~ → официальные.
10. ~~Ride Deck / Persona Ride~~ → не нужны, базовая эра.
11. ~~Локализация~~ → EN + RU с первого дня.
12. ~~Листы TD01/TD02~~ → получены из вики, лежат в `content/cards-mvp.md`.
13. ~~Токены~~ → 1 токен = 1 бустер.
14. ~~Бан-лист~~ → банов в MVP нет.
15. ~~Параллельные арты~~ → отдельные принты, привязка к базовому номеру карты.
16. ~~Название формата~~ → **Classic**.
17. ~~Лимиты коллекции~~ → **нет**, 4 копии по имени — только правило декбилдера.
18. ~~Таймер хода~~ → 90 с на ход, банк 5 мин, авто-end по истечении.
19. ~~Gold за матч~~ → 30 / 15 / 20 (победа / поражение / ничья), правило **Gold = XP / 5**.
20. ~~Размер бустера~~ → **5 карт**, из них 1 гарантированно R или выше.
21. ~~Веса слота R+~~ → **R 70 / RR 22 / RRR 7 / SP 1**.
### 3.2 Блокирующие MVP
Открытых вопросов нет. Все решения по MVP зафиксированы в §0.0 и §0.0.1.
### 3.3 Контент и правила
18. Таксономия редкостей BT01: какие редкости там реально есть (C/R/RR/RRR/SP?) и как в неё вписываются S01–S12.
19. Источник `triggerType` для 94 карт: ручная разметка, OCR по иконкам или decklog.
20. Итоговый список механик MVP — после матрицы «карта → механика».
21. Нужны ли анимированные карты и эффекты в MVP (влияет на бюджет клиента).
### 3.4 Экономика
22. Сгорает ли пыль в конце сезона; есть ли лимит на токены.
23. Что ещё продавать за Gold, чтобы не было инфляции.
24. Гринд баттлпасса: 58 500 XP за 30 дней ≈ 10+ матчей в день. Оставляем?
### 3.5 Техника и эксплуатация
25. Таймзона сбросов (сезон/квесты/территории) — предлагаю UTC.
26. Хранение истории матчей и реплеев: как глубоко, что видно игроку.
27. Логи и аналитика: что логируем, срок хранения, PII.
28. Бэкапы: RPO/RTO, проверка восстановления.
29. Бюджет на сервер: VPS или облако? Это определяет потолок онлайна.
30. Что происходит после 30 с реконнекта и через N минут отсутствия.
31. Политика версий: сколько старых версий клиента поддерживаем.
### 3.6 Продукт
32. Юридический план на случай takedown (арты официальные — риск высокий).
33. Сторы: Google Play / App Store / только APK (после ПК-релиза).
34. Модерация фидбека: кто читает, есть ли голосование.
35. «Вес колоды» в матчмейкинге — оставляем или убираем.
36. Маркетинг: сайт, Discord, соцсети — кто и когда.