# Подтверждение участия Для всех форматов игр за 24 часа до `start_at` сервер отправляет письмо капитану. Проверка запускается при старте сервера, затем раз в минуту. Отправка последовательная: большая рассылка занимает дополнительное время. Команды без email видны организатору, но письмо им отправить невозможно. ## Правила - `pending` — ожидает ответа; команда сохраняет право участвовать. - `confirmed` — подтверждено капитаном, первым ходом команды (`first_action`) или автоматически при регистрации менее чем за сутки. - `cancelled` — отменено; команда остаётся в истории организатора, но исключается из игры, ответов организатору, результатов, карты и PDF с QR-кодами. - Ровно за 24 часа автоматического подтверждения нет. - Ответ окончательный: повтор того же ответа успешен, противоположный отклоняется. - После планового начала или выхода игры из `draft` новые ответы не принимаются. - Перенос игры и повторный сбор подтверждений не поддерживаются. Правило поздней регистрации вычисляется в сервисе перед созданием команды для формы и ручного добавления. Существующие команды миграция не изменяет: они остаются в статусе `pending`. Даты без часового пояса в существующих `games.start_at` и `teams.created_at` считаются UTC. ## Запуск 1. Применить миграцию `20260915120000_add_team_participation.sql` через обычный `goose up`. 2. Обновить сервер и фронтенд вместе: фронтенд должен обслуживать `/participation`. 3. Проверить существующие SMTP-настройки, `APP_BASE_URL`, `PARTICIPATION_SECRET`. `GAME_TIMEZONE` задаёт часовой пояс письма, по умолчанию `Asia/Barnaul`. Рассылка запускается автоматически. Если `APP_BASE_URL`, `PARTICIPATION_SECRET` или часовой пояс некорректны, сервер пишет причину отключения рассылки в журнал. Не менять `PARTICIPATION_SECRET` между попытками отправки: HMAC-токен привязан к команде и этому секрету. В БД хранится только SHA-256 токена. Уже отправленные ссылки проверяются по сохранённому хешу. Токен передаётся в URL-фрагменте и теле API-запроса, не в query string. Не включать тела запросов `/api/participation/*` в access-логи. Неудачные попытки повторяются через пять минут автоматически, максимум восемь раз на команду. После восьмой неудачи новые попытки не запускаются; ошибка остаётся видна организатору. Пятиминутная аренда задания защищает от одновременной обработки серверами и восстанавливается после падения. Одна попытка ограничена минутой. Ошибки сохранения результата записываются в журнал. SMTP не обеспечивает ровно одну доставку: если письмо принято, а результат не сохранён, возможен дубль с той же ссылкой. `participation_sent_at` означает принятие письма SMTP, а не прочтение письма или гарантированное попадание во входящие. ## Проверка ```sh go test ./... TEST_DATABASE_URL='host=localhost port=5432 user=test dbname=test sslmode=disable' \ go test ./internal/repos/teams_repo ./internal/services/game_service -count=1 ``` Интеграционные тесты создают и удаляют собственные схемы. SMTP заменён тестовой реализацией; реальным капитанам тесты ничего не отправляют.