The Camp StaffHub
Staff and member platform for a 330K-member Discord community.
Public landing page. The tools need staff sign-in.
- Community
- 330K+ members
- In voice
- 100+ at a time
- Hosting
- Self-managed VPS
- Live since
- Sep 2026
The Camp bills itself as the most active voice server on Discord. Its staff needed one place to log moderation reports and appeals, manage ranks and see who is actually doing the work, instead of spreadsheets and pasted messages.
I designed, built and run that platform end to end: the schema, sign-in, admin tools, the integration with the community's Discord bot, hosting, backups and deploys. It later grew a member-facing side with points, levels and collectible profile cards.


Staff
Discord sign-in
whitelist-gated
nginx
TLS, rate limits
Next.js on PM2
App Router, cluster
PostgreSQL
Prisma
Bot
Discord bot
?card, ?rank, role changes
Bot API
points, levels, cards
Chromium renderer
PNG or animated GIF
Cache
saved card versions
What it does
The parts worth talking about
Reports and appeals
Staff file reports and appeals through validated forms that post formatted embeds to the right Discord channels via webhooks, with an excuse-note system and a searchable, point-based rules checklist beside them.
Moderator accountability
Mod points, a leaderboard for any month or year, and a Mod Audit tool that exports a day-by-day calendar workbook (.xlsx), replacing a manual Excel-tallying routine.
A member economy
Points, chat and voice XP, levels with role rewards, achievements, a card shop and a sticker draw. XP boosts stack without ever touching points, and a test script checks that the points paid are identical with and without them.
Profile cards rendered on demand
The bot asks the site for a member's card and a warm headless Chromium renders it to a PNG or an animated GIF, then caches it. A layout checker measures every card across nine themes; it found 12 layout problems and now reports none.
A two-way bot bridge
The bot polls the site's API for points and levels, while a loopback-only HTTP bridge lets the site call into the bot, so changing an Internal Affairs status grants or revokes the matching Discord role almost instantly.
Operations I own
PM2 cluster behind nginx with rate limiting, Let's Encrypt, nightly AES-256 encrypted backups to the VPS and Google Drive with a tested restore, and BBR congestion control that fixed stalled image downloads for members in the Philippines.
What went wrong
Incidents that changed how I work
Each of these reached production. Each one is now a rule or an automated check.
A reload that only reloaded one app
A combined `pm2 reload a b` restarted just the first process, so the bot's API ran day-old code for about 34 hours. The deploy script now restarts each app as its own command and checks that every process has a fresh uptime.
The silent CSS 404
The card renderer is its own `next start` process and kept serving references to hashed stylesheets that a newer build had deleted. The site looked fine; only card images lost their layout. The renderer is now restarted by every deploy and a check fetches its CSS.
A deploy that deleted files
An rsync flag deleted files it shouldn't have. Deploys now ship `git archive HEAD` through a plain tar extract that never deletes anything on the server, behind a clean-tree check and a database backup.
Stack
Built with
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS 4
- Prisma 7
- PostgreSQL
- Auth.js (Discord OAuth)
- Playwright
- sharp
- ExcelJS
- zod
- PM2
- nginx