Admin Panel
Admin layout, server-side auth guard, stats dashboard, content moderation (books, comments, reports), user management, and system notification CRUD.
The admin panel is a sub-application under /admin/ with its own layout, auth guard, and set of API routes. Access is restricted to users with the admin or moderator role.
Layout and Access Control
The admin layout (app/admin/layout.tsx) is a Next.js layout file that wraps all /admin/* routes. Every request to an admin page goes through two checks:
- Authentication check - calls
auth()and redirects to/library?error=unauthenticatedif the user is not logged in. - Role check - calls
checkIsStaff()fromauth.ts, which queriesuser_rolesusing the admin client. Non-staff users are redirected to/library?error=unauthorized.
The layout renders:
- An
<AdminSidebar>(server component) with a navigation menu and user info. - An
<AdminLayout>(client component) that manages the mobile sidebar overlay.
Pages inside the admin layout do not import AppLayout - the admin layout provides its own shell.
Dashboard
/admin/ displays aggregate statistics and recent activity. The stats are fetched from GET /api/admin/stats, which runs three aggregate queries:
- Total books count
- Total users count
- Total purchases count
The admin dashboard also shows a recent-activity timeline populated from the purchases and books tables, joined with user profiles.
Content Moderation
Books
/admin/books displays a searchable, filterable table of all books. Each row shows the title, author, language, and status. Admins can:
- Approve a book - updates
books.statusto"processed". - Reject a book - updates
books.statusto"failed". - Delete a book - removes the book and its characters. Uses the admin client to bypass RLS.
Categories
/admin/categories is a full CRUD interface for the categories table. Categories have a name, slug, image URL, and an optional image upload. Admin API routes use getAdminClient() for all category mutations.
Comments
/admin/comments displays all book_comments with the associated book title, user profile, and content. Moderators can delete comments. Comments are fetched via the admin client (bypassing RLS so all comments are visible regardless of ownership).
Reports
/admin/reports lists user-submitted reports on books, comments, or other users. Reports have status tracking (pending/resolved/dismissed). Admins can:
- Resolve a report - marks it as handled.
- Dismiss a report - marks it as reviewed with no action.
User Management
/admin/users lists all profiles with their role and status. The view is searchable by name and email. Admins can:
- Change a user's role between
user,moderator, andadmin. - Block or unblock a user (updating the
statusfield inprofiles). - View the user's email, display name, and current role.
All mutations go through the admin client to bypass RLS.
System Notifications
/admin/notifications is a CRUD interface for system-wide notifications. Notifications have:
- A title and message body
- A type (info, warning, error, success)
- An optional target user ID (if null, the notification is broadcast to all users)
- Read/unread tracking per recipient
When an admin creates a notification targeting all users, the frontend inserts individual rows into the notifications table for every user with an active profile. The notification bell in the AppLayout sidebar polls for unread count.
Platform Settings
/admin/settings shows a key-value settings panel backed by the settings table. Each setting is a row with a key and value (both JSON). Settings are fetched and updated via GET/PUT /api/admin/settings.
Data Model
TypeScript type system, core entities (Book, Character, Session), Supabase table mapping, snake_case/camelCase conversion pattern, and the type modules that mirror the DB schema.
Observability and Debug Mode
Debug mode architecture, environment variables, mock auth/storage, and how the frontend logs client-side errors and exposes health check endpoints.