# 02. Admin Routes With Controls And Services Dashboard meta: id: landing-pages-and-admin-02 feature: landing-pages-and-admin priority: P1 depends_on: [] tags: [implementation, routes, admin, dashboard, auth] objective: - Create admin-only routes at `/admin` with authentication guards, a main dashboard showing service health and metrics, and a blog management interface for creating/editing blog posts and marking featured posts. deliverables: - `/web/src/routes/(admin)/index.tsx` — Admin dashboard overview - `/web/src/routes/(admin)/blog.tsx` — Blog post list and management - `/web/src/routes/(admin)/blog/new.tsx` — Create new blog post - `/web/src/routes/(admin)/blog/[slug].tsx` — Edit existing blog post - `/web/src/routes/(admin)/services.tsx` — Services health/status dashboard - `/web/src/routes/(admin)/users.tsx` — User management overview - Admin layout wrapper with sidebar navigation - tRPC router endpoints for admin CRUD operations - Role-based access guard middleware steps: - Create `(admin)` route group directory at `/web/src/routes/(admin)/` - Build admin layout component with sidebar navigation (Dashboard, Blog, Services, Users) - Implement role-based access guard: - Check user has `role` of `family_admin` or `support` in database - Redirect unauthorized users to `/dashboard` with error toast - Use existing Clerk auth + database role check - Create admin dashboard page (`/admin`): - Summary cards: total users, active subscriptions, blog posts count, alerts this week - Services status overview (DarkWatch, VoicePrint, SpamShield, HomeTitle, RemoveBrokers) - Recent activity feed (new signups, recent alerts, recent blog views) - Create blog management pages: - List view: table of all blog posts with slug, title, author, date, status, featured toggle - New post form: title, slug (auto-generated), excerpt, content (markdown editor), author, cover image URL, tags, published toggle, featured toggle - Edit post form: same fields pre-populated from database - Featured post toggle: only one post can be featured at a time - Create services dashboard page: - Health status indicators for each service - Metrics per service (usage counts, error rates, response times) - Ability to toggle service maintenance mode - Create users management page: - Searchable/filterable user table - User details: name, email, role, subscription tier, join date - Role management (change user role) - Wire up tRPC endpoints: - `admin.blog.list` — fetch all blog posts with pagination - `admin.blog.create` — create new blog post - `admin.blog.update` — update existing blog post - `admin.blog.delete` — soft delete blog post - `admin.blog.toggleFeatured` — set/unset featured post - `admin.dashboard.stats` — fetch dashboard statistics - `admin.services.status` — fetch service health data - `admin.users.list` — fetch user list with filters - `admin.users.updateRole` — update user role - Add admin guard middleware/procedure decorator to tRPC router tests: - Unit: Admin guard correctly blocks non-admin users - Unit: Blog form validation (required fields, unique slug, single featured post) - Integration: Admin routes accessible only by users with admin/support roles - Integration: Blog CRUD operations persist correctly to database - Integration: Featured post toggle enforces single-featured constraint acceptance_criteria: - Navigating to `/admin` redirects to `/login` if not authenticated - Navigating to `/admin` redirects to `/dashboard` if authenticated but not admin - Admin dashboard shows summary cards with real data from database - Blog list page shows all posts from database (not hardcoded) - Creating a blog post via admin form saves to `blogPosts` table - Editing a blog post updates the database record - Featured post toggle marks one post as featured and unmarks any previously featured post - Services dashboard shows health status for each product service - Users page shows searchable list with role management - Admin sidebar navigation works correctly across all admin pages validation: - `cd /Users/mike/Code/Kordant/web && pnpm dev` then navigate to `/admin` - Test with non-admin user: should redirect to `/dashboard` - Test with admin user: should show dashboard - Create a test blog post and verify it appears in the database - Toggle featured post and verify only one is featured at a time - Check tRPC endpoints return correct data notes: - Database schema already has `blogPosts` table in `marketing.ts` with fields: id, slug, title, excerpt, content, authorName, coverImageUrl, tags, published, publishedAt, viewCount - Need to add `featured` boolean column to `blogPosts` table - User roles defined in schema: `["user", "family_admin", "family_member", "support"]` - Admin access should be granted to `family_admin` and `support` roles - Use existing Clerk auth integration for session management - Consider using a rich text editor or markdown editor for blog content (e.g., TipTap, Slate, or simple textarea) - Admin route group `(admin)` follows SolidStart convention for route grouping - Reference existing dashboard layout pattern in `/web/src/components/dashboard/Sidebar.tsx` for sidebar styling