This guide will help you set up Forge locally and make your first contribution.
Knight Hacks Dev Team Members: You'll have access to shared environment variables and private channels.
External Contributors: You're welcome to contribute! You'll need to set up your own credentials for certain features, but most of the app works without them.
Before you begin, ensure you have the following installed:
- Node.js LTS (v20.16.0 or higher)
- pnpm (v9.6.0 or higher)
- Docker Desktop
- A POSIX/Unix terminal (Linux, macOS, or WSL for Windows users)
git clone https://github.com/KnightHacks/forge.git
cd forgepnpm installCreate a .env file in the repository root.
You have access to the shared environment variables document in Notion. Copy those values into your .env file.
If you don't have access, you need a Knight Hacks email. Reach out to secretary@knighthacks.org to get access.
You'll need to set up your own credentials. Use .env.example as a template.
Minimum Required Setup:
To open the app locally, you need Discord OAuth credentials:
- Go to the Discord Developer Portal
- Create a new application
- Get your Client ID and Client Secret
- Add these to your
.envfile
Optional Services (for specific features):
You only need these if you're working on the corresponding features:
- Events Pages (hack or club): Google Cloud Platform project with Calendar API enabled. Get the JSON credentials and add to
.env - Email Functions: Set up Listmonk (self-hosted or cloud) and get access keys
- S3/Object Storage: Set up MinIO (self-hosted or cloud) and get access keys
See .env.example for all required environment variable names.
Start the local Postgres database with Docker:
docker compose upIMPORTANT!
You must apply the committed migrations to your local database before running the project. This is a common source of errors for new contributors. The most common symptom is a "Failed to get current session" error on Blade pages.
pnpm db:migrateWhen you change files in packages/db/src/schemas, generate a new migration and commit it:
pnpm db:generatePull requests with schema changes are expected to include the generated files in packages/db/drizzle/. CI verifies that migrations are committed, that they apply on a fresh database, and that they can upgrade a prod-like sanitized dataset.
Optional: View the database contents with Drizzle Studio:
pnpm db:studioThis opens a GUI at local.drizzle.studio.
If you need to work on admin-level pages or test permission-based features, you'll need superadmin access. This requires a one-time bootstrap step.
Why is this needed?
Forge uses a role-based permission system. To access admin features, you need a role with permissions. But to create roles, you need admin access. This creates a chicken-and-egg problem for fresh databases. The bootstrap script solves this by directly inserting a superadmin role into the database.
How to bootstrap:
- Start the database and run Blade at least once
- Log in to Blade using Discord OAuth (this creates your user record)
- Get your Discord user ID (right-click your profile in Discord with Developer Mode enabled)
- Choose any Discord role ID to link to the superadmin role (this is just metadata stored in the database)
- Run the bootstrap script:
pnpm db:bootstrap <discord-role-id> <discord-user-id>Example:
pnpm db:bootstrap 1321955700540309645 238081392481665025After running this, you'll have full superadmin permissions and can manage other roles through the Blade UI.
Dev Team Members Only: If you have access to the shared MinIO instance, you can pull a sanitized copy of production data to test with realistic data locally. This restores data into the database currently pointed to by DATABASE_URL, so make sure you have already run pnpm db:migrate first.
pnpm db:pullThis downloads and inserts production data into your local database without removing existing data (like your superadmin role).
If you want to completely replace your local database with the production snapshot:
pnpm db:pull --truncateNote: You can run the superadmin bootstrap script after pulling production data if needed.
pnpm devThis starts all apps concurrently. Each app will be available at its own port.
pnpm dev --filter=@forge/bladeReplace @forge/blade with any app name.
When running the apps, they will be available at the following ports:
| App | Package Name | Port | URL | Description |
|---|---|---|---|---|
| Blade | @forge/blade |
3000 | http://localhost:3000 | Main monolithic app (membership, hacker registration, dues, events) |
| Club | @forge/club |
3001 | http://localhost:3001 | Club site (frontend only) |
| 2025 | @forge/2025 |
3002 | http://localhost:3002 | Knight Hacks VIII 2025 hackathon site (frontend only) |
| Guild | @forge/guild |
3003 | http://localhost:3003 | Member networking site (Knight Hacks LinkedIn) |
| GemiKnights | @forge/gemiknights |
3005 | http://localhost:3005 | GemiKnights 2025 hackathon site (frontend only) |
| TK | @forge/tk |
N/A | N/A | Discord bot for Knight Hacks server |
| Cron | @forge/cron |
N/A | N/A | Cron job server |
Most features work out of the box with just Discord OAuth configured.
Features that require additional setup:
- Events pages (hack or club) - requires Google Calendar API
- Email sending - requires Listmonk
- File uploads/S3 operations - requires MinIO
Look for issues labeled Onboarding on GitHub. These are beginner-friendly tasks designed for new contributors.
- Before getting started developing, make sure you understand our GitHub Etiquette
- Create a new branch for your changes
- Make your changes
- Test your changes locally
- Run checks before submitting:
If you changed any schema files, also run
pnpm db:migrate pnpm format pnpm lint pnpm typecheck pnpm build
pnpm db:generateand commit the generated migration files. - Commit your changes (use lowercase, descriptive commit messages)
- Push your branch and open a pull request
See CONTRIBUTING.md for detailed guidelines on commits, pull requests, and testing.
Ask questions in the private dev team Discord channel.
Ask questions in the Knight Hacks Discord server.
You can also join the broader Knight Hacks community Discord for general support.
Make sure Docker is running and the Postgres container is up:
docker compose psIf the container isn't running, start it with docker compose up.
If a port is already in use, stop the conflicting process or change the port in the app's configuration.
Make sure you're using the correct versions:
node --version # Should be >= 20.16.0
pnpm --version # Should be >= 9.6.0Now that you're set up, explore the codebase:
- Check out the Architecture Overview to understand how everything fits together
- Look at the API & Permissions guide for backend development guidelines
- Read our GitHub Etiquette guide for how to contribute to the project