๐Ÿฆ– RAPTOR
←→ or space to navigate  ·  F fullscreen
๐Ÿฆ– SELF-HOSTABLE · OPEN SOURCE · DOGFOOD BUILD

Raptor runs the whole hackathon.

An open, self-hostable submission & judging platform โ€” built backend-first, so role isolation and deadlines are never optional. docker compose up and there is no cloud account to sign up for.

21+
modules shipped
0
cloud dependencies
T1 T2
tiers verified live
โš ๏ธ THE PROBLEM

Hackathon tooling makes organizers
choose between trust and control.

Every mainstream option asks an organizer to hand over event data, judge scores, and participant trust to somebody else's servers โ€” or to build permission checks that only hold up as long as nobody opens dev tools.

๐Ÿ”’

Vendor lock-in

Cloud-only SaaS tools own the event's data, its judges' scores, and its certificates โ€” with no self-host path out.

๐ŸŽญ

Client-side trust

A permission check that "works" only because a button is hidden or disabled is not a permission check.

๐Ÿ•

Deadline theater

A countdown timer is not a deadline if the server never actually checks it at the moment of the write.

โœ… THE SOLUTION

One platform. The entire lifecycle.
Enforced server-side, every time.

Registration, team formation, submissions, automated verification, judge assignment, weighted + bonus scoring, cross-judge normalization, dense-rank results with genuine tie-sharing, public voting, signed certificates, comments, and a platform-wide leaderboard โ€” on infrastructure an organizer actually controls.

๐Ÿ“ค Submit
→
โœ… Verify
→
โš–๏ธ Assign
→
๐Ÿ“Š Score
→
๐Ÿ“ Normalize
→
๐Ÿ† Publish
→
๐Ÿ“œ Certify
๐Ÿ—๏ธ ARCHITECTURE

Self-hosted, top to bottom.

Plain protocols and self-hosted primitives only โ€” Postgres, Redis, and this code. No cloud database, no auth-as-a-service, no hosted CAPTCHA, no provider-specific mail API.

๐Ÿ”Œ

api · NestJS

The only service web ever talks to. Every scoped guard lives here, server-side, never trusted from the client.

๐Ÿ–ฅ๏ธ

web · Next.js

Purely a client of api over HTTP โ€” no network path to Postgres or Redis exists at all.

โš™๏ธ

worker · BullMQ

A separate process for anything async/slow: submission verification checks and global-ranking recomputes.

๐Ÿ˜

postgres + ๐ŸŸฅ redis

Internal-network-only, zero published host ports, ever, under any configuration.

0
host ports on data tier
1
command to boot everything
100%
TypeScript, one type system

๐Ÿ”‘ Auth & Role Isolation

There is no global "is this user an organizer" check anywhere in this codebase โ€” every privileged route is scoped to one event, resolved from the request path.

๐Ÿ”

Argon2 + hashed tokens

Passwords hashed with argon2. Session, verification, and invitation tokens are random, high-entropy, and stored hashed โ€” the raw value never persists after issuance.

๐Ÿงญ

Per-event RBAC

@RequireEventRole(...) resolves eventId from the path and checks membership for that exact event, not a global role.

โœ‰๏ธ

Verified by design

Email verification, forced password set on a staff account's first login โ€” no dormant unverified accounts with standing access.

๐Ÿ•ต๏ธ

No UI-only gates

A check that "works" only because a button is hidden client-side does not count โ€” guards are tested by calling the route directly.

๐Ÿ“… Event Lifecycle & Deadlines

12 real phases, not a single status flag โ€” and every deadline is checked against server time, at the moment of the write.

Registration
→
Building
→
Submissions
→
Judging
→
Results
→
Voting
โฑ๏ธ

Never a client timestamp

A disabled button, a countdown timer, or a forged submittedAt field is never trusted as a substitute for a real server check.

๐Ÿ”

Re-checked on every write

Not just on page load โ€” every single mutating request re-validates the current phase before it's allowed to happen.

๐Ÿ‘ฅ Team Management

Form a team in seconds, with a roster that locks the instant it matters.

๐Ÿ”—

Shareable invite link

Create or join a team with one link โ€” no email round-trip required to get a squad together.

๐Ÿ› ๏ธ

Roster management

Kick a member, regenerate the invite link โ€” full control while the team is still forming.

๐Ÿ”’

Permanent lock on submit

The roster locks the moment the team submits โ€” keyed directly off the submission record, not a separate timer.

๐Ÿ“ค Submissions & Public Gallery

Public-by-default โ€” the gallery is viewable with no login at all.

๐Ÿ”„

Draft → submit → resubmit

Unlimited resubmission right up until the deadline โ€” no penalty for iterating.

๐Ÿ”

Searchable, filterable

The public gallery supports real text search and track filtering โ€” not just a static list.

๐Ÿ›ก๏ธ

Content-verified uploads

Files are validated by actual magic bytes, never extension or client MIME type, and re-encoded server-side before storage.

โœ… Automated Verification

Every submission is checked against its real GitHub repo before a judge ever sees it.

๐Ÿ™

Real GitHub repo check

An async check runs against the submitted repository on a separate BullMQ worker process โ€” never inline with the request, never blocking the submit.

๐Ÿšฆ

Organizer approval gate

An organizer explicitly approves or disqualifies a submission before it reaches judging โ€” verification informs a human, it never auto-decides.

๐Ÿ”‘

Encrypted access token

An admin-supplied GitHub token is AES-256-GCM encrypted at rest โ€” never stored as raw, usable plaintext.

๐Ÿ“Œ

Documented timestamp source

Verification reads one specific, documented timestamp (commit or push time) against the event window โ€” not a forgeable client value.

โš–๏ธ Judge Assignment

Manual or algorithmic โ€” and once a judge scores a project, that assignment is permanent.

๐ŸŽฏ

Manual or algorithmic

Assign by hand for a small event, or let the algorithm balance load across judges automatically.

๐Ÿ“

Per-judge caps

A configurable cap per judge, with an explicit organizer override when real life needs an exception.

๐Ÿ”

No-show reassignment

A judge who never shows can be reassigned cleanly โ€” but only before they've actually submitted a score.

๐Ÿ”’ Locks permanently on first score

๐Ÿ“Š Scoring & Rubric

Organizer-defined, weighted, and never silently overwritten.

โš–๏ธ

Weighted rubric

Organizers define the exact criteria and weights a judge scores against โ€” no one-size-fits-all rubric.

๐ŸŒŸ

Bonus tracks & awards

Optional bonus-track scoring plus special-award nominations, layered on top of the core rubric.

๐Ÿ—‚๏ธ

Immutable revision history

A judge can revise a score any number of times โ€” every prior version is kept, never overwritten.

๐Ÿ“ Cross-Judge Normalization

One harsh judge, or one generous one, can't quietly decide a whole event's outcome.

๐Ÿ“ˆ

Per-judge z-score calibration

Every judge's scores are calibrated against their own scoring history, with a documented fallback for judges with too little data.

๐Ÿ”’

Locks when results go live

The normalization method is permanently locked the moment results are published โ€” no retroactive method-shopping.

๐Ÿงฎ Independently re-derived & proven โ€” NORMALIZATION.md Bonus: Normalization Proof โ€” Claimed

๐Ÿ† Results & Dense-Rank Leaderboard

Genuine ties share a place. Never an arbitrary coin-flip tiebreak.

๐Ÿฅ‡

Dense ranking

Two teams with the identical score both show rank 1 โ€” the next real rank is 2, not 3.

๐Ÿ“

Draft → publish

Results are staged as a draft, reviewed, then explicitly published โ€” never live by accident.

๐Ÿงพ

Audited corrections

Any post-publish correction is fully logged โ€” what changed, by whom, and why.

Same tie-rendering shared between the full leaderboard and its homepage teaser โ€” one component, not two

๐Ÿ—ณ๏ธ Public Voting

A real audience ballot โ€” without handing anti-abuse to a third party.

โœ…

Single-choice ballot

A curated shortlist, one vote per verified voter, per round.

๐Ÿงฉ

Self-hosted proof-of-work

Anti-Sybil / anti-ballot-stuffing CAPTCHA, computed and checked entirely in-house โ€” zero third-party CAPTCHA dependency, by design.

๐Ÿ™ˆ

Tallies hidden mid-round

Results stay hidden until the round actually closes, so an early leader can't sway the votes still coming in.

๐Ÿ“œ Signed Certificates

A certificate that can actually prove it's real.

๐Ÿ”

Ed25519 signed

Every participation and winner certificate is cryptographically signed โ€” not just a PDF that claims to be official.

๐Ÿงช

Independently verifiable

Anyone can verify a certificate's signature โ€” the download and the live web view run the exact same verification code path.

๐Ÿ–ผ๏ธ

Public certificate gallery

Earned certificates are browsable publicly โ€” a real, checkable record, not a private download link.

๐Ÿ’ฌ Comments & ๐ŸŒ Global Ranking

Discussion that's safe to render, and a reputation that follows you across events.

๐Ÿงผ

Sanitized, threaded comments

One shared sanitization code path, used identically everywhere content renders โ€” preview, production, certificate view, download โ€” never two implementations that could silently drift.

๐ŸŒ

Platform-wide leaderboard

A single ranking across every event a person has ever competed in, with its own tie-break rules and a per-person history drill-down.

๐Ÿ–ฅ๏ธ Organizer Shell & ๐ŸŽญ Demo Mode

One dashboard to run the whole event โ€” and one flag to try the whole lifecycle risk-free.

๐Ÿ—‚๏ธ

Unified admin shell

Event setup, verification queue, assignment board, scoring oversight, results publishing, CSV export, and a per-event audit-log viewer, all in one place.

๐ŸŽญ

DEMO_MODE=true

Spins up a fully isolated sandbox database with four events spanning the whole lifecycle โ€” real event data is never touched, under any circumstance, while it's on.

๐Ÿ›ก๏ธ Security, By Default

Nine non-negotiable rules, enforced everywhere โ€” not just where it was convenient.

01

Authorization is server-side, always. If it "works" only because a button is hidden client-side, it does not work.

02

Deadlines checked against server time, at the moment of the write โ€” never a client timestamp.

03

Nothing sensitive stored raw โ€” argon2 passwords, hashed session & invitation tokens.

05

Every privileged action is audit-logged โ€” role changes, invitations, publishing, admin bypasses.

06

Zero third-party hosted dependency, ever โ€” no cloud DB, no auth-as-a-service, no hosted CAPTCHA.

๐Ÿ›ก๏ธ Bonus: Threat Model โ€” ClaimedSybil votes · ballot stuffing · scraping · judge collusion · deadline gaming

๐Ÿ… Tiers Claimed โ€” Verified, Not Assumed

Flipped to true only once a tier's acceptance checks have actually passed against the organizers' own run.py โ€” never claimed ahead of that.

T1
โœ…
Core โ€” verified live
T2
โœ…
Judging โ€” verified live
T3
๐Ÿ•“
Public โ€” human review
T4
๐Ÿ•“
Stretch โ€” human review

$ python run.py .dogfood.toml --fixtures apps/api/prisma/fixtures.json
T1 gallery is public ................. PASS
T2 judge cannot see peer scores ...... PASS
claimed T1 T2, verified T1 T2

๐Ÿงฉ Built, Tested, Documented

Every module's stage doc ends with its own "what I'm testing" list โ€” treated as a minimum, not a suggestion.

21+
modules shipped
512
backend tests passing
9
non-negotiable principles
0
cloud dependencies
TypeScript everywhere NestJS Next.js Prisma + Postgres Redis + BullMQ Docker Compose Ed25519 Argon2 AES-256-GCM
๐Ÿ™Œ CREDITS

Built by two teams,
shipped as one platform.

Four-Eyed Gems logo
Four-Eyed Gems
Collaborating team
beTheNoob logo
beTheNoob
Collaborating team