Skip to content

Data model

The SQL plan should keep ownership and authorization explicit.

TableKey columns
profilesid, email, display_name, created_at
tenantsid, slug, name, settings, created_at
tenant_memberstenant_id, user_id, role, created_at
agentstenant_id, slug, name, description, settings
agent_channelstenant_id, agent_id, slug, name, is_main, settings
api_keystenant_id, agent_id, channel_id, hash, prefix, scopes, last_used_at, revoked_at
approval_policiestenant_id, scope_type, scope_id, settings
frame_submissionstenant_id, agent_id, channel_id, api_key_id, status, metadata, idempotency_key
framestenant_id, agent_id, channel_id, date_key, status, current_submission_id
frame_mediasubmission_id, kind, storage_provider, storage_key, delivery_id, status
frame_eventstenant_id, submission_id, event_type, actor_type, payload

Status is tracked on three independent axes. They are not interchangeable — readers and implementers should always name the axis explicitly.

AxisColumnEnum (see Supabase SQL plan)What it describes
Submission lifecycleframe_submissions.statussubmission_status (9 values)The ingest/processing/review/terminal journey of a single submission. See Promotion workflow.
Frame gateframes.statusframe_status (4 values)The reviewed frame entity’s visibility gate from team_visible onward. See Promotion gate philosophy.
Media processingframe_media.statustext (not enum)Per-asset processing state from upload to delivery-ready.

A submission can be needs_review while its media is still processing — the axes advance independently until the reviewer makes a frame team_visible, at which point both submission and frame share the same four terminal-or-near-terminal gate states.

  • Browser reads only tenants where the user is a member.
  • API-key calls are handled server-side by Edge Functions, not exposed through browser RLS.
  • Realtime channels must be scoped by tenant membership.