All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 1m2s
- Frontend: PKCE flow (oauth.ts, AuthCallback code exchange, 401 interceptor) - Backend: token introspection via SuperOAuth (no more JWT secret) - User model: superOauthId (unified) replaces oauthId+provider - Cookies httpOnly session + refresh token - POST /auth/refresh endpoint - Gitea CI workflow (vps-runner pattern) - DB_SYNC env var for initial schema creation
11 KiB
11 KiB
TetaRdPG — Brief Sprint 4
Statut : ⬜ À lancer Objectif : Succès individuels + Succès communautaires + Hall of Fame + Profil joueur enrichi Stack : NestJS · MySQL · TypeORM Prérequis : Sprint 3 livré ✅ (items, forge, craft, economy, twitch) Source design :
TetaRdPG/Sprint 4 _ Focus Succès & Hall of Fame.docx+Annexes/5. Système de succès.docx
Scope Sprint 4
✅ In scope
- Entité
achievements— catalogue de succès avec critères de déblocage - Entité
player_achievements— suivi progression par joueur - 5 catégories : Progression, Combat, Zones, Équipements, Économie
- Récompenses au déblocage : Or, XP bonus, titres honorifiques
- Entité
community_goals— objectifs collectifs (monstres tués, TetardCoin cumulés) - Barre de progression communautaire
- Récompenses communautaires : boosts globaux temporaires (XP/loot)
- Hall of Fame mensuel — classement contributeurs + badges
- Interface profil enrichi : badges, titres, % progression succès
- Seeds : 15 succès individuels + 3 objectifs communautaires
- API : voir section dédiée
❌ Out of scope
- Notifications Twitch temps réel (extension Twitch) — Sprint 5
- GIGABOSS communautaire (événement 72h) — Sprint événements
- Marché communautaire (échange joueurs) — Sprint économie avancée
- Guildes et alliances — Sprint social
- Boutique événementielle — Sprint économie avancée
- Frontend React complet
Décisions de design (game-designer)
| Décision | Valeur | Justification |
|---|---|---|
| Tracking succès | Event-driven : chaque action (combat, craft, forge, level) émet un check | Pas de cron — cohérent avec le pattern lazy du projet |
| Catégories succès | 5 : progression, combat, zones, equipment, economy | GDD §5.1 |
| Paliers succès | 3 niveaux par succès (bronze/silver/gold) | Engagement long terme |
| Récompenses déblocage | Or + titre. Pas d'item pour éviter la complexité inventaire Sprint 4 | Simplification — items récompense = Sprint 5 |
| Titres joueur | 1 titre actif à la fois, affiché sur le profil | GDD §4 titres liés aux zones |
| Community goals | Reset mensuel, contribution individuelle trackée | GDD §5.2 |
| Hall of Fame | Classement mensuel, top 10, badges persistants | GDD §5.3 |
| Boost communautaire | Stocké en DB, appliqué comme multiplicateur dans combat/craft | Ex: +20% XP pendant 3j |
| Progression communautaire | Compteur global incrémenté à chaque action qualifiante | Pas de WebSocket — poll GET |
Schéma DB
achievements
id uuid PK
key varchar(50) UNIQUE -- 'combat_100', 'level_50', 'zone_marais_complete'
name varchar(100)
description text
category varchar(20) -- 'progression' | 'combat' | 'zones' | 'equipment' | 'economy'
tier varchar(10) -- 'bronze' | 'silver' | 'gold'
criteria_type varchar(30) -- 'combat_wins' | 'level_reached' | 'gold_accumulated' | ...
criteria_value int -- seuil à atteindre
reward_gold int default 0
reward_title varchar(100) NULL -- titre débloqué (nullable)
player_achievements
id uuid PK
character_id uuid FK characters
achievement_id uuid FK achievements
progress int default 0 -- compteur courant
unlocked boolean default false
unlocked_at timestamp NULL
community_goals
id uuid PK
name varchar(100)
description text
criteria_type varchar(30) -- 'total_monsters_killed' | 'total_tetardcoin' | ...
target_value bigint -- objectif collectif
current_value bigint default 0
reward_type varchar(30) -- 'xp_boost' | 'loot_boost'
reward_multiplier decimal(3,2) -- ex: 1.20 = +20%
reward_duration_hours int -- durée du boost
period_start date
period_end date
completed boolean default false
completed_at timestamp NULL
community_contributions
id uuid PK
community_goal_id uuid FK community_goals
character_id uuid FK characters
contribution_value bigint default 0
hall_of_fame
id uuid PK
character_id uuid FK characters
period varchar(7) -- '2026-04' format YYYY-MM
rank int
contribution_total bigint
badge varchar(50) -- 'top1_april_2026'
active_boosts (communautaires)
id uuid PK
boost_type varchar(30) -- 'xp_boost' | 'loot_boost'
multiplier decimal(3,2)
expires_at timestamp
source_goal_id uuid FK community_goals
Seeds
Succès individuels (15)
| Key | Nom | Catégorie | Tier | Critère | Seuil | Récompense Or | Titre |
|---|---|---|---|---|---|---|---|
combat_10 |
Apprenti Guerrier | combat | bronze | combat_wins | 10 | 50 | — |
combat_100 |
Guerrier Aguerri | combat | silver | combat_wins | 100 | 200 | Guerrier Aguerri |
combat_1000 |
Légende du Combat | combat | gold | combat_wins | 1000 | 1000 | Légende |
level_10 |
Aventurier | progression | bronze | level_reached | 10 | 100 | — |
level_50 |
Héros | progression | silver | level_reached | 50 | 500 | Héros |
level_100 |
Légende Vivante | progression | gold | level_reached | 100 | 2000 | Légende Vivante |
gold_1000 |
Marchand | economy | bronze | gold_accumulated | 1000 | 100 | — |
gold_10000 |
Négociant | economy | silver | gold_accumulated | 10000 | 500 | Négociant |
gold_100000 |
Magnat | economy | gold | gold_accumulated | 100000 | 2000 | Magnat |
forge_5 |
Apprenti Forgeron | equipment | bronze | forge_upgrades | 5 | 100 | — |
forge_25 |
Maître Forgeron | equipment | silver | forge_upgrades | 25 | 500 | Maître Forgeron |
forge_100 |
Forgeron Légendaire | equipment | gold | forge_upgrades | 100 | 2000 | Forgeron Légendaire |
craft_5 |
Artisan Novice | equipment | bronze | craft_completed | 5 | 75 | — |
craft_25 |
Artisan Confirmé | equipment | silver | craft_completed | 25 | 300 | Artisan |
craft_100 |
Grand Artisan | equipment | gold | craft_completed | 100 | 1500 | Grand Artisan |
Objectifs communautaires (3)
| Nom | Critère | Cible | Boost | Durée |
|---|---|---|---|---|
| Chasse aux Monstres | total_monsters_killed | 10 000 | +20% XP | 72h |
| Trésor Communautaire | total_gold_earned | 1 000 000 | +15% loot | 48h |
| Fièvre de la Forge | total_forge_upgrades | 500 | +10% XP | 48h |
API Sprint 4
# Succès individuels
GET /api/achievements → catalogue complet des succès
GET /api/achievements/me → progression du joueur (avec %)
POST /api/achievements/claim/:id → réclamer la récompense d'un succès débloqué
# Succès communautaires
GET /api/community/goals → objectifs en cours + barre progression
GET /api/community/goals/:id/top → top 10 contributeurs d'un objectif
GET /api/community/boosts → boosts actifs (multiplicateurs en cours)
# Hall of Fame
GET /api/halloffame/current → classement du mois en cours
GET /api/halloffame/:period → classement historique (ex: 2026-04)
# Profil enrichi
GET /api/profile/me → stats + titre actif + badges + succès count
PUT /api/profile/title → { title: "Héros" } → changer titre actif
Architecture modules
src/
├── achievement/
│ ├── achievement.entity.ts
│ ├── player-achievement.entity.ts
│ ├── achievement.module.ts
│ ├── achievement.service.ts → check + unlock logic
│ ├── achievement.controller.ts
│ └── achievement.listener.ts → écoute events combat/craft/forge/levelup
├── community/
│ ├── community-goal.entity.ts
│ ├── community-contribution.entity.ts
│ ├── active-boost.entity.ts
│ ├── community.module.ts
│ ├── community.service.ts
│ └── community.controller.ts
├── halloffame/
│ ├── hall-of-fame.entity.ts
│ ├── halloffame.module.ts
│ ├── halloffame.service.ts → calcul mensuel + badge attribution
│ └── halloffame.controller.ts
├── profile/
│ ├── profile.module.ts
│ ├── profile.service.ts
│ └── profile.controller.ts
└── database/
├── achievements-seed.ts
└── community-goals-seed.ts
Intégration modules existants
CombatService — émission événements succès
// Après résolution combat — émettre pour achievement tracker
if (result.winner === 'player') {
this.eventEmitter.emit('achievement.check', {
characterId: character.id,
type: 'combat_wins',
increment: 1,
});
this.eventEmitter.emit('community.contribute', {
characterId: character.id,
type: 'total_monsters_killed',
increment: 1,
});
}
ForgeService / CraftService — même pattern
// Après forge réussie
this.eventEmitter.emit('achievement.check', {
characterId, type: 'forge_upgrades', increment: 1,
});
this.eventEmitter.emit('community.contribute', {
characterId, type: 'total_forge_upgrades', increment: 1,
});
Boosts actifs — application dans CombatEngine
// Dans CombatService — vérifier boosts communautaires actifs
const xpBoost = await this.communityService.getActiveMultiplier('xp_boost');
rewards.xp = Math.floor(baseXp * xpBoost); // xpBoost = 1.0 si aucun boost
Migration TypeORM
Sprint4Achievements — 6 tables :
achievements, player_achievements,
community_goals, community_contributions,
hall_of_fame, active_boosts
+ ALTER characters ADD active_title VARCHAR(100) NULL
+ ALTER characters ADD total_gold_earned BIGINT DEFAULT 0 -- tracking cumulé pour succès
Critères de validation integrator
GET /api/achievements→ 15 succès seedés, 5 catégoriesPOST /api/combat/start→ victoire →player_achievements.progressincrémenté pourcombat_wins- 10 victoires → succès
combat_10débloqué automatiquement GET /api/achievements/me→ progression visible avec %POST /api/achievements/claim/:id→ or crédité, titre disponible- Claim succès déjà réclamé → 400
PUT /api/profile/title→ titre actif changéGET /api/profile/me→ titre, badges, count succèsGET /api/community/goals→ 3 objectifs avec barre progression- Combat victoire →
community_contributionsincrémentée GET /api/community/goals/:id/top→ top 10 contributeurs- Objectif communautaire atteint → boost créé dans
active_boosts GET /api/community/boosts→ multiplicateur actif- Combat avec boost actif → XP = baseXp × multiplier
- Boost expiré → non retourné par GET
GET /api/halloffame/current→ classement mois en cours- Sans cookie → 401 sur toutes les routes protégées
- Level up →
player_achievements.progressincrémenté pourlevel_reached - Forge → incrémente
forge_upgrades+total_forge_upgradescommunautaire