Add performance ranking and heady badges

This commit is contained in:
fullsizemalt 2025-12-26 21:28:25 -08:00
parent 43e37f5c98
commit 992cb3db98
3 changed files with 97 additions and 102 deletions

View file

@ -99,6 +99,36 @@ def read_performance(slug: str, session: Session = Depends(get_session)):
# Sort by rating desc, then date desc # Sort by rating desc, then date desc
other_performances.sort(key=lambda x: (x.avg_rating or 0, x.show_date), reverse=True) other_performances.sort(key=lambda x: (x.avg_rating or 0, x.show_date), reverse=True)
# --- Calculate Ranking for Current Performance ---
current_perf_stats = rating_map.get(performance_id, {"avg": 0.0, "count": 0})
current_avg = current_perf_stats["avg"] or 0.0
current_rating_count = current_perf_stats["count"]
# Build list of all performances with their ratings for ranking
all_rated_perfs = []
for p, s, v in all_perfs_data:
stats = rating_map.get(p.id, {"avg": 0.0, "count": 0})
all_rated_perfs.append({"id": p.id, "avg": stats["avg"] or 0.0, "count": stats["count"]})
# Sort by avg rating desc
all_rated_perfs.sort(key=lambda x: x["avg"], reverse=True)
# Find rank (1-indexed)
rank = None
for i, item in enumerate(all_rated_perfs):
if item["id"] == performance_id:
rank = i + 1
break
total_versions = len(all_perfs_data)
# Heady = top 20% with at least 1 rating and avg >= 8.0
is_heady = False
if current_rating_count > 0 and current_avg >= 8.0:
if rank and total_versions > 0:
percentile = rank / total_versions
is_heady = percentile <= 0.2 # Top 20%
# Construct response manually to include extra fields # Construct response manually to include extra fields
# We need to ensure nested models (show, song) are validated correctly # We need to ensure nested models (show, song) are validated correctly
perf_dict = performance.model_dump() perf_dict = performance.model_dump()
@ -112,6 +142,11 @@ def read_performance(slug: str, session: Session = Depends(get_session)):
perf_dict['gap'] = gap perf_dict['gap'] = gap
perf_dict['times_played'] = times_played perf_dict['times_played'] = times_played
perf_dict['other_performances'] = other_performances perf_dict['other_performances'] = other_performances
perf_dict['rank'] = rank
perf_dict['total_versions'] = total_versions
perf_dict['avg_rating'] = current_avg
perf_dict['rating_count'] = current_rating_count
perf_dict['is_heady'] = is_heady
return perf_dict return perf_dict

View file

@ -1,6 +1,6 @@
# Elmeg Platform Roadmap # Elmeg Platform Roadmap
**Last Updated:** 2025-12-26 **Last Updated:** 2025-12-27
--- ---
@ -34,7 +34,22 @@
--- ---
## Recent Completions (Dec 26, 2025) ## Recent Completions (Dec 27, 2025)
| Feature | Status |
|---------|--------|
| Auth Persistence Fix | ✅ Fixed - added missing DB columns for preferences |
| Review Display | ✅ Shows avatar, username, localized date, granular score |
| Rating System | ✅ Shows user's existing rating, added `/ratings/me` endpoint |
| Activity Feed | ✅ Living links to entities, accurate type language |
| Username Consistency | ✅ Fixed - feed now uses Profile username |
| Notification Prefs Backend | ✅ Added DB columns (theme, email_on_reply, etc) |
| Avatar Unlock System | ✅ XP tiers implemented in settings |
| Duplicate Performances | ✅ Fixed - deleted 220 duplicates |
| Score Precision | ✅ Fixed - database column changed to FLOAT |
| UI Polish | ✅ Removed emojis, music icon, updated site description |
## Previous Completions (Dec 26, 2025)
| Feature | Status | | Feature | Status |
|---------|--------| |---------|--------|
@ -45,54 +60,23 @@
| SPF DNS record fixed | ✅ Complete | | SPF DNS record fixed | ✅ Complete |
| Password reset tested | ✅ Complete | | Password reset tested | ✅ Complete |
## Previous Completions (Dec 23, 2025) ---
## Current Sprint
### In Progress
| Feature | Status | | Feature | Status |
|---------|--------| |---------|--------|
| Privacy Settings (3 toggles) | ✅ Complete | | Performance Ranking | 🔄 Backend + Frontend |
| Sticky Settings Sidebar | ✅ Complete | | Heady Badges | 🔄 Visual polish for top-rated |
| Bug Tracker MVP | ✅ Deployed |
| Auth Console Error Fix | ✅ Fixed |
| Videos Page Link Fix | ✅ Fixed |
| Hide Test Users | ✅ Implemented |
| Bandcamp/Nugs Links | ✅ Complete |
| Enhanced Footer | ✅ Deployed |
| **Postal Mail Server** | ✅ Built & Deployed |
| **Email DNS Records** | ✅ SPF/DKIM/DMARC/RP |
| **SMTP Integration** | ✅ Backend configured |
--- ### Up Next
## Postal Mail Server Details | Feature | Priority |
|---------|----------|
### Infrastructure | Theme persistence (frontend) | Medium |
| Email notification triggers | Low |
| Component | Details |
|-----------|---------|
| Location | tangible-aacorn (Hetzner ARM64) |
| Build | Custom ARM64 from source |
| Database | MariaDB 11 |
| Queue | RabbitMQ 3.13 |
| Routing | Traefik with Let's Encrypt |
### DNS Records (Cloudflare)
| Type | Name | Value |
|------|------|-------|
| A | postal | 159.69.219.254 (DNS only) |
| A | smtp | 159.69.219.254 (DNS only) |
| MX | @ | smtp.elmeg.xyz (Priority 10) |
| TXT | @ | v=spf1 mx a ip4:159.69.219.254 ~all |
| TXT | postal-VkYvkc._domainkey | v=DKIM1; t=s; h=sha256; p=... |
| TXT | _dmarc | v=DMARC1; p=none; rua=mailto:admin@elmeg.xyz |
| CNAME | psrp | smtp.elmeg.xyz |
### Admin Access
- **URL:** <https://postal.elmeg.xyz>
- **Login:** <admin@elmeg.xyz>
- **Organization:** Elmeg
- **Mail Server:** main
--- ---
@ -105,40 +89,18 @@
| Privacy: Public Profile | ✅ Done | | Privacy: Public Profile | ✅ Done |
| Privacy: Show Attendance | ✅ Done | | Privacy: Show Attendance | ✅ Done |
| Privacy: Leaderboards | ✅ Done | | Privacy: Leaderboards | ✅ Done |
| Theme Persistence | ✅ Works client-side | | Theme Persistence | ✅ Backend ready |
| Notification Toggles | ✅ UI + Backend ready |
| Avatar XP Unlock System | ✅ Complete |
### Phase 2: Notifications (Deferred) ### Phase 2: Notifications (Backend Ready)
| Feature | Dependency | Status | | Feature | Status |
|---------|------------|--------| |---------|--------|
| Comment Replies | Notification system | Ready to implement | | Comment Replies Pref | ✅ Backend column added |
| New Show Added | Import trigger hook | Needs backend work | | Chase Song Pref | ✅ Backend column added |
| Chase Song Played | Post-import check | Needs backend work | | Weekly Digest Pref | ✅ Backend column added |
| Weekly Digest | Email templates + cron | Future | | Email Triggers | ❌ Not implemented |
---
## External Links System
### ✅ Phase 1: Database + Admin - COMPLETE
### ✅ Phase 2: Frontend Display - COMPLETE
### Phase 3: Import Tools (Future)
---
## Bug Tracker
**Status: ✅ DEPLOYED at `/bugs`**
---
## Avatar System Roadmap
### ✅ Phase 1: Jewel Tones (Complete)
### Phase 2-4: (Future)
--- ---
@ -148,36 +110,17 @@
- [x] Test email verification flow end-to-end - [x] Test email verification flow end-to-end
- [x] Test password reset flow end-to-end - [x] Test password reset flow end-to-end
- [ ] Performance ranking display
- [ ] Heady badges for top-rated versions
### Medium Priority ### Medium Priority
- [ ] Theme persistence to frontend
- [ ] Analytics provider decision - [ ] Analytics provider decision
- [ ] Notification preferences backend
- [ ] Avatar unlock system
### Low Priority ### Low Priority
- [ ] bugs.elmeg.xyz subdomain - [ ] bugs.elmeg.xyz subdomain
- [ ] Data export (GDPR) - [ ] Data export (GDPR)
- [ ] Account deletion - [ ] Account deletion
- [ ] Email notification triggers
---
## Implementation Priority
### Immediate (Testing)
1. [x] Register test account to trigger verification email
2. [x] Registration UX shows "Check Your Email" message
3. [x] Test password reset flow
4. [x] Monitor email deliverability in Postal dashboard
### This Week
- [ ] Answer analytics question
- [ ] Theme persistence to user preferences
### Next Sprint
- [ ] Notification preferences backend
- [ ] Avatar unlock system

View file

@ -67,11 +67,22 @@ export default async function PerformanceDetailPage({ params }: { params: Promis
</Link> </Link>
<div> <div>
{/* Context Badge */} {/* Context Badge */}
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-2 flex-wrap">
<Badge variant="secondary" className="bg-primary/10 text-primary border-primary/20"> <Badge variant="secondary" className="bg-primary/10 text-primary border-primary/20">
<Sparkles className="h-3 w-3 mr-1" /> <Sparkles className="h-3 w-3 mr-1" />
Specific Performance Specific Performance
</Badge> </Badge>
{performance.is_heady && (
<Badge className="bg-yellow-500/10 text-yellow-600 border-yellow-500/20 border">
<Sparkles className="h-3 w-3 mr-1" />
Heady Version
</Badge>
)}
{performance.rank && performance.total_versions && (
<Badge variant="outline" className="font-mono">
#{performance.rank} of {performance.total_versions}
</Badge>
)}
{performance.set_name && ( {performance.set_name && (
<Badge variant="outline">{performance.set_name}</Badge> <Badge variant="outline">{performance.set_name}</Badge>
)} )}
@ -136,7 +147,13 @@ export default async function PerformanceDetailPage({ params }: { params: Promis
Rate This Version Rate This Version
</div> </div>
<SocialWrapper type="ratings"> <SocialWrapper type="ratings">
<EntityRating entityType="performance" entityId={performance.id} /> <EntityRating
entityType="performance"
entityId={performance.id}
rank={performance.rank}
ratingCount={performance.rating_count}
isHeady={performance.is_heady}
/>
</SocialWrapper> </SocialWrapper>
</div> </div>
</div> </div>