Missões diárias e semanais — um motivo para voltar
Agora cada partida terminada faz avançar um conjunto de missões diárias e semanais, concede XP no instante em que você completa uma e alimenta um novo ranking semanal.

Em palavras simples
Até agora, a única progressão em opolyx era uma recompensa única por vencer uma partida. Não havia nada para perseguir no dia a dia. As missões mudam isso: um pequeno conjunto de objetivos diários e semanais que avançam toda vez que você termina uma partida, vencendo ou perdendo.
Você não resgata nada e não há botão para apertar — no instante em que uma partida termina, o servidor confere suas missões, credita as que você completou e soma o XP direto ao seu nível. Seis missões rodam ao mesmo tempo:
- Diárias — jogue 1 partida, jogue 3 partidas, vença 1 partida.
- Semanais — jogue 10 partidas, vença 3 partidas, vença 3 partidas no modo Rápido.
- As missões diárias reiniciam todo dia; as semanais reiniciam toda segunda-feira.
| Missão | Frequência | Meta | Recompensa |
|---|---|---|---|
| Jogue uma partida | Diária | 1 | +50 XP |
| Continue jogando | Diária | 3 | +120 XP |
| Vença uma partida | Diária | 1 | +150 XP |
| Regular | Semanal | 10 partidas | +300 XP |
| Numa sequência | Semanal | 3 vitórias | +400 XP |
| Demônio da velocidade | Semanal | 3 vitórias no Rápido | +400 XP |
Terminar partidas também rende pontos no ranking semanal, então quanto mais você joga, mais alto sobe. O ranking reinicia toda semana, dando a todos uma chance limpa de chegar ao topo na manhã de segunda.
Para os mais técnicos
O esquema para um ciclo de retenção completo já existia, mas estava adormecido e nunca lido — missions / user_missions (frequência, meta, progresso, xp_reward) e weekly_top (week_start, pontos). A migração 0031 o ligou ao caminho de recompensa de fim de partida já existente, em vez de inventar algo novo.
Num fim de partida real, o daemon percorre cada jogador humano e chama um único RPC com papel de serviço. Ele avança cada missão que o fim satisfaz no ciclo atual, concede o XP na primeira vez que uma meta é cruzada e soma à contagem de pontos semanal:
-- 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| Correspondência de evento | Avança | Pontos |
|---|---|---|
| {"event":"play"} | Cada partida terminada | +20 |
| {"event":"win"} | Somente vitórias | +200 |
| {"event":"play","mode":"speed"} | Somente partidas no Rápido | +20 |
A idempotência é uma linha de guarda por (partida, usuário), então um commit repetido nunca paga duas vezes. Uma armadilha de escalonamento de privilégios apareceu na hora de aplicar: os privilégios padrão do Postgres concedem EXECUTE nas novas funções a anon/authenticated, e revoke … from public não remove isso. Uma função de recompensa SECURITY DEFINER chamável por qualquer usuário logado é uma fazenda de XP — corrigido com revoke … from public, anon, authenticated para que apenas {postgres, service_role} possa chamá-la, igual a award_game_winner.
As recompensas são só de XP por enquanto — as moedas pertencem à trilha de monetização, que precisa antes de um ralo de gasto. Tanto o painel da página Jogar quanto o Ranking leem o progresso do ciclo atual no cliente, com a semana ancorada ao mesmo limite de segunda-feira que o Postgres usa, para que os dois nunca discordem.
