Staff Dashboard Implementation Plan
🎯 Overview
A secure, enterprise-grade staff dashboard for managing Clerk users and system administration, accessible only to authorized @do.dev staff members.
🔒 Security Architecture
Defense in Depth (4 Layers)
-
Layer 1: Next.js Middleware
- Protects all
/staff/*routes - Checks authentication, email domain, and staff access
- Redirects unauthorized users before page render
- Protects all
-
Layer 2: Layout Server Component
- Server-side verification in
/staff/layout.tsx - Double-checks credentials at page level
- Returns 404 for unauthorized (don't reveal dashboard exists)
- Server-side verification in
-
Layer 3: Convex Functions
- Every staff query/mutation calls
requireStaffAccess() - Validates JWT claims for staffDashboardAccess
- Independent of Next.js layer
- Every staff query/mutation calls
-
Layer 4: Client Components
- UI-level hiding of sensitive elements
- Already authorized at this point (UX only)
Access Requirements (BOTH must be true)
- ✅ User email ends with
@do.dev - ✅
user.privateMetadata.staffDashboardAccess === true
📊 Data Architecture
Clerk Integration
Private Metadata Storage:
user.privateMetadata = {
staffDashboardAccess: boolean
}JWT Claims Configuration:
- Configure Clerk JWT template to include
staffDashboardAccessin claims - Enables Convex to check access without additional API calls
Convex Database Schema
staffAuditLogs table:
{
_id: Id<"staffAuditLogs">,
_creationTime: number,
staffUserId: string, // Clerk user ID
staffUserEmail: string,
action: string, // "view_user", "grant_staff_access", etc.
targetUserId?: string, // If action involves another user
details: object, // JSON details of the action
ipAddress?: string,
userAgent?: string
}userProfiles table:
{
_id: Id<"userProfiles">,
_creationTime: number,
clerkUserId: string,
lastActive?: number,
notes?: string, // Staff notes about user
tags?: string[], // Admin tags
customData?: object
}🗂️ File Structure
apps/homepage-web/
├── app/
│ ├── staff/ # Staff-only routes
│ │ ├── layout.tsx # Staff layout with auth check
│ │ ├── page.tsx # Dashboard overview
│ │ ├── users/
│ │ │ ├── page.tsx # User list
│ │ │ └── [userId]/
│ │ │ └── page.tsx # User detail page
│ │ ├── audit-logs/
│ │ │ └── page.tsx # Audit log viewer
│ │ └── settings/
│ │ └── page.tsx # Staff settings
│ └── middleware.ts # Update for /staff protection
├── components/
│ └── staff/ # Staff-only components
│ ├── StaffSidebar.tsx
│ ├── StaffHeader.tsx
│ ├── UserTable.tsx
│ ├── UserCard.tsx
│ ├── AuditLogTable.tsx
│ ├── StatCard.tsx
│ └── ConfirmationDialog.tsx
├── lib/
│ ├── auth/
│ │ └── staff-auth.ts # Staff authorization utilities
│ └── errors/
│ └── staff-errors.ts # Error handling
├── convex/
│ ├── schema.ts # Update with staff tables
│ ├── _helpers/
│ │ └── staffAuth.ts # Convex staff auth helper
│ └── staff/ # Staff-only functions
│ ├── dashboard.ts # Dashboard queries
│ ├── users.ts # User management queries/mutations
│ └── auditLogs.ts # Audit log queries
└── scripts/
└── grant-staff-access.ts # Initial setup script🚀 Implementation Phases
Phase 1: Foundation (Security First)
Priority: CRITICAL
- Create Convex schema for audit logs and user profiles
- Implement
lib/auth/staff-auth.tsutilities - Create Convex
requireStaffAccess()helper - Create
scripts/grant-staff-access.tsfor initial setup - Set up error handling utilities
Deliverables:
- ✅ Convex schema deployed
- ✅ Auth utilities tested
- ✅ First staff member granted access
Phase 2: Route Protection
Priority: HIGH
- Update
middleware.tsto protect/staffroutes - Create
app/staff/layout.tsxwith server-side auth - Create basic unauthorized/404 pages
Deliverables:
- ✅ All /staff routes protected
- ✅ Unauthorized users blocked
- ✅ Proper error pages
Phase 3: Core UI
Priority: HIGH
- Build staff dashboard overview page
- Create Convex queries for dashboard stats
- Build user list UI with table, search, filters
- Create user detail page
- Implement basic navigation
Deliverables:
- ✅ Functional dashboard overview
- ✅ User list with search
- ✅ User detail views
- ✅ Navigation working
Phase 4: Advanced Features
Priority: MEDIUM
- Create Convex mutations for user operations
- Implement audit log viewer
- Add confirmation dialogs for destructive actions
- Build staff member management UI
Deliverables:
- ✅ User management operations
- ✅ Audit trail viewer
- ✅ Safety confirmations
- ✅ Staff access control
Phase 5: Security Hardening
Priority: HIGH
- Comprehensive error handling
- Security testing checklist
- Rate limiting on write operations
- Loading states and optimistic updates
Deliverables:
- ✅ All security tests pass
- ✅ Error handling comprehensive
- ✅ Production ready
🎨 UI/UX Design
Dashboard Overview Sections
-
Key Metrics Cards:
- Total Users
- Active Users (24h/7d/30d)
- Staff Users
- New Users (today/week/month)
-
Recent Activity Feed:
- Last 10 user signups
- Recent staff actions
- User profile updates
-
Quick Actions:
- Search user
- View audit logs
- Add staff member
User Management Features
- List all users with pagination
- Search by email, name, user ID
- Filter by status (active, banned, etc.)
- View user metadata and settings
- Grant/revoke staff access
- Add staff notes
- View activity history
Component Design Principles
- Use ShadCN UI components for consistency
- Warning colors (amber/orange) for admin actions
- Clear confirmation dialogs for dangerous operations
- Real-time updates via Convex reactivity
- Responsive design (desktop-first for staff tools)
🔧 Configuration Requirements
Clerk Setup
-
JWT Template Configuration (CRITICAL):
Dashboard → JWT Templates → Create/Edit "convex" Claims: { "staffDashboardAccess": "{{user.private_metadata.staffDashboardAccess}}" } -
Initial Staff User:
pnpm tsx scripts/grant-staff-access.ts user@do.dev
Convex Deployment
# Deploy schema changes
pnpm convex:deploy
# Verify deployment
npx convex dev✅ Security Testing Checklist
Authentication Tests
- Unauthenticated user blocked from /staff routes
- Authenticated non-@do.dev user blocked
- Authenticated @do.dev user without flag blocked
- Only authorized users can access dashboard
Authorization Tests
- Middleware blocks before page render
- Layout performs server-side check
- Convex functions reject unauthorized
- User losing access mid-session is blocked
Edge Cases
- Email domain change → immediate denial
- User modifying own staff access → rejected
- Expired token → forced re-auth
- Invalid user ID → proper error
Audit Trail
- All staff actions logged
- Failed access attempts logged
- Logs immutable by staff
- Sufficient context for investigation
Data Privacy
- privateMetadata never exposed to client
- Sensitive data not in error messages
- Dashboard hidden from normal users
🚨 Critical Security Notes
-
Never expose staff dashboard existence to unauthorized users
- Return 404, not "unauthorized"
- No hints in client-side code
- No analytics tracking for unauthorized attempts
-
Prevent self-modification
- Staff cannot grant/revoke own staff access
- Requires another staff member
-
Audit everything
- Every read operation logs to audit trail
- Include IP, user agent, timestamp
- Store before/after state for changes
-
Rate limiting
- Implement rate limits on write operations
- Prevent abuse even from authorized staff
📝 Operations to Implement
Read Operations (Queries)
- List all users with pagination
- Search users by email/name
- Get user details
- Get user sessions
- View audit logs with filters
- Dashboard statistics
Write Operations (Mutations)
- Update user metadata
- Grant/revoke staff access (with reason)
- Ban/unban users
- Delete users (double confirmation)
- Add staff notes to users
Operations NOT to Implement
- Password reset (users do this themselves)
- Email verification bypass
- Direct session manipulation
🔍 Error Handling Strategy
Error Types
export class StaffAuthError extends Error {
code: "NO_AUTH" | "INVALID_DOMAIN" | "NO_STAFF_ACCESS" | "REVOKED"
}Error Responses
- Authentication errors → redirect to home
- Authorization errors → log and show 404
- Clerk API errors → retry with exponential backoff
- Convex errors → show user-friendly message
- All errors logged to audit trail
📈 Success Metrics
- ✅ Zero unauthorized access to staff routes
- ✅ 100% audit coverage of staff actions
- ✅ <100ms auth check overhead
- ✅ All security tests passing
- ✅ Comprehensive error handling
🎓 Next Steps
- Review and approve this plan
- Configure Clerk JWT template
- Begin Phase 1 implementation
- Test each phase thoroughly
- Deploy to production with monitoring
Estimated Total Development Time: 7-11 hours Priority: HIGH (Security-critical feature) Status: Ready for implementation