Missions quotidiennes et hebdomadaires — une raison de revenir
Chaque partie terminée fait désormais avancer un ensemble de missions quotidiennes et hebdomadaires, accorde de l’XP à l’instant où vous en accomplissez une, et alimente un nouveau classement hebdomadaire.

En clair
Jusqu’ici, la seule progression dans opolyx était une récompense unique pour avoir gagné une partie. Il n’y avait rien à poursuivre au jour le jour. Les missions changent cela : un petit ensemble d’objectifs quotidiens et hebdomadaires qui avancent chaque fois que vous terminez une partie, que vous gagniez ou perdiez.
Vous ne réclamez rien et il n’y a aucun bouton à presser — à l’instant où une partie se termine, le serveur vérifie vos missions, crédite celles que vous avez accomplies et ajoute l’XP directement à votre niveau. Six missions tournent à la fois :
- Quotidiennes — jouez 1 partie, jouez 3 parties, gagnez 1 partie.
- Hebdomadaires — jouez 10 parties, gagnez 3 parties, gagnez 3 parties en mode Rapide.
- Les missions quotidiennes se réinitialisent chaque jour ; les hebdomadaires, chaque lundi.
| Mission | Fréquence | Objectif | Récompense |
|---|---|---|---|
| Jouer une partie | Quotidienne | 1 | +50 XP |
| Continuer à jouer | Quotidienne | 3 | +120 XP |
| Gagner une partie | Quotidienne | 1 | +150 XP |
| Régulier | Hebdomadaire | 10 parties | +300 XP |
| En série | Hebdomadaire | 3 victoires | +400 XP |
| Démon de la vitesse | Hebdomadaire | 3 victoires en Rapide | +400 XP |
Terminer des parties rapporte aussi des points au classement hebdomadaire : plus vous jouez, plus vous montez. Le classement se réinitialise chaque semaine, offrant à chacun une chance nette d’atteindre le sommet le lundi matin.
Pour les curieux techniques
Le schéma d’une boucle de rétention complète existait déjà mais restait dormant et jamais lu — missions / user_missions (fréquence, objectif, progression, xp_reward) et weekly_top (week_start, points). La migration 0031 l’a branché sur le chemin de récompense de fin de partie existant plutôt que d’inventer quoi que ce soit de nouveau.
À une vraie fin de partie, le daemon parcourt chaque joueur humain et appelle un unique RPC en rôle de service. Il fait avancer chaque mission que la fin satisfait pour le cycle en cours, accorde l’XP la première fois qu’un objectif est franchi et ajoute au décompte de points hebdomadaire :
-- 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| Correspondance d’événement | Fait avancer | Points |
|---|---|---|
| {"event":"play"} | Chaque fin de partie | +20 |
| {"event":"win"} | Victoires seulement | +200 |
| {"event":"play","mode":"speed"} | Parties en Rapide seulement | +20 |
L’idempotence repose sur une ligne de garde par (partie, utilisateur), si bien qu’un commit rejoué ne paie jamais deux fois. Un piège d’élévation de privilèges est apparu au moment de l’application : les privilèges par défaut de Postgres accordent EXECUTE sur les nouvelles fonctions à anon/authenticated, et revoke … from public ne l’enlève pas. Une fonction de récompense SECURITY DEFINER appelable par tout utilisateur connecté est une ferme à XP — corrigé avec revoke … from public, anon, authenticated pour que seuls {postgres, service_role} puissent l’appeler, comme award_game_winner.
Les récompenses sont uniquement en XP pour l’instant — les pièces relèvent de la piste de monétisation, qui a d’abord besoin d’un puits de dépense. Le panneau de la page Jouer et le classement lisent tous deux la progression du cycle en cours côté client, la semaine étant ancrée à la même borne du lundi que celle de Postgres, si bien que les deux ne divergent jamais.
