Admin & RBAC
RBAC Enforcement
Authorization is enforced at two layers:
auth_middleware— validates the session token and injectsrole: Roleinto request extensions. All/adminroutes require this middleware.require_admin— readsrolefrom extensions and returns403 Forbiddenif notRole::Admin. Zero additional DB queries.
Admin Stats
GET /admin/stats aggregates platform-wide metrics in a single handler, performing multiple DB queries:
COUNT(*) FROM users WHERE deleted_at IS NULLCOUNT(*) FROM users WHERE created_at > NOW() - INTERVAL '24 hours'(active today = created today, a proxy metric)COUNT(*) FROM conversationsCOUNT(*) FROM messages(API layer messages table)- Count of intelligence resources via gRPC
ResourceService.ListResources
User Management
| Operation | Query |
|---|---|
list_users | SELECT * FROM users ORDER BY created_at DESC LIMIT $1 OFFSET $2 with optional ILIKE search on email or username |
get_user | SELECT * FROM users WHERE id = $1 |
update_user_role | UPDATE users SET role = $1::user_role WHERE id = $2 |
delete_user | DELETE FROM users WHERE id = $1 (hard delete, cascades sessions/accounts) |
Note: Admin
delete_useris a hard delete (DELETE FROM users), whereas user self-deletion viaDELETE /user/delete-accountis a soft delete (SET deleted_at = NOW()). These two paths have different cascade behaviors.
Resource Management
Admin-managed resources (documents for RAG ingestion) are now exposed on /resources (admin-only middleware), and proxied to the Intelligence service:
Resource types (mapped from string to pb::ResourceType enum):
"text"→TEXT"markdown"→MARKDOWN"pdf"→PDF"html"→HTML"url"→WEBSITE(triggers Playwright scraper)"code"→CODE"file"→ file-content ingestion path
Global resources (is_global: true): searchable by all users in hybrid search. Global resources are typically set by admins for shared knowledge base documents.
Contributor Queue (Admin Review)
Admins also review contributor submissions via:
GET /resources/submissions?status=pending|approved|rejectedPOST /resources/submissions/{id}/reviewwith{ action: "approve" | "reject", feedback?: string }
On approve, the API forwards content to the Intelligence service (AddResource) and marks the submission as approved.
Weaknesses
-
Role change inconsistency (admin path): Changing a user’s role via
PATCH /admin/users/{id}/roleupdatesusers.rolebut does NOT update existing sessions’rolecolumn. Active sessions retain the old role until expiry (7 days) or re-login. -
Hard vs soft delete asymmetry: Hard-deleting a user via admin bypasses the recovery mechanism available through
POST /auth/recover-account. -
No audit log: Admin operations (role changes, user deletions, resource additions) are not logged to an audit trail. Only
TraceLayerHTTP logs exist. -
gRPC timeout: Resource ingestion timeout is 3000s (50 min). A failure mid-ingestion may leave an
ingestion_jobinprocessingstate with no recovery path from the Rust layer.