Admin Panel Overview
Location: apps/admin/
Tech stack: Next.js 15 + Ant Design 5 + TanStack Query + React Router v6
The admin panel is a warm parchment-themed SPA (#F7F4ED background) used by moderators and admins for content moderation, user management, governance, and platform analytics.
Base URL: https://admin.regulus.app (Vercel deployment) API base: All calls go to GET /api/v1/admin/* unless noted.
Authentication
Login via POST /identity/login with role = 'admin' or role = 'moderator'. JWT stored in memory (AuthProvider). ProtectedShell redirects to /login when unauthenticated.
Pages
Dashboard (/)
Endpoints used:
GET /admin/metrics— cached 30s server-side
Metrics shown:
users— total registered userspostsTotal— all postsinvitesActive— active invite codesreportsOpen— unresolved reportspostsHidden— moderator-hidden postsrepliesHidden— moderator-hidden repliesmauActive— monthly active users
Attention queue: shows when reportsOpen + postsHidden + repliesHidden > 0.
Invite Codes (/invite-codes)
Endpoints: GET /admin/invite-codes, POST /admin/invite-codes/generate, POST /admin/invite-codes/:id/revoke
Columns: code, status, generated by, reserved until, used by, used at, expires at. Actions: Revoke active codes, generate admin-issued codes.
Users (/users + /users/:id)
Endpoints: GET /admin/users, GET /admin/users/:id, POST /admin/users/:id/ban, POST /admin/users/:id/unban, PATCH /admin/users/:id/role
List: id, username, email, role, banned status, created at, post/circle count. User detail (/users/:id):
- Profile info
- Role selector (user/moderator/admin)
- Ban/unban with reason
- Reputation history
- Invite tree position
- Posts list
Circles (/circles)
Endpoints: GET /admin/circles, DELETE /admin/circles/:id
Columns: id, owner, kind, name, member count, created at. Actions: Delete circle (admin only, emits audit log entry).
Posts (/posts)
Endpoints: GET /admin/posts, POST /admin/posts/:id/hide, POST /admin/posts/:id/unhide, DELETE /admin/posts/:id
Columns: title, author, format, interest, visibility, depth, journalism, boost score, reactions, replies, created at, hidden. Filters: format, interest, visibility, journalism, hidden only. Actions: Hide/unhide, soft-delete.
Replies (/replies)
Endpoints: GET /admin/replies, POST /admin/replies/:id/hide, POST /admin/replies/:id/unhide
Columns: body snippet, kind, author, post, created at, hidden. Actions: Hide/unhide.
Reports (/reports)
Endpoints: GET /admin/reports, POST /admin/reports/:id/review, POST /admin/reports/:id/dismiss
Columns: target type/id, reason, reporter, status, created at. Filters: status (open/reviewed/dismissed), target type. Actions: Review (sets reviewed_by + timestamp), Dismiss.
Reputation (/reputation)
Endpoints: GET /admin/reputation/events, POST /admin/reputation/adjust, GET /admin/reputation/appeals, POST /admin/reputation/appeals/:id/resolve
Tabs:
- Events: Reputation ledger across all users.
- Adjust: Manual rep adjustment
{ userId, interestId, delta, note }. - Appeals: Pending/accepted/rejected appeals. Resolve with optional
restoreDelta. - Peer Votes:
GET /admin/reputation/votes— view all peer votes for moderation.
Contribution (/contribution)
Endpoints: GET /admin/contribution
Shows top contributors by score. Columns: user, total score, breakdown by kind.
Economy (/economy)
Endpoints: GET /admin/economy/wallets, GET /admin/economy/payments
Tabs:
- Wallets: All wallets sorted by balance. Columns: user, balance, lifetime_earned, lifetime_spent.
- Payments: Payment ledger. Columns: sender, receiver, emotion, tier, amount, post, reversed, created at.
Audit Log (/audit-log)
Endpoints: GET /admin/audit-log
All privileged mutations. Columns: action, actor, target_type, target_id, ip, created at. Filters: action type, actor, date range.
Conversations (/conversations)
Endpoints: GET /admin/conversations
Columns: kind, title, member count, message count, created at. Actions: View members (no message content access — privacy).
AI Sessions (/assistant-sessions)
Endpoints: GET /admin/assistant-sessions
Columns: user, topic, status, turn count, started at, completed at.
Discovery Intents (/intents)
Endpoints: GET /admin/intents
Columns: user, intent, note, isActive, updated at.
Media (/media)
Endpoints: GET /admin/media
Columns: owner, bucket, key, mime type, size, status, created at. Actions: Mark as reviewed, soft-delete orphans.
Interests (/interests + /interests/:idOrSlug)
Endpoints: GET /admin/interests, POST /admin/interests, PATCH /admin/interests/:id
List all interests with level, slug, parent, user count. Interest detail: top users by reputation, recent posts, wiki entry.
Series (/series)
Endpoints: GET /admin/series
Columns: title, author, item count, follower count, created at.
Wiki Proposals (/wiki)
Endpoints: GET /admin/wiki/proposals, POST /admin/wiki/proposals/:id/approve, POST /admin/wiki/proposals/:id/reject
Columns: interest, proposer, status, net votes, summary, created at. Actions: Approve (creates new WikiEntry version), Reject.
Settings (/settings)
Endpoints: GET /admin/feature-flags, PATCH /admin/feature-flags/:key
Manage feature flags (e.g., emoji-pay, wiki, personas-ui). Also: broadcast message to all users POST /admin/broadcast { title, body }.
Broadcast Modal
Global button in header for admins. Sends POST /admin/broadcast { title, body }:
- Creates
Notificationrows for all non-banned users. - Emits
admin.broadcast.sent→ push fan-out viaPushService.
Theme Tokens
colorPrimary: '#1F1B16'
colorBgBase: '#F7F4ED' // warm parchment
colorBgContainer: '#FFFFFF'
colorBorder: '#E6DFCF'
Menu.itemSelectedBg: '#EFE9D7'
Table.rowHoverBg: '#EFE9D7'