Skip to main content

System architecture diagram

This diagram shows the complete system. Every arrow is an HTTP request — no WebSocket, no message queues, no background workers.

Component interaction summary

ComponentTalks toProtocolPurpose
FrontendBackend APIHTTPS REST + SSEAll user actions: chat, vote, thread management
FrontendSupabase AuthHTTPSUser login/signup, obtain JWT
Admin PanelBackend APIHTTPS REST (proxied via Worker)CRUD operations on all entities
Backend APISupabase/PostgreSQLHTTPS (PostgREST)Data persistence for all tables
Backend APIGroqHTTPSPrimary AI chat completions
Backend APIBytezHTTPSSecondary AI chat completions
Backend APISupabase AuthJWT validationVerify user identity on each request

Repositories

Backend API

DualMind_Back — .NET 8 REST API with JWT auth, AI provider gateway, and Supabase data access

Frontend

DualMind UI — Vanilla JS SPA with SSE streaming, served via Cloudflare Workers

Admin Panel

DualMind Admin UI — Cloudflare Worker dashboard with full CRUD for all entities

Backend architecture

The backend is a .NET 8 ASP.NET Core Web API located at src/DualMind.API/.

Directory structure

  • src/DualMind.API/
    • AI/
      • Contracts/ — IChatProvider, ChatRequest, GroqResponse, AIStreamEvent
      • Gateway/ — ChatProviderFactory routes to correct provider
      • Providers/ — GroqService, BytezService implementations
    • Controllers/
      • Api/
        • ArenaController.cs — POST /api/arena/chat, /dualchat, /chat/stream
      • Admin/
        • AdminDashboardController.cs
        • AdminAIModelsController.cs
        • AdminUsersController.cs
        • AdminComparisonsController.cs
        • AdminModelVotesController.cs
        • AdminThreadsController.cs
        • AdminProvidersController.cs
      • ModelsController.cs — GET /api/models
      • ThreadsController.cs — CRUD /api/threads
      • UsersController.cs — POST /api/users/sync
      • SettingsController.cs — GET /api/settings/feature-flag/
      • HealthController.cs — GET /health
      • SpeechController.cs — POST /api/speech/generate
    • Core/
      • Exceptions/ — ProviderExhaustedException
      • Models/ — User, AIModel, Comparison, ModelVote, Thread DTOs
      • Services/ — ModelSelector, ThreadsService, etc.
    • Infrastructure/
      • Configuration/ — EnvConfig, SupabaseSettings
      • Data/ — SupabaseService, AdminSupabaseClient
    • Program.cs — App bootstrap, DI registration, middleware
    • Dockerfile

Key design patterns

  • : ChatProviderFactory routes requests to the correct provider based on model metadata.
  • Automatic fallback: If a provider fails, the system falls back to Groq with llama-3.3-70b-versatile. If Groq fails, it tries an alternative Groq model.
  • : Automatic rotation on auth errors, rate limits, and cooldowns.
  • : UserSyncService.EnsureUserExistsAsync() is called before any data-writing operation.

Dependency injection (Program.cs)

// AI Providers — typed HttpClient to prevent socket exhaustion
builder.Services.AddHttpClient<GroqService>(c => c.Timeout = TimeSpan.FromSeconds(45));
builder.Services.AddHttpClient<BytezService>(c => c.Timeout = TimeSpan.FromSeconds(300));
builder.Services.AddScoped<IChatProviderFactory, ChatProviderFactory>();

// Core services
builder.Services.AddSingleton<IModelSelector, ModelSelector>();
builder.Services.AddScoped<IThreadsService, ThreadsService>();
builder.Services.AddScoped<IThreadMessagesService, ThreadMessagesService>();
builder.Services.AddScoped<IModelStatsService, ModelStatsService>();
builder.Services.AddScoped<ILeaderboardModelSelector, LeaderboardModelSelector>();
builder.Services.AddScoped<IComparisonLogger, ComparisonLogger>();
builder.Services.AddScoped<IMessageLogger, MessageLogger>();
builder.Services.AddScoped<IUserSyncService, UserSyncService>();
builder.Services.AddScoped<ISystemSettingsService, SystemSettingsService>();

// Data access
builder.Services.AddHttpClient<ISupabaseService, SupabaseService>();
builder.Services.AddHttpClient<IAdminSupabaseClient, AdminSupabaseClient>();
builder.Services.AddScoped<IProviderConfigService, ProviderConfigService>();

Frontend architecture

The frontend is a vanilla JavaScript single-page application served via Cloudflare Workers.

Directory structure

  • DualMind UI/
    • js/
      • api/
        • DualMindApi.js — Main API client facade
        • config/ApiConfig.js — Base URL, timeout configuration
        • core/HttpClient.js — Fetch wrapper with retry, auth headers
        • services/
          • ArenaService.js — chat(), dualChat(), streamChat()
          • ThreadService.js — CRUD threads and messages
          • ModelService.js — getModels()
          • UserService.js — syncUser()
      • app-final.js — Main application entry point
      • arena-core.js — Arena battle UI logic
    • components/
      • chat/ChatView.js — Chat message rendering
      • ChatInput.js — User input component
      • Header.js — Top navigation
      • ShareModal.js — Thread sharing dialog
    • css/ — Stylesheets
    • config.js — Global configuration (API URL, Supabase keys)
    • index.html — Main entry HTML
    • worker.js — Cloudflare Worker (serves static + proxies API)
    • wrangler.jsonc — Cloudflare deployment config

Key patterns

  • API client facade: DualMindApi class wraps all HTTP calls. Services like ArenaService, ThreadService encapsulate endpoint-specific logic.
  • SSE streaming: Uses fetch() with ReadableStream (not EventSource) for streaming chat responses.
  • Auth flow: Supabase JS client handles OAuth/email login. JWT stored in Supabase session, injected as Authorization: Bearer header on every API call.
  • Config-driven: window.DUALMIND_CONFIG provides runtime configuration for API base URL, streaming settings, timeouts, and feature flags.

Admin panel architecture

The admin panel is a separate Cloudflare Workers application.
  • DualMind Admin UI/
    • public/
      • js/
        • api/ — Admin API client
        • pages/ — Page-specific JS (users, models, etc.)
        • utils.js — Shared utilities
      • partials/
        • sidebar.html — Navigation sidebar
        • topbar.html — Top bar
      • index.html — Dashboard page
      • users.html — User management
      • models.html — Model management
      • comparisons.html — Comparison browser
      • config.js — API base URL config
      • auth-gate.js — Admin authentication check
    • worker.js — Cloudflare Worker entry point
    • wrangler.toml — Deployment config
    • package.json

Admin worker proxy pattern

The admin Cloudflare Worker intercepts all requests:
  1. /api/* routes are proxied to the backend (BACKEND_URL env var, default: https://api.dualmindlab.tech)
  2. Static files are served from the public/ directory via the ASSETS binding
  3. Extensionless paths fall back to .html files (e.g., /users/users.html)
  4. SPA fallback returns index.html for unmatched routes

Environment variables

VariableRequiredDescription
SUPABASE_URLYesSupabase project URL (e.g., https://xxx.supabase.co)
SUPABASE_SERVICE_ROLE_KEYYesService role key for server-side DB access
SUPABASE_KEYFallbackAnon key (used if service role key not set)
JWT_SECRETRecommendedSupabase JWT secret for HS256 token validation
GROQ_API_KEYOptionalGroq API key (overrides database keys)
The service role key bypasses Row Level Security. Never expose it in client-side code.

Next steps

Request Lifecycle

Detailed execution flow from HTTP request to response

Backend Deep Dive

Controllers, services, data access, and middleware pipeline

Data Flow Diagrams

Mermaid diagrams for every major operation

Database Schema

Complete table definitions and ER diagram