Ежедневные и еженедельные задания — повод вернуться
Каждая завершённая игра теперь двигает набор ежедневных и еженедельных заданий, начисляет XP в момент выполнения любого из них и питает новый еженедельный рейтинг.

Простыми словами
До сих пор единственным развитием в opolyx была разовая награда за победу в игре. Гнаться изо дня в день было не за чем. Задания это меняют: небольшой набор ежедневных и еженедельных целей, которые продвигаются каждый раз, когда вы завершаете игру, победив или проиграв.
Ничего забирать не нужно и нет кнопки, которую надо нажимать — в момент завершения игры сервер проверяет ваши задания, засчитывает выполненные и добавляет XP прямо к вашему уровню. Одновременно идут шесть заданий:
- Ежедневные — сыграйте 1 игру, сыграйте 3 игры, выиграйте 1 игру.
- Еженедельные — сыграйте 10 игр, выиграйте 3 игры, выиграйте 3 игры в Speed.
- Ежедневные задания сбрасываются каждый день; еженедельные — каждый понедельник.
| Задание | Частота | Цель | Награда |
|---|---|---|---|
| Сыграй игру | Ежедневно | 1 | +50 XP |
| Продолжай играть | Ежедневно | 3 | +120 XP |
| Выиграй игру | Ежедневно | 1 | +150 XP |
| Постоянство | Еженедельно | 10 игр | +300 XP |
| В ударе | Еженедельно | 3 победы | +400 XP |
| Демон скорости | Еженедельно | 3 победы в Speed | +400 XP |
Завершение игр также приносит очки еженедельного рейтинга, так что чем больше вы играете, тем выше поднимаетесь. Рейтинг сбрасывается каждую неделю, давая всем чистый шанс на вершину в утро понедельника.
Для тех, кому интересны детали
Схема для полноценной петли удержания уже существовала, но лежала без дела и не читалась — missions / user_missions (частота, цель, прогресс, xp_reward) и weekly_top (week_start, очки). Миграция 0031 подключила её к существующему пути награды за завершение, а не изобретала что-то новое.
При реальном завершении daemon проходит по каждому живому игроку и вызывает один RPC с ролью service-role. Он продвигает каждое задание, которое завершение выполняет в текущем цикле, начисляет XP при первом пересечении цели и добавляет к недельному счётчику очков:
-- grant_play_rewards(p_game, p_user, p_won): security definer, service-role only
-- daily cadence = current_date; weekly = date_trunc('week', now())
-- weekly_top.points += 20 (play) + (won ? 200 : 0) + mission_xp_earned
-- idempotent per (game_id, user_id) via the game_play_grants guard; bots skipped| Совпадение события | Продвигает | Очки |
|---|---|---|
| {"event":"play"} | Каждое завершение | +20 |
| {"event":"win"} | Только победы | +200 |
| {"event":"play","mode":"speed"} | Только игры в Speed | +20 |
Идемпотентность обеспечивает строка-страж на каждую пару (игра, пользователь), поэтому повторный commit никогда не платит дважды. При применении всплыла ловушка эскалации привилегий: привилегии Postgres по умолчанию дают EXECUTE на новые функции для anon/authenticated, а revoke … from public это не убирает. Функция награды SECURITY DEFINER, вызываемая любым авторизованным пользователем, — это ферма XP; исправлено через revoke … from public, anon, authenticated, чтобы вызывать её могли только {postgres, service_role}, как у award_game_winner.
Награды пока только в XP — монеты относятся к треку монетизации, которому сначала нужен сток трат. И панель на странице игры, и рейтинг читают прогресс текущего цикла на стороне клиента, а неделя привязана к той же границе понедельника, что использует Postgres, поэтому они никогда не расходятся.
