First-run tour
The admin follows a sidebar-groups + focus-content layout. Everything you can do is in the sidebar (permission-aware, hidden if your role can’t do it). The URL always reflects state so links are shareable.
Sidebar groups
Section titled “Sidebar groups”The nav is organized around what you’re trying to do, not how the DB is shaped:
| Group | What lives here |
|---|---|
Dashboard (/) | KPI tiles + trend graphs. First thing you see after login. |
Catalog (/series, /catalog/*) | Series list, wizard, episode editor, genres, tropes, cast. |
Media (/media/*) | Uploads, library, retry/reprocess. |
Curation (/curation/*) | For You home, collections, preview-reel ordering, free-today rotation. |
Users (/users/*) | Search, User 360, segments. |
Moderation (/moderation/*) | Comment queue, reports queue. |
Monetization (/monetization/*, /pricing/*) | Pricing overrides, coin packages, subscriptions, promos. |
Payments (/payments/*) | Transactions, refunds, reconciliation. |
Analytics (/analytics/*) | Overview, revenue, content, funnel, economy. |
Engagement (/engagement/*, /push) | Push composer, streaks & rewards config. |
System (/system/*, /audit) | Admin users, roles, approvals, audit log, feature flags, settings. |
The ⌘K command palette
Section titled “The ⌘K command palette”Press ⌘K (macOS) or Ctrl+K (Windows/Linux) from anywhere. The palette lets you:
- Jump to a route: start typing “series” or “refunds” and hit Enter.
- Jump to a user: paste an email, phone number (E.164), or user ID.
- Jump to a series: paste a series ID or slug.
- Jump to a transaction: paste a transaction ID.
Palette entries respect your permissions: you won’t see “Refunds” if you don’t have payments:read.
Every list looks the same
Section titled “Every list looks the same”Every list surface uses TanStack Table with:
- URL-state filters: every filter, sort, and page cursor lives in the query string. Copy the URL to share the exact view with a teammate.
- Server-side pagination via opaque cursors (
?cursor=…). No offset pagination. - Bulk actions where relevant (multi-select in comments queue, schedules, users).
- CSV export on transactions and audit log.
Destructive actions
Section titled “Destructive actions”Any destructive or high-impact action pops a typed-confirmation modal:
- Type the resource name (e.g. the series title) to unlock the Confirm button.
- Add an audit note: the reason string that gets attached to the AuditLog entry and, if applicable, the AdminApproval record.
Actions that hit the two-person rule (see below) go to a queue instead of executing immediately.
The approvals concept (two-person rule)
Section titled “The approvals concept (two-person rule)”Some actions can’t be done alone. They’re written into an admin_approvals row with status=pending, and a different admin with the right permission must approve them in System → Approvals.
What routes through approvals:
| Action | Threshold | Who approves |
|---|---|---|
| Refund | > $50 (5000 cents) | payments:refund (finance / superadmin) |
| Coin grant | > 2000 coins | wallet:adjust (finance / superadmin, not the requester) |
| Series deletion | Always | Second catalog:delete holder |
| Role changes | Always | Second roles:manage (superadmin) |
| GDPR anonymize | Always | Second users:anonymize |
Approval decisions themselves are audited (AuditLog entry with the payload diff). If the same admin somehow tries to approve their own request, the API returns approver_must_differ (403).
Audit log
Section titled “Audit log”Every mutating admin action writes to AuditLog with:
admin_id: who did itaction: the operation (user.ban,refund.execute,series.create, …)ref_type/ref_id: the target (user:abc,series:xyz)before/afterJSON: full diff for reconstructionip/user_agent: provenancecreated_at
Read it at System → Audit log. Analyst and finance have audit:read; support and moderator do not.
What content ships in EN + AR + ID
Section titled “What content ships in EN + AR + ID”Any content field with a localized version has three tabs at edit time:
- EN: English (default)
- AR: Arabic (RTL preview)
- ID: Bahasa Indonesia
The admin UI itself stays in English. Only content fields (series/episode titles, synopses, collection labels, push copy, etc.) localize.