Next.js 16 + TypeScript + Turbopack implementation for a Rust game server whitelist website. The app includes a public whitelist request flow, applicant decision emails, an admin-only moderation panel behind Google OAuth, PostgreSQL persistence via Prisma, SMTP notifications, Steam profile resolution, and a secure RCON approval path.
- Next.js App Router with TypeScript
- Turbopack for local development
- Prisma with PostgreSQL
- NextAuth with Google OAuth and admin email allowlist
- Nodemailer for SMTP delivery
- Steam Web API integration for vanity URL and profile resolution
- RCON dispatch for server-side whitelist approval
Copy .env.example to .env and configure:
DATABASE_URLAPP_URLGOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRETAUTH_SECRETADMIN_ALLOWLISTADMIN_NOTIFICATION_EMAILSSTEAM_API_KEYSMTP_HOST,SMTP_PORT,SMTP_SECURE,SMTP_USER,SMTP_PASS,SMTP_FROMRCON_HOST,RCON_PORT,RCON_PASSWORD,RCON_TIMEOUT_MS,RCON_WHITELIST_COMMAND_TEMPLATE
Create a PostgreSQL database that matches the name in DATABASE_URL.
Example with a dedicated local PostgreSQL user:
psql -U postgres -h localhostThen run:
CREATE USER rust_user WITH PASSWORD 'replace-with-a-strong-password';
CREATE DATABASE rust_whitelist;
GRANT ALL PRIVILEGES ON DATABASE rust_whitelist TO rust_user;To make sure that user can use the public schema inside the database, connect to the new database and grant schema access:
psql -U postgres -h localhost -d rust_whitelistGRANT ALL ON SCHEMA public TO rust_user;
ALTER SCHEMA public OWNER TO rust_user;After that, set DATABASE_URL in .env to match the new user:
DATABASE_URL="postgresql://rust_user:replace-with-a-strong-password@localhost:5432/rust_whitelist"
If your PostgreSQL host, port, username, password, or database name is different, change the connection string accordingly.
After the database exists, apply the schema:
npm run prisma:generate
npm run db:pushTo wipe the database and recreate it from the current Prisma schema, run:
npx prisma db push --force-resetThis deletes all existing data.
If you want the usual follow-up steps afterward:
npm run prisma:generate
npx prisma db push --force-reset
npm run buildThis project uses Google OAuth for admin sign-in.
- Open the Google Cloud Console.
- Create or select a project.
- Go to
APIs & Services->OAuth consent screenand configure the app. - Go to
APIs & Services->Credentials. - Click
Create Credentials->OAuth client ID. - Choose
Web application. - Add your authorized origins. Local development example:
http://localhost:3000
- Add your authorized redirect URIs. Local development example:
http://localhost:3000/api/auth/callback/google
- Copy the generated values into
.env:
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
For production, also add your live domain and live callback URL.
npm install --legacy-peer-deps
npm run prisma:generate
npm run db:push
npm run devOpen http://localhost:3000.
Make sure your production .env is configured first, especially:
APP_URLset to your live domainDATABASE_URLpointing to your production PostgreSQL databaseGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETAUTH_SECRET- SMTP settings
- RCON settings
Before starting the app, make sure the production database schema is applied:
npm install --legacy-peer-deps
npm run prisma:generate
npm run db:pushThen build and start the production server:
npm run build
npm run startBy default, Next.js will serve the app on port 3000.
If you are running behind a reverse proxy or Cloudflare Tunnel, point that service at your running Next.js server.
For Google OAuth in production, remember to add your live site values in Google Cloud:
Authorized origin: https://your-domain.example
Authorized redirect URI: https://your-domain.example/api/auth/callback/google
/landing page/requestpublic whitelist request form/sign-inadmin login page/adminadmin dashboard/admin/requests/[id]admin-only request detail route for internal sharing
- A player submits an email address, a Steam profile URL, and a reason for joining.
- The server normalizes the profile URL, resolves SteamID64, stores the request, and emails the admins.
- Admins review the request from the dashboard or direct request route.
- Approval sends the configured RCON whitelist command using the resolved SteamID64.
- Applicants receive an approval or rejection email, with an optional admin-written message.
- The public form accepts Steam community profile URLs only.
- Applicant emails cannot be reused while another request is pending or approved.
- Rejected applicant emails have a 24-hour cooldown before they can be used again.
- Admin access is limited to Google accounts present in
ADMIN_ALLOWLIST. - Approval is blocked until a valid SteamID64 is available.
- RCON credentials remain server-side and are never exposed to the client.
npm run devnpm run buildnpm run lintnpm run prisma:generatenpm run db:pushnpm run db:studio