Изменение логики любимых и основных фракций (#17) #20

Merged
NotBigGhost merged 2 commits from issue-17-faction-favorite-and-most-played into dev 2026-09-07 19:03:06 +03:00
Collaborator

Что сделано

Любимая фракция перестала быть вычислением и стала полем профиля. Раньше она выводилась из истории как самая частая среди партий с ручным выбором; теперь игрок выбирает её сам в кастомизации профиля из полного справочника — все 12 фракций, независимо от дополнений активной группы, потому что это свойство игрока, а не группы. В БД — users.favorite_faction_id (FK на factions, ON DELETE SET NULL, миграция 0010), в API — необязательное поле PATCH /api/users/me/profile.

Основная фракция переименована в «Чаще всего играет на». Её логику менять не пришлось: в stats_service она и так считалась как самая игранная по всем партиям, включая рандомные раздачи, — ровно то, что просит ТЗ. Добавился только предложный падеж: FactionStat.name_ru_prepositional заполняется из словаря в faction_service. Словарь держим в коде, а не колонкой в БД — набор фракций задан игрой и не меняется; фракция, заведённая админом мимо словаря, выводится в именительном и ничего не ломает.

Отдельно стоит отметить правку, без которой фича была бы с багом: update_my_profile всегда писал bio, а фронт правит «о себе» и фракцию разными запросами. Роутер переведён на model_dump(exclude_unset=True) и обновляет только реально пришедшие поля — иначе сохранение одного «о себе» обнуляло бы выбранную фракцию. На это есть отдельный тест.

Публичный профиль правок не потребовал: он использует ту же карточку и ту же схему ProfileStats. Служебное поле chosen_games существовало только ради старой «любимой» и убрано из SQL вместе с ней.

Коммиты

  • 60b22dd Профиль: любимая фракция — выбор игрока, а не вывод из статистики
  • befabba Профиль: выбор любимой фракции и строка «Чаще всего играет на»

Проверки

  • alembic upgrade head — миграция накатилась на dev-базу, столбец favorite_faction_id на месте; идемпотентна по образцу 0009
  • pytest — 69 passed (было 65). Два теста старой логики переписаны: их проверки main_faction сохранены и теперь описывают новую семантику, утверждения про most_played_faction убраны. Добавлены тесты на установку и сброс любимой фракции, отказ на несуществующем faction_id, сохранение фракции при правке bio, а также словарь падежей с fallback
  • npm run gen:api — схема пересобрана с живого бэкенда; most_played_faction из контракта ушёл
  • npm run build (tsc --noEmit && vite build) — зелёный
  • Визуальная проверка на dev-стенде — не выполнена: стенд остановлен, расширение Claude in Chrome к сессии не подключено

Отклонения от плана

Нет, план выполнен как есть. Одна деталь всплыла по ходу: favorite_faction_id пришлось добавить в два места роутера — и в build_me (ответ GET /me, из которого форма берёт текущее значение), и в update_me (ответ на смену ника), иначе второй отдавал бы null.

Словарь предложного падежа

Орках · Ультрамаринах · Эльдарах · Хаоситах · Имперской гвардии · Тау · Некронах · Тиранидах · Инквизиции · Сёстрах битвы · Друкхари · Адептус Механикус

Closes #17

## Что сделано **Любимая фракция** перестала быть вычислением и стала полем профиля. Раньше она выводилась из истории как самая частая среди партий с ручным выбором; теперь игрок выбирает её сам в кастомизации профиля из полного справочника — все 12 фракций, независимо от дополнений активной группы, потому что это свойство игрока, а не группы. В БД — `users.favorite_faction_id` (FK на `factions`, `ON DELETE SET NULL`, миграция `0010`), в API — необязательное поле `PATCH /api/users/me/profile`. **Основная фракция** переименована в **«Чаще всего играет на»**. Её логику менять не пришлось: в `stats_service` она и так считалась как самая игранная по всем партиям, включая рандомные раздачи, — ровно то, что просит ТЗ. Добавился только предложный падеж: `FactionStat.name_ru_prepositional` заполняется из словаря в `faction_service`. Словарь держим в коде, а не колонкой в БД — набор фракций задан игрой и не меняется; фракция, заведённая админом мимо словаря, выводится в именительном и ничего не ломает. Отдельно стоит отметить правку, без которой фича была бы с багом: `update_my_profile` всегда писал `bio`, а фронт правит «о себе» и фракцию разными запросами. Роутер переведён на `model_dump(exclude_unset=True)` и обновляет только реально пришедшие поля — иначе сохранение одного «о себе» обнуляло бы выбранную фракцию. На это есть отдельный тест. Публичный профиль правок не потребовал: он использует ту же карточку и ту же схему `ProfileStats`. Служебное поле `chosen_games` существовало только ради старой «любимой» и убрано из SQL вместе с ней. ## Коммиты - `60b22dd` Профиль: любимая фракция — выбор игрока, а не вывод из статистики - `befabba` Профиль: выбор любимой фракции и строка «Чаще всего играет на» ## Проверки - `alembic upgrade head` — миграция накатилась на dev-базу, столбец `favorite_faction_id` на месте; идемпотентна по образцу `0009` - `pytest` — **69 passed** (было 65). Два теста старой логики переписаны: их проверки `main_faction` сохранены и теперь описывают новую семантику, утверждения про `most_played_faction` убраны. Добавлены тесты на установку и сброс любимой фракции, отказ на несуществующем `faction_id`, сохранение фракции при правке `bio`, а также словарь падежей с fallback - `npm run gen:api` — схема пересобрана с живого бэкенда; `most_played_faction` из контракта ушёл - `npm run build` (`tsc --noEmit && vite build`) — зелёный - Визуальная проверка на dev-стенде — **не выполнена**: стенд остановлен, расширение Claude in Chrome к сессии не подключено ## Отклонения от плана Нет, план выполнен как есть. Одна деталь всплыла по ходу: `favorite_faction_id` пришлось добавить в два места роутера — и в `build_me` (ответ `GET /me`, из которого форма берёт текущее значение), и в `update_me` (ответ на смену ника), иначе второй отдавал бы `null`. ## Словарь предложного падежа Орках · Ультрамаринах · Эльдарах · Хаоситах · Имперской гвардии · Тау · Некронах · Тиранидах · Инквизиции · Сёстрах битвы · Друкхари · Адептус Механикус Closes #17
Agent added 2 commits 2026-09-07 16:18:22 +03:00
Раньше «любимая» вычислялась как самая частая среди партий с ручным
выбором фракции. Теперь это поле профиля: users.favorite_faction_id
(FK на factions, ON DELETE SET NULL, миграция 0010) и необязательное
поле в PATCH /api/users/me/profile.

Роутер профиля переведён на model_dump(exclude_unset=True) и обновляет
только пришедшие поля — иначе сохранение одного «о себе» обнуляло бы
выбранную фракцию.

«Основная фракция» логику не меняет (она и так считалась по всем партиям,
включая рандомные раздачи) и переезжает в подпись «Чаще всего играет на»:
FactionStat получает name_ru_prepositional из словаря предложного падежа
в faction_service. Словарь в коде, а не в БД: набор фракций задан игрой;
фракция вне словаря выводится в именительном.

Служебное chosen_games существовало только ради старой «любимой» — убрано
из SQL вместе с ней.

#17

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps52xzuUXnWrJ5SRnEeaLk
В кастомизации профиля появился выбор любимой фракции из полного
справочника (PickerSelect, все 12 фракций): фракция — свойство игрока,
а не группы, поэтому список не зависит от подключённых дополнений.
Дополнение показано в строке опции приглушённым текстом, снятие выбора —
кнопкой «Убрать».

В карточке статистики «Любимая фракция» теперь берётся из профиля, а
«Основная фракция» переименована в «Чаще всего играет на» и печатает
название в предложном падеже. Публичный профиль правок не потребовал —
он использует ту же карточку и ту же схему.

schema.d.ts пересобран с живого бэкенда (npm run gen:api).

#17

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps52xzuUXnWrJ5SRnEeaLk
NotBigGhost merged commit 45f2b2007f into dev 2026-09-07 19:03:06 +03:00
NotBigGhost deleted branch issue-17-faction-favorite-and-most-played 2026-09-07 19:03:06 +03:00
Sign in to join this conversation.