The Validator Journey feature implements a multi-tiered leaderboard system that tracks users' progression from waitlist to active validator status. This document provides a detailed technical breakdown of how the system works at the model, view, and function level.
The system uses a type-based leaderboard system that determines user placement based on their contributions/badges. Each leaderboard type has its own point calculation and ranking system.
Purpose: Represents a user's position on a specific leaderboard type.
Key Fields:
user: ForeignKey to User modeltype: CharField with choices ['validator', 'builder', 'validator-waitlist', 'validator-waitlist-graduation']total_points: PositiveIntegerField - points specific to this leaderboard typerank: PositiveIntegerField - user's position on the leaderboardlast_update: DateTimeField - timestamp of last update
Key Methods:
update_points_without_ranking(): Updates user's total points without recalculating ranksdetermine_user_leaderboards(user): Class method that determines which leaderboards a user belongs toupdate_leaderboard_ranks(leaderboard_type): Class method that recalculates ranks for a specific leaderboardupdate_points(contribution): Updates points based on contribution typecalculate_rank(): Calculates rank based on leaderboard-specific logic
Unique Constraint: (user, type) - ensures one entry per user per leaderboard type
Location: Top of leaderboard/models.py
Structure: Dictionary mapping leaderboard types to lambda functions that determine membership.
TYPES_RULES = {
'validator': lambda user: (
# Has validator badge only
Contribution.objects.filter(
user=user,
contribution_type__slug='validator'
).exists()
),
'builder': lambda user: (
# Has builder contribution
Contribution.objects.filter(
user=user,
contribution_type__category__slug='builder'
).exists()
),
'validator-waitlist': lambda user: (
# Has validator-waitlist badge but NOT validator badge
Contribution.objects.filter(
user=user,
contribution_type__slug='validator-waitlist'
).exists() and
not Contribution.objects.filter(
user=user,
contribution_type__slug='validator'
).exists()
),
'validator-waitlist-graduation': lambda user: (
# Has both validator-waitlist and validator badges
Contribution.objects.filter(
user=user,
contribution_type__slug='validator-waitlist'
).exists() and
Contribution.objects.filter(
user=user,
contribution_type__slug='validator'
).exists()
)
}Logic Flow:
- Each rule is a lambda function that takes a user object
- Returns boolean indicating if user belongs to that leaderboard
- Validator-waitlist excludes graduated users (they move to validator-waitlist-graduation)
- Graduation leaderboard shows users with both badges
Important: Each leaderboard type has its own point calculation:
validator: Points from validator category contributionsbuilder: Points from builder category contributionsvalidator-waitlist: Points from validator category contributions (before graduation)validator-waitlist-graduation: Points frozen at graduation moment
Fields:
node_version: CharField - inherited from NodeVersionMixin
Graduation Tracking:
- When validator contribution is assigned, system captures current waitlist points
- Points are frozen in validator-waitlist-graduation leaderboard entry
Trigger: post_save on Contribution model
Location: Lines 216-233
Function Flow:
- Triggered when any contribution is saved
- Calls
update_user_leaderboard_entries(user)(plural) - Logs point calculations for debugging
Location: Lines 235-268 Purpose: Core function that manages user's leaderboard placements
Algorithm:
def update_user_leaderboard_entries(user):
# Step 1: Determine eligible leaderboards using TYPES_RULES
user_leaderboards = LeaderboardEntry.determine_user_leaderboards(user)
# Step 2: Remove from ineligible leaderboards
LeaderboardEntry.objects.filter(user=user).exclude(
type__in=user_leaderboards
).delete()
# Step 3: Handle graduation case first
if 'validator-waitlist-graduation' in user_leaderboards:
# Check if graduation entry exists
grad_entry = LeaderboardEntry.objects.filter(
user=user,
type='validator-waitlist-graduation'
).first()
if not grad_entry:
# New graduation - freeze points from waitlist
waitlist_entry = LeaderboardEntry.objects.filter(
user=user,
type='validator-waitlist'
).first()
if waitlist_entry:
LeaderboardEntry.objects.create(
user=user,
type='validator-waitlist-graduation',
total_points=waitlist_entry.total_points,
last_update=timezone.now()
)
# Step 4: Update points for each leaderboard type
for leaderboard_type in user_leaderboards:
if leaderboard_type == 'validator-waitlist-graduation':
continue # Points are frozen at graduation
# Calculate points based on leaderboard type
if leaderboard_type == 'validator':
points = calculate_validator_points(user)
elif leaderboard_type == 'builder':
points = calculate_builder_points(user)
elif leaderboard_type == 'validator-waitlist':
points = calculate_waitlist_points(user)
LeaderboardEntry.objects.update_or_create(
user=user,
type=leaderboard_type,
defaults={
'total_points': points,
'last_update': timezone.now()
}
)
# Step 5: Recalculate ranks for affected leaderboards
for leaderboard_type in user_leaderboards:
update_leaderboard_type_ranks(leaderboard_type)Helper Functions:
def calculate_validator_points(user):
"""Calculate points from validator category contributions"""
return Contribution.objects.filter(
user=user,
contribution_type__category__slug='validator'
).aggregate(total=Sum('frozen_global_points'))['total'] or 0
def calculate_builder_points(user):
"""Calculate points from builder category contributions"""
return Contribution.objects.filter(
user=user,
contribution_type__category__slug='builder'
).aggregate(total=Sum('frozen_global_points'))['total'] or 0
def calculate_waitlist_points(user):
"""Calculate points from validator category before graduation"""
# Get graduation date if exists
grad_contribution = Contribution.objects.filter(
user=user,
contribution_type__slug='validator'
).first()
query = Contribution.objects.filter(
user=user,
contribution_type__category__slug='validator'
)
if grad_contribution:
# Only count contributions before graduation
query = query.filter(
contribution_date__lt=grad_contribution.contribution_date
)
return query.aggregate(total=Sum('frozen_global_points'))['total'] or 0
def update_leaderboard_type_ranks(leaderboard_type):
"""Update ranks for a specific leaderboard type"""
if leaderboard_type == 'validator-waitlist-graduation':
# Rank by graduation date (most recent first)
entries = LeaderboardEntry.objects.filter(
type=leaderboard_type
).order_by('-last_update')
else:
# Rank by points
entries = LeaderboardEntry.objects.filter(
type=leaderboard_type
).order_by('-total_points', 'user__name')
for i, entry in enumerate(entries):
entry.rank = i + 1
entry.save(update_fields=['rank'])Key Points:
- User appears on ALL leaderboards they qualify for
- Each leaderboard has its own point calculation
- Graduation freezes points in graduation leaderboard
- Rank calculation varies by leaderboard type
Location: Lines 40-337 Purpose: Main API endpoint for leaderboard data
Key Methods:
Function: Filters leaderboard by type parameter
def get_queryset(self):
queryset = super().get_queryset()
# Get type from query params
leaderboard_type = self.request.query_params.get('type')
if leaderboard_type:
queryset = queryset.filter(type=leaderboard_type)
else:
# Default to validator leaderboard
queryset = queryset.filter(type='validator')
# Get ordering parameter
order = self.request.query_params.get('order', 'asc')
if order == 'desc':
return queryset.order_by('-rank')
return queryset.order_by('rank')Endpoint: /api/v1/leaderboard/validator-waitlist-stats/
Purpose: Provides statistics for waitlist dashboard
Returns:
{
'total_participants': count of waitlist users,
'total_contributions': sum of contributions from waitlist users,
'total_graduated_contributions': sum of contributions from graduated users,
'total_points': sum of points from waitlist users,
'total_graduated_points': sum of points in graduation leaderboard,
'total_graduated': count of users who graduated
}Modified Method: highlights() action (Lines 302-350)
New Parameter: waitlist_only=true
- Shows contributions from waitlist users
- For graduated users, only shows contributions from before graduation
Implementation:
if waitlist_only:
# Get users with validator-waitlist contribution
waitlist_type = ContributionType.objects.filter(slug='validator-waitlist').first()
waitlist_users = Contribution.objects.filter(
contribution_type=waitlist_type
).values_list('user_id', flat=True).distinct()
# Get graduated users and their graduation dates
graduated_users = {}
validator_contributions = Contribution.objects.filter(
contribution_type__slug='validator',
user_id__in=waitlist_users
).select_related('user')
for vc in validator_contributions:
graduated_users[vc.user_id] = vc.contribution_date
# Build query for highlights
q_objects = Q()
for user_id in waitlist_users:
if user_id in graduated_users:
# Graduated user - only show pre-graduation contributions
q_objects |= Q(
contribution__user_id=user_id,
contribution__contribution_date__lt=graduated_users[user_id]
)
else:
# Still on waitlist - show all contributions
q_objects |= Q(contribution__user_id=user_id)
queryset = queryset.filter(q_objects)Purpose: Recalculate all leaderboard entries and ranks
def recalculate_all_leaderboards():
"""
Admin command to recalculate all leaderboard entries.
Called from admin shortcuts.
"""
from django.db import transaction
with transaction.atomic():
# Step 1: Clear all existing entries
LeaderboardEntry.objects.all().delete()
# Step 2: Process each user
users = User.objects.filter(
contributions__isnull=False
).distinct()
for user in users:
update_user_leaderboard_entries(user)
# Step 3: Update ranks for each leaderboard type
for leaderboard_type in ['validator', 'builder', 'validator-waitlist', 'validator-waitlist-graduation']:
update_leaderboard_type_ranks(leaderboard_type)
print(f"Recalculated {users.count()} users across all leaderboards")Key State Variables:
let waitlistUsers = $state([]); // All waitlist participants
let newestWaitlistUsers = $state([]); // 5 most recent joiners
let graduatedUsers = $state([]); // Graduated validators (from graduation leaderboard)
let featuredContributions = $state([]); // Highlighted contributions
let statistics = $state({}); // Waitlist statistics
// Loading states for progressive rendering
let statsLoading = $state(true);
let waitlistLoading = $state(true);
let graduatedLoading = $state(true);
let featuredLoading = $state(true);onMount(async () => {
// Load sections independently for better UX
fetchStatistics(); // Fast - loads first
fetchWaitlistData(); // Main data
fetchGraduatedUsers(); // Secondary data
fetchFeaturedContributions(); // Enhancement data
});Purpose: Load waitlist participants
async function fetchWaitlistData() {
waitlistLoading = true;
const response = await leaderboardAPI.getLeaderboardByType('validator-waitlist');
waitlistUsers = response.data;
// Extract newest joiners
newestWaitlistUsers = [...waitlistUsers]
.sort((a, b) => new Date(b.last_update) - new Date(a.last_update))
.slice(0, 5);
waitlistLoading = false;
}Purpose: Load graduated validators from graduation leaderboard
async function fetchGraduatedUsers() {
graduatedLoading = true;
const response = await leaderboardAPI.getLeaderboardByType('validator-waitlist-graduation');
graduatedUsers = response.data;
graduatedLoading = false;
}leaderboardAPI = {
// Get specific leaderboard type
getLeaderboardByType: (type, order = 'asc') =>
api.get('/leaderboard/', { params: { type, order } }),
// Get waitlist statistics
getWaitlistStats: () =>
api.get('/leaderboard/validator-waitlist-stats/'),
// Main leaderboard function
getLeaderboard: (params) => {
return api.get('/leaderboard/', { params });
}
}- User receives 'validator-waitlist' contribution
update_leaderboard_on_contributionsignal firesupdate_user_leaderboard_entriescalled:- Determines user qualifies for 'validator-waitlist' leaderboard
- Calculates points from validator category contributions
- Creates LeaderboardEntry with type='validator-waitlist'
- Recalculates waitlist ranks by points
- User appears on waitlist page
- User receives 'validator' contribution
- Signal fires,
update_user_leaderboard_entriescalled:- TYPES_RULES['validator'] returns True
- TYPES_RULES['validator-waitlist-graduation'] returns True
- TYPES_RULES['validator-waitlist'] returns False
- Creates validator leaderboard entry with validator points
- Creates graduation entry with frozen waitlist points
- Deletes waitlist leaderboard entry
- Recalculates ranks (points for validator, date for graduation)
- User appears in graduation leaderboard sorted by graduation date
- User removed from waitlist, appears on validator leaderboard
- User earns new contribution
- Signal determines which leaderboards are affected
- Points recalculated based on contribution category:
- Validator contributions → validator and waitlist leaderboards
- Builder contributions → builder leaderboard
- Graduation leaderboard points remain frozen
- Ranks recalculated for affected leaderboards
- Admin triggers recalculation from admin panel
recalculate_all_leaderboards()function called- All leaderboard entries deleted and rebuilt
- Each user processed to determine leaderboard memberships
- Points calculated per leaderboard type
- Ranks recalculated for all leaderboards
- Batch Operations: Ranks updated in bulk after all entries modified
- Deferred Ranking:
update_points_without_ranking()for batch updates - Query Optimization: Select_related and prefetch_related used extensively
- Separate Point Calculations: Each leaderboard calculates its own points
Backend Potential N+1 Issues:
TYPES_RULESevaluation - Each rule may query contributions table- Fix: Prefetch all user contributions once, pass to rules
update_user_leaderboard_entries- Multiple point calculations- Fix: Single aggregated query for all contribution types
- Rank calculation - Loading each entry separately
- Fix: Use bulk_update for rank updates
Frontend Potential N+1 Issues:
- User enrichment in waitlist data - Fetching each user separately
- Fix: Batch fetch all users, create lookup map
- Contribution fetching for dates - Individual queries per user
- Fix: Single query with user_id__in filter
- Rules Evaluation: Multiple queries per user during rule checking
- Rank Recalculation: O(n log n) for each leaderboard type
- Signal Cascades: Multiple contributions can trigger redundant updates
- Simultaneous Badges: User with both waitlist and validator badges
- Resolution: Appears in graduation leaderboard with frozen points
- Missing Profiles: User without any qualifying criteria
- Resolution: No leaderboard entries created
- Points at Graduation: Always captured when validator badge assigned
- Resolution: Frozen in graduation leaderboard entry
- Graduation Flow: Verify user moves from waitlist to graduation leaderboard
- Points Consistency: Different points per leaderboard type
- Rank Accuracy: No gaps or duplicates in rankings
- Rule Evaluation: TYPES_RULES correctly identify user types
- API Filtering: Type parameter correctly filters results
- Frontend State: Waitlist page shows waitlist and graduated users correctly
- Recalculation Function: Test admin recalculation in various scenarios:
- Empty database
- Single user with multiple contributions
- Multiple users with various badges
- Users at different journey stages
# Create waitlist user
user1 = User.objects.create(email='waitlist@test.com')
Contribution.objects.create(
user=user1,
contribution_type=ContributionType.objects.get(slug='validator-waitlist'),
points=10
)
# Graduate user to validator
validator_contrib = Contribution.objects.create(
user=user1,
contribution_type=ContributionType.objects.get(slug='validator'),
points=5
)
# Verify leaderboard changes
assert not LeaderboardEntry.objects.filter(user=user1, type='validator-waitlist').exists()
assert LeaderboardEntry.objects.filter(user=user1, type='validator').exists()
assert LeaderboardEntry.objects.filter(user=user1, type='validator-waitlist-graduation').exists()
# Verify frozen points
grad_entry = LeaderboardEntry.objects.get(user=user1, type='validator-waitlist-graduation')
assert grad_entry.total_points == 10 # Frozen at graduation
# Test recalculation
from leaderboard.admin import recalculate_all_leaderboards
recalculate_all_leaderboards()
assert LeaderboardEntry.objects.filter(user=user1).count() == 2 # validator and graduation- No special configuration required
- Uses existing Django settings
- No new environment variables
- Uses existing VITE_API_URL
- Remove deprecated fields:
- Remove
categoryfield from LeaderboardEntry - Remove database column preservation for
leaderboard_type - Remove
points_at_waitlist_graduationfrom Validator model
- Remove
- Remove legacy support: Remove category parameter handling in views
- Consolidate point calculations: Create centralized point calculation service
- Optimize queries: Implement prefetch patterns to eliminate N+1 queries