<!-- source: openspec/current/db/types.md -->

---
title: DB — Types
status: stable
owner: pavel
audience: [pavel, ai, engineer]
tldr: Database type shape for the db package — generation rules, table and RPC inventory, regeneration steps, and TypeScript conventions.
---
# DB — types

> Part of openspec/current/db/ — split from db.md on 2026-05-12

## Database types

`packages/db/src/types.ts` — generated by `supabase gen types typescript` against the live project (`nifagnmgwoqkplegsicy`, eu-central-2). Top-level shape: `Database` type with one schema (`public`); plus a recursive `Json` type for JSONB columns. The shape today:

- **Tables (10):** `canvas_sessions`, `canvas_messages`, `canvas_files`, `canvas_invitees`, `canvas_project_instructions`, `canvas_tool_uses`, `inbox`, `projects`, `studio_prompt_templates`, plus the auth-managed `auth.users` (not in `public`). Each with `Row`, `Insert`, `Update`, `Relationships` shapes. The legacy `canvas_artifacts` table — three-name versioned column shape from v1 — was retired by RAP-44 → RAP-70 (runtime rewire) and dropped by RAP-75 (`supabase/migrations/20260505163010_rap_75_drop_canvas_artifacts.sql`).
- **Functions (2 RPCs, added 2026-05-03 via change `replace-listusers-with-rpc`):** `get_user_displays(p_canvas_id: string, p_user_ids: string[])` returning a roster array (`id`, `email`, `display_name`, `avatar_url`, `default_persona`, `is_platform_owner`); `get_user_id_by_email(p_email: string)` returning a user id string. Each appears under `Functions` with its `Args` and `Returns` types and is callable via `supabase.rpc("<name>", args)` against either client. See `entities.md § Public RPCs`.
- **Views, Enums, CompositeTypes:** declared as empty `Record`s.

> **By design:** there is no `public.profiles` table and no `auth.users` triggers. Workspace access is gated via the `platform_owner` flag on `auth.users.raw_app_meta_data` and per-canvas membership in `canvas_invitees`, both checked in middleware (`packages/auth/src/proxy.ts`). User display fields (`display_name`, `avatar_url`) come from `auth.users.user_metadata` at the auth-package layer, not from a project schema table.

---

## TypeScript conventions

### `Database` generic on every `createClient`

Both `client.ts:5` and `admin.ts:9` pass `<Database>` to `createClient` so consumer queries are type-safe (`db.from("profiles").select(...)` autocompletes). Type fidelity depends on `types.ts` being current — see Known gaps in `spec.md`.

---

## Regenerating types

The live Supabase project (`nifagnmgwoqkplegsicy`, eu-central-2) is the source of truth.

1. Run `pnpm --filter @rapoport-studio/db generate-types`. This invokes `supabase gen types typescript --project-id nifagnmgwoqkplegsicy > src/types.ts` (wired in `packages/db/package.json:12`).
2. Commit the regenerated file. Diff review: confirm `Json`, `Database`, schema names, and `Tables`/`Views`/`Functions`/`Enums`/`CompositeTypes` shape are all present.
3. Update `entities.md § Database types` if the table count or schema shape changes.
4. Re-run `pnpm --filter @rapoport-studio/db typecheck` and (in consumer packages) `pnpm --filter @rapoport-studio/auth typecheck` to surface drift.

---

## Adding a new table

Out of scope for this package — schema lives in Supabase, applied via SQL migrations. After a schema change:

1. Apply the migration in Supabase.
2. Regenerate types (above).
3. Update consumers (e.g., `packages/auth`) if their queries reference the changed shape.
