The Beest codebase is what runs on https://beest.hackclub.com. That website is the You Ship We Ship platform allowing participants to sign in, create and share projects, recieve feedback and earn prizes through the shop.
This is a monorepo with two applications:
| Layer | Stack | Role |
|---|---|---|
backend/ |
NestJS 11, TypeORM, PostgreSQL | Single source of truth - all auth, business logic, and data access |
frontend/ |
SvelteKit 2, Svelte 5 | Thin proxy - renders UI, sets cookies, forwards requests to the backend |
git clone https://github.com/hackclub/beest
cd beest
# Start the database
docker compose -f docker-compose.dev.yml up -d
# Backend
cd backend
npm install
cp .env.example .env # fill in credentials
npm run migration:run
npm run start:dev # runs on :3001
# Frontend (in a second terminal)
cd frontend
npm install
npm run dev # runs on :5173# Airtable
AIRTABLE_API_KEY=
AIRTABLE_BASE_ID=
AIRTABLE_TABLE_NAME=
# Hack Club Auth OAuth
CLIENT_ID=
CLIENT_SECRET=
REDIRECT_URI=http://localhost:5173/oauth/callback
# JWT & encryption
JWT_SECRET=
DB_ENCRYPTION_KEY= # 32-byte hex string for AES-256-GCM
# Hackatime OAuth
HACKATIME_CLIENT_ID=
HACKATIME_CLIENT_SECRET=
HACKATIME_REDIRECT_URI=http://localhost:5173/auth/hackatime/callback
HACKATIME_BASE_URL=https://hackatime.hackclub.com
# Database
DATABASE_URL=postgresql://postgres:password@localhost:5432/postgres
# Slack
SLACK_BOT_TOKEN=BACKEND_URL=http://localhost:3001docker compose up --buildBoth backend/ and frontend/ have their own multi-stage Dockerfiles (Node 22 Alpine). Point DATABASE_URL at your PostgreSQL instance and set all backend env vars.
| Service | Internal Port |
|---|---|
| Frontend | 3000 |
| Backend | 3001 |
| PostgreSQL | 5432 |
All endpoints live under the backend at /api. Auth-protected routes require a Bearer JWT in the Authorization header.
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/api/health |
GET | — | Health check |
/api/auth/start |
POST | — | Begin OAuth flow |
/api/auth/handle-callback |
POST | — | Complete OAuth, issue tokens |
/api/auth/refresh |
POST | — | Rotate refresh token |
/api/auth/me |
GET | JWT | Current user claims |
/api/auth/logout |
POST | — | Invalidate session |
/api/auth/rsvp |
POST | JWT | RSVP using authenticated session |
/api/auth/scope |
GET | JWT | Check user permissions |
/api/rsvp |
POST | — | Submit an RSVP |
/api/hackatime/start |
POST | JWT | Begin Hackatime OAuth |
/api/hackatime/callback |
POST | JWT | Complete Hackatime OAuth |
/api/hackatime/projects |
GET | JWT | User's Hackatime project names |
/api/projects |
GET | JWT | List user's projects |
/api/projects |
POST | JWT | Create a project |
/api/projects/:id |
PATCH | JWT | Update a project |
/api/projects/:id |
DELETE | JWT | Delete a project |
/api/projects/hours |
GET | JWT | Hackatime hours breakdown |
/api/leaderboard |
GET | JWT | Top 10 users by approved hours |
/api/onboarding/status |
GET | JWT | Onboarding step completion |
/api/onboarding/two-emails |
POST | JWT | Confirm different Slack email |
/api/onboarding/sticker-link |
GET | JWT | User's unique sticker form link |
/api/audit-log |
GET | JWT | User's audit log entries |
/api/admin/users |
GET | Admin | List all users |
/api/admin/users/:id |
GET | Admin | Get specific user |
/api/admin/users/:id/ban |
POST | Admin | Ban a user |
/api/admin/users/:id/perms |
PATCH | Admin | Update user permissions |
Made with <3 by euan , give it a ⭐