HackQ: One Command Center for Hackathon Chaos
Inspiration
Every hackathon, the pattern repeats: your team is spread across four or five tabs — Discord for chat, Miro for ideas, Trello for tasks, a shared doc for deadlines, and yet another app to know who's doing what. The countdown to submission is ticking, and someone always misses a message. We wanted to ask: what if a hackathon team had one place — one beautifully focused workspace — where the chat, the idea board, the task board, the deadline, and the team itself all lived together?
So we built HackQ: a realtime command center designed specifically for the 24–48 hours of a hackathon. Dark, motion-heavy, and built to feel premium — because the tool you stare at during the final hours should make you want to keep working.
What it does
- Landing page with a liquid cursor, scroll-driven reveals, and a hosted hero video.
- Auth — signup/login with email verification, plus a built-in breach check: every new password is tested against HaveIBeenPwned's 5-billion-password database before the account is created.
- Rooms — create or join a team via a shareable invite code or a clean URL (
/room/night-owl). Joining requires lead approval; non-members only ever see a private wall. - Workspace modules:
- Chat — realtime text and voice notes (recorded in-browser, rendered as waveform bubbles).
- Idea board — a FigJam-style infinite canvas with pan/zoom, sticky notes, and live presence cursors.
- Tasks — a Notion-style board with status, priority, assignees, and due dates.
- Mood check-ins — one-tap team vibe radar.
- Team & roles — live roster, permissions matrix, and a custom-role studio with per-capability toggles.
- Control centre — live countdown ring, settings, approvals, ownership transfer, leave, and disband.
- A rooms dashboard after login — if you're in multiple teams, you pick where you're headed instead of getting dumped into the last room.
How we built it
Architecture. Next.js 16 (App Router) + TypeScript on the front, Supabase on the back: PostgreSQL with Row-Level Security on every table, Supabase Auth for sessions, and Supabase Realtime for live updates. The whole data layer sits behind security-definer RPCs and RLS policies shipped as eight versioned migrations (0001 schema → 0008 function lockdown).
Design system. A matte-black, noise-textured aesthetic with animated beams, custom-built on Tailwind 4 with Motion, GSAP, and Lenis. The dotted-map background is the open-source Magic UI DottedMap component — we extended and hardened it for our theme.
The security journey was the most interesting build. We audit-tested the app like attackers:
- Invite-code enumeration: any signed-in user could read every team's invite codes through the REST API. Fixed by restricting
teamsSELECT to members and moving all lookups into security-definer RPCs that return only the minimum fields. - Membership bypass: anyone could insert themselves into any team they knew the id of. We removed the self-insert path entirely — membership now requires lead approval, enforced in SQL.
- Open redirects:
?next=parameters were sanitized with a same-origin guard. - Capability enforcement: custom-role permissions are enforced server-side with a
team_can()RLS helper, not just hidden in the UI. - A Pro-plan paywall: Supabase's "leaked password protection" is paid — so we built the same check for free using HaveIBeenPwned's k-anonymity API. The password is SHA-1-hashed and only 5 hex characters are ever sent:
$$\text{prefix} = H(\text{password})[:5], \qquad |\text{prefix}| = 20 \text{ bits}$$
The full hash is matched locally against the returned suffixes — the password never leaves the browser, and the whole check costs nothing.
Challenges we ran into
- RLS is a trap if you don't know the rules. We learned that revoking
EXECUTEon a helper function used inside RLS policies breaks every query in the app — and that security-definer functions are exposed as public RPC endpoints by default. Both cost us real debugging time. - Hydration mismatches. The liquid cursor and the login-error state were client-only, so React's server HTML disagreed with the first client paint. Fixing it properly (mount gates + server-rendered search-param state) taught us a lot about SSR.
- Voice-note playback. Reusing one
<audio>element across notes hit a classic Chromium footgun — assigningsrcwithoutload()left the element in a stale state whereplay()resolved but nothing was heard. We now reset +load()explicitly and wait forcanplaythrough. - Performance on cheap laptops. The full-viewport goo filter re-rasterized on every pointer move; the dotted map re-rendered 5,000 dots per frame. We added device-performance fallbacks, froze the map, and debounced realtime refetches so bursts don't re-download history.
- Ownership transfer. A plain
UPDATE teams SET owner_id = …is rejected by RLS becauseWITH CHECKre-evaluates on the new row — so the handover runs in a security-definer RPC that verifies the rules itself, atomically.
Accomplishments that we're proud of
- A genuinely security-hardened realtime app — RLS everywhere, zero known attack surface left open after a full audit.
- A free replacement for a paid security feature (breach checking) done the privacy-first way.
- The idea board: realtime presence cursors, FigJam-style dragging, and container-query-aware layout.
- Voice notes with in-browser recording and waveform rendering — no backend audio processing needed.
- A design that made a hackathon tool feel like a premium product, from the liquid cursor to the countdown ring with its honest "seconds hand."
What we learned
Next.js App Router and React 19 server/client boundaries; Supabase RLS, security-definer functions, and Realtime; motion design that stays performant; the k-anonymity trick for privacy-preserving APIs; and — most of all — that security is a feature you build in, not bolt on. Every EXECUTE grant, every policy expression, and every URL parameter deserves scrutiny.
What's next for HackQ
Onboarding with team-size and event presets, calendar sync for submission deadlines, task-to-idea linking, and push notifications for approvals. Long-term: make HackQ the default first tab for every hackathon team.
Built With
- api
- audio
- auth
- canvas
- css
- git
- gsap
- haveibeenpwned
- html5
- javascript
- mediarecorder
- motion
- next.js
- postgresql
- react
- realtime
- rest
- security
- supabase
- tailwind
- typescript
- vercel
- web
- websockets
Log in or sign up for Devpost to join the conversation.