Skip to content

About

Role-based hackathon management platform: teams, submissions, weighted judging and live results.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

HackSphere β€” Where Ideas Become Innovation Typing animation

React TypeScript Vite Tailwind CSS Node.js Express Prisma SQLite Socket.IO

Three.js Radix UI TanStack Query React Router Zod Vitest Playwright Node Status


✨ Features Β β€’Β  🧭 Lifecycle Β β€’Β  πŸ—οΈ Architecture Β β€’Β  🧰 Tech Stack Β β€’Β  πŸš€ Getting Started Β β€’Β  🌍 Deployment

πŸ“– About

HackSphere is a full-stack, role-based hackathon management platform that covers the whole event, from the first announcement to the published leaderboard.

πŸ§‘β€πŸ’» Participants discover events, form teams, pick a challenge and submit their build
πŸŽ›οΈ Organizers configure and run the entire hackathon: stages, challenges, rubric, registrations, judges, results
βš–οΈ Judges score projects against a weighted rubric and leave feedback
πŸ›‘οΈ Administrators verify organizers, moderate accounts and events, and review an audit trail

The interface is light-first: a bright canvas, bento-grid dashboards, glass navigation, clay tiles and avatars, and neumorphic toggles. Dark mode is available as an optional, reduced theme (profile menu or Profile β†’ Appearance).

✨ Features

Feature Details
πŸ” Role-based access One identity, several contexts. Every permission is enforced on the server; the UI only hides what a user can't use
πŸ‘₯ Team formation Create or join one team per hackathon, invite members, request to join, transfer leadership, with team-size limits enforced
🧩 Challenges Problem statements with optional team limits; the choice locks after a final submission
πŸ“¦ Submissions Needs an approved registration and a live hackathon; locks at the deadline unless the organizer grants an extension
βš–οΈ Weighted judging Per-criterion 0 to 10 scores, weighted average, tie-breaks, conflict-of-interest declarations
πŸ… Results and awards Rankings stay private until published; top three plus best project per challenge are generated
πŸ”” Real-time updates Socket.IO rooms per user and per event for live notifications
πŸ“Ž Secure uploads 15 MB limit, type allow-list, access-controlled downloads
🧾 Audit log Admins can review sensitive actions: role changes, suspensions, verifications
🎨 Light-first design system Bento, glass, clay and neumorphic surfaces, accessible by default
β™Ώ Accessibility Focus rings, skip links, linked error messages, keyboard-operable switches, prefers-reduced-motion respected

🧭 Hackathon Lifecycle

Every hackathon moves through a clear set of stages. The stage colours are identical everywhere (badges, stepper and charts).

Hackathon lifecycle

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6','tertiaryColor':'#F8FAFF'}}}%%
stateDiagram-v2
    direction LR
    [*] --> Draft : organizer creates event
    Draft --> Announced : publish
    Announced --> RegistrationOpen : open registration
    RegistrationOpen --> Live : start hackathon
    Live --> Judging : submissions lock
    Judging --> Completed : publish results
    Completed --> [*]
Loading

πŸ‘€ Roles and Permissions

Role How you get it Can do
πŸ‘€ Visitor Not signed in Browse published hackathons, schedules, rules and results
πŸ§‘β€πŸ’» Participant Default account Create or join one team per hackathon, accept invitations, request to join teams, save hackathons
🚩 Team leader Creating a team (or receiving leadership) Invite, approve requests, remove members, transfer leadership, choose the challenge, register, submit
πŸŽ›οΈ Organizer Organizer account verified by an admin, or added as co-organizer Create events, move stages, manage challenges and rubric, review registrations, grant extensions, assign judges, announce, publish results
βš–οΈ Judge Added to a specific hackathon by its organizer Score assigned final submissions, write feedback, declare conflicts of interest
πŸ›‘οΈ Admin Platform role Change roles, suspend accounts (ends their sessions), verify organizers, moderate events, read the audit log
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6'}}}%%
flowchart LR
    V(["πŸ‘€ Visitor"]) -->|sign up| P(["πŸ§‘β€πŸ’» Participant"])
    P -->|creates a team| L(["🚩 Team leader"])
    P -->|added by organizer| J(["βš–οΈ Judge"])
    P -->|organizer account| UO(["⏳ Unverified organizer"])
    UO -->|verified by admin| O(["πŸŽ›οΈ Organizer"])
    A(["πŸ›‘οΈ Admin"]) -.->|verifies and moderates| UO
    A -.->|changes roles, suspends| P
Loading

Rules the server enforces

  • A person can be on only one team per hackathon (database unique constraint), and judges of a hackathon can't join a team in it.
  • Team size limits apply to invitations, joins and registration.
  • Problem statements can have a team limit; the challenge locks after a final submission.
  • Submissions need an approved registration and a live hackathon, and lock at the deadline unless the organizer grants that team an extension.
  • Final submissions require a challenge, a 50+ character summary, a repository link and a demo or video link.
  • The rubric locks once any judge starts scoring, so scores stay comparable.
  • Judges can't score their own team; a conflict declaration removes their draft and notifies organizers.
  • Rankings stay private until the organizer publishes them.

βš–οΈ Scoring

Each judge rates every criterion from 0 to 10. A judge's score is the weighted average

$$ S = \frac{\sum_i w_i , r_i}{\sum_i w_i} $$

and a team's final score is the mean of its submitted evaluations.

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6'}}}%%
flowchart LR
    R["Judge rates each criterion<br/>0 to 10"] --> W["Weighted average<br/>per judge"]
    W --> M["Mean of submitted<br/>evaluations per team"]
    M --> K{"Tie?"}
    K -->|no| RK["Rank"]
    K -->|yes| T["Earlier final submission wins"]
    T --> C{"Still tied?"}
    C -->|no| RK
    C -->|yes| S["Teams share a rank"]
    RK --> AW["πŸ… Awards: top 3 + best per challenge"]
    S --> AW
    M -.->|no evaluations| U["Listed but unranked,<br/>flagged to organizers"]
Loading

πŸ—οΈ Architecture

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6','tertiaryColor':'#F8FAFF'}}}%%
flowchart LR
    subgraph Client["πŸ–₯️ Client Β· React 19 + Vite"]
        UI["Pages and layouts"]
        RQ["TanStack Query"]
        RR["React Router 7"]
        H3D["Hero3D Β· React Three Fiber<br/>lazy-loaded"]
        RTH["Real-time hooks"]
        UI --> RQ
        UI --> RR
        UI --> H3D
        UI --> RTH
    end

    subgraph Server["βš™οΈ Server Β· Node.js + Express"]
        MW["Auth middleware<br/>requireAuth Β· requireRole"]
        RT["Routes<br/>auth Β· events Β· manage Β· teams<br/>judging Β· notifications Β· dashboard Β· admin"]
        LIB["Domain logic<br/>access rules Β· scoring Β· results<br/>notifications Β· uploads"]
        SIO["Socket.IO<br/>user and event rooms"]
        MW --> RT --> LIB
        LIB --> SIO
    end

    DB[("πŸ—„οΈ SQLite<br/>Prisma 7")]
    FS[("πŸ“ uploads/<br/>Multer")]

    RQ -->|"REST /api Β· httpOnly cookie"| MW
    RTH <-->|"WebSocket /socket.io"| SIO
    LIB --> DB
    LIB --> FS
Loading

Authentication flow

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6','actorBkg':'#EDE9FF','actorBorder':'#7058F5'}}}%%
sequenceDiagram
    autonumber
    participant B as Browser
    participant A as Express API
    participant D as SQLite via Prisma

    B->>A: POST /api/auth/login with email and password
    A->>D: Find user by email
    D-->>A: User and Argon2id hash
    A->>A: Verify password with Argon2id
    A->>A: Generate random session token
    A->>D: Store SHA-256 hash of the token
    A-->>B: Set-Cookie httpOnly session token
    B->>A: Later requests carry the cookie
    A->>D: Look up session by token hash
    A->>A: requireAuth then requireRole
    A-->>B: Authorised response
Loading

Submission to results

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6','actorBkg':'#EDE9FF','actorBorder':'#7058F5'}}}%%
sequenceDiagram
    autonumber
    actor L as Team leader
    actor O as Organizer
    actor J as Judge
    participant S as HackSphere API

    L->>S: Register team and choose challenge
    O->>S: Approve registration
    L->>S: Final submission (summary, repo, demo)
    S-->>L: Confetti and confirmation
    O->>S: Assign judges and move stage to Judging
    J->>S: Score each criterion 0 to 10
    S->>S: Weighted average, mean, tie-breaks
    O->>S: Publish results
    S-->>L: Rankings and awards visible
Loading

Conceptual data model

A simplified view of the main entities. The full schema (15 entities plus sessions and reset tokens) lives in server/prisma/schema.prisma.

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6'}}}%%
erDiagram
    USER ||--o{ SESSION : has
    USER ||--o{ NOTIFICATION : receives
    USER ||--o{ TEAM_MEMBER : joins
    USER ||--o{ EVALUATION : writes
    USER ||--o{ AUDIT_LOG : triggers
    HACKATHON ||--o{ CHALLENGE : defines
    HACKATHON ||--o{ RUBRIC_CRITERION : scored_by
    HACKATHON ||--o{ TEAM : hosts
    HACKATHON ||--o{ JUDGE_ASSIGNMENT : assigns
    TEAM ||--o{ TEAM_MEMBER : has
    TEAM |o--o| REGISTRATION : registers
    TEAM |o--o| SUBMISSION : delivers
    CHALLENGE |o--o{ TEAM : chosen_by
    SUBMISSION ||--o{ EVALUATION : receives
Loading

🧰 Tech Stack

Layer Technology Notes
🎨 Frontend React TypeScript Vite SPA with fast HMR
πŸ’… Styling Tailwind CSS Custom design tokens
🧱 Components Radix UI Dialog, tabs, dropdown in a shadcn-style local kit (client/src/components/ui.tsx)
🎞️ Animation Motion motion/react, respects reduced-motion
🧊 3D Three.js Landing hero only, lazy-loaded
πŸ“Š Charts Recharts Dashboards and analytics
πŸ”„ Data TanStack Query React Router Server state and routing
βš™οΈ Backend Node.js Express Zod REST API with Zod validation
πŸ—„οΈ Database Prisma SQLite better-sqlite3 driver adapter
πŸ”‘ Auth Argon2 Sessions Server-managed sessions, SHA-256 token hash in DB
πŸ“‘ Real time Socket.IO Per-user and per-event rooms
πŸ“€ Uploads Multer 15 MB limit, type allow-list, access-controlled downloads
πŸ§ͺ Testing Vitest Testing Library Playwright Unit, component and end-to-end

Note

Prisma 7 needs prisma.config.ts (included) and generates the client into server/src/generated/prisma. npm run setup does this; re-run npm run db:generate after editing schema.prisma.

πŸ“ Project Structure

hacksphere/
β”œβ”€β”€ server/
β”‚   β”œβ”€β”€ prisma/schema.prisma      15 entities + sessions/reset tokens
β”‚   β”œβ”€β”€ prisma/seed.ts            demo data for every stage and role
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ index.ts              HTTP + Socket.IO bootstrap
β”‚   β”‚   β”œβ”€β”€ app.ts                Express app, routes, static client (prod)
β”‚   β”‚   β”œβ”€β”€ middleware/auth.ts    sessions, requireAuth, requireRole
β”‚   β”‚   β”œβ”€β”€ lib/                  access rules, scoring, results, notifications, uploads
β”‚   β”‚   └── routes/               auth, events, manage, teams, judging,
β”‚   β”‚                             notifications, dashboard, admin
β”‚   └── tests/                    scoring unit tests, API smoke test
└── client/
    β”œβ”€β”€ src/
    β”‚   β”œβ”€β”€ index.css             design tokens: palette, glass, clay, neumorphic
    β”‚   β”œβ”€β”€ components/           UI kit, Dialog, Tabs, Toast, Countdown, Confetti,
    β”‚   β”‚                         Hero3D, EventCard
    β”‚   β”œβ”€β”€ layouts/              public layout, app shell with role-aware sidebar
    β”‚   β”œβ”€β”€ auth/                 session context
    β”‚   β”œβ”€β”€ lib/                  API client, types, formatting, real-time hooks
    β”‚   └── pages/                public, auth, app (participant/leader),
    β”‚                             organize, judge, admin
    └── e2e/                      Playwright specs

πŸš€ Getting Started

1. Prerequisites

Tool Version
Node.js 20.19 or newer (22 LTS recommended)
npm 10+
OS Windows, macOS or Linux

Tip

No database server is needed. SQLite is a single file (server/dev.db) that is created for you.

2. Clone

git clone https://github.com/LoganthP/HackSphere.git
cd HackSphere

3. Run it

Open two terminals in the project folder.

Terminal 1: API server

cd server
npm install
cp .env.example .env        # Windows PowerShell: copy .env.example .env
npm run setup               # generates Prisma client, creates dev.db, loads demo data
npm run dev                 # http://localhost:4000

Terminal 2: web app

cd client
npm install
npm run dev                 # http://localhost:5173

Open http://localhost:5173. The dev server proxies /api and /socket.io to port 4000, so cookies and live updates work without extra configuration.

⚑ Shortcut: use the root scripts
npm run install:all     # install server and client dependencies
npm run setup           # prepare the database
npm run dev:server      # terminal 1
npm run dev:client      # terminal 2
npm test                # run tests

4. Sign in with a demo account

Every account uses the password HackSphere@123. On the sign-in page (in development) you can click an account to fill it in.

Role Email What to try
πŸ§‘β€πŸ’» Participant student@hacksphere.dev Accept Ananya's invitation to Null Pointers
🚩 Team leader leader@hacksphere.dev Register Null Pointers, choose a challenge, invite members
πŸŽ›οΈ Organizer organizer@hacksphere.dev Approve registrations, assign judges, publish HealthHack results
βš–οΈ Judge judge@hacksphere.dev Score DoseBuddy and ClinicFlow in HealthHack Sprint
πŸ›‘οΈ Admin admin@hacksphere.dev Verify the Tech Club VVCE organizer, review the audit log
⏳ Unverified organizer techclub@hacksphere.dev See the verification-pending state

5. Explore the seeded hackathons

The seed creates one hackathon at every stage:

Hackathon Stage
🟑 Campus Build Night Announced
🟒 CodeVerse 2026 Registration open
πŸ”΅ GreenGrid Live
πŸ”΄ HealthHack Sprint Judging
🟣 FinTech Forge Completed, results published
βšͺ AI for Bharat Private draft

To start over at any time:

cd server && npm run db:reset

πŸ“œ Scripts

server/

Command Purpose
npm run dev API with auto-reload
npm start API without reload
npm run setup Generate Prisma client, create tables, seed
npm run db:reset Wipe the database and re-seed
npm run db:seed Re-seed only
npm run db:generate Regenerate the Prisma client
npm test Unit tests (scoring, ranking, tie-breaks)
npm run smoke 67 end-to-end API checks across all roles
npm run typecheck TypeScript check

client/

Command Purpose
npm run dev Vite dev server
npm run build Typecheck and production build to client/dist
npm test Component tests (Vitest + Testing Library)
npm run e2e Playwright tests, desktop and mobile

Run npx playwright install chromium once before the first npm run e2e.

Note

npm run smoke needs a fresh seed and the server running.

🎨 Design System

Swatch Token Value Used for
Primary violet #7058F5 (#5A41E6 for buttons, for contrast) Brand, primary actions, focus rings
Electric blue #4285FF "Live now" stage, charts
Coral #FF7890 "Judging" stage, alerts, unread badges
Sunny yellow #FFC857 "Announced" stage, highlights, warnings
Mint #3DCFAE "Registration open" stage, success, progress
Canvas white #F8FAFF Page background
Text navy #202747 Body text
  • Type: Bricolage Grotesque for headings, Figtree for body (bundled, so the app works offline).
  • Bento grid: dashboards and the command center.
  • Glassmorphism: sidebar, top bar, overlays, featured cards.
  • Claymorphism: stat tiles, avatars, podium, empty-state icons, the 3D hero.
  • Neumorphism: toggles, pressed buttons, active nav indicator only.
  • Motion: one orchestrated reveal per screen, spring dialogs, sliding nav indicator, confetti only for registration and final submission. All motion respects prefers-reduced-motion.
  • Accessibility: visible focus rings, skip links, labelled controls with linked error messages, keyboard-operable switches, text colour picked automatically for WCAG contrast on coloured surfaces.

🌍 Deployment

Option A: Single host (simplest)

Build the client and let the API serve it:

cd client && npm run build
cd ../server && NODE_ENV=production npm start      # serves the app and API on :4000

Everything is on one origin, so session cookies work with the default COOKIE_SAMESITE=lax. Put it behind HTTPS (cookies are Secure in production).

Option B: Split hosting

Use a Vercel or Netlify frontend plus a persistent Node host (Render, Railway, Fly.io or a VPS). The host needs a persistent disk for dev.db and uploads/, so serverless functions are not suitable.

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#EDE9FF','primaryBorderColor':'#7058F5','primaryTextColor':'#202747','lineColor':'#5A41E6'}}}%%
flowchart LR
    U(["🌐 Browser"]) --> FE["Vercel / Netlify<br/>static client"]
    FE -->|"rewrite /api/* and /socket.io/*"| BE["Persistent Node host<br/>Render Β· Railway Β· Fly.io Β· VPS"]
    BE --> DB[("SQLite + uploads/<br/>persistent disk")]
Loading
Approach What to do
βœ… Easiest: rewrite Add a rewrite on the frontend host so /api/* and /socket.io/* proxy to your API. The browser sees one site and cookies just work
πŸ”§ Without a rewrite Set VITE_API_URL=https://api.example.com when building the client. On the server set CLIENT_ORIGIN=https://your-frontend.app and COOKIE_SAMESITE=none (requires HTTPS)

Important

SQLite suits a classroom deployment and moderate single-server load. For multiple servers, switch the Prisma datasource to PostgreSQL.

Configuration reference

Variable Where Purpose
PORT server/.env API port (default 4000)
CLIENT_ORIGIN server/.env Allowed frontend origin when split-hosted
COOKIE_SAMESITE server/.env lax for one origin, none for split hosting over HTTPS
NODE_ENV server production serves the built client and sets Secure cookies
VITE_API_URL client build API base URL when not using a proxy or rewrite

πŸ› οΈ Troubleshooting

Problem Fix
"Can't reach the HackSphere server" Start the API (cd server && npm run dev) before using the app
npm install fails building better-sqlite3 or argon2 Use Node 20.19+ or 22 LTS, which have prebuilt binaries. On Windows, re-run the install from a fresh terminal
Cannot find module '../generated/prisma/client' Run npm run db:generate in server/
Port 4000 or 5173 in use Change PORT in server/.env; for the client run npx vite --port 5174 and set CLIENT_ORIGIN to match
Password reset email never arrives There is no mail server in the prototype. The reset link is printed in the API terminal and shown on screen in development
3D shapes on the landing page don't appear The hero needs WebGL; everything else works without it. Slower machines may take a few seconds in dev mode
Want a clean slate cd server && npm run db:reset

About

Role-based hackathon management platform: teams, submissions, weighted judging and live results.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages