622 lines
84 KiB
Markdown
622 lines
84 KiB
Markdown
# 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, соцсети — кто и когда.
|