Skip to content

Admin UI Guide

Multi-tenant clinic management with RBAC authentication

Version: 1.5.1 Updated: 2026-01-16


Overview

The Vitara Admin UI provides a React-based web interface for managing clinic configurations, EMR integrations, user accounts, and audit logs. It supports two distinct user roles with separate dashboards.

URL: https://{host}/admin/


User Roles

Role Access Description
Vitara Admin All clinics Platform administrators with full system access
Clinic Manager Own clinic Single-clinic administrators for self-service

Authentication

JWT-Based Authentication

The admin system uses PassportJS + JWT for authentication:

  • Access tokens (1 hour expiry)
  • Refresh tokens (7 days expiry)
  • bcrypt password hashing (cost factor 12)
  • Account lockout after 5 failed attempts (15 min)

Login Flow

  1. User submits email/password to /api/auth/login
  2. Server validates credentials against admin_users table
  3. Returns JWT access token + refresh token
  4. Frontend stores tokens in localStorage
  5. All API requests include Authorization: Bearer {token}

Password Requirements

  • Minimum 8 characters
  • At least one letter and one number
  • Checked against common passwords

Vitara Admin Features

Dashboard (/admin/dashboard)

  • Clinic Statistics: Total, active, live, pending approval counts
  • Recent Activity: Last 24 hours audit log summary
  • Quick Actions: Links to clinic/user management

Clinic Management (/admin/clinics)

Feature Description
List Clinics Paginated table with search and status filter
Create Clinic Add new clinic with name, slug, timezone
View/Edit Clinic Update clinic details, contact info, status
EMR Configuration Configure OSCAR connection (URL, API key, OAuth)
Preferences Language, booking rules, reminders
Go-Live Workflow Validate and enable EMR integration

User Management (/admin/users)

Feature Description
List Users Paginated table with role filter
Create User Add vitara_admin or clinic_manager
Edit User Update name, email, role, clinic assignment
Reset Password Admin-initiated password reset
Unlock Account Clear failed login attempts
Activate/Deactivate Enable or disable user accounts

Audit Logs (/admin/audit-logs)

Feature Description
Query Logs Filter by action, user, date range
View Details See changes and metadata per entry
Activity Summary Dashboard widget with counts by action

Clinic Manager Features

My Clinic (/admin/my-clinic)

Feature Description
Clinic Info View clinic name, timezone, contact details
Edit Preferences Update booking rules, reminder hours
Request Go-Live Submit request for EMR activation

Limitations

Clinic Managers cannot:

  • View or manage other clinics
  • Create or manage users
  • View system-wide audit logs
  • Directly enable EMR live status

Go-Live Workflow

The go-live workflow ensures clinics are properly configured before enabling real EMR operations.

Validation Checks

Check Requirement
Status Clinic must be active or pending_approval
EMR URL OSCAR base URL must be configured
API Key EMR API key must be set
Provider Default provider number must be configured

Process

  1. Vitara Admin: Configure EMR settings for clinic
  2. Clinic Manager: Test in demo mode, request go-live
  3. Vitara Admin: Run validation checks
  4. Vitara Admin: Enable emr_live if all checks pass
  5. System: Voice agent now uses real EMR for this clinic

Demo Mode

When emr_live = false:

  • Voice agent returns mock/demo data
  • No real EMR operations performed
  • Clinic can test voice agent safely
  • Demo patient: "Demo Patient" (DEMO-001)
  • Demo provider: "Dr. Demo Doctor" (DEMO-DR-001)

API Response Format

Standard Response Structure

All admin API endpoints return responses in a consistent format:

{
  "success": true,
  "data": [...],
  "pagination": {
    "page": 1,
    "pageSize": 10,
    "total": 25,
    "totalPages": 3
  }
}

The frontend api.js service unwraps this structure: - For paginated endpoints: Returns { data: [...], pagination: {...} } - For non-paginated endpoints: Returns just the data array/object

Database Field Naming

The API returns PostgreSQL column names directly. Frontend components use these field names:

Table Field Description
clinic_config clinic_id UUID primary key
clinic_config clinic_name Clinic display name
clinic_config clinic_created_at Creation timestamp
clinic_config emr_live EMR live status boolean
admin_users id UUID primary key
admin_users email User email
admin_users role vitara_admin or clinic_manager
audit_log changes JSONB - before/after values
audit_log metadata JSONB - additional context

JSONB Field Handling

PostgreSQL JSONB columns are auto-parsed by the pg driver. The backend uses safeJsonParse() to handle both pre-parsed objects and string values:

function safeJsonParse(value) {
  if (value === null || value === undefined) return null;
  if (typeof value === 'object') return value; // Already parsed
  try {
    return JSON.parse(value);
  } catch {
    return value;
  }
}

API Endpoints

Authentication

Method Endpoint Description
POST /api/auth/login User login
POST /api/auth/logout User logout
POST /api/auth/refresh Refresh access token
POST /api/auth/change-password Change own password
GET /api/auth/me Get current user info

Admin - Clinics (Vitara Admin only)

Method Endpoint Description
GET /api/admin/clinics List clinics (paginated)
GET /api/admin/clinics/stats Get clinic statistics
POST /api/admin/clinics Create new clinic
GET /api/admin/clinics/:id Get clinic details
PUT /api/admin/clinics/:id Update clinic
DELETE /api/admin/clinics/:id Delete clinic
PUT /api/admin/clinics/:id/emr-config Update EMR configuration
POST /api/admin/clinics/:id/test-connection Test EMR connection
GET /api/admin/clinics/:id/validate-go-live Validate go-live requirements
POST /api/admin/clinics/:id/go-live Set EMR live status

Admin - Users (Vitara Admin only)

Method Endpoint Description
GET /api/admin/users List users (paginated)
POST /api/admin/users Create user
GET /api/admin/users/:id Get user details
PUT /api/admin/users/:id Update user
DELETE /api/admin/users/:id Delete user
POST /api/admin/users/:id/reset-password Reset user password
POST /api/admin/users/:id/unlock Unlock user account
POST /api/admin/users/:id/activate Activate user
POST /api/admin/users/:id/deactivate Deactivate user

Admin - Audit Logs (Vitara Admin only)

Method Endpoint Description
GET /api/admin/audit-logs List audit logs (paginated)
GET /api/admin/audit-logs/summary Get activity summary

Clinic Manager - Self-Service

Method Endpoint Description
GET /api/clinic/me Get own clinic
PUT /api/clinic/preferences Update clinic preferences
POST /api/clinic/request-go-live Request go-live status

Database Tables

admin_users

Column Type Description
id UUID Primary key
email VARCHAR(255) Unique, lowercase
password_hash VARCHAR(255) bcrypt hash
role VARCHAR(50) vitara_admin or clinic_manager
clinic_id UUID FK to clinic_config (for managers)
first_name VARCHAR(100) Optional
last_name VARCHAR(100) Optional
is_active BOOLEAN Account status
failed_login_attempts INTEGER Lockout counter
locked_until TIMESTAMP Lockout expiry

audit_log

Column Type Description
id UUID Primary key
action VARCHAR(100) e.g., auth.login, clinic.update
resource_type VARCHAR(50) e.g., clinic_config, admin_user
resource_id UUID Affected resource ID
user_id UUID Acting user
user_email VARCHAR(255) For display
user_role VARCHAR(50) Role at time of action
changes JSONB Before/after values
metadata JSONB Additional context
ip_address INET Request IP
created_at TIMESTAMP Immutable

Configuration

Environment Variables

Variable Default Description
JWT_SECRET (required) Access token signing key
JWT_REFRESH_SECRET (required) Refresh token signing key
JWT_EXPIRES_IN 1h Access token expiry
JWT_REFRESH_EXPIRES_IN 7d Refresh token expiry
EMR_DEMO_MODE true Enable demo responses

Seeding Initial Admin

-- Create first Vitara Admin (password: changeme123)
INSERT INTO admin_users (
  id, email, password_hash, role, is_active
) VALUES (
  gen_random_uuid(),
  'admin@vitara.io',
  '$2a$12$...(bcrypt hash)...',
  'vitara_admin',
  true
);

Security Features

Feature Implementation
Password Hashing bcrypt with cost factor 12
JWT Tokens HS256 algorithm, short-lived
Account Lockout 5 failed attempts = 15 min lock
Audit Logging All admin actions logged
RBAC Role-based access control middleware
Input Validation Joi schemas on all endpoints

Tech Stack

Component Technology
Frontend React 18, React Router, Tailwind CSS
Build Vite
Backend Express.js
Auth PassportJS, JWT
Database PostgreSQL
Validation Joi

Support

For admin UI issues, contact support@vitaravox.com