apps/web/src/routes/admin/README.md
The admin interface at /admin provides content management capabilities for the Char website.
Access is restricted to whitelisted email addresses defined in src/lib/team.ts (ADMIN_EMAILS).
Users must be authenticated via Supabase to access admin routes. Non-admin users are redirected to the home page. In development mode, authentication is bypassed with a mock dev@local user.
/admin/media)Upload, organize, and manage media assets stored in Supabase Storage.
/admin/collections)Full-featured blog editor with the following capabilities:
Requires GitHub credentials (stored in Supabase admins table). Users without GitHub credentials are redirected to authenticate via GitHub.
Complete flow from editing to publication:
1. User Edits a Published Article
/admin/collections and select a published article2. Save Creates a PR
blog/{slug}-{timestamp} (or uses existing one)main, ready to mergeharshikaalagh-netizen as reviewer on PR creation3. GitHub Actions Trigger
blog-auto-format.yml - Auto-formats MDX files with dprint, commits changes back to branchblog-grammar-check.yml - Runs AI grammar check (Anthropic), posts suggestions as PR comment4. User Continues Editing (Optional)
5. Reviewer Merges PR
All API endpoints require admin authentication (bypassed in development mode).
GET /api/admin/media/list - List files in a directoryPOST /api/admin/media/upload - Generate signed uploads for media filesPOST /api/admin/media/delete - Delete files (batch)POST /api/admin/media/move - Move/rename filesPOST /api/admin/media/create-folder - Create foldersPOST /api/admin/blog/upload-image - Generate signed uploads for blog imagesPOST /api/admin/import/google-docs - Parse published Google DocPOST /api/admin/import/save - Save MDX file to repositoryGET /api/admin/content/list - List content files in a folderGET /api/admin/content/list-drafts - List draft articles from branchesGET /api/admin/content/pending-pr - Check if article has a pending edit PRGET /api/admin/content/get-branch-file - Get file content from a branchGET /api/admin/content/history - Get git commit history for a filePOST /api/admin/content/save - Save content (creates PR for published articles)POST /api/admin/content/create - Create new content filePOST /api/admin/content/publish - Publish/unpublish an articlePOST /api/admin/content/rename - Rename a content filePOST /api/admin/content/duplicate - Duplicate a content filePOST /api/admin/content/delete - Delete a content fileThe editorial workflow is powered by three GitHub Actions workflows in .github/workflows/:
blog-auto-format.yml - Auto-formats MDX files with dprint on push to blog/** branches and commits changes backblog-grammar-check.yml - Runs AI-powered grammar check (Anthropic) on article PRs and posts suggestions as commentsblog-slack-notify.yml - Sends Slack notifications for article changes with editorial status detection (edit, new article, submit for review, unpublish)blog-grammar-check.yml and blog-slack-notify.yml trigger on PRs to main that modify apps/web/content/articles/** on blog/ branches. blog-auto-format.yml triggers on pushes to blog/** branches.
The following environment variables are required:
GITHUB_TOKEN - GitHub personal access token with repo write accessANTHROPIC_API_KEY - Anthropic API key for AI grammar checkingSLACK_BOT_TOKEN - Slack bot token for sending notificationsSLACK_BLOG_CHANNEL_ID - Slack channel ID for blog notificationsThe admin interface uses TanStack Router (React Start) with file-based routing. Routes are defined in:
src/routes/admin/ - Page componentssrc/routes/api/admin/ - API endpointssrc/hooks/use-media-api.tsx - Media API client hooksrc/functions/admin.ts - Admin authentication helperssrc/lib/team.ts - Admin email whitelist and team member dataAdmin authentication is handled by the fetchAdminUser() function which checks if the current user's email is in the ADMIN_EMAILS whitelist.