Next.js + Convex app for a keyboard-first admin dashboard and public realtime leaderboard, with Google Sheets as the canonical source of truth.
- Public leaderboard at
/leaderboard - Admin spreadsheet-style editor at
/admin - Shared-passcode admin auth with signed HttpOnly cookie
- Google Sheets canonical data model with Convex realtime cache
- Sync pipeline:
- Google Sheet edits -> Apps Script webhook -> Convex poll/merge
- Fallback poll every 30s
- Dashboard edits -> Convex optimistic update + queued writeback to Sheets
Copy .env.example to .env.local and set:
GOOGLE_SPREADSHEET_IDGOOGLE_SERVICE_ACCOUNT_JSONorGOOGLE_SERVICE_ACCOUNT_FILESHEET_WEBHOOK_SECRETADMIN_PASSCODEADMIN_COOKIE_SECRETCONVEX_DEPLOYMENTNEXT_PUBLIC_CONVEX_URL
Share your Google Sheet with this service account as Editor:
skill-tree-leaderboard@hack-sv.iam.gserviceaccount.com
Never commit service-account JSON keys. service-accounts/*.json is gitignored.
pnpm dev
pnpm lint
pnpm convex:dev
pnpm convex:deployThe app expects these tabs (and can initialize/repair headers from the admin dashboard button):
Skills:SkillID,SkillName,Category,XP,Active,UpdatedAtAttendees:AttendeeID,FullName,Active,UpdatedAtCompletions:CompletionID,Timestamp,AttendeeID,SkillID,SkillXP,WildcardXP,TotalXP,UpdatedAt,Source
Metadata columns are hidden by schema setup.
Use docs/apps-script-webhook.gs as the sheet-side webhook trigger script.
Arrow keys: navigateTab / Shift+Tab: move horizontallyEnter / Shift+Enter: commit and move verticallyEsc: cancel edit⌘C / Ctrl+C: copy⌘V / Ctrl+V: paste⌘D / Ctrl+D: fill down⌘S / Ctrl+S: force queue flush + sheet sync?: toggle keymap overlay