Practice Arena System - Current Implementation Summary
✅ Your Requirements (ALL IMPLEMENTED)
1. ✅ Remove Seat Limits for Practice Arenas (NOT Tournaments)
Status: FULLY IMPLEMENTED
- Practice Arenas: NO seat limits - unlimited players can join
- Tournaments: KEEP seat limits (unchanged - still use
totalSeatsfield)
The practice arena schema has been completely transformed:
- Removed fields:
totalSeats,numberOfPlayers,entryFee,winner,tournament,startAt,endedAt - Added fields:
currentWeekStartDate,currentWeekEndDate,isWeeklyCycle
2. ✅ Winner Declared on Weekend
Status: FULLY IMPLEMENTED
- Winners are declared at the end of each week (Sunday 23:59:59)
- Automated cron job runs every hour to check if week has ended
- When Sunday ends, the system:
- Finds the winner (lowest non-zero score)
- Marks winner in weekly leaderboard
- Creates reward distribution entry
- Sends winner notification
3. ✅ Arena Resets After Weekend for New Week
Status: FULLY IMPLEMENTED
- After Sunday night winner declaration, arena automatically resets
- New week cycle starts Monday 00:00:00
- Previous week's leaderboard is preserved for history
- New leaderboard created for the new week
System Architecture
Weekly Cycle Flow
Monday 00:00:00 ──────────────────────────> Sunday 23:59:59
│ │
│ Players join (unlimited) │
│ Players submit scores (unlimited) │
│ Leaderboard updates in real-time │
│ │
└──────────────────────────────────────────┘
│
Cron Job Triggers
│
┌──────┴──────┐
│ Find Winner │
│ (Lowest > 0)│
└──────┬──────┘
│
┌──────┴──────────┐
│ Create Reward │
│ (Pending Admin) │
└──────┬──────────┘
│
┌──────┴──────┐
│ Reset Arena │
│ (New Week) │
└─────────────┘
Database Schema
PracticeArena Model
{
game: ObjectId, // Reference to Game
status: 'ACTIVE' | 'INACTIVE',
rules: string,
name: string,
currentWeekStartDate: Date, // Monday 00:00:00
currentWeekEndDate: Date, // Sunday 23:59:59
isWeeklyCycle: boolean // Always true
}
Key Differences from Tournament:
- ❌ NO
totalSeatsfield - ❌ NO
entryFeefield - ❌ NO
numberOfPlayersfield - ❌ NO
winnerfield (winners stored in ArenaWeeklyLeaderboard) - ✅ Weekly cycle dates instead
- ✅ Status is ACTIVE/INACTIVE (not OPEN/IN_PROGRESS/OVER)
Tournament Model (UNCHANGED - Still Has Seat Limits)
{
game: ObjectId,
product: ObjectId,
seller: string,
status: 'OPEN' | 'IN_PROGRESS' | 'OVER' | 'UNFILLED',
entryFee: number, // ✅ Tournaments still have fees
totalSeats: number, // ✅ Tournaments still have seat limits
numberOfPlayers: number, // ✅ Tournaments track player count
expectedPlayers: number,
winner: ObjectId,
// ... other tournament-specific fields
}
Cron Job Configuration
File: src/cron/arenas.cron.ts
Schedule: Runs every 1 hour (60 minutes)
- Checks if any arena's
currentWeekEndDatehas passed - Processes all ended weeks in a single run
Startup Delay: 30 seconds after server start
setTimeout(runWeeklyArenas, 30_000) // Initial run after 30s
setInterval(runWeeklyArenas, 60*60*1000) // Then every hour
Why hourly?
- Catches ended weeks promptly (within 1 hour of Sunday midnight)
- Low overhead (quick query, only processes ended weeks)
- Reliable and simple
Winner Selection Logic
Criteria (in order):
- Lowest score > 0 (zero scores excluded as invalid)
- First submission time (tiebreaker via
updatedAt)
const winner = await ArenaWeeklyLeaderboard.findOne({
arena: arena._id,
weekStartDate: arena.currentWeekStartDate,
weekEndDate: arena.currentWeekEndDate,
score: { $gt: 0 } // Exclude zero scores
})
.sort({ score: 1, updatedAt: 1 }) // Lowest score, earliest submission
API Endpoints
Public Endpoints (No Auth)
GET /api/v1/practice-arenas- List all active arenasGET /api/v1/practice-arenas?game=:gameId- Get arena by gameGET /api/v1/practice-arenas/:id- Get specific arenaGET /api/v1/practice-arenas/:id/leaderboard- Get current week leaderboard
Authenticated Endpoints
POST /api/v1/practice-arenas/:id/join- Join arena (unlimited times)POST /api/v1/practice-arenas/:id/score- Submit score (unlimited times)GET /api/v1/practice-arenas/played- Get user's played arenas
Admin Endpoints
POST /api/admin/practice-arenas- Create new arenaGET /api/admin/practice-arenas- List all arenasPUT /api/admin/practice-arenas/:id- Update arenaGET /api/admin/arena-rewards- List reward distributionsPUT /api/admin/arena-rewards/:id/approve- Approve rewardPUT /api/admin/arena-rewards/:id/reject- Reject rewardGET /api/admin/arena-rewards/config- Manage reward configs
Key Features
✅ No Seat Limits - Unlimited players can join practice arenas ✅ No Entry Fees - Completely free to play ✅ Weekly Cycles - Monday to Sunday automatic cycles ✅ Weekend Winners - Declared at end of week (Sunday night) ✅ Auto Reset - Arena resets Monday morning for new week ✅ Historical Data - All past weeks preserved ✅ Real-time Leaderboard - Updates as scores submitted ✅ Fraud Prevention - Zero scores excluded ✅ Reward System - Country-specific rewards with admin approval ✅ Unlimited Plays - Join and submit scores unlimited times per week
Comparison: Practice Arena vs Tournament
| Feature | Practice Arena | Tournament |
|---|---|---|
| Seat Limits | ❌ NO (Unlimited) | ✅ YES (totalSeats) |
| Entry Fee | ❌ NO (Free) | ✅ YES (entryFee in points) |
| Duration | Weekly cycle (Mon-Sun) | Custom dates |
| Winner Declaration | End of week (Sunday) | When seats fill |
| Auto Reset | ✅ YES (Every Monday) | ❌ NO (One-time) |
| Join Limit | Unlimited | Limited by seats |
| Score Limit | Unlimited submissions | Unlimited submissions |
| Rewards | Admin approval required | Auto-distributed |
| Status | ACTIVE/INACTIVE | OPEN/IN_PROGRESS/OVER |
| Historical Data | All weeks preserved | Single instance |
Current Status
✅ All Requirements Met
- Seat limits removed - Practice arenas have unlimited capacity
- Tournaments unchanged - Still use seat-based system
- Weekend winner declaration - Happens Sunday night via cron
- Weekly reset - Arena resets Monday morning automatically
No Code Changes Needed
The system already implements everything you requested! The only issue was outdated documentation, which has now been updated to reflect the current implementation.
Documentation Updated
- ✅
docs/practice-arenas-api.md- Complete rewrite - ✅
docs/PRACTICE_ARENA_SUMMARY.md- This summary document - ✅
ARENA_REWARDS_IMPLEMENTATION.md- Already existed (detailed implementation notes)
Testing the System
1. Create a Practice Arena (Admin)
POST /api/admin/practice-arenas
{
"game": "<game_id>",
"name": "Weekly Challenge",
"rules": "Best score wins!"
}
2. Join Arena (User)
POST /api/v1/practice-arenas/:id/join
# Returns: { "ok": true, "arena": { "_id": "..." } }
# Can join unlimited times
3. Submit Scores (User)
POST /api/v1/practice-arenas/:id/score
{ "score": 150 }
# Can submit unlimited times
# Only best (lowest) score kept
4. Check Leaderboard
GET /api/v1/practice-arenas/:id/leaderboard
# See current week rankings
5. Wait for Sunday Night
- Cron job runs automatically
- Winner declared (lowest score > 0)
- Arena resets for Monday
6. Approve Rewards (Admin)
GET /api/admin/arena-rewards
# See pending rewards
PUT /api/admin/arena-rewards/:id/approve
# Approve and distribute points
Monitoring & Logs
Check job logs to verify cron execution:
JobLog.find({ job: 'ARENA_WEEKLY_CYCLE' })
.sort({ runAt: -1 })
.limit(10)
Successful run meta:
{
"action": "processWeeklyArenas",
"total": 5,
"successes": [
{
"arenaId": "...",
"winner": "user123",
"score": 150,
"country": "US",
"rewardAmount": 100,
"ledgerType": "TOPUP"
}
],
"failures": []
}
Summary
Your practice arena system is fully operational with:
- ✅ Unlimited seats (no player cap)
- ✅ Free to play (no entry fees)
- ✅ Weekly cycles (Monday-Sunday)
- ✅ Weekend winner declaration (Sunday night)
- ✅ Automatic weekly reset (Monday morning)
- ✅ Tournaments unaffected (still use seat limits)
No code changes required - system already implements all your requirements!