VoiceAssist Docs

System Configuration

Environment variables and platform settings

stabledocs2025-11-27human
configurationreference

Configuration Reference

VoiceAssist V2 - Complete Configuration Guide

This document provides comprehensive documentation for all configuration options available in VoiceAssist V2.

Table of Contents

Environment Variables

Environment Settings

VariableRequiredDefaultDescriptionValidation
ENVIRONMENTYes-Deployment environmentdevelopment, staging, production
DEBUGNofalseEnable debug modetrue, false
APP_NAMENoVoiceAssistApplication nameAny string
APP_VERSIONNo2.0.0Application versionSemantic version
LOG_LEVELNoINFOLogging levelDEBUG, INFO, WARNING, ERROR, CRITICAL

Usage:

ENVIRONMENT=production DEBUG=false LOG_LEVEL=INFO

Validation Rules:

  • ENVIRONMENT must be one of: development, staging, production
  • DEBUG should be false in production
  • LOG_LEVEL should be WARNING or higher in production

Database Configuration

VariableRequiredDefaultDescriptionValidation
POSTGRES_HOSTYes-PostgreSQL hostnameValid hostname or IP
POSTGRES_PORTYes5432PostgreSQL port1-65535
POSTGRES_USERYes-PostgreSQL usernameAlphanumeric + underscore
POSTGRES_PASSWORDYes-PostgreSQL passwordMin 16 chars, strong password
POSTGRES_DBYes-Database nameAlphanumeric + underscore
DATABASE_URLYes-Full database connection stringValid PostgreSQL URL

Usage:

POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_USER=voiceassist POSTGRES_PASSWORD=secure_complex_password_min_16_chars POSTGRES_DB=voiceassist DATABASE_URL=postgresql://voiceassist:secure_password@postgres:5432/voiceassist

Validation Rules:

  • Password must be at least 16 characters
  • Password should contain uppercase, lowercase, numbers, special chars
  • Use PostgreSQL 16+ with pgvector extension
  • Connection string format: postgresql://user:password@host:port/database

Production Recommendations:

  • Use connection pooling: Add ?pool_size=20&max_overflow=40 to DATABASE_URL
  • Enable SSL: Add ?sslmode=require for production
  • Use managed PostgreSQL service (AWS RDS, Google Cloud SQL, etc.)

Redis Configuration

VariableRequiredDefaultDescriptionValidation
REDIS_HOSTYes-Redis hostnameValid hostname or IP
REDIS_PORTYes6379Redis port1-65535
REDIS_PASSWORDYes-Redis passwordMin 16 chars
REDIS_URLYes-Full Redis connection stringValid Redis URL
REDIS_DBNo0Redis database number0-15

Usage:

REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD=secure_redis_password_min_16_chars REDIS_URL=redis://:secure_password@redis:6379/0

Validation Rules:

  • Redis 7+ recommended
  • Password must be set in production
  • Connection string format: redis://[:password@]host:port[/db]

Production Recommendations:

  • Use Redis Cluster for high availability
  • Enable persistence (AOF + RDB)
  • Set maxmemory policy: allkeys-lru
  • Use managed Redis (AWS ElastiCache, Redis Cloud, etc.)

Qdrant Vector Database

VariableRequiredDefaultDescriptionValidation
QDRANT_HOSTYes-Qdrant hostnameValid hostname or IP
QDRANT_PORTYes6333Qdrant HTTP port1-65535
QDRANT_URLYes-Full Qdrant URLValid HTTP URL
QDRANT_COLLECTIONYesmedical_knowledgeCollection nameAlphanumeric + underscore
QDRANT_API_KEYNo-Qdrant API keyAny string (required if auth enabled)

Usage:

QDRANT_HOST=qdrant QDRANT_PORT=6333 QDRANT_URL=http://qdrant:6333 QDRANT_COLLECTION=medical_knowledge

Validation Rules:

  • Qdrant v1.7+ required
  • Collection name must match [a-zA-Z0-9_]+
  • Use HTTPS URL in production

Production Recommendations:

  • Use Qdrant Cloud for managed service
  • Enable authentication with API key
  • Configure quantization for cost savings
  • Set up replication for high availability

Nextcloud Integration

VariableRequiredDefaultDescriptionValidation
NEXTCLOUD_URLYes-Nextcloud instance URLValid HTTP/HTTPS URL
NEXTCLOUD_ADMIN_USERYes-Admin usernameAny string
NEXTCLOUD_ADMIN_PASSWORDYes-Admin passwordMin 12 chars
NEXTCLOUD_DB_PASSWORDYes-Nextcloud DB passwordMin 16 chars

Usage:

NEXTCLOUD_URL=https://nextcloud.example.com NEXTCLOUD_ADMIN_USER=admin NEXTCLOUD_ADMIN_PASSWORD=secure_admin_password NEXTCLOUD_DB_PASSWORD=secure_db_password

Validation Rules:

  • Nextcloud 29+ recommended
  • Use HTTPS in production
  • Admin password should be strong

Production Recommendations:

  • Deploy Nextcloud on separate infrastructure
  • Use managed database for Nextcloud
  • Enable 2FA for admin account
  • Configure email for notifications

OpenAI API

VariableRequiredDefaultDescriptionValidation
OPENAI_API_KEYYes-OpenAI API keyStarts with sk-
OPENAI_MODELNogpt-4GPT model to useValid OpenAI model name
OPENAI_EMBEDDING_MODELNotext-embedding-3-smallEmbedding modelValid embedding model
OPENAI_MAX_TOKENSNo512Max tokens per response1-4096
OPENAI_TEMPERATURENo0.1Model temperature0.0-2.0

Usage:

OPENAI_API_KEY=sk-your-real-api-key-here OPENAI_MODEL=gpt-4-turbo-preview OPENAI_EMBEDDING_MODEL=text-embedding-3-small OPENAI_MAX_TOKENS=512 OPENAI_TEMPERATURE=0.1

Validation Rules:

  • API key must start with sk- or sk-proj-
  • Model must be available in your OpenAI account
  • Temperature must be between 0.0 and 2.0

Cost Management:

  • Use gpt-4-turbo-preview for lower costs
  • Use text-embedding-3-small (1536 dimensions) instead of large (3072)
  • Set reasonable OPENAI_MAX_TOKENS to control costs
  • Monitor usage at https://platform.openai.com/usage

Security Configuration

VariableRequiredDefaultDescriptionValidation
SECRET_KEYYes-Application secret keyMin 32 chars, hex
JWT_SECRETYes-JWT signing secretMin 32 chars, hex
JWT_ALGORITHMNoHS256JWT algorithmHS256, RS256
ACCESS_TOKEN_EXPIRE_MINUTESNo15Access token TTL5-60 minutes
REFRESH_TOKEN_EXPIRE_DAYSNo7Refresh token TTL1-30 days
PASSWORD_MIN_LENGTHNo12Minimum password length8-128

Usage:

SECRET_KEY=$(openssl rand -hex 32) JWT_SECRET=$(openssl rand -hex 32) JWT_ALGORITHM=HS256 ACCESS_TOKEN_EXPIRE_MINUTES=15 REFRESH_TOKEN_EXPIRE_DAYS=7 PASSWORD_MIN_LENGTH=12

Generation Commands:

# Generate SECRET_KEY openssl rand -hex 32 # Generate JWT_SECRET openssl rand -hex 32

Validation Rules:

  • Both secrets must be exactly 64 hex characters (32 bytes)
  • Secrets must be different from each other
  • Never commit secrets to version control
  • Rotate secrets every 90 days in production

HIPAA Compliance:

  • Use strong secrets (32+ bytes)
  • Rotate tokens regularly
  • Log all authentication events
  • Implement automatic logout after inactivity

Observability Configuration (Phase 8)

VariableRequiredDefaultDescriptionValidation
ENABLE_METRICSNotrueEnable Prometheus metricstrue, false
ENABLE_TRACINGNotrueEnable distributed tracingtrue, false
JAEGER_HOSTNojaegerJaeger hostnameValid hostname
JAEGER_PORTNo6831Jaeger agent UDP port1-65535
OTLP_ENDPOINTNo-OTLP collector endpointValid URL or empty
LOG_RETENTION_DAYSNo90Log retention period30-365 (HIPAA: 30-90)
GRAFANA_ADMIN_USERNoadminGrafana admin usernameAny string
GRAFANA_ADMIN_PASSWORDYes-Grafana admin passwordMin 12 chars

Usage:

ENABLE_METRICS=true ENABLE_TRACING=true JAEGER_HOST=jaeger JAEGER_PORT=6831 LOG_RETENTION_DAYS=90 GRAFANA_ADMIN_PASSWORD=secure_grafana_password

Validation Rules:

  • LOG_RETENTION_DAYS must be 30-90 for HIPAA compliance
  • Grafana password should be strong

Production Recommendations:

  • Keep metrics and tracing enabled
  • Use external OTLP collector in production
  • Set up Grafana dashboards for monitoring
  • Configure AlertManager for critical alerts

Application Settings

VariableRequiredDefaultDescriptionValidation
MAX_UPLOAD_SIZENo104857600Max file upload size (bytes)Positive integer
ENABLE_CORSNotrueEnable CORStrue, false
ALLOWED_ORIGINSNo*CORS allowed originsComma-separated URLs
RATE_LIMIT_PER_MINUTENo100API rate limit1-10000

Usage:

MAX_UPLOAD_SIZE=104857600 # 100MB ENABLE_CORS=true ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com RATE_LIMIT_PER_MINUTE=100

Validation Rules:

  • MAX_UPLOAD_SIZE in bytes (100MB = 104857600)
  • ALLOWED_ORIGINS should not be * in production
  • Rate limit should be tuned based on usage patterns

Configuration Validation

Startup Validation

VoiceAssist validates all configuration on startup. The validation includes:

  1. Required Variables: Ensures all required env vars are present
  2. Format Validation: Validates formats (URLs, emails, hex strings)
  3. Connectivity Tests: Tests connections to PostgreSQL, Redis, Qdrant
  4. Secret Strength: Validates secret key strength and uniqueness
  5. HIPAA Compliance: Checks retention policies and security settings

Validation Errors

If validation fails, the application will:

  • Log detailed error messages
  • Exit with non-zero status code
  • Provide guidance on how to fix the issue

Example validation error:

ConfigValidationError: JWT_SECRET must be exactly 64 hex characters (got 32)
Fix: Generate a new secret with: openssl rand -hex 32

Security Best Practices

Secret Management

  1. Never commit secrets to Git

    # Add to .gitignore echo ".env" >> .gitignore
  2. Use environment-specific secrets

    • Development: .env.development
    • Staging: .env.staging
    • Production: Use secret manager (AWS Secrets Manager, HashiCorp Vault)
  3. Rotate secrets regularly

    • JWT secrets: Every 90 days
    • API keys: When team members leave
    • Database passwords: Every 180 days
  4. Use external secret managers in production

    # AWS Secrets Manager example aws secretsmanager get-secret-value --secret-id voiceassist/prod/jwt-secret

HIPAA Compliance Checklist

  • LOG_RETENTION_DAYS set to 30-90 days
  • Strong passwords (16+ characters) for all services
  • PHI redaction enabled in logs (automatic in Phase 8)
  • TLS/SSL enabled for all external connections
  • Access logs enabled and monitored
  • Automatic session timeout configured
  • Audit logging enabled
  • Backup encryption enabled

Configuration Examples

Development Environment

# .env.development ENVIRONMENT=development DEBUG=true LOG_LEVEL=DEBUG # Use Docker Compose hostnames POSTGRES_HOST=postgres REDIS_HOST=redis QDRANT_HOST=qdrant NEXTCLOUD_URL=http://nextcloud # Simple passwords for development POSTGRES_PASSWORD=devpass123 REDIS_PASSWORD=devpass123 JWT_SECRET=$(openssl rand -hex 32) # Observability ENABLE_METRICS=true ENABLE_TRACING=true

Production Environment

# .env.production ENVIRONMENT=production DEBUG=false LOG_LEVEL=WARNING # Production hostnames POSTGRES_HOST=prod-db.rds.amazonaws.com POSTGRES_PORT=5432 REDIS_HOST=prod-redis.elasticache.amazonaws.com REDIS_PORT=6379 QDRANT_URL=https://prod-cluster.qdrant.tech # Strong secrets from secret manager SECRET_KEY=${AWS_SECRET_MANAGER:voiceassist/prod/secret-key} JWT_SECRET=${AWS_SECRET_MANAGER:voiceassist/prod/jwt-secret} POSTGRES_PASSWORD=${AWS_SECRET_MANAGER:voiceassist/prod/db-password} # Production URLs NEXTCLOUD_URL=https://files.example.com ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com # HIPAA compliance LOG_RETENTION_DAYS=90 ACCESS_TOKEN_EXPIRE_MINUTES=15 # Observability ENABLE_METRICS=true ENABLE_TRACING=true JAEGER_HOST=prod-jaeger.example.com

Docker Compose Override

For local development with custom settings:

# docker-compose.override.yml version: "3.8" services: voiceassist-server: environment: - DEBUG=true - LOG_LEVEL=DEBUG - OPENAI_API_KEY=${OPENAI_API_KEY} # From host environment

Troubleshooting

Common Configuration Issues

Issue: "Database connection failed"

Solution:
1. Check POSTGRES_HOST is accessible
2. Verify POSTGRES_PASSWORD is correct
3. Ensure PostgreSQL is running: docker compose ps postgres
4. Check network connectivity: docker compose exec voiceassist-server ping postgres

Issue: "OpenAI API authentication failed"

Solution:
1. Verify OPENAI_API_KEY format (starts with sk-)
2. Check API key is active at https://platform.openai.com/api-keys
3. Ensure sufficient API credits
4. Check for typos in .env file

Issue: "Jaeger trace export failed"

Solution:
1. Check JAEGER_HOST is accessible
2. Verify JAEGER_PORT (default 6831)
3. Ensure Jaeger is running: docker compose ps jaeger
4. Check ENABLE_TRACING=true

Configuration Testing

Validate Configuration

# Check environment variables are set docker compose exec voiceassist-server env | grep -E "(POSTGRES|REDIS|OPENAI)" # Test database connection docker compose exec voiceassist-server python -c "from app.core.database import engine; engine.connect()" # Test Redis connection docker compose exec voiceassist-server python -c "from app.core.redis import redis_client; redis_client.ping()" # Verify secrets are strong [ ${#JWT_SECRET} -eq 64 ] && echo "JWT_SECRET length OK" || echo "ERROR: JWT_SECRET must be 64 chars"

Health Checks

# Check API health curl http://localhost:8000/health # Check readiness (all dependencies) curl http://localhost:8000/ready # Check metrics endpoint curl http://localhost:8000/metrics | grep voiceassist_up

Configuration Schema (JSON Schema)

For programmatic validation, use this JSON Schema:

{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "VoiceAssist Configuration", "type": "object", "required": [ "POSTGRES_HOST", "REDIS_HOST", "QDRANT_HOST", "NEXTCLOUD_URL", "OPENAI_API_KEY", "SECRET_KEY", "JWT_SECRET" ], "properties": { "ENVIRONMENT": { "type": "string", "enum": ["development", "staging", "production"] }, "DEBUG": { "type": "boolean" }, "POSTGRES_HOST": { "type": "string", "minLength": 1 }, "POSTGRES_PORT": { "type": "integer", "minimum": 1, "maximum": 65535, "default": 5432 }, "JWT_SECRET": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "LOG_RETENTION_DAYS": { "type": "integer", "minimum": 30, "maximum": 365, "default": 90 } } }

Additional Resources

  • Environment Setup Guide: docs/DEVELOPMENT_SETUP.md
  • Security Guidelines: docs/SECURITY_COMPLIANCE.md
  • Deployment Guide: docs/DEPLOYMENT.md
  • Troubleshooting: docs/TROUBLESHOOTING.md

Document Version: 1.0 Last Updated: 2025-11-21 Maintainer: VoiceAssist Team


Admin Panel Specifications

Overview

The VoiceAssist Admin Panel provides a centralized web interface for system configuration, monitoring, and management. Accessible at admin.asimo.io.

Technology Stack

Frontend

  • Framework: React 18+ with TypeScript
  • Build Tool: Vite
  • Styling: Tailwind CSS
  • Component Library: shadcn/ui or Tremor (for dashboards)
  • Charts: Recharts or Chart.js
  • Tables: TanStack Table (React Table v8)
  • State Management: Zustand or React Context

Backend

  • Framework: FastAPI (Python)
  • Authentication: JWT with admin role
  • Database: PostgreSQL for admin data
  • Real-time: WebSocket for live metrics

Standard API Envelope

All admin API calls return a standard envelope. See server/README.md for complete specification.

Use the same TypeScript types and fetch helper from WEB_APP_SPECS.md (can be shared package or duplicated).

Usage Example - KB Management

// admin/hooks/useKBManagement.ts import { useMutation, useQuery } from "@tanstack/react-query"; import { fetchAPI, APIError } from "@/lib/api"; import { KnowledgeDocument, IndexingJob } from "@/types"; // From DATA_MODEL.md import { toast } from "@/lib/toast"; export function useKBDocuments() { return useQuery({ queryKey: ["kb-documents"], queryFn: async () => { return fetchAPI<KnowledgeDocument[]>("/api/admin/kb/documents"); }, }); } export function useUploadDocument() { return useMutation({ mutationFn: async (file: File) => { const formData = new FormData(); formData.append("file", file); return fetchAPI<IndexingJob>("/api/admin/kb/upload", { method: "POST", body: formData, headers: { // Don't set Content-Type, let browser set it with boundary }, }); }, onSuccess: (job) => { toast.success(`Upload started: ${job.id}`); }, onError: (error: APIError) => { if (error.code === "VALIDATION_ERROR") { toast.error("Invalid file format. Only PDF and DOCX supported."); } else if (error.code === "CONFLICT") { toast.error("A document with this name already exists"); } else { toast.error(`Upload failed: ${error.message}`); } }, }); } export function useReindexDocuments() { return useMutation({ mutationFn: async (docIds: string[]) => { return fetchAPI<{ job_count: number }>("/api/admin/kb/reindex", { method: "POST", body: JSON.stringify({ document_ids: docIds }), }); }, }); }

API Integration Examples

Note: For canonical entity definitions (JSON Schema, Pydantic, TypeScript), see DATA_MODEL.md. This section provides usage examples specific to the admin panel.

Knowledge Base Management (TypeScript):

// services/api/admin.ts import axios from "axios"; const api = axios.create({ baseURL: import.meta.env.VITE_API_URL, withCredentials: true, // Send JWT cookies headers: { "Content-Type": "application/json", }, }); export interface DocumentUploadResponse { documentId: string; filename: string; status: string; message: string; } export interface DocumentListResponse { id: string; filename: string; sourceType: string; specialty: string; status: string; fileSize: number; chunkCount?: number; uploadedAt: string; indexedAt?: string; } export interface ReindexRequest { documentIds: string[]; force: boolean; } export interface ReindexResponse { jobId: string; documentCount: number; status: string; message: string; } // Upload document export async function uploadDocument( file: File, sourceType: string, specialty: string, ): Promise<DocumentUploadResponse> { const formData = new FormData(); formData.append("file", file); formData.append("sourceType", sourceType); formData.append("specialty", specialty); const response = await api.post("/api/admin/knowledge/upload", formData, { headers: { "Content-Type": "multipart/form-data", }, }); return response.data; } // List documents export async function listDocuments( skip: number = 0, limit: number = 50, status?: string, ): Promise<DocumentListResponse[]> { const response = await api.get("/api/admin/knowledge/documents", { params: { skip, limit, status }, }); return response.data; } // Trigger reindex export async function triggerReindex(documentIds: string[] = [], force: boolean = false): Promise<ReindexResponse> { const response = await api.post("/api/admin/knowledge/reindex", { documentIds, force, }); return response.data; } // Get vector DB stats export async function getVectorDBStats(): Promise<VectorDBStatsResponse> { const response = await api.get("/api/admin/knowledge/stats"); return response.data; }

React Hook for Document Management:

// hooks/useDocuments.ts import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import * as adminApi from '@/services/api/admin'; export function useDocuments(skip = 0, limit = 50, status?: string) { return useQuery({ queryKey: ['documents', skip, limit, status], queryFn: () => adminApi.listDocuments(skip, limit, status), }); } export function useUploadDocument() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ file, sourceType, specialty, }: { file: File; sourceType: string; specialty: string; }) => adminApi.uploadDocument(file, sourceType, specialty), onSuccess: () => { // Invalidate documents list to refetch queryClient.invalidateQueries({ queryKey: ['documents'] }); }, }); } export function useReindexDocuments() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ documentIds, force, }: { documentIds: string[]; force: boolean; }) => adminApi.triggerReindex(documentIds, force), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['documents'] }); }, }); } // Usage in component function KnowledgeBaseManager() { const { data: documents, isLoading } = useDocuments(0, 50); const uploadMutation = useUploadDocument(); const reindexMutation = useReindexDocuments(); const handleUpload = (file: File) => { uploadMutation.mutate({ file, sourceType: 'textbook', specialty: 'cardiology', }); }; const handleReindexAll = () => { reindexMutation.mutate({ documentIds: [], // Empty = reindex all force: false, }); }; return ( <div> <button onClick={handleReindexAll} disabled={reindexMutation.isPending}> Reindex All Documents </button> {/* Document list and upload UI */} </div> ); }

Real-time Metrics with WebSocket:

// hooks/useRealtimeMetrics.ts import { useEffect, useState } from 'react'; export interface SystemMetrics { cpuUsage: number; memoryUsage: number; diskUsage: number; activeSessions: number; apiCallsToday: number; errorRate: number; } export function useRealtimeMetrics() { const [metrics, setMetrics] = useState<SystemMetrics | null>(null); const [isConnected, setIsConnected] = useState(false); useEffect(() => { const ws = new WebSocket(`${import.meta.env.VITE_WS_URL}/admin/metrics`); ws.onopen = () => { setIsConnected(true); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); setMetrics(data); }; ws.onerror = (error) => { console.error('WebSocket error:', error); }; ws.onclose = () => { setIsConnected(false); }; return () => { ws.close(); }; }, []); return { metrics, isConnected }; } // Usage in dashboard component function Dashboard() { const { metrics, isConnected } = useRealtimeMetrics(); if (!isConnected) { return <div>Connecting to metrics stream...</div>; } if (!metrics) { return <div>Loading metrics...</div>; } return ( <div className="grid grid-cols-4 gap-4"> <MetricCard title="Active Sessions" value={metrics.activeSessions} /> <MetricCard title="API Calls Today" value={metrics.apiCallsToday} /> <MetricCard title="CPU Usage" value={`${metrics.cpuUsage}%`} /> <MetricCard title="Error Rate" value={`${metrics.errorRate}%`} /> </div> ); }

Authentication & Authorization

Access Control

  • Admin Role: Full access to all features
  • Viewer Role: Read-only access (future)
  • API Keys: Secure management with limited scopes

Security

  • Strong password requirements
  • Two-factor authentication (TOTP)
  • Session timeout
  • Login attempt limiting
  • Audit log of all admin actions

Interface Layout

┌─────────────────────────────────────────────────────┐
│  Header                                              │
│  [Logo] Admin Panel          Dr. Nazmy [Logout] ⚙️  │
├──────────────┬──────────────────────────────────────┤
│              │                                       │
│  Sidebar     │  Main Content Area                   │
│  Menu        │                                       │
│              │  [Dashboard/Settings/etc content]    │
│  📊 Dashboard│                                       │
│  ⚙️  System  │                                       │
│  🤖 AI Models│                                       │
│  📚 Knowledge│                                       │
│  👤 Users    │                                       │
│  📈 Analytics│                                       │
│  🔌 Integrations                                     │
│  🔒 Security │                                       │
│  📋 Logs     │                                       │
│              │                                       │
└──────────────┴──────────────────────────────────────┘

Core Pages

1. Dashboard (/dashboard)

Full Dashboard Wireframe:

┌─────────────────────────────────────────────────────────────────────────────────────┐
│ VoiceAssist Admin                   🔔 Alerts (2)     Dr. Nazmy ▼     [Logout]     │
├─────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                      │
│  Dashboard                                                    Last updated: 10s ago │
│                                                                                      │
│  ┌──────────────────┬──────────────────┬──────────────────┬──────────────────┐    │
│  │ Active Sessions  │ API Calls Today  │ Avg Response     │ Error Rate       │    │
│  │                  │                  │                  │                  │    │
│  │      3           │      1,247       │      1.8s        │      0.3%        │    │
│  │  ↑ +1 today      │  ↑ +12% vs avg  │  ↓ -0.2s         │  ↓ -0.1%         │    │
│  └──────────────────┴──────────────────┴──────────────────┴──────────────────┘    │
│                                                                                      │
│  ┌───────────────────────────────┬───────────────────────────────────────────┐    │
│  │ System Resources              │ Service Status                             │    │
│  │                               │                                            │    │
│  │  CPU Usage          68%  ████ │  ┌───────────────────────┬──────────┐    │    │
│  │  Memory Usage       45%  ███  │  │ FastAPI Backend       │  🟢 Up   │    │    │
│  │  GPU Usage (Ollama) 82%  █████│  │ PostgreSQL            │  🟢 Up   │    │    │
│  │  Disk Space         28%  ██   │  │ Redis Cache           │  🟢 Up   │    │    │
│  │  Network I/O        ↑12MB/s   │  │ Vector DB (Qdrant)    │  🟢 Up   │    │    │
│  │  WS Connections     3 active  │  │ Ollama (Local LLM)    │  🟢 Up   │    │    │
│  │                               │  │ OpenAI API            │  🟢 Up   │    │    │
│  │  [View Details]               │  │ Nextcloud             │  🟡 Slow │    │    │
│  │                               │  └───────────────────────┴──────────┘    │    │
│  │                               │                                            │    │
│  └───────────────────────────────┴───────────────────────────────────────────┘    │
│                                                                                      │
│  ┌──────────────────────────────────────────────────────────────────────────┐     │
│  │ Response Time (Last 24 Hours)                                             │     │
│  │                                                                            │     │
│  │  5s  ┤                                                                     │     │
│  │  4s  ┤                                                                     │     │
│  │  3s  ┤          ▄                                                          │     │
│  │  2s  ┤  ▄▄▄▄▄▄▄█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  Cloud API                         │     │
│  │  1s  ┤▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  Local Model                       │     │
│  │  0s  └─┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──────────                     │     │
│  │       00 02 04 06 08 10 12 14 16 18 20 22 Now                            │     │
│  └──────────────────────────────────────────────────────────────────────────┘     │
│                                                                                      │
│  ┌──────────────────────────────────┬──────────────────────────────────────┐      │
│  │ Recent Activity                  │ Quick Actions                         │      │
│  │                                  │                                       │      │
│  │  [10:32] Query: HTN management   │  [⟳ Restart Services]                │      │
│  │  [10:28] Document indexed: DAPA  │  [🗑️ Clear Cache]                    │      │
│  │  [10:15] Query: Drug interaction │  [📚 Update Knowledge Base]          │      │
│  │  [09:58] Error: Nextcloud timeout│  [📋 View System Logs]               │      │
│  │  [09:45] Query: Lab interpretation│ [✓ Run Health Check]                │      │
│  │                                  │                                       │      │
│  │  [View All Activity]             │                                       │      │
│  └──────────────────────────────────┴──────────────────────────────────────┘      │
│                                                                                      │
│  ┌──────────────────────────────────────────────────────────────────────────┐     │
│  │ Alerts & Notifications                                                    │     │
│  │                                                                            │     │
│  │  ⚠️  [10:33] Nextcloud response time degraded (1.2s → 3.5s)              │     │
│  │  ℹ️  [08:00] Backup completed successfully (Database: 2.3GB)             │     │
│  │                                                                            │     │
│  │  [View All Alerts]                                                        │     │
│  └──────────────────────────────────────────────────────────────────────────┘     │
│                                                                                      │
└─────────────────────────────────────────────────────────────────────────────────────┘

Dashboard Components Summary

System metrics defined in OBSERVABILITY.md.

System Overview Cards:

  • Active Sessions: Current WebSocket/REST sessions
  • API Calls Today: Total API requests with trend indicator
  • Avg Response Time: Mean latency with change indicator
  • Error Rate: Percentage of failed requests with trend

Real-Time Metrics:

  • CPU, Memory, GPU usage with bar indicators
  • Disk space utilization
  • Network I/O (upload/download)
  • Active WebSocket connections count

Service Status Table:

  • Health check status for each service (🟢 Up, 🟡 Degraded, 🔴 Down)
  • Last check timestamp
  • Click to view detailed metrics

Response Time Chart:

  • Line chart showing 24-hour latency trends
  • Separate lines for local model vs cloud API
  • Hoverable data points

Recent Activity Feed:

  • Last 10-20 system events
  • Query summaries (sanitized)
  • Document indexing events
  • Error notifications

Quick Actions:

  • One-click service management
  • Cache clearing
  • Knowledge base updates
  • Log viewing
  • Health check execution

2. System Settings (/system)

System settings are global - they affect all users and the entire VoiceAssist instance.

System Settings Interface

Complete TypeScript interface for system-level configuration:

// admin-panel/src/types/systemSettings.ts export interface SystemSettings { // General System Configuration general: { systemName: string; // Display name (e.g., "VoiceAssist Production") systemDescription: string; // Description for documentation timezone: string; // Default system timezone (IANA) language: "en" | "es" | "fr"; // Default interface language maintenanceMode: boolean; // Enable maintenance mode (blocks users) maintenanceMessage: string; // Message shown during maintenance }; // Data Retention & Cleanup dataRetention: { conversationLogs: number; // Days to keep conversation logs (7-365) errorLogs: number; // Days to keep error logs (30-365) accessLogs: number; // Days to keep access logs (30-730) auditLogs: number; // Days to keep audit logs (365-2555) tempFiles: number; // Days to keep temp files (1-30) autoCleanup: boolean; // Enable automatic cleanup cleanupSchedule: string; // Cron expression for cleanup }; // Backup Configuration backup: { enabled: boolean; destination: "local" | "nextcloud" | "s3" | "custom"; schedule: string; // Cron expression retention: number; // Number of backups to keep includeDatabase: boolean; includeVectorDB: boolean; includeDocuments: boolean; includeConfiguration: boolean; includeLogs: boolean; compression: "none" | "gzip" | "zstd"; encryption: boolean; }; // Model Routing & AI Configuration ai: { // Default model preferences defaultLocalModel: string; // e.g., "llama-3.1-8b" defaultCloudModel: string; // e.g., "gpt-4-turbo" defaultEmbeddingModel: string; // e.g., "text-embedding-3-large" // Routing rules routingStrategy: "auto" | "always_local" | "always_cloud"; phiDetectionEnabled: boolean; // Auto-detect PHI and route to local phiKeywords: string[]; // Keywords that trigger PHI detection // Performance limits maxConcurrentRequests: number; // Max concurrent AI requests requestTimeout: number; // Timeout in seconds retryAttempts: number; // Number of retry attempts // Rate limiting (per user) rateLimits: { queriesPerMinute: number; queriesPerHour: number; queriesPerDay: number; }; // Cost controls costLimits: { dailyLimit: number; // $ per day monthlyLimit: number; // $ per month alertThreshold: number; // % threshold for alerts (e.g., 80) }; }; // Logging & Monitoring logging: { level: "DEBUG" | "INFO" | "WARN" | "ERROR"; structuredLogging: boolean; // JSON format logToFile: boolean; logToConsole: boolean; logToSyslog: boolean; sensitiveDataRedaction: boolean; // Redact PHI/PII from logs performanceLogging: boolean; // Log slow queries performanceThreshold: number; // ms threshold for slow query logging }; // Security & Privacy security: { // Session management sessionTimeout: number; // Minutes of inactivity maxSessionDuration: number; // Max session duration in hours requireStrongPasswords: boolean; passwordMinLength: number; passwordRequireSpecialChars: boolean; passwordExpiryDays: number; // 0 = never // Two-factor authentication twoFactorRequired: boolean; twoFactorMethod: "totp" | "sms" | "email"; // API security apiRateLimiting: boolean; apiRateLimit: number; // Requests per minute corsOrigins: string[]; // Allowed CORS origins // Audit logging auditAllActions: boolean; auditLoginAttempts: boolean; auditDataAccess: boolean; auditConfigChanges: boolean; }; // Email Notifications (for alerts) email: { enabled: boolean; smtpHost: string; smtpPort: number; smtpUsername: string; smtpPassword: string; // Encrypted in storage smtpTLS: boolean; fromAddress: string; adminEmails: string[]; // Admins to notify }; // Feature Flags features: { voiceEnabled: boolean; fileUploadEnabled: boolean; knowledgeBaseEnabled: boolean; nextcloudIntegration: boolean; calendarIntegration: boolean; emailIntegration: boolean; webSearchEnabled: boolean; betaFeatures: boolean; }; // Resource Limits resources: { maxUploadSize: number; // MB maxDocuments: number; // Max documents in KB (0 = unlimited) maxVectorDBSize: number; // GB (0 = unlimited) maxConcurrentUsers: number; // (0 = unlimited) }; } // Default system settings export const DEFAULT_SYSTEM_SETTINGS: SystemSettings = { general: { systemName: "VoiceAssist", systemDescription: "Medical AI Assistant", timezone: "UTC", language: "en", maintenanceMode: false, maintenanceMessage: "System is currently under maintenance. Please check back soon.", }, dataRetention: { conversationLogs: 30, errorLogs: 90, accessLogs: 90, auditLogs: 365, tempFiles: 7, autoCleanup: true, cleanupSchedule: "0 2 * * *", // Daily at 2 AM }, backup: { enabled: true, destination: "local", schedule: "0 2 * * *", // Daily at 2 AM retention: 7, includeDatabase: true, includeVectorDB: true, includeDocuments: true, includeConfiguration: true, includeLogs: false, compression: "gzip", encryption: true, }, ai: { defaultLocalModel: "llama-3.1-8b", defaultCloudModel: "gpt-4-turbo", defaultEmbeddingModel: "text-embedding-3-large", routingStrategy: "auto", phiDetectionEnabled: true, phiKeywords: ["patient", "MRN", "DOB", "SSN", "medical record"], maxConcurrentRequests: 10, requestTimeout: 60, retryAttempts: 3, rateLimits: { queriesPerMinute: 20, queriesPerHour: 100, queriesPerDay: 1000, }, costLimits: { dailyLimit: 50, monthlyLimit: 1000, alertThreshold: 80, }, }, logging: { level: "INFO", structuredLogging: true, logToFile: true, logToConsole: true, logToSyslog: false, sensitiveDataRedaction: true, performanceLogging: true, performanceThreshold: 1000, }, security: { sessionTimeout: 30, maxSessionDuration: 8, requireStrongPasswords: true, passwordMinLength: 12, passwordRequireSpecialChars: true, passwordExpiryDays: 90, twoFactorRequired: false, twoFactorMethod: "totp", apiRateLimiting: true, apiRateLimit: 60, corsOrigins: [], auditAllActions: true, auditLoginAttempts: true, auditDataAccess: true, auditConfigChanges: true, }, email: { enabled: false, smtpHost: "", smtpPort: 587, smtpUsername: "", smtpPassword: "", smtpTLS: true, fromAddress: "", adminEmails: [], }, features: { voiceEnabled: true, fileUploadEnabled: true, knowledgeBaseEnabled: true, nextcloudIntegration: true, calendarIntegration: true, emailIntegration: false, webSearchEnabled: true, betaFeatures: false, }, resources: { maxUploadSize: 500, maxDocuments: 0, maxVectorDBSize: 0, maxConcurrentUsers: 0, }, };

Settings Comparison: User vs System

Setting CategoryUser Settings (Per-User)System Settings (Global)
Theme✅ User chooses dark/light❌ Not configurable globally
Language✅ User's preferred language✅ Default system language
Voice Input✅ User enables/disables✅ System enables feature
Citations✅ User's display preference❌ Not applicable
Logging❌ Not user-configurable✅ System log level
Backups❌ Not user-configurable✅ System backup schedule
AI Models✅ User preference (fast/quality)✅ System default models
Rate Limits❌ Applied system-wide✅ System rate limit rules
Data Retention✅ User's conversation retention✅ System-wide retention policy

System Settings Backend API

# app/api/endpoints/admin/system_settings.py from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.api.deps import get_db, get_admin_user from app.models.user import User from app.models.system_settings import SystemSettings as SystemSettingsModel from app.api.schemas.system_settings import SystemSettingsSchema from app.core.config import settings router = APIRouter() @router.get("/system/settings", response_model=SystemSettingsSchema) async def get_system_settings( db: Session = Depends(get_db), current_user: User = Depends(get_admin_user) ): """ Get system settings. Admin only. """ system_settings = db.query(SystemSettingsModel).first() if not system_settings: # Return defaults return SystemSettingsSchema.get_defaults() return system_settings.settings @router.patch("/system/settings", response_model=SystemSettingsSchema) async def update_system_settings( settings_update: SystemSettingsSchema, db: Session = Depends(get_db), current_user: User = Depends(get_admin_user) ): """ Update system settings. Admin only. Validates settings and logs changes to audit log. """ system_settings = db.query(SystemSettingsModel).first() if not system_settings: # Create initial settings system_settings = SystemSettingsModel(settings={}) db.add(system_settings) # Merge updates updated_settings = {**system_settings.settings, **settings_update.dict(exclude_unset=True)} # Validate critical settings if updated_settings['ai']['maxConcurrentRequests'] < 1: raise HTTPException(status_code=400, detail="maxConcurrentRequests must be >= 1") if updated_settings['dataRetention']['conversationLogs'] < 7: raise HTTPException(status_code=400, detail="Conversation log retention must be >= 7 days") # Log change to audit log from app.models.audit_log import AuditLog audit_entry = AuditLog( user_id=current_user.id, action='system_settings_update', resource='system_settings', changes=settings_update.dict(exclude_unset=True) ) db.add(audit_entry) system_settings.settings = updated_settings db.commit() db.refresh(system_settings) # Trigger settings reload in all services from app.core.events import emit_settings_change emit_settings_change() return system_settings.settings @router.post("/system/settings/validate") async def validate_system_settings( settings: SystemSettingsSchema, current_user: User = Depends(get_admin_user) ): """ Validate system settings without saving. Returns validation errors if any. """ errors = [] # Validate email settings if enabled if settings.email.enabled: if not settings.email.smtpHost: errors.append("SMTP host is required when email is enabled") if not settings.email.fromAddress: errors.append("From address is required when email is enabled") # Validate backup settings if settings.backup.enabled: if settings.backup.retention < 1: errors.append("Backup retention must be at least 1") # Validate AI settings if settings.ai.rateLimits.queriesPerMinute < 1: errors.append("Rate limit must be at least 1 query per minute") if errors: return {"valid": False, "errors": errors} return {"valid": True, "errors": []}

System Settings Storage

System settings are stored in:

  1. PostgreSQL system_settings table (single row)
  2. Redis cache for fast access (with 5-minute TTL)
  3. File backup in /etc/voiceassist/system.json (read on startup)

When settings change:

  1. Database is updated
  2. Redis cache is invalidated
  3. WebSocket broadcast to all services
  4. Services reload configuration

3. AI Models Configuration (/models)

Model Selection

Local Models (Ollama)

┌──────────────────────────────────────────┐
│ Local Model: [Dropdown]                  │
│   ● Llama 3.1 8B                         │
│   ● Llama 3.1 70B                        │
│   ● Mistral 7B                           │
│   ● Mixtral 8x7B                         │
│                                           │
│ [Download New Model]                     │
└──────────────────────────────────────────┘

Cloud API Configuration

┌──────────────────────────────────────────┐
│ OpenAI                                    │
│   API Key: [••••••••••••key] [Test]      │
│   Model: gpt-4-turbo                     │
│   Max Tokens: 4096                       │
│   Temperature: 0.7                       │
│                                           │
│ Anthropic Claude (Optional)              │
│   API Key: [Not configured] [Add]        │
└──────────────────────────────────────────┘

Routing Logic

┌──────────────────────────────────────────┐
│ Request Routing                          │
│                                           │
│ ☑️ Auto-route based on privacy          │
│ ☐ Always use local model                │
│ ☐ Always use cloud API                  │
│                                           │
│ Classification Rules:                    │
│   • File access → Local                  │
│   • PHI detected → Local                 │
│   • Medical literature → Cloud           │
│   • Complex reasoning → Cloud            │
│                                           │
│ [Edit Rules]                             │
└──────────────────────────────────────────┘

Embedding Models

  • OpenAI text-embedding-3-large (cloud)
  • Local embedding model (if installed)
  • Benchmark performance

Model Performance

  • Average response time per model
  • Token usage and costs
  • Success/failure rates
  • Switch recommendations based on usage

4. Knowledge Base Management (/knowledge)

Full Knowledge Base Page Wireframe:

┌──────────────────────────────────────────────────────────────────────────────────────┐
│ Knowledge Base Management                                         [Upload Document] │
├──────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                       │
│  ┌────────────────────────────────────────────────────────────────────────────┐     │
│  │ 📊 Statistics                                                               │     │
│  │                                                                              │     │
│  │  ┌──────────────┬──────────────┬──────────────┬──────────────┐            │     │
│  │  │ Documents    │ Total Chunks │ Vector Size  │ Avg Query    │            │     │
│  │  │              │              │              │ Latency      │            │     │
│  │  │    247       │    128,452   │    8.4 GB    │    0.12s     │            │     │
│  │  └──────────────┴──────────────┴──────────────┴──────────────┘            │     │
│  │                                                                              │     │
│  │  Most Queried Topics: Cardiology (487) · Diabetes (312) · ID (234)         │     │
│  └────────────────────────────────────────────────────────────────────────────┘     │
│                                                                                       │
│  ┌────────────────────────────────────────────────────────────────────────────┐     │
│  │ 🔧 Indexing Jobs                                   [View All Jobs]          │     │
│  │                                                                              │     │
│  │  ⏳ In Progress: "SPRINT Trial" (PDF, 45 pages) - 67% complete             │     │
│  │  ✅ Completed: "Harrison's Ch. 234-240" - 3 minutes ago                    │     │
│  │  ❌ Failed: "corrupted_file.pdf" - Invalid format [Retry]                  │     │
│  └────────────────────────────────────────────────────────────────────────────┘     │
│                                                                                       │
│  ┌────────────────────────────────────────────────────────────────────────────┐     │
│  │ 📚 Document Library                                                         │     │
│  │                                                                              │     │
│  │  [🔍 Search documents...]                                                   │     │
│  │                                                                              │     │
│  │  Filters:  Type: [All ▼]  Specialty: [All ▼]  Status: [Indexed ▼]        │     │
│  │  Sort by: [Last Modified ▼]                              Showing 1-10 of 247│     │
│  │                                                                              │     │
│  │  ┌───┬─────────────────────┬───────────┬────────┬──────────┬────────────┐ │     │
│  │  │ ☑ │ Name                │ Type      │ Pages  │ Chunks   │ Actions    │ │     │
│  │  ├───┼─────────────────────┼───────────┼────────┼──────────┼────────────┤ │     │
│  │  │ ☐ │ Harrison's Princ... │ Textbook  │ 3,402  │  18,234  │ 👁️ ⚙️ ⬇️ 🗑️│ │     │
│  │  │   │ Internal Medicine   │           │        │          │            │ │     │
│  │  │   │ 21st Edition        │           │        │          │            │ │     │
│  │  │   │ 🏷️ Cardiology, GI   │ ✅ Indexed│        │ 12 days  │            │ │     │
│  │  ├───┼─────────────────────┼───────────┼────────┼──────────┼────────────┤ │     │
│  │  │ ☐ │ DAPA-HF Trial       │ Journal   │   15   │    145   │ 👁️ ⚙️ ⬇️ 🗑️│ │     │
│  │  │   │ NEJM 2019           │           │        │          │            │ │     │
│  │  │   │ 🏷️ Cardiology       │ ✅ Indexed│        │ 3 days   │            │ │     │
│  │  ├───┼─────────────────────┼───────────┼────────┼──────────┼────────────┤ │     │
│  │  │ ☐ │ 2023 AHA/ACC HTN    │ Guideline │   86   │    892   │ 👁️ ⚙️ ⬇️ 🗑️│ │     │
│  │  │   │ Guidelines          │           │        │          │            │ │     │
│  │  │   │ 🏷️ Cardiology, HTN  │ ✅ Indexed│        │ 1 week   │            │ │     │
│  │  ├───┼─────────────────────┼───────────┼────────┼──────────┼────────────┤ │     │
│  │  │ ☐ │ UpToDate: DKA Mgmt  │ Reference │    8   │     67   │ 👁️ ⚙️ ⬇️ 🗑️│ │     │
│  │  │   │ Updated Oct 2024    │           │        │          │            │ │     │
│  │  │   │ 🏷️ Endocrinology    │ ✅ Indexed│        │ 2 days   │            │ │     │
│  │  ├───┼─────────────────────┼───────────┼────────┼──────────┼────────────┤ │     │
│  │  │ ☐ │ IDSA Sepsis Guide   │ Guideline │   42   │    438   │ 👁️ ⚙️ ⬇️ 🗑️│ │     │
│  │  │   │ 2024 Edition        │           │        │          │            │ │     │
│  │  │   │ 🏷️ ID, ICU          │ ⏳ Indexing│       │ Now      │            │ │     │
│  │  └───┴─────────────────────┴───────────┴────────┴──────────┴────────────┘ │     │
│  │                                                                              │     │
│  │  [◀ Previous]  [1] [2] [3] ... [25]  [Next ▶]                              │     │
│  │                                                                              │     │
│  │  Bulk Actions: [☑ Select All]  [⚙️ Re-index Selected]  [🗑️ Delete Selected] │     │
│  └────────────────────────────────────────────────────────────────────────────┘     │
│                                                                                       │
└──────────────────────────────────────────────────────────────────────────────────────┘

Upload Document Modal:

┌─────────────────────────────────────────────────────────────┐
│ Upload Medical Documents                            [✕ Close]│
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                       │   │
│  │        📄 Drag & Drop Files Here                     │   │
│  │                  or                                   │   │
│  │             [Browse Files]                            │   │
│  │                                                       │   │
│  │  Supported: PDF, DOCX (max 500 MB)                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                               │
│  Selected Files:                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ • harrison_chapter_45.pdf (12.4 MB)           [✕]   │   │
│  │ • ACC_HF_Guidelines_2024.pdf (5.8 MB)         [✕]   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                               │
│  Document Type: [Dropdown ▼]                                 │
│    ● Medical Textbook                                         │
│    ○ Journal Article                                          │
│    ○ Clinical Guideline                                       │
│    ○ Reference Material (UpToDate, etc.)                     │
│    ○ Trial/Study                                              │
│                                                               │
│  Specialty Tags: [Multi-select]                              │
│    [Cardiology ✕] [Endocrinology ✕] [+ Add Tag]             │
│                                                               │
│  Metadata (Optional):                                         │
│    Title: _______________________________________________     │
│    Author(s): ___________________________________________     │
│    Publication Year: [2024 ▼]                                │
│    Edition/Version: _____________________________________     │
│    DOI/PMID: ____________________________________________     │
│                                                               │
│  Indexing Options:                                            │
│    ☑ Start indexing immediately                              │
│    ☑ Extract metadata automatically                          │
│    ☑ Detect specialty from content                           │
│    ☐ High priority (index first)                            │
│                                                               │
│  [Cancel]                              [Upload & Index] ✓   │
│                                                               │
└─────────────────────────────────────────────────────────────┘

Document Detail View:

┌─────────────────────────────────────────────────────────────┐
│ Document Details                                   [✕ Close] │
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  📖 Harrison's Principles of Internal Medicine - Chapter 45  │
│     Atrial Fibrillation and Flutter                          │
│                                                               │
│  ┌──────────────────┬────────────────────────────────────┐  │
│  │ Status           │ ✅ Indexed                         │  │
│  │ Document Type    │ Medical Textbook                   │  │
│  │ Specialty        │ Cardiology, Arrhythmia             │  │
│  │ Pages            │ 18                                  │  │
│  │ Chunks Generated │ 124                                 │  │
│  │ File Size        │ 2.4 MB                              │  │
│  │ Uploaded         │ Nov 10, 2024 10:34 AM              │  │
│  │ Last Indexed     │ Nov 10, 2024 10:38 AM (4m 23s)    │  │
│  │ Uploaded By      │ Dr. Nazmy                          │  │
│  └──────────────────┴────────────────────────────────────┘  │
│                                                               │
│  Metadata:                                                    │
│  ┌───────────────────────────────────────────────────────┐  │
│  │ Authors:  Dennis Kasper, Stephen Hauser, et al.       │  │
│  │ Edition:  21st Edition                                 │  │
│  │ Year:     2022                                         │  │
│  │ Publisher: McGraw-Hill                                 │  │
│  │ ISBN:     978-1264268504                               │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                               │
│  Usage Statistics:                                            │
│  ┌───────────────────────────────────────────────────────┐  │
│  │ Times Cited:      487                                  │  │
│  │ Last Accessed:    2 hours ago                          │  │
│  │ Avg Relevance:    0.82 (High)                          │  │
│  │ Most Cited In:    AF management, stroke prevention    │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                               │
│  Indexing Details:                                            │
│  ┌───────────────────────────────────────────────────────┐  │
│  │ Chunking Strategy: Semantic (500 token windows)       │  │
│  │ Embedding Model:   text-embedding-3-large             │  │
│  │ Vector Dimensions: 3072                                │  │
│  │ Processing Time:   4m 23s                              │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                               │
│  Sample Chunks (first 3 of 124):                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │ 1. "Atrial fibrillation (AF) is the most common      │  │
│  │     sustained cardiac arrhythmia, affecting 1-2% of  │  │
│  │     the general population..."                        │  │
│  │                                                        │  │
│  │ 2. "Risk stratification for stroke prevention uses   │  │
│  │     the CHA2DS2-VASc score. Patients with scores     │  │
│  │     ≥2 should receive anticoagulation..."            │  │
│  │                                                        │  │
│  │ 3. "Rate control strategies include beta-blockers,   │  │
│  │     calcium channel blockers, and digoxin..."         │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                               │
│  [⬇️ Download PDF]  [⚙️ Re-index]  [🗑️ Delete Document]     │
│                                                               │
└─────────────────────────────────────────────────────────────┘

Knowledge Base Management Endpoints

All KB management endpoints use the standard API envelope pattern. See server/README.md for complete specification.

EndpointMethodPurposeRequestResponse
/api/admin/kb/documentsGETList documentsQuery params (filters)APIEnvelope<KnowledgeDocument[]>
/api/admin/kb/documents/{id}GETGet document details-APIEnvelope<KnowledgeDocument>
/api/admin/kb/documentsPOSTUpload documentFormData (file)APIEnvelope<IndexingJob>
/api/admin/kb/documents/{id}DELETEDelete document-APIEnvelope<{success: true}>
/api/admin/kb/jobsGETList indexing jobsQuery params (state filter)APIEnvelope<IndexingJob[]>
/api/admin/kb/jobs/{id}GETGet job details-APIEnvelope<IndexingJob>
/api/admin/kb/jobs/{id}/retryPOSTRetry failed job-APIEnvelope<IndexingJob>
/api/admin/kb/reindexPOSTBulk reindex{document_ids: string[]}APIEnvelope<{job_count: number}>
/api/admin/kb/searchPOSTTest search{query, filters}APIEnvelope<SearchResult[]>

All endpoints return standard APIEnvelope as defined in server/README.md. All entity types reference DATA_MODEL.md.


Indexing Job UI Flow

Complete flow from document upload to indexed status:

┌────────────────────────────────────────────────────────────────┐
│                   Document Upload & Indexing Flow               │
└────────────────────────────────────────────────────────────────┘

User selects file
    ↓
[1. Client validation]
    └─→ Check file type (PDF, DOCX)
    └─→ Check file size (< 50MB)
    ↓
[2. Upload: POST /api/admin/kb/documents]
    └─→ FormData with file
    └─→ Returns: APIEnvelope<IndexingJob>
    ↓
[3. Job created: state = "pending"]
    └─→ Show in "Indexing Jobs" list
    └─→ Display: "Queued"
    ↓
[4. Backend worker picks up job]
    └─→ State transition: pending → running
    ↓
[5. Job running: state = "running"]
    └─→ UI polls: GET /api/admin/kb/jobs/{id}
    └─→ Display progress: "Processing... {processed_chunks}/{total_chunks}"
    └─→ Show spinner
    ↓
[6a. Success: state = "completed"]
    └─→ Display: "✓ Indexed successfully"
    └─→ Show document in KB list
    └─→ Stop polling

[6b. Failure: state = "failed"]
    └─→ Display: "✗ Failed: {error_message}"
    └─→ Show "Retry" button
    └─→ Stop polling

[7. User clicks "Retry" (if failed)]
    └─→ POST /api/admin/kb/jobs/{id}/retry
    └─→ Job state: failed → pending
    └─→ Resume polling

Polling Strategy:
- Interval: 2 seconds while job is "running"
- Exponential backoff if server errors
- Stop when state is "completed" or "failed"
- Timeout after 5 minutes (show error)

Alternative: WebSocket Updates
- Connect to /ws/admin/jobs
- Receive real-time state updates
- No polling needed

Indexing Jobs Hook Example

Complete React hook for managing indexing jobs:

// admin/hooks/useIndexingJobs.ts import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { fetchAPI } from "@/lib/api"; import { IndexingJob } from "@/types"; // From DATA_MODEL.md interface UseIndexingJobsOptions { stateFilter?: "pending" | "running" | "completed" | "failed"; pollInterval?: number; // Milliseconds (default: 2000) } export function useIndexingJobs(options: UseIndexingJobsOptions = {}) { const { stateFilter, pollInterval = 2000 } = options; const queryClient = useQueryClient(); // Fetch jobs list const jobsQuery = useQuery({ queryKey: ["indexing-jobs", stateFilter], queryFn: async () => { const params = new URLSearchParams(); if (stateFilter) params.append("state", stateFilter); return fetchAPI<IndexingJob[]>(`/api/admin/kb/jobs?${params.toString()}`); }, refetchInterval: (data) => { // Poll if any jobs are running const hasRunningJobs = data?.some((job) => job.state === "running"); return hasRunningJobs ? pollInterval : false; }, }); // Retry failed job const retryJob = useMutation({ mutationFn: async (jobId: string) => { return fetchAPI<IndexingJob>(`/api/admin/kb/jobs/${jobId}/retry`, { method: "POST", }); }, onSuccess: () => { // Refetch jobs list queryClient.invalidateQueries({ queryKey: ["indexing-jobs"] }); toast.success("Job retry initiated"); }, onError: (error: APIError) => { if (error.code === "VALIDATION_ERROR") { toast.error("Cannot retry: Max retries exceeded"); } else { toast.error(`Retry failed: ${error.message}`); } }, }); // Bulk reindex const reindexDocuments = useMutation({ mutationFn: async (documentIds: string[]) => { return fetchAPI<{ job_count: number }>("/api/admin/kb/reindex", { method: "POST", body: JSON.stringify({ document_ids: documentIds }), }); }, onSuccess: (data) => { queryClient.invalidateQueries({ queryKey: ["indexing-jobs"] }); toast.success(`${data.job_count} indexing jobs created`); }, }); return { jobs: jobsQuery.data || [], isLoading: jobsQuery.isLoading, isError: jobsQuery.isError, error: jobsQuery.error, retryJob: retryJob.mutate, isRetrying: retryJob.isPending, reindexDocuments: reindexDocuments.mutate, isReindexing: reindexDocuments.isPending, }; } // Fetch single job with detailed progress export function useIndexingJob(jobId: string) { return useQuery({ queryKey: ["indexing-job", jobId], queryFn: async () => { return fetchAPI<IndexingJob>(`/api/admin/kb/jobs/${jobId}`); }, refetchInterval: (data) => { // Poll while job is running return data?.state === "running" ? 2000 : false; }, enabled: !!jobId, }); }

Usage in Component:

// admin/components/IndexingJobsList.tsx export function IndexingJobsList() { const { jobs, isLoading, retryJob } = useIndexingJobs({ stateFilter: undefined, // Show all jobs }); if (isLoading) return <Spinner />; return ( <div className="jobs-list"> <h2>Indexing Jobs</h2> <table> <thead> <tr> <th>Document</th> <th>State</th> <th>Progress</th> <th>Started</th> <th>Actions</th> </tr> </thead> <tbody> {jobs.map(job => ( <tr key={job.id}> <td>{job.doc_key}</td> <td> <JobStateBadge state={job.state} /> </td> <td> {job.state === 'running' && ( <ProgressBar value={job.processed_chunks} max={job.total_chunks || 100} /> )} {job.processed_chunks}/{job.total_chunks || '?'} </td> <td>{formatDate(job.started_at)}</td> <td> {job.state === 'failed' && ( <button onClick={() => retryJob(job.id)}> Retry </button> )} </td> </tr> ))} </tbody> </table> </div> ); }

Document Library Features

Table View:

  • Checkbox for bulk operations
  • Sortable columns (name, type, pages, indexed date)
  • Expandable rows showing tags and metadata
  • Status indicators (✅ Indexed, ⏳ Indexing, ❌ Failed, 📝 Pending)
  • Action buttons (👁️ View, ⚙️ Re-index, ⬇️ Download, 🗑️ Delete)

Filters & Search:

  • Full-text search across titles, authors, content
  • Filter by document type (textbook, journal, guideline, etc.)
  • Filter by specialty (multi-select)
  • Filter by status (indexed, pending, failed)
  • Filter by date range
  • Sort by: name, date added, date modified, pages, usage count

Document Actions:

  • 👁️ View details & metadata with usage stats
  • ⚙️ Re-index (with progress tracking)
  • ⬇️ Download original PDF
  • 🗑️ Delete (with confirmation)
  • 📊 View citation analytics

Bulk Operations

Available Actions:

  • Select all / Select filtered
  • Batch re-indexing with priority queue
  • Batch delete with confirmation
  • Export metadata to CSV/JSON
  • Bulk tag editing
  • Backup selected documents

Indexing Status Panel

Real-time Progress:

  • Current job name and status
  • Progress bar with percentage
  • Estimated time remaining
  • Chunks processed / total
  • Error count

Queue Management:

  • List of pending indexing jobs
  • Priority queue reordering
  • Pause/resume indexing
  • Cancel job option
  • Retry failed jobs

Vector Database Statistics

Metrics Display:

  • Total documents indexed
  • Total text chunks generated
  • Total vector embeddings
  • Database disk size
  • Index memory usage
  • Average query latency
  • Query throughput (queries/sec)
  • Cache hit rate

Top Queried Topics:

  • Bar chart of most-accessed specialties
  • Most cited documents
  • Trending topics this week
  • Underutilized documents

5. User Management (/users)

Note: For single-user initially, this section is minimal. Expandable for multi-user future.

User Profile

  • Name and email
  • Profile picture
  • Medical specialty
  • Preferences

Session Management

  • Active sessions
  • Device/browser info
  • Last activity
  • Revoke session

API Keys (Personal)

  • Generate API keys for programmatic access
  • Scoped permissions
  • Usage tracking
  • Revoke keys

6. Analytics & Usage (/analytics)

Query Analytics

Overview Metrics

  • Total queries (by period)
  • Unique topics
  • Most common medical specialties
  • Peak usage times

Query Type Distribution (Pie Chart)

  • Medical literature: 40%
  • Textbook queries: 25%
  • System commands: 20%
  • Web search: 15%

Popular Topics (Bar Chart)

  • Cardiology: 120 queries
  • Diabetes: 95 queries
  • Infectious Disease: 78 queries
  • ...

Response Time Trends (Line Chart)

  • Average response time over 30 days
  • Separate lines for local vs cloud

Cost Analysis

API Usage

Month: November 2024

OpenAI API:
  - Total tokens: 2,450,000
  - Estimated cost: $45.00
  - Breakdown:
    • GPT-4: $38.00 (1.8M tokens)
    • Embeddings: $5.00 (650k tokens)
    • Realtime API: $2.00 (4.5 hours)

Other APIs:
  - OpenEvidence: $10.00 (subscription)

Total: $55.00

Cost Trends (Line Chart)

  • Daily/monthly spend over time
  • Forecast next month

Knowledge Base Analytics

  • Most accessed documents
  • Citation frequency
  • Specialties most queried
  • Recent additions performance

User Activity

  • Sessions per day
  • Average session duration
  • Conversation length (messages)
  • Voice vs text usage ratio

Export Reports

  • Generate PDF reports
  • CSV data export
  • Custom date ranges

7. Integrations (/integrations)

Nextcloud

┌──────────────────────────────────────────┐
│ Nextcloud Integration                    │
│                                           │
│ Status: 🟢 Connected                     │
│ URL: https://asimo.io/nextcloud          │
│ Username: mohammednazmy                  │
│                                           │
│ ☑️ Auto-index medical documents          │
│ ☑️ Backup conversations                  │
│ ☐ Sync bookmarks                         │
│                                           │
│ Last Sync: 2 minutes ago                 │
│                                           │
│ [Test Connection] [Disconnect]           │
└──────────────────────────────────────────┘

Calendar (macOS/Google)

┌──────────────────────────────────────────┐
│ Calendar Integration                     │
│                                           │
│ Status: 🟢 Enabled                       │
│ Source: macOS Calendar (AppleScript)     │
│                                           │
│ ☑️ Read events                           │
│ ☑️ Create events                         │
│ ☑️ Update events                         │
│ ☐ Delete events (disabled for safety)   │
│                                           │
│ [Test] [Configure]                       │
└──────────────────────────────────────────┘

Email

┌──────────────────────────────────────────┐
│ Email Integration                        │
│                                           │
│ Status: 🟡 Configured but disabled       │
│                                           │
│ IMAP Server: imap.gmail.com              │
│ SMTP Server: smtp.gmail.com              │
│ Email: doctor@example.com                │
│                                           │
│ ☐ Enable email access                   │
│                                           │
│ [Configure] [Test]                       │
└──────────────────────────────────────────┘

PubMed

┌──────────────────────────────────────────┐
│ PubMed / NCBI                            │
│                                           │
│ Status: 🟢 Active (Public API)           │
│                                           │
│ API Key (optional): [Not set]            │
│   (Increases rate limit if provided)     │
│                                           │
│ Queries today: 87 / 10,000 limit         │
│                                           │
│ [Test API]                               │
└──────────────────────────────────────────┘

OpenEvidence

┌──────────────────────────────────────────┐
│ OpenEvidence                             │
│                                           │
│ Status: 🔴 Not configured                │
│                                           │
│ API Key: [_______________] [Save]        │
│                                           │
│ [Sign up] [Test]                         │
└──────────────────────────────────────────┘
┌──────────────────────────────────────────┐
│ Web Search                               │
│                                           │
│ Provider: [Brave Search API ▼]          │
│ API Key: [••••••••••••key]              │
│                                           │
│ ☑️ Enable web search                     │
│                                           │
│ [Test] [Configure]                       │
└──────────────────────────────────────────┘

8. Security & Privacy (/security)

Privacy Settings

┌──────────────────────────────────────────┐
│ Data Retention                           │
│                                           │
│ Conversation logs: [30 days ▼]          │
│ Error logs: [90 days ▼]                 │
│ Access logs: [1 year ▼]                 │
│                                           │
│ ☑️ Log all queries (for debugging)       │
│ ☐ Include PHI in logs (DANGEROUS)       │
└──────────────────────────────────────────┘

PHI Detection Rules

  • Keyword list (MRN, patient name patterns, etc.)
  • Regex patterns
  • Directory blacklist (never send to cloud)
  • Test PHI detector with examples

Data Handling Policy

  • Document current privacy approach
  • HIPAA compliance checklist
  • Link to full privacy policy

Encryption

  • Encryption at rest: Status
  • Encryption in transit: Status
  • Key management

Access Logs

  • Admin login history
  • Failed login attempts
  • API access patterns
  • Suspicious activity alerts

9. Logs & Monitoring (/logs)

Log Viewer

Real-Time Logs

┌──────────────────────────────────────────────────┐
│ [■ Pause] [⟳ Auto-refresh] [⬇️ Download]        │
├──────────────────────────────────────────────────┤
│ 2024-11-19 14:32:15 [INFO] New query received   │
│ 2024-11-19 14:32:16 [INFO] Routed to cloud      │
│ 2024-11-19 14:32:18 [INFO] Response generated   │
│ 2024-11-19 14:32:18 [DEBUG] Citations: 2        │
│ 2024-11-19 14:33:01 [ERROR] Nextcloud timeout   │
│ 2024-11-19 14:33:02 [WARN] Retrying connection  │
└──────────────────────────────────────────────────┘

Filters

  • Log level (DEBUG, INFO, WARN, ERROR)
  • Service (backend, vector-db, ollama, etc.)
  • Time range
  • Search text

Error Tracking

  • Error summary dashboard
  • Error rate over time
  • Most common errors
  • Stack traces
  • Error resolution status

Performance Logs

  • Slow query log (> 5s)
  • API latency tracking
  • Database query performance

10. Backups & Maintenance (/maintenance)

Backup Configuration

┌──────────────────────────────────────────┐
│ Automated Backups                        │
│                                           │
│ Destination: Nextcloud                   │
│ Schedule: Daily at 2:00 AM               │
│                                           │
│ Backup includes:                         │
│ ☑️ PostgreSQL database                   │
│ ☑️ Vector database                       │
│ ☑️ Uploaded documents                    │
│ ☑️ Configuration files                   │
│ ☐ Conversation logs                      │
│                                           │
│ Retention: [7 days ▼]                    │
│                                           │
│ Last backup: 8 hours ago                 │
│ Status: Success                          │
│                                           │
│ [Run Backup Now] [Restore]               │
└──────────────────────────────────────────┘

System Maintenance

  • Database vacuum and optimization
  • Clear old logs
  • Rebuild vector index
  • Clear Redis cache
  • Prune old Docker images

Health Checks

  • Run comprehensive system test
  • Check all integrations
  • Verify model availability
  • Test API endpoints
  • Database connectivity

Update Management

  • Check for updates
  • View changelog
  • Schedule update
  • Rollback to previous version

Mobile Responsiveness

  • Responsive layout for tablet access
  • Essential metrics on mobile
  • Touch-friendly controls
  • Simplified navigation

Notifications & Alerts

Alert Types

  • Critical: Service down
  • Warning: High error rate, disk space low
  • Info: Update available, backup completed

Notification Channels

  • In-app notifications
  • Email alerts
  • Webhook (Slack, Discord, etc.)

Alert Configuration

  • Set thresholds (CPU > 90%, error rate > 5%, etc.)
  • Enable/disable specific alerts
  • Quiet hours

Tools & External Integrations

The admin panel provides comprehensive management of the tools layer and external service integrations. See TOOLS_AND_INTEGRATIONS.md for complete tool specifications.

Tools Overview Dashboard

// Page: /admin/tools interface ToolStatus { tool_name: string; enabled: boolean; category: 'calendar' | 'file' | 'medical' | 'calculation' | 'search'; total_calls_24h: number; success_rate: number; avg_duration_ms: number; last_error?: string; last_error_at?: string; phi_enabled: boolean; requires_confirmation: boolean; } // Display: Grid of tool cards {tools.map(tool => ( <ToolCard> <Header> <Icon /> {tool.tool_name} <StatusBadge success_rate={tool.success_rate} /> </Header> <Metrics> <Stat label="Calls (24h)" value={tool.total_calls_24h} /> <Stat label="Success Rate" value={`${tool.success_rate}%`} /> <Stat label="Avg Duration" value={`${tool.avg_duration_ms}ms`} /> </Metrics> <Footer> <Toggle checked={tool.enabled} onChange={toggleTool} /> <Button onClick={viewDetails}>Details</Button> </Footer> </ToolCard> ))}

Key Metrics:

  • Total tool calls per tool (24h, 7d, 30d)
  • Success rate percentage
  • Average execution duration
  • Error rate and last error
  • PHI detection rate

Tool Configuration

// Page: /admin/tools/:tool_name interface ToolConfiguration { tool_name: string; enabled: boolean; timeout_seconds: number; rate_limit_per_user: number; rate_limit_window_seconds: number; requires_confirmation: boolean; phi_enabled: boolean; custom_settings?: Record<string, any>; } // Example: Calendar Tool Configuration <Form> <Toggle label="Enable Tool" checked={config.enabled} /> <NumberInput label="Timeout (seconds)" value={config.timeout_seconds} min={5} max={300} /> <NumberInput label="Rate Limit (calls per user)" value={config.rate_limit_per_user} min={1} max={1000} /> <NumberInput label="Rate Limit Window (seconds)" value={config.rate_limit_window_seconds} options={[60, 300, 3600]} /> <Toggle label="Require User Confirmation" checked={config.requires_confirmation} description="High-risk actions require explicit user approval" /> <Toggle label="Allow PHI" checked={config.phi_enabled} description="Enable this tool for queries containing PHI" /> <Button type="submit">Save Configuration</Button> </Form>

External API Integrations

// Page: /admin/integrations interface ExternalIntegration { name: string; category: 'medical_search' | 'calendar' | 'file_storage' | 'guidelines'; status: 'connected' | 'disconnected' | 'error'; api_key_configured: boolean; last_tested_at?: string; last_test_status?: 'success' | 'failure'; requests_24h: number; error_rate: number; } // List of integrations: const integrations: ExternalIntegration[] = [ { name: 'OpenEvidence', category: 'medical_search', status: 'connected', api_key_configured: true, last_tested_at: '2025-11-20T10:30:00Z', last_test_status: 'success', requests_24h: 342, error_rate: 0.02, }, { name: 'PubMed (NCBI E-utilities)', category: 'medical_search', status: 'connected', api_key_configured: false, // Public API last_tested_at: '2025-11-20T09:15:00Z', last_test_status: 'success', requests_24h: 156, error_rate: 0.01, }, // ... more integrations ]; <IntegrationsList> {integrations.map(integration => ( <IntegrationCard> <Header> <StatusIndicator status={integration.status} /> <h3>{integration.name}</h3> <CategoryBadge category={integration.category} /> </Header> <Metrics> <Stat label="Requests (24h)" value={integration.requests_24h} /> <Stat label="Error Rate" value={`${(integration.error_rate * 100).toFixed(1)}%`} /> <Stat label="Last Tested" value={formatRelativeTime(integration.last_tested_at)} /> </Metrics> <Actions> <Button onClick={() => configureIntegration(integration.name)}> Configure </Button> <Button onClick={() => testConnection(integration.name)}> Test Connection </Button> </Actions> </IntegrationCard> ))} </IntegrationsList>

Supported Integrations:

IntegrationCategoryAPI Key RequiredPHI SafePurpose
OpenEvidenceMedical SearchYesYes (external)Evidence-based medicine search
PubMed (NCBI)Medical SearchNoYes (external)Biomedical literature search
NextcloudFile StorageNo (internal)No (local PHI)Document storage and retrieval
CalDAV ServerCalendarNo (internal)No (local PHI)Calendar events (via Nextcloud)
Google Custom SearchWeb SearchYesYes (external)General medical web search

Integration Configuration UI

// Page: /admin/integrations/:integration_name interface IntegrationConfig { name: string; enabled: boolean; api_key?: string; api_url?: string; timeout_seconds: number; retry_attempts: number; rate_limit?: number; custom_headers?: Record<string, string>; } // Example: OpenEvidence Configuration <Form> <TextInput label="API Key" type="password" value={config.api_key} placeholder="sk_test_..." helpText="Get your API key from openevidence.com/api-keys" /> <TextInput label="API Base URL" value={config.api_url} placeholder="https://api.openevidence.com/v1" /> <NumberInput label="Timeout (seconds)" value={config.timeout_seconds} min={10} max={60} /> <NumberInput label="Retry Attempts" value={config.retry_attempts} min={0} max={5} /> <NumberInput label="Rate Limit (requests/minute)" value={config.rate_limit} helpText="Leave empty for no limit" /> <Button type="button" onClick={testConnection}> Test Connection </Button> <Button type="submit"> Save Configuration </Button> </Form>

Tool Invocation Logs

// Page: /admin/tools/logs interface ToolInvocationLog { id: string; tool_name: string; user_email: string; session_id: string; call_id: string; arguments: Record<string, any>; status: 'completed' | 'failed' | 'timeout' | 'cancelled'; duration_ms: number; phi_detected: boolean; confirmation_required: boolean; user_confirmed?: boolean; error_code?: string; error_message?: string; created_at: string; } // Display: Searchable table with filters <ToolLogsTable> <Filters> <Select label="Tool" options={allTools} value={filter.tool_name} /> <Select label="Status" options={['all', 'completed', 'failed', 'timeout']} value={filter.status} /> <Toggle label="PHI Only" checked={filter.phi_only} /> <DateRangePicker label="Date Range" value={filter.date_range} /> </Filters> <Table> <thead> <tr> <th>Timestamp</th> <th>Tool</th> <th>User</th> <th>Status</th> <th>Duration</th> <th>PHI</th> <th>Actions</th> </tr> </thead> <tbody> {logs.map(log => ( <tr> <td>{formatDateTime(log.created_at)}</td> <td><code>{log.tool_name}</code></td> <td>{log.user_email}</td> <td><StatusBadge status={log.status} /></td> <td>{log.duration_ms}ms</td> <td>{log.phi_detected && <PHIBadge />}</td> <td> <Button onClick={() => viewDetails(log)}>View</Button> </td> </tr> ))} </tbody> </Table> </ToolLogsTable>

Tool Usage Analytics

// Page: /admin/analytics/tools interface ToolAnalytics { tool_name: string; period: '24h' | '7d' | '30d'; total_calls: number; unique_users: number; success_count: number; failure_count: number; timeout_count: number; avg_duration_ms: number; p95_duration_ms: number; p99_duration_ms: number; phi_detection_rate: number; calls_per_day: Array<{ date: string; count: number }>; } // Visualizations: <Analytics> <MetricsGrid> <MetricCard title="Total Tool Calls" value={analytics.total_calls} trend={+12.5} period="vs last 7d" /> <MetricCard title="Success Rate" value={`${(analytics.success_count / analytics.total_calls * 100).toFixed(1)}%`} trend={+2.3} /> <MetricCard title="Avg Duration" value={`${analytics.avg_duration_ms}ms`} trend={-45} trendLabel="faster" /> <MetricCard title="Unique Users" value={analytics.unique_users} trend={+8} /> </MetricsGrid> <TimeSeriesChart title="Tool Calls Over Time" data={analytics.calls_per_day} xKey="date" yKey="count" /> <BarChart title="Tool Usage by Tool" data={toolsUsage} xKey="tool_name" yKey="total_calls" /> <PieChart title="Tool Status Distribution" data={[ { label: 'Success', value: analytics.success_count }, { label: 'Failed', value: analytics.failure_count }, { label: 'Timeout', value: analytics.timeout_count }, ]} /> </Analytics>

Tool Health Monitoring

// Component: ToolHealthMonitor interface ToolHealth { tool_name: string; status: 'healthy' | 'degraded' | 'down'; last_successful_call?: string; consecutive_failures: number; health_check_at: string; } <HealthMonitor> {toolsHealth.map(health => ( <HealthCard status={health.status}> <h4>{health.tool_name}</h4> {health.status === 'down' && ( <Alert severity="error"> Tool is down. {health.consecutive_failures} consecutive failures. Last success: {formatRelativeTime(health.last_successful_call)} </Alert> )} {health.status === 'degraded' && ( <Alert severity="warning"> Tool performance degraded. Error rate above threshold. </Alert> )} {health.status === 'healthy' && ( <Alert severity="success"> Tool operating normally. </Alert> )} </HealthCard> ))} </HealthMonitor>

Related Documentation:

API for Admin Panel

Endpoints

GET    /api/admin/dashboard          - Dashboard metrics
GET    /api/admin/services/status    - Service health
POST   /api/admin/services/restart   - Restart service
GET    /api/admin/models             - List models
PATCH  /api/admin/models/config      - Update model config
GET    /api/admin/knowledge          - List documents
POST   /api/admin/knowledge/upload   - Upload document
DELETE /api/admin/knowledge/:id      - Delete document
POST   /api/admin/knowledge/reindex  - Trigger reindex
GET    /api/admin/analytics/queries  - Query analytics
GET    /api/admin/analytics/costs    - Cost data
GET    /api/admin/integrations       - Integration status
PATCH  /api/admin/integrations/:name - Update integration
GET    /api/admin/logs               - Fetch logs
GET    /api/admin/users              - List users
POST   /api/admin/backup             - Trigger backup
GET    /api/admin/health             - System health check

Contextual Help & AI Assistant

The admin panel includes integrated help features that connect to the documentation site and provide AI-powered assistance.

HelpButton Component

Available from packages/ui, links to relevant documentation from any admin page:

// Usage in admin pages import { HelpButton } from "@voiceassist/ui"; <HelpButton docPath="admin/security" // Path to docs page section="permissions" // Optional section anchor variant="icon" | "text" | "both" // Display mode size="sm" | "md" | "lg" // Button size /> // Opens: https://assistdocs.asimo.io/admin/security#permissions

Implementation:

  • Location: packages/ui/src/components/HelpButton.tsx
  • Uses NEXT_PUBLIC_DOCS_URL environment variable
  • Opens docs in new tab with appropriate section hash
  • Keyboard accessible (Tab + Enter)

AskAIButton Component

Embedded in admin panel pages to provide contextual AI assistance:

// Location: apps/admin-panel/src/components/shared/AskAIButton.tsx <AskAIButton context={{ page: "security", // Current page context feature: "audit-logs", // Specific feature userId: currentUser.id, // Optional user context }} position="bottom-right" // Fab position />

User Flow:

  1. User clicks "Ask AI" floating action button
  2. Dialog opens with text input field
  3. Page context is pre-filled (user can modify)
  4. Submit sends request to /api/ai/docs/ask
  5. AI response includes relevant doc citations
  6. User can click citations to open full documentation

API Endpoint:

// POST /api/ai/docs/ask interface DocsAskRequest { question: string; context?: { page?: string; feature?: string; userId?: string; }; } interface DocsAskResponse { answer: string; citations: Array<{ doc_path: string; title: string; section?: string; relevance: number; }>; confidence: number; }

Backend Integration:

  • Uses docs_search_tool for semantic search across documentation
  • Leverages Qdrant platform_docs collection (1536-dim embeddings)
  • Returns top-k relevant passages with citations
  • Confidence score indicates answer quality

See Also:


Security Considerations

  • Admin panel on separate subdomain
  • Strong authentication required
  • Rate limiting on all endpoints
  • Audit log all admin actions
  • No sensitive data in client-side code
  • HTTPS only
  • CSRF protection

Future Enhancements

Advanced Features

  • Multi-user management with roles
  • Team collaboration features
  • Custom dashboard widgets
  • Scheduled reports via email
  • Mobile admin app
  • A/B testing for model performance
  • Cost optimization recommendations
  • Automated scaling suggestions

AI-Powered Admin

  • Anomaly detection in metrics
  • Predictive maintenance alerts
  • Intelligent log analysis
  • Automatic optimization suggestions