Любимая фракция перестала быть вычислением и стала полем профиля. Раньше она выводилась из истории как самая частая среди партий с ручным выбором; теперь игрок выбирает её сам в кастомизации профиля из полного справочника — все 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.
Словарь предложного падежа
Орках · Ультрамаринах · Эльдарах · Хаоситах · Имперской гвардии · Тау · Некронах · Тиранидах · Инквизиции · Сёстрах битвы · Друкхари · Адептус Механикус
## Что сделано
**Любимая фракция** перестала быть вычислением и стала полем профиля. Раньше она выводилась из истории как самая частая среди партий с ручным выбором; теперь игрок выбирает её сам в кастомизации профиля из полного справочника — все 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
Раньше «любимая» вычислялась как самая частая среди партий с ручным
выбором фракции. Теперь это поле профиля: 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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Что сделано
Любимая фракция перестала быть вычислением и стала полем профиля. Раньше она выводилась из истории как самая частая среди партий с ручным выбором; теперь игрок выбирает её сам в кастомизации профиля из полного справочника — все 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на месте; идемпотентна по образцу0009pytest— 69 passed (было 65). Два теста старой логики переписаны: их проверкиmain_factionсохранены и теперь описывают новую семантику, утверждения проmost_played_factionубраны. Добавлены тесты на установку и сброс любимой фракции, отказ на несуществующемfaction_id, сохранение фракции при правкеbio, а также словарь падежей с fallbacknpm run gen:api— схема пересобрана с живого бэкенда;most_played_factionиз контракта ушёлnpm run build(tsc --noEmit && vite build) — зелёныйОтклонения от плана
Нет, план выполнен как есть. Одна деталь всплыла по ходу:
favorite_faction_idпришлось добавить в два места роутера — и вbuild_me(ответGET /me, из которого форма берёт текущее значение), и вupdate_me(ответ на смену ника), иначе второй отдавал быnull.Словарь предложного падежа
Орках · Ультрамаринах · Эльдарах · Хаоситах · Имперской гвардии · Тау · Некронах · Тиранидах · Инквизиции · Сёстрах битвы · Друкхари · Адептус Механикус
Closes #17