Skip to main content

Overview

The admin panel is a separate Cloudflare Workers application providing a management dashboard for all DualMind Lab entities: users, AI models, threads, comparisons, votes, and providers.

Technology stack

AspectChoice
LanguageVanilla JavaScript
HostingCloudflare Workers
BundlerWrangler (Cloudflare CLI)
API AccessProxied through Worker to backend

Directory structure

DualMind Admin UI/
├── public/
│   ├── js/
│   │   ├── api/              # Admin API client
│   │   ├── pages/            # Page-specific logic
│   │   └── utils.js          # Shared utilities
│   ├── partials/
│   │   ├── sidebar.html      # Navigation sidebar
│   │   └── topbar.html       # Top bar
│   ├── assets/
│   │   ├── css/              # Stylesheets
│   │   └── js/               # Vendor scripts
│   ├── index.html            # Dashboard
│   ├── users.html            # User management
│   ├── models.html           # Model management
│   ├── comparisons.html      # Comparison browser
│   ├── config.js             # API base URL
│   └── auth-gate.js          # Admin auth check
├── worker.js                 # Cloudflare Worker entry
├── wrangler.toml             # Deployment config
└── package.json

Worker proxy pattern

The worker.js is the entry point. It handles three responsibilities:

1. API proxy (/api/*)

All requests starting with /api/ are forwarded to the backend:
worker.js
if (pathname.startsWith('/api/')) {
    const backendUrl = env.BACKEND_URL || 'https://api.dualmindlab.tech';
    const backendRequestUrl = new URL(pathname + url.search, backendUrl);
    // Forward with original headers + X-Forwarded-Host
    const backendResponse = await fetch(new Request(backendRequestUrl, {
        method: request.method,
        headers: headers,
        body: request.method !== 'GET' ? request.body : null,
    }));
    // Add CORS headers and return
}

2. Static file serving

Non-API requests are served from the ASSETS binding (Cloudflare Workers Sites KV):
if (env.ASSETS) {
    let assetResponse = await env.ASSETS.fetch(request);
    // Add security headers: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection
}

3. Clean URL routing

  • Extensionless paths try .html suffix (e.g., /users serves users.html)
  • Unmatched routes fall back to index.html

Admin API endpoints

All admin endpoints are at /api/admin/* on the backend. The admin panel calls these through its Worker proxy.
PageBackend endpointsOperations
Dashboard/api/admin/dashboard/stats, /recent-activity, /model-performanceRead-only stats
Users/api/admin/usersList, create, update, delete, search
Models/api/admin/modelsList, create, update, delete, search, toggle status
Threads/api/admin/threadsList, create, update, delete, search by user
Comparisons/api/admin/comparisonsList, delete, search, filter by user/model
Votes/api/admin/votesList, delete, stats by model
Providers/api/admin/providersCRUD providers, manage API keys

Authentication

The admin panel uses the same Supabase JWT as the main frontend. The auth-gate.js script checks for a valid session on page load and redirects to login if missing.
Admin endpoints on the backend currently do not enforce role-based access control. Any authenticated user can access admin APIs. This is a known limitation for the college project scope.

Deployment

# Development
npm run dev          # wrangler dev (local)

# Production
npm run deploy       # wrangler deploy
npm run deploy:prod  # wrangler deploy --env production
Environment variables are configured in wrangler.toml:
  • BACKEND_URL — Backend API base URL