Back to blog
Building a Separate Admin Panel on the Same API (Without Leaking Access)
When Peeksy started getting real users, we needed a way to see what was happening: signups by day, plan distribution, top links, flagged accounts. The usual operator-level view.
The options we considered:
- A separate admin API service
- A separate database read replica with a BI tool on top
- Admin routes bolted onto the existing API
We went with option 3. Here's how we did it cleanly, and where the traps are.
The guard structure
Every admin route in Peeksy sits under /admin/*. Before anything reaches a route handler, two middleware layers run:
Layer 1 — JWT auth. Same middleware as every other authenticated route. Verifies the Bearer token, decodes the user ID, attaches it to context. Nothing special here.
Layer 2 — Admin check. A separate middleware that reads is_admin from the users table for the authenticated user ID. If it's false, the request gets a 403 immediately.