FlagForge is built on Next.js 16 with the App Router, written entirely in TypeScript. The platform uses MongoDB for persistent storage, NextAuth v4 for Google OAuth authentication, Tailwind CSS with shadcn/ui for styling, Upstash Redis for token blacklisting, and the Notion API to serve blog and resources content. Understanding this stack helps you navigate the codebase and make contributions confidently.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/flagForgeCTF/flagForge/llms.txt
Use this file to discover all available pages before exploring further.
Technology stack
Next.js 16 (App Router)
All routing, server components, and API routes use the Next.js App Router with TypeScript throughout.
MongoDB + Mongoose
Mongoose schemas define all data models. The database connection is managed in
utils/db.ts.NextAuth v4
Google OAuth authentication with session-based cookies. Configuration lives in
lib/authOptions.ts.Tailwind CSS + shadcn/ui
Utility-first styling with shadcn/ui primitives. Global styles are in
app/globals.css.Upstash Redis
Used for token blacklisting to invalidate sessions on logout. Logic lives in
lib/tokenBlacklist.ts.Notion API
Blog posts and resources are sourced from Notion via
@notionhq/client and notion-to-md.Project structure
The repository follows the Next.js App Router convention. Here is a breakdown of the key directories:The
/app/api/ directory contains all REST API route handlers. Every handler validates the user session before processing a request.Directory reference
| Directory | Purpose |
|---|---|
/app | Next.js App Router pages and layouts |
/app/api | REST API endpoints as Next.js route handlers |
/components | Reusable React components |
/models | Mongoose schemas for MongoDB collections |
/interfaces | Shared TypeScript interfaces and types |
/middleware | Auth middleware (token blacklist, admin checks) |
/utils | Database connection, auth helpers, Discord notifier |
Dynamic flag system
The dynamic flag system is FlagForge’s core feature. It generates a unique, user-specific flag for each challenge so that players cannot share flags with each other.Architecture diagram
Flag generation
When a user starts a challenge, the frontend callsPOST /api/problems/dynamic-flag. The API validates the session, checks whether a flag already exists for that user and question, and either returns the existing flag or generates a new one. Generation reads the challenge’s flag template and applies one of four strategies:
| Type | Description | Example |
|---|---|---|
GUID | Random UUID | flag{1bab71b8-117f-4dea-a047-340b72101d7b} |
TEAM_HASH | SHA256(salt + userId + questionId) | flag{hello_world_5418ce4d815c} |
LEET | Leet-speak transformation | flag{H3ll0_W0r1d} |
CLEET | Complex leet with special characters | flag{H3!!0_W0r!d} |
The
FLAG_SALT environment variable is required for TEAM_HASH generation. Set it to a secure random value in your .env file.Storage and TTL
Generated flags are saved to the DynamicFlag MongoDB collection with aexpiresAt field set 24 hours in the future. A TTL index on expiresAt automatically removes expired documents. A compound index on (userId, questionId) ensures fast lookups during validation.
Validation flow
When a user submits a flag,POST /api/problems/[id] runs the following checks:
- Session check — reject unauthenticated requests
- Duplicate check — reject if the user already solved this challenge
- Dynamic flag check — query the
DynamicFlagcollection for a matching, non-expired document - Fallback to static — if no dynamic flag is found, compare against the challenge’s static flag stored on the
Questiondocument
UserQuestion record, updates the user’s total score, awards points minus any hint penalties, and deletes the used dynamic flag.
API layer
All API route handlers live in/app/api/ and follow the Next.js App Router convention (route.ts files). Every handler begins with a session check — unauthenticated requests receive a 401 response.
Key API groups:
| Route prefix | Responsibility |
|---|---|
/api/auth | NextAuth session endpoints |
/api/problems | Challenge listing, flag generation, flag submission |
/api/leaderboard | Leaderboard data |
/api/admin | Admin-only operations |
/api/profile | User profile reads and updates |
/api/blogs | Notion-backed blog content |
Middleware
FlagForge uses two middleware layers that run on every request:- Token blacklist middleware (
middleware/tokenBlacklist.ts) — checks Upstash Redis for the request’s session token. If the token has been blacklisted (e.g., after logout), the request is rejected. - Admin token middleware (
middleware/adminToken.ts) — verifies a secondary admin token for privileged routes under/api/admin/.
middleware.ts file composes these checks and applies them to the appropriate route matchers.