The real-time event judging infrastructure built for colleges & Events. From Google Sheets to live leaderboard in under 5 minutes.
🌐 Live Demo · 📖 Docs · 🐛 Report Bug · 💡 Request Feature
The real-time event judging infrastructure built for colleges/Events.
- Why EventRank
- Features
- Screenshots
- Architecture
- Tech Stack
- Getting Started
- Environment Variables
- Database Setup
- Deployment
- Roadmap
- Contributing
- Summary
Most college events still run on Google Forms + Excel sheets + WhatsApp coordination.
Judges submit scores on paper. Organizers manually calculate rankings. Results get announced 2 hours after the event ends. The audience has no idea what's happening.
EventRank fixes this.
| The Old Way | With EventRank |
|---|---|
| Paper scoresheets | Mobile-first digital scoring |
| Manual Excel calculation | Automatic weighted scoring |
| Results after 2 hours | Live leaderboard, real-time |
| No role management | Super Admin → Club Admin → Judge |
| Sheet upload + manual cleanup | Google Sheets direct import |
| One organizer managing everything | Multiple judges simultaneously |
| No audience engagement | Public live leaderboard with themes |
Full platform oversight from a single dashboard. Manage multiple college clubs, approve organizers, monitor platform health metrics, database storage, and live system diagnostics — all in real-time.
Three-tier role system built for real college structures:
Super Admin (Platform Owner — You)
└── Club Admin (Coding Club, Dance Society, Robotics Club...)
└── Judges (Assigned per event)
Club Admins manage their own events independently. Judges only see their assigned event. Zero cross-contamination between organizations — enforced at the database level via Row Level Security.
Paste a Google Sheets link or drop an Excel/CSV file. EventRank automatically:
- Fetches the sheet (no API key needed for public sheets)
- Analyzes all columns with fuzzy header matching
- Shows confidence scores for each detected field
- Lets admin visually select/remap columns
- Detects and flags duplicate enrollment numbers before import
Create multiple rounds per event (Prelims, Semi-Finals, Finals). Per round, define unlimited custom scoring criteria with:
- Custom name (Innovation, Presentation, Technical Depth...)
- Max score per criteria
- Weightage multiplier
- Drag-to-reorder priority
- Deadline per round with auto-lock
Scoring modes: AVG · SUM · AVG + Penalty · SUM + Penalty
Judges receive a 24-hour magic invite link. They set a PIN and land directly on their scoring interface — no app download, no complex login.
Mobile-first scoring features:
- Card-by-card participant flow on mobile
- Large number-grid buttons (no tiny inputs)
- Auto-save on blur with visual confirmation
- Scored / Pending filter tabs
- Enrollment number visible to prevent mix-ups
- Sticky progress bar — always visible
- Offline detection with pending sync indicator
- Completion celebration when all participants scored
Public leaderboard — no login required. Share the URL, project it on screen, let the audience watch rankings update live.
Leaderboard features:
- 🔴 LIVE badge with real-time updates
- 🥇🥈🥉 Top 3 highlighted with podium styling
- ↑↓ Rank change animations
- Per-criteria score breakdown columns
- Weighted total with progress bars
- Self-search — participants find their own name instantly
- "X of Y participants scored" scoring progress
- 5 admin-selectable themes
Olympic-style animated winners reveal. Designed for projector display at the end of your event. Top 3 animate onto the podium with confetti burst — built for the crowd moment.
Admin selects the leaderboard theme before publishing — matched to event type:
| Theme | Best For |
|---|---|
| ⚫ Cyber Dark | Hackathons, Tech events |
| 🟢 Stadium | Sports, Athletics |
| ⚪ Minimal Light | Business, Case competitions |
| 🎨 Festival | Cultural events, Dance |
| 🏆 Royal Gold | Annual fests, Grand finals |
- Row Level Security (RLS) on every table — database-enforced
- JWT-injected claims — judges cannot access other events
- Score range validation — server-side, not just client
- 24-hour expiring invite links — judges only
- Service role key — server-side only, never exposed to browser
- Rate limiting on score submissions
- Event status flow — Draft → Active → Scoring Locked → Ended
┌─────────────────────────────────────────────────────┐
│ VERCEL EDGE │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ Next.js 14 │ │ Edge Runtime │ │ CDN Cache │ │
│ │ App Router │ │ Leaderboard │ │ 30s TTL │ │
│ └──────┬──────┘ └──────┬───────┘ └────────────┘ │
└─────────┼────────────────┼───────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────┐
│ SUPABASE (Mumbai) │
│ │
│ ┌──────────────┐ ┌─────────────────────────┐ │
│ │ PostgreSQL │ │ Supabase Realtime │ │
│ │ + RLS │ │ (scores table) │ │
│ │ + Indexes │ │ WebSocket channel │ │
│ │ + Mat. View │ │ per event │ │
│ └──────────────┘ └─────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌─────────────────────────┐ │
│ │ Auth (JWT) │ │ Storage │ │
│ │ Magic Links │ │ (future uploads) │ │
│ └──────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Judge inputs score (mobile)
↓
Optimistic UI update (instant feel)
↓
Server Action validates:
- Score within criteria max_score range
- Judge is assigned to this event
- Event status = 'active'
↓
Supabase UPSERT (conflict on participant+criteria+judge)
↓
Realtime broadcast to leaderboard channel
↓
Leaderboard recalculates + re-ranks
↓
Audience sees update (< 1 second)
| Layer | Technology | Why |
|---|---|---|
| Framework | Next.js 14 App Router | Server Components, Edge Runtime, Server Actions |
| Language | TypeScript | Type safety across full stack |
| Styling | Tailwind CSS | Rapid UI, consistent design system |
| Database | Supabase PostgreSQL | RLS, Realtime, free tier generous |
| Auth | Supabase Auth | Magic links, JWT, session management |
| Realtime | Supabase Realtime | WebSocket per event channel |
| File Parsing | papaparse + xlsx | CSV + Excel sheet parsing |
| Icons | lucide-react | Consistent icon set |
| Toasts | sonner | Non-blocking notifications |
| Deployment | Vercel | Edge network, auto CI/CD |
Time to deploy: ~20 minutes — Follow every step in order.
| Requirement | Version | Verify With |
|---|---|---|
| Node.js | 18.x or higher | node --version |
| npm | 9.x or higher | npm --version |
| Git | Any | git --version |
| Supabase Account | Free tier works | supabase.com |
| Vercel Account (optional) | Free tier works | vercel.com |
| Docker (optional) | 20.x+ | docker --version |
git clone https://github.com/suryansh-tech/event-Handle-app.git
cd event-Handle-app
npm installExpected: ~30 dependencies installed, zero errors.
Troubleshoot: If@supabase/ssrfails, upgrade to Node 18+.
- Go to database.new and sign in (or supabase.com/dashboard)
- Click "New Project"
- Configure:
- Name:
eventrank(or any name you prefer) - Database Password: Choose a strong password — save it securely
- Region: Select the region closest to your users (e.g.
Mumbaifor India,US Eastfor North America)
- Name:
- Click "Create new project"
- Wait 2–3 minutes for provisioning to finish
Once your Supabase project is ready:
- In the Supabase Dashboard sidebar, click Settings (gear icon) → API
- Copy these 3 values:
| What | Where to Find | Example |
|---|---|---|
| Project URL | Under "Project URL" | https://abcdefgh.supabase.co |
| Anon Key | Under "Project API keys" → anon public |
eyJhbGci... |
| Service Role Key | Under "Project API keys" → service_role secret → click Reveal |
eyJhbGci... |
Create your .env.local file in the project root:
cp .env.example .env.localEdit .env.local and paste your values:
NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key-here
⚠️ NEVER commit.env.localto Git. It is already in.gitignore.
⚠️ NEVER prefixSUPABASE_SERVICE_ROLE_KEYwithNEXT_PUBLIC_— it must stay server-side only.
See ENV_GUIDE.md for a detailed step-by-step walkthrough with screenshots.
Go to your Supabase Dashboard → SQL Editor → New query.
Run each migration file one at a time, in this exact order. Copy the full contents of each file from supabase/migrations/ and execute:
| # | File | What It Does |
|---|---|---|
| 1 | 001_initial_schema.sql |
Creates all core tables (profiles, events, rounds, participants, criteria, scores, event_judges) + RLS policies + get_leaderboard RPC function |
| 2 | 001c_fix_role_constraint.sql |
Adds club_admin to the allowed profile roles |
| 3 | 002_judge_invites.sql |
Creates judge_invites table for 24-hour magic invite links |
| 4 | 003_result_modes_penalties.sql |
Adds result_mode column to events, creates participant_penalties table, upgrades get_leaderboard to support SUM/AVG/Penalty modes |
| 5 | 004_round_deadlines.sql |
Adds deadline column to rounds for auto-lock |
| 6 | 005_fix_scores_rls.sql |
Allows super_admin to also submit scores (not just judges) |
| 7 | 007_restore_full_leaderboard.sql |
Restores full leaderboard function without row limits |
| 8 | 007b_organizations_schema.sql |
Creates organizations table, adds org_id/phone/alt_email/last_active_at to profiles, adds org_id to events |
| 9 | 008_performance_indexes.sql |
Creates 15 B-Tree indexes — critical for production performance |
| 10 | 009_jwt_claims_policy.sql |
Creates JWT claims trigger, replaces ALL RLS policies to use JWT instead of profile joins — the single biggest performance upgrade |
| 11 | 010_update_leaderboard_jwt.sql |
Updates get_leaderboard function to use JWT claims |
| 12 | 011_club_admin_policies.sql |
Adds tenant-scoped RLS policies for club_admin role |
Verification: After running all 12 migrations, go to Table Editor and confirm these 10 tables exist:
profiles · events · event_judges · rounds · participants · criteria · scores · judge_invites · participant_penalties · organizations
- In the Supabase Dashboard → Database → Replication (or Publications)
- Find the publication named
supabase_realtime - Toggle ON for the
scorestable
Without this, the live leaderboard will NOT receive real-time score updates.
Option A — Automated (Recommended):
node --env-file=.env.local scripts/setup-db.mjsThis automatically creates:
- ✅ Auth user:
admin@eventrank.com/Admin@yourpassword - ✅ Profile row with
role = 'super_admin'
⚠️ Change the default password immediately after first login.
Option B — Manual:
- Go to Supabase → Authentication → Users → Add User
- Enter your email and a strong password, check "Auto Confirm User"
- After creation, copy the user's UUID from the table
- Go to SQL Editor and run:
INSERT INTO public.profiles (id, name, email, role) VALUES (
'<paste-user-uuid-here>',
'Your Name',
'your@email.com',
'super_admin'
);npm run devOpen http://localhost:3000 and log in with your Super Admin credentials.
Expected: You are redirected to the /super-admin dashboard showing Platform Stats, Organizers, and Events tabs.
After deploying to your production domain:
- Go to Supabase → Authentication → URL Configuration
- Set:
| Field | Value |
|---|---|
| Site URL | https://your-domain.com |
| Redirect URLs | https://your-domain.com/auth/callback |
Without this, magic links and auth callbacks will fail in production.
- Changed default super admin password
- Verified Realtime is ON for
scorestable - Tested full judge flow: invite → open link → set PIN → score participants
- Verified public leaderboard loads at
/leaderboardwithout login - Tested Google Sheets import with a public sheet URL
- Enabled Connection Pooling in Supabase (Dashboard → Settings → Database → Connection Pooling → Transaction mode) if expecting 30+ simultaneous judges
| Variable | Where to Find | Required |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Supabase → Settings → API → Project URL | ✅ |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Supabase → Settings → API → Publishable key (anon public) |
✅ |
SUPABASE_SERVICE_ROLE_KEY |
Supabase → Settings → API → Secret key (service_role secret) |
✅ |
⚠️ NEVER commit.env.localto Git. It is already in.gitignore.
⚠️ NEVER prefixSUPABASE_SERVICE_ROLE_KEYwithNEXT_PUBLIC_— it must stay server-side only.
profiles — User accounts with roles (super_admin, club_admin, judge, viewer)
organizations — College clubs / organizer groups
events — Individual competition events
participants — Imported students per event
rounds — Scoring rounds per event (Prelims, Finals...)
criteria — Scoring criteria per round (Innovation, max 10, weightage 2x)
scores — Judge scores (upsert on participant+criteria+judge)
event_judges — Judge ↔ Event assignment mapping
judge_invites — 24-hour magic invite link tokens
participant_penalties — Per-participant penalty deductions
All indexes are created automatically by migration 008_performance_indexes.sql. These include:
-- Key indexes (15 total) covering:
idx_participants_event_id -- Participant lookups by event
idx_scores_judge_id -- Score lookups by judge
idx_scores_participant_id -- Score lookups by participant
idx_scores_criteria_id -- Score lookups by criteria
idx_scores_participant_criteria -- Composite for leaderboard RPC
idx_event_judges_event_id -- Judge assignment lookups
idx_event_judges_judge_id -- Judge assignment lookups
idx_rounds_event_id -- Round lookups by event
idx_criteria_round_id -- Criteria lookups by round
idx_penalties_event_id -- Penalty lookups by event
idx_profiles_org_id -- Club admin org scoping
idx_events_org_id -- Event org scoping
idx_events_is_active -- Active event filtering
-- ...and moreImpact: Read queries under heavy load drop from ~3–8 seconds to 50–150 milliseconds.
Supabase Dashboard → Settings → Database → Connection Pooling → Enable
Mode: Transaction
Required for handling 30+ simultaneous judges without exhausting connection limits.
One-click deploy:
Manual deploy:
# Install Vercel CLI
npm install -g vercel
# Login
vercel login
# Deploy
vercel --prodWhen prompted, set these environment variables in the Vercel dashboard:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEY
Required after deploy — Update Supabase Auth URLs:
Supabase → Authentication → URL Configuration
Site URL: https://your-app.vercel.app
Redirect URLs: https://your-app.vercel.app/auth/callback
# Build (NEXT_PUBLIC_ vars must be passed at build time for Next.js client bundle)
docker build \
--build-arg NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co \
--build-arg NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key \
-t eventrank:latest .
# Run
docker run -p 3000:3000 \
-e NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co \
-e NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key \
-e SUPABASE_SERVICE_ROLE_KEY=your-service-key \
eventrank:latestAccess the app at http://localhost:3000.
# Build the production bundle
npm run build
# Start the production server
npm startThe output: 'standalone' setting in next.config.mjs produces a self-contained server.js. You can copy .next/standalone/ to any server with Node.js 18+.
- Multi-org role hierarchy
- Google Sheets direct import
- Real-time live leaderboard
- Mobile-first judge dashboard
- Winners podium with animations
- 5 leaderboard themes
- Super admin diagnostics
- Export CSV results
- Tiebreaker resolution system
- Team events support
- Auto certificate generation
- AI event summary (Claude API)
- WhatsApp result notifications
- Offline judge scoring (PWA)
- Multi-college inter-college events
Contributions are welcome! Please follow these steps:
# Fork the repo
# Create your feature branch
git checkout -b feature/AmazingFeature
# Commit your changes
git commit -m 'Add AmazingFeature'
# Push to the branch
git push origin feature/AmazingFeature
# Open a Pull RequestPlease make sure to:
- Follow the existing code style
- Test on both mobile and desktop
- Update this README if adding new features
EventRank is a production-ready, multi-tenant event judging platform built on the Next.js 16 + Supabase stack. It solves the problem of manual, error-prone event scoring by providing:
- A 4-role access control system (Super Admin → Club Admin → Judge → Viewer) with JWT-based RLS
- Real-time judging with offline support (IndexedDB queue + auto-sync), debounced batch saves, and cross-judge broadcast awareness
- A PostgreSQL-powered leaderboard using stored procedures with weighted scoring, penalties, and 4 calculation modes
- A premium UI with animated podium, dark sci-fi leaderboard, and glassmorphism admin dashboards
- 16 documented performance optimizations that reduce query times from 3-8 seconds to 50-150ms at scale
The system is specifically optimized for the Supabase free tier, using polling instead of realtime subscriptions and text-only data to stay within storage/bandwidth limits. It can comfortably handle 5,000+ participants × 10 judges × multiple rounds within free tier constraints.
Key architectural decisions include:
- Server Actions over API routes for simplified, type-safe data mutations
- Dual Supabase client pattern (user-scoped + admin) for secure privilege separation
- Dynamic imports for admin tab components to reduce initial bundle size
- PostgreSQL RPC for computationally expensive leaderboard calculations
Suryansh Porwal — NIET, Greater Noida
Solving real-world college problems with scalable, real-time technology.
From manual judging chaos → live leaderboard systems.
🚀 Next.js · Supabase · TypeScript
If EventRank helped your college event, give it a ⭐ on GitHub!









