Skip to main content

Overview

DualMind Lab uses PostgreSQL hosted on Supabase. All tables live in the public schema. The backend accesses data via Supabase’s PostgREST API (not an ORM).
9 tables in the public schema. All primary keys are UUID v4. The backend uses the Supabase service role key (bypasses RLS).

Entity relationship diagram

Table definitions

users

Stores all registered users. Synced from Supabase Auth via UserSyncService.EnsureUserExistsAsync().

ai_models

Registry of all AI models available for comparison.

threads

Conversation threads owned by users.

thread_messages

Individual messages within a thread. Supports both single-model and dual-model responses.

comparisons

Records of dual-chat arena comparisons.

model_votes

User votes on comparison outcomes.

providers

AI provider registry (Groq, Bytez, etc.).

provider_api_keys

API keys for each provider with rotation and health tracking.

system_settings

Key-value store for system configuration and feature flags.

Key relationships

  • threads.user_idusers.user_id (thread ownership)
  • thread_messages.thread_idthreads.thread_id (message belongs to thread)
  • comparisons.user_idusers.user_id (who created the comparison)
  • comparisons.model1_id / model2_idai_models.model_id
  • model_votes.comparison_idcomparisons.comparison_id
  • model_votes.winner_model_idai_models.model_id
  • provider_api_keys.provider_nameproviders.provider_name
The UserSyncService.EnsureUserExistsAsync() pattern exists because Supabase Auth creates users in auth.users but not in public.users. The backend must insert the public.users row before any operation that references user_id as a foreign key.