> ## Documentation Index
> Fetch the complete documentation index at: https://dev-doc.dualmindlab.tech/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These are the DualMind developer and admin docs. The API base URL is https://api.dualmindlab.tech and the local API runs on http://localhost:5079.
> Never send POST, PUT, PATCH or DELETE requests to the production API while developing; use a local API and a development Supabase project.
> Environment variables are documented by name only. Never ask for or print secret values.
> Admin routes under /api/admin require a Supabase access token for a user whose public.users.role is admin. The PUT routes for users, models, providers and threads write every field, so send the full record; PUT /api/admin/keys/{keyId} writes only the fields you send (sending api_key replaces the key).

# Supabase setup

> What a Supabase project needs before the DualMind API, arena and admin panel can use it: auth, tables, views, flags and functions.

Use this checklist to stand up a new environment (a development project, or a fresh production project). Keep values out of git: the API reads them from environment variables, the Workers from secrets.

<Steps>
  <Step title="Create the project and collect its settings">
    From **Project settings → API** you need the project URL, the anon key, the service-role key and the JWT secret. They map to `SUPABASE_URL`, `SUPABASE_ANON_KEY`, `SUPABASE_SERVICE_ROLE_KEY` and `JWT_SECRET` (see [Local setup](/development/setup#environment-variables)).

    <Warning>
      The service-role key bypasses row-level security. It belongs only in the API's environment, never in the arena, the admin panel or any repository.
    </Warning>
  </Step>

  <Step title="Configure Auth">
    * Enable **Email** (with confirmation) and **Google**.
    * Add the redirect URLs for the arena (`https://arena.dualmindlab.tech/auth-callback.html` and your localhost equivalent) and the admin panel.
    * Keep the project on the HS256 JWT secret, or update the API to validate with JWKS before you switch signing keys (see [Authentication](/architecture/authentication#token-validation)).
  </Step>

  <Step title="Create the tables">
    The most reliable way is to copy the schema from an existing environment with the Supabase CLI, for example `supabase db dump --schema public > schema.sql` against the source project, then apply it to the new project. Keep that file out of the docs repositories.

    If you build the tables by hand, create `users`, `ai_models`, `providers`, `provider_api_keys`, `comparisons`, `model_votes`, `threads`, `thread_messages`, `system_settings`, `telegram_sessions` and `model_leaderboard` with the columns in [Database schema](/database/schema). Then add:

    * a unique constraint on `model_votes (comparison_id, user_id)`,
    * foreign keys from `comparisons`, `model_votes`, `threads` and `thread_messages` to their parents,
    * defaults: `users.role = 'user'`, `threads.visibility = 'private'`, `ai_models.status = 'active'`, `model_leaderboard.elo_score = 1000`.
  </Step>

  <Step title="Create the views and the ELO function">
    Create `calculate_elo_update`, `v_leaderboard` and `v_comparisons_masked` as described in [Voting and ELO](/concepts/voting#elo-and-the-leaderboard). Copy the current definitions from the production project's SQL editor rather than writing them from scratch, so environments don't drift.
  </Step>

  <Step title="Seed reference data">
    * `providers`: `groq`, `google`, `cloudflare` (enabled).
    * `ai_models`: at least two active Groq or Google models, so random battles work.
    * `model_leaderboard`: one row per model you want on the leaderboard.
    * `system_settings`: `public_sharing` set to on if shared links should work without signing in.
  </Step>

  <Step title="Create the storage bucket">
    Create the `avatars` bucket in **Storage** for arena profile pictures.
  </Step>

  <Step title="Deploy the Edge Functions">
    `send-admin-email` (admin panel email) and `email-wel-safe` (arena welcome email). Their source isn't in the application repositories; copy them from the production project.
  </Step>

  <Step title="Create the first admin">
    Sign up in the arena, then create a thread, run a battle or chat so `UserSyncService` creates your row in `public.users`. Set `role = 'admin'` on that row from the table editor. From then on, promote others from the admin panel.
  </Step>
</Steps>

## Check it

```bash theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
# API reaches the database (admin token required)
curl -H "Authorization: Bearer $ADMIN_TOKEN" http://localhost:5079/api/admin/dashboard/health

# Leaderboard view is readable
curl http://localhost:5079/api/arena/model-stats

# Feature flag
curl http://localhost:5079/api/settings/feature-flag/public_sharing
```

<Note>
  In September 2026 the API's `SupabaseService` was fixed to send the `apikey` and `Authorization` headers itself, instead of relying on how its `HttpClient` was registered. If PostgREST calls return `401` with "No API key found", check that `SUPABASE_SERVICE_ROLE_KEY` (or `SUPABASE_SERVICE_KEY`) is set.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.