Skip to main content

Users & Profiles

auth.users — managed by Supabase

Authentication identity lives entirely in Supabase Auth's auth.users table. We do not own this table, do not migrate it, and do not duplicate its columns into public.

ColumnTypeNotes
idUUIDThe canonical user identifier — referenced by every domain table
emailvarchar
phonetext
email_confirmed_attimestamptz
created_attimestamptz
updated_attimestamptz

Roles (user, moderator, admin) are encoded as JWT claims (e.g. app_role), not as a column on auth.users. The application layer signs that claim into the JWT during/after login; clients can never set it.

profiles — shipped

The dating-side view of a user. Created explicitly via POST /profiles after sign-up — there is no on_auth_user_created trigger because most fields are NOT NULL and require user input.

Source: profile.schema.ts.

ColumnTypeNotes
idUUID PKDrizzle defaultRandom()
user_idUUID, unique, NOT NULL1:1 with auth.users.id
first_nametext
biotext | null
dating_purposetextFK target: dating_purposes.code
show_dating_purposeboolean
hometowntextFree-text for now
birth_datedate
religiontextFK target: religions.code
zodiacenum zodiacServer-derived from birth_date
heightintegercm, 55..272
family_plantextFK target: family_plans.code
alcohol_attitudeenum attitudepositive / neutral / negative
smoking_attitudeenum attitudesame
financial_statetextFK target: financial_state.code
body_typetextFK target: body_type.code

Postgres enums

CREATE TYPE attitude AS ENUM ('positive', 'neutral', 'negative');
CREATE TYPE zodiac AS ENUM (
'aquarius','pisces','aries','taurus','gemini','cancer',
'leo','virgo','libra','scorpio','sagittarius','capricorn'
);
CREATE TYPE education_level AS ENUM (
'basic_general','average_general','secondary_special',
'bachelor','specialty','master','postgraduate'
);

Adding values to a Postgres enum is one-way and requires a separate ALTER TYPE … ADD VALUE migration.

Reference / lookup tables — shipped

All share the (id serial PK, code text) shape via the referenceColumns factory and are seeded from src/infra/db/seeds/.

TableSeed values
dating_purposesdating, relationship, friendship, chatting
body_typeslim, normal, fit, sportive, muscular, stocky, chubby
family_plansno-dont-want, no-not-soon, no-maybe-in-future, no-but-want-to, already-have
financial_stateunemployed, studying, irregular-income, low-income, middle-income, wealthy
religionscatholicism, orthodoxy, islam, protestantism, buddhism, hinduism, atheism, agnosticism, judaism

Add new values via a migration that simply INSERT … ON CONFLICT DO NOTHING.

languages

ColumnTypeNotes
idserial PK
codevarchar(2), uniqueISO 639-1
name_rutext, uniqueRussian name
native_nametext, uniqueLocalized native name

Source: languages.schema.ts.

Planned tables

profile_educations (planned, scaffolded)

ColumnType
idUUID
profile_idUUID FK → profiles.id
levelenum education_level
in_progressboolean

profile_languages (planned, scaffolded)

Join table:

ColumnType
profile_idUUID FK → profiles.id
language_idint FK → languages.id

friendships (planned)

ColumnTypeNotes
idUUID PK
requester_idUUIDFK → auth.users.id
addressee_idUUIDFK → auth.users.id
statustextpending, accepted, rejected, blocked
created_attimestamptz
CREATE UNIQUE INDEX friendships_pair_uniq
ON friendships(LEAST(requester_id, addressee_id), GREATEST(requester_id, addressee_id));
CREATE INDEX friendships_status_idx ON friendships(status);

Relationship overview

Row-Level Security

The full convention is documented in api/docs/RLS-NOTES.md. Highlights:

  • RLS enabled on every table we own. Denied-by-default.
  • Lookup tables (dating_purposes, body_type, etc.) — readable by anon + authenticated. They contain zero PII and the signup form needs them before the user has a JWT.
  • profilesauthenticated may SELECT/INSERT/UPDATE only their own row (auth.uid() = user_id). anon SELECT is REVOKEd so PostgREST does not even list the table.
  • Cross-user reads (matching, feed, friend graph) are deliberately not granted at the DB layer. They go through the API server running as service_role after applying business-rule authorization in code.