RankIT runs the scoring side of school competitions: admins set up events and criteria, tabulators record judges' scores, grievance officers file deductions, and everyone else watches live rankings on a public page. It replaces spreadsheets passed between judges with one auditable system that computes event, category and overall weighted rankings and prints the official reports. Live at rankit.jevoelorbilla.dev.
Screenshots
Live rankings![]() |
Display mode![]() |
Tabulator scoring![]() |
Event setup![]() |
Master report![]() |
Grievance deductions![]() |
Admin analytics![]() |
Light theme![]() |
Phone (tabulator)![]() |
Phone (live rankings, light)![]() |
- Public live leaderboard by event, category and overall weighted ranking
- Big-screen display mode for projectors, with auto-rotating views and a QR code
- Role consoles for admin, tabulator and grievance staff, built for phones and tablets
- Criteria-based and set-based (sports) scoring with automatic rankings
- Accounts are created by signing in with Google or GitHub; admins assign each person's role
- Sign in later with Google, GitHub or a username and password set at first sign-in
- A superadmin can only recover admin access: promote an admin or reset an admin's password
- Auditable grievance deductions with reasons
- Master report PDFs: main results, deduction notes, weighted rankings
- Audit trail and analytics for admins
- Light, dark and system themes; works on phones and tablets
| Layer | Tools |
|---|---|
| Frontend | React 19.3.1, React Router 6.30.6, Vite 6.4.5, @react-pdf/renderer 4.9.0, qrcode 1.5.4 |
| Backend | Node.js 22.14.0, Express 5.2.1, Mongoose 9.12.0, Zod 4.6.7, Helmet 8.3.0 |
| Database | MongoDB (Atlas in production) |
| Testing | Vitest 4.1.12, Supertest, mongodb-memory-server |
| Hosting | Vercel (one project: static app + API function), MongoDB Atlas |
Prerequisites: Node.js 22+, and MongoDB running locally (or an Atlas URI).
cp backend/.env.example backend/.env # then set JWT_SECRET
npm ci --prefix backend && npm ci --prefix frontend-react
npm run seed:users --prefix backend && npm run seed:events --prefix backend
npm run dev --prefix backend # API on http://localhost:5000
npm start --prefix frontend-react # app on http://localhost:3000The seeders create demo accounts such as mark (admin) and al (tabulator) with the password from SEED_PASSWORD (default 1234). They only run against a local database.
The API reads backend/.env; see backend/.env.example, which has Local, Development and Production blocks (only Local is active). The frontend needs no variables in development: Vite proxies /api to the API.
Environment variables
| Variable | Where | Purpose |
|---|---|---|
MONGODB_URI |
backend | MongoDB connection string |
JWT_SECRET |
backend | Signs session cookies; use a long random value |
JWT_EXPIRES_IN |
backend | Session length, e.g. 12h |
APP_URL |
backend | Public URL used for OAuth redirect URIs (defaults to the Vercel production domain) |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET |
backend | Enables "Continue with Google" (optional) |
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET |
backend | Enables "Continue with GitHub" (optional) |
CORS_ORIGIN |
backend | Extra allowed browser origins (optional: the app and API share one origin) |
PORT, HOST |
backend | Local server bind (default 5000, 0.0.0.0) |
SEED_PASSWORD |
backend | Demo password for the local seeders |
VITE_DEV_API_TARGET |
frontend | Where the dev proxy sends /api (default http://localhost:5000) |
VITE_API_URL |
frontend | Only if the API is on another origin (default /api) |
- Admin creates an event with its criteria (or sets for sports), adds contestants and assigns a tabulator.
- Tabulator records each judge's scores; rankings update immediately.
- Grievance files deductions with a reason when a rule is broken.
- Everyone follows the public page at
/; admins choose which events and ranking views are visible. Put/display(or/display/<eventId>) on a projector: it rotates event, category and overall standings every 15 seconds (?seconds=20,?rotate=0to pin). Press F for full screen, Space to pause. - Admin prints the master report when the event is finalized.
New staff sign in with Google or GitHub, set a password, and wait while an admin assigns their role under Users → New sign-ups. Setup steps and the logos to upload are in docs/deployment.md.
Deploying: import the repo into Vercel as one project (root directory = repo root); see docs/deployment.md.
Project structure
backend/ Express API: routes, controllers, models, validation, tests, seed scripts
frontend-react/ React app: pages, components (ui kit), hooks, styles
api/ Vercel serverless entry (loads backend/server.js)
docs/ Deployment guide, screenshots, brand assets (logo exports for OAuth and social cards)
.github/ CI workflow
Scripts
| Package | Script | Does |
|---|---|---|
| backend | npm run dev |
API with auto-reload |
| backend | npm test |
API tests (in-memory MongoDB) |
| backend | npm run lint |
ESLint |
| backend | npm run seed:users / seed:events |
Local demo data |
| backend | npm run create:superadmin |
Superadmin (admin recovery) for any database |
| backend | npm run migrate:accounts |
One-off upgrade of pre-3.0 accounts (-- --dry-run to preview) |
| frontend-react | npm start |
Dev server with /api proxy |
| frontend-react | npm test / npm run lint |
Unit tests / ESLint |
| frontend-react | npm run build / npm run preview |
Production build / serve it with production headers |
Work on a feat/... or fix/... branch and use Conventional Commits with the bumped version at the end of the subject, e.g. feat: add CSV export (v2.5.0). Keep npm run lint, npm test and npm run build green, and update this README with every change.
Source-available under the Sprucetrap Source-Available License 1.0: free for non-commercial use with credit.









