[Phase 3] Implement user management page for admins
Resolved 💬 3 comments Opened Nov 7, 2025 by gloos Closed Jan 9, 2026
Description
Create an admin-only user management page that allows administrators to view all users, manage roles, and monitor user activity.
Dependencies
- Issue #52 (Role-based access control must be implemented first)
- Issue #53 (Admin RPC functions required)
Requirements
Page Location: apps/web/src/app/(authenticated)/admin/users/page.tsx
Functionality:
- Display paginated user list with:
- Role (user/admin)
- Registration date
- Last login
- Total files uploaded
- Total LLM usage cost
- Role management:
- Toggle user/admin role
- Confirmation dialog for role changes
- User activity summary:
- Link to view user's files
- Link to view user's LLM usage details
Server Component Pattern:
import { createRouteHandlerClient } from '@/lib/supabase';
import { requireAdmin } from '@/lib/auth-utils';
export default async function UsersPage() {
await requireAdmin();
const supabase = createRouteHandlerClient();
const { data: users } = await supabase.rpc('get_all_users_admin', {
p_limit: 50,
p_offset: 0
});
return <UserManagementTable users={users} />;
}
Required RPC (add to migration 20251108000004):
CREATE OR REPLACE FUNCTION get_all_users_admin(
p_limit INTEGER DEFAULT 50,
p_offset INTEGER DEFAULT 0
)
RETURNS TABLE (
id UUID,
email TEXT,
role TEXT,
created_at TIMESTAMPTZ,
last_sign_in_at TIMESTAMPTZ,
file_count BIGINT,
total_llm_cost NUMERIC
) SECURITY DEFINER AS $$
BEGIN
-- Verify admin access
IF NOT EXISTS (
SELECT 1 FROM profiles
WHERE id = auth.uid() AND role = 'admin'
) THEN
RAISE EXCEPTION 'Unauthorized: Admin access required';
END IF;
RETURN QUERY
SELECT
p.id,
au.email::TEXT,
p.role,
p.created_at,
au.last_sign_in_at,
COUNT(DISTINCT f.id) as file_count,
COALESCE(SUM(l.cost_usd), 0) as total_llm_cost
FROM profiles p
JOIN auth.users au ON au.id = p.id
LEFT JOIN files f ON f.created_by = p.id
LEFT JOIN llm_usage l ON l.user_id = p.id
GROUP BY p.id, au.email, p.role, p.created_at, au.last_sign_in_at
ORDER BY p.created_at DESC
LIMIT p_limit OFFSET p_offset;
END;
$$ LANGUAGE plpgsql;
Acceptance Criteria
- [ ] Admin middleware protection works (non-admins redirected)
- [ ] User list displays all required fields
- [ ] Pagination works correctly
- [ ] Role toggle updates database and shows confirmation
- [ ] Links to user files and usage details work
- [ ] Server Component pattern (no client-side data fetching)
Testing
- [ ] Verify admin can access page
- [ ] Verify regular users get 403/redirect
- [ ] Test role change functionality
- [ ] Verify pagination with 50+ users
Phase
Phase 3: Admin Features
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗