В профиле появился список партий, которого там не было вовсе. Выборки партий по игроку в бэкенде тоже не существовало — только по группе, поэтому добавлен stats_service.user_match_list: завершённые партии игрока, свежие сверху. Сборку элементов списка вынес из group_match_list в общий _match_items и переиспользовал в обеих функциях, чтобы не держать её в двух копиях.
Витрину профиля задают две колонки в users (миграция 0011): history_mode (all / best) и history_detail (compact / full). Режим применяется на бэкенде, а не на клиенте — это витрина владельца, и в том же виде профиль видят гости. GET /api/users/{user_id}/matches отдаёт список вместе с mode и detail, так что гостю хватает одного запроса, чтобы отрисовать историю как задумал владелец.
На фронте — блок «История игр» с двумя тумблерами в «Аккаунте» и новый компонент MatchHistory: подробный режим переиспользует MatchListView (тот же список, что у группы, со всеми участниками), компактный рисует строку с результатом самого игрока — место, фракция, дата, длительность. Публичный профиль показывает ту же историю без контролов: страница намеренно read-only.
Уточнения ТЗ
В задаче не было критериев готовности, поэтому они были согласованы отдельно и зафиксированы планом в комментарии к #1: настройки хранятся в БД, «подробность» — это два режима карточки, «лучшая партия» выбирается по League Points, история видна и гостям.
Одна деталь всплыла при написании тестов и стоит упоминания: первое место даёт 1.0 очка независимо от размера стола, так что «победа на четверых весомее победы на двоих» — неверно. Разница возникает на непризовых местах: второе из четырёх — это (4-2)/3 ≈ 0.67, второе из двух — (2-2)/1 = 0. Тест на режим best построен именно на этом и проверяет, что берётся партия с лучшими очками, а не самая свежая.
Коммиты
be80891 Профиль: история партий игрока и настройки её витрины
9dda7de Профиль: блок истории игр с переключателями режима и подробности
pytest — 74 passed (было 69). Добавлено пять тестов: в историю идут только завершённые партии игрока; чужая партия внутри его же группы не попадает; режим best берёт партию с максимальными очками, а не свежую; настройки сохраняются, мусорное значение отклоняется и не сбивает сохранённое; гость видит историю в режиме владельца
npm run gen:api + npm run build (tsc --noEmit && vite build) — зелёные
Визуальная проверка на dev-стенде — не выполнена: расширение Claude in Chrome к сессии не подключено
Отклонения от плана
Нет, план выполнен как есть.
Осознанно не сделано
Отдельного выключателя «скрыть историю целиком» задача не просит — режимы ограничены all / best. Если понадобится, это третье значение history_mode, а не новая колонка.
## Что сделано
В профиле появился список партий, которого там не было вовсе. Выборки партий по игроку в бэкенде тоже не существовало — только по группе, поэтому добавлен `stats_service.user_match_list`: завершённые партии игрока, свежие сверху. Сборку элементов списка вынес из `group_match_list` в общий `_match_items` и переиспользовал в обеих функциях, чтобы не держать её в двух копиях.
Витрину профиля задают две колонки в `users` (миграция `0011`): `history_mode` (`all` / `best`) и `history_detail` (`compact` / `full`). Режим применяется **на бэкенде, а не на клиенте** — это витрина владельца, и в том же виде профиль видят гости. `GET /api/users/{user_id}/matches` отдаёт список вместе с `mode` и `detail`, так что гостю хватает одного запроса, чтобы отрисовать историю как задумал владелец.
На фронте — блок «История игр» с двумя тумблерами в «Аккаунте» и новый компонент `MatchHistory`: подробный режим переиспользует `MatchListView` (тот же список, что у группы, со всеми участниками), компактный рисует строку с результатом самого игрока — место, фракция, дата, длительность. Публичный профиль показывает ту же историю без контролов: страница намеренно read-only.
## Уточнения ТЗ
В задаче не было критериев готовности, поэтому они были согласованы отдельно и зафиксированы планом в комментарии к #1: настройки хранятся в БД, «подробность» — это два режима карточки, «лучшая партия» выбирается по League Points, история видна и гостям.
Одна деталь всплыла при написании тестов и стоит упоминания: **первое место даёт 1.0 очка независимо от размера стола**, так что «победа на четверых весомее победы на двоих» — неверно. Разница возникает на непризовых местах: второе из четырёх — это `(4-2)/3 ≈ 0.67`, второе из двух — `(2-2)/1 = 0`. Тест на режим `best` построен именно на этом и проверяет, что берётся партия с лучшими очками, а не самая свежая.
## Коммиты
- `be80891` Профиль: история партий игрока и настройки её витрины
- `9dda7de` Профиль: блок истории игр с переключателями режима и подробности
## Проверки
- `alembic upgrade head` — `0011` накатилась поверх `0010`, цепочка миграций линейна
- `pytest` — **74 passed** (было 69). Добавлено пять тестов: в историю идут только завершённые партии игрока; чужая партия внутри его же группы не попадает; режим `best` берёт партию с максимальными очками, а не свежую; настройки сохраняются, мусорное значение отклоняется и не сбивает сохранённое; гость видит историю в режиме владельца
- `npm run gen:api` + `npm run build` (`tsc --noEmit && vite build`) — зелёные
- Визуальная проверка на dev-стенде — **не выполнена**: расширение Claude in Chrome к сессии не подключено
## Отклонения от плана
Нет, план выполнен как есть.
## Осознанно не сделано
Отдельного выключателя «скрыть историю целиком» задача не просит — режимы ограничены `all` / `best`. Если понадобится, это третье значение `history_mode`, а не новая колонка.
Closes #1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Выборки партий по игроку в бэкенде не было — только по группе. Добавлен
stats_service.user_match_list: завершённые партии игрока, свежие сверху;
сборка элементов вынесена из group_match_list в общий _match_items, чтобы
не дублировать её в двух местах.
Витрина профиля задаётся двумя колонками в users (миграция 0011):
history_mode (all/best) и history_detail (compact/full). Режим применяется
на бэкенде, а не на клиенте: это витрина владельца, и в том же виде
профиль видят гости. В режиме best берётся партия с максимальными League
Points из SCORED_CTE (при равных очках — более свежая).
GET /api/users/{user_id}/matches отдаёт список вместе с mode и detail —
гостю хватает одного запроса, чтобы отрисовать историю как задумал владелец.
#1
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
В «Аккаунте» появился блок «История игр» с двумя тумблерами — «Только
лучшая партия» и «Подробные карточки»; выбор уходит в профиль, поэтому
переживает перезаход и другое устройство.
Новый компонент MatchHistory: подробный режим переиспользует список партий
группы (MatchListView со всеми участниками), компактный рисует строку с
результатом самого игрока — место, фракция, дата и длительность.
Публичный профиль показывает ту же историю в режиме владельца и без
контролов: страница намеренно read-only.
schema.d.ts пересобран с живого бэкенда (npm run gen:api).
#1
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Что сделано
В профиле появился список партий, которого там не было вовсе. Выборки партий по игроку в бэкенде тоже не существовало — только по группе, поэтому добавлен
stats_service.user_match_list: завершённые партии игрока, свежие сверху. Сборку элементов списка вынес изgroup_match_listв общий_match_itemsи переиспользовал в обеих функциях, чтобы не держать её в двух копиях.Витрину профиля задают две колонки в
users(миграция0011):history_mode(all/best) иhistory_detail(compact/full). Режим применяется на бэкенде, а не на клиенте — это витрина владельца, и в том же виде профиль видят гости.GET /api/users/{user_id}/matchesотдаёт список вместе сmodeиdetail, так что гостю хватает одного запроса, чтобы отрисовать историю как задумал владелец.На фронте — блок «История игр» с двумя тумблерами в «Аккаунте» и новый компонент
MatchHistory: подробный режим переиспользуетMatchListView(тот же список, что у группы, со всеми участниками), компактный рисует строку с результатом самого игрока — место, фракция, дата, длительность. Публичный профиль показывает ту же историю без контролов: страница намеренно read-only.Уточнения ТЗ
В задаче не было критериев готовности, поэтому они были согласованы отдельно и зафиксированы планом в комментарии к #1: настройки хранятся в БД, «подробность» — это два режима карточки, «лучшая партия» выбирается по League Points, история видна и гостям.
Одна деталь всплыла при написании тестов и стоит упоминания: первое место даёт 1.0 очка независимо от размера стола, так что «победа на четверых весомее победы на двоих» — неверно. Разница возникает на непризовых местах: второе из четырёх — это
(4-2)/3 ≈ 0.67, второе из двух —(2-2)/1 = 0. Тест на режимbestпостроен именно на этом и проверяет, что берётся партия с лучшими очками, а не самая свежая.Коммиты
be80891Профиль: история партий игрока и настройки её витрины9dda7deПрофиль: блок истории игр с переключателями режима и подробностиПроверки
alembic upgrade head—0011накатилась поверх0010, цепочка миграций линейнаpytest— 74 passed (было 69). Добавлено пять тестов: в историю идут только завершённые партии игрока; чужая партия внутри его же группы не попадает; режимbestберёт партию с максимальными очками, а не свежую; настройки сохраняются, мусорное значение отклоняется и не сбивает сохранённое; гость видит историю в режиме владельцаnpm run gen:api+npm run build(tsc --noEmit && vite build) — зелёныеОтклонения от плана
Нет, план выполнен как есть.
Осознанно не сделано
Отдельного выключателя «скрыть историю целиком» задача не просит — режимы ограничены
all/best. Если понадобится, это третье значениеhistory_mode, а не новая колонка.Closes #1
🤖 Generated with Claude Code
Выборки партий по игроку в бэкенде не было — только по группе. Добавлен stats_service.user_match_list: завершённые партии игрока, свежие сверху; сборка элементов вынесена из group_match_list в общий _match_items, чтобы не дублировать её в двух местах. Витрина профиля задаётся двумя колонками в users (миграция 0011): history_mode (all/best) и history_detail (compact/full). Режим применяется на бэкенде, а не на клиенте: это витрина владельца, и в том же виде профиль видят гости. В режиме best берётся партия с максимальными League Points из SCORED_CTE (при равных очках — более свежая). GET /api/users/{user_id}/matches отдаёт список вместе с mode и detail — гостю хватает одного запроса, чтобы отрисовать историю как задумал владелец. #1 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>