Raypx

Schema

Database schema tables, columns, and conventions.

The database schema is defined in two files under packages/database/src/schema/:

  • auth.ts -- Tables managed by Better Auth (user, session, account, verification).
  • app.ts -- Application tables (profiles, subscriptions, conversations, etc.).

Auth Tables

Defined in packages/database/src/schema/auth.ts:

user

ColumnTypeConstraintsDescription
idtextPKUser ID (set by Better Auth).
nametextNOT NULLDisplay name.
emailtextNOT NULL, UNIQUEEmail address.
email_verifiedbooleanNOT NULL, default falseWhether email is verified.
imagetextnullableAvatar URL.
created_attimestamptzNOT NULL, default now()Creation time.
updated_attimestamptzNOT NULL, auto-updateLast update time.

Indexes: idx_user_email on email.

session

ColumnTypeConstraintsDescription
iduuidPK, UUID v7Session ID.
tokentextNOT NULL, UNIQUESession token.
expires_attimestamptzNOT NULLExpiration time.
user_idtextNOT NULL, FK -> user.id, CASCADEOwner.
ip_addresstextnullableClient IP.
user_agenttextnullableBrowser user-agent.
last_activetimestamptzNOT NULL, default now()Last activity.
created_attimestamptzNOT NULL, default now()Creation time.
updated_attimestamptzNOT NULL, auto-updateLast update time.

Indexes: idx_session_token, idx_session_user_id.

account

ColumnTypeConstraintsDescription
iduuidPK, UUID v7Account ID.
account_idtextNOT NULLProvider account ID.
provider_idtextNOT NULLProvider name.
user_idtextNOT NULL, FK -> user.id, CASCADEOwner.
access_tokentextnullableOAuth access token.
refresh_tokentextnullableOAuth refresh token.
id_tokentextnullableOAuth ID token.
passwordtextnullableHashed password.
scopetextnullableOAuth scopes.
created_attimestamptzNOT NULLCreation time.
updated_attimestamptzNOT NULL, auto-updateLast update time.

Unique index: uidx_account_provider_account on (provider_id, account_id).

verification

ColumnTypeConstraintsDescription
iduuidPK, UUID v7Verification ID.
identifiertextNOT NULLEmail or phone being verified.
valuetextNOT NULLVerification token.
expires_attimestamptzNOT NULLToken expiration.
created_attimestamptzNOT NULLCreation time.
updated_attimestamptzNOT NULL, auto-updateLast update time.

App Tables

Defined in packages/database/src/schema/app.ts:

profile

User settings and preferences.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtext--FK -> user.id, CASCADE, UNIQUE.
default_modeltext"mock:raypx-1"Default AI model.
preferred_localetext"en-US"Preferred language.
output_tonetext"professional"Output style.
marketing_opt_inbooleanfalseEmail marketing consent.
created_attimestamptznow()Creation time.
updated_attimestamptzauto-updateLast update time.

subscription

Billing subscription state.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtext--FK -> user.id, CASCADE.
providertext"manual"Payment provider.
plan_tiertext"free"Plan tier (free, pro).
statustext"trialing"Status (trialing, active, past_due, cancelled).
current_period_starttimestamptznullPeriod start.
current_period_endtimestamptznullPeriod end.
cancel_at_period_endbooleanfalseCancellation flag.

conversation

AI conversation threads.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtext--FK -> user.id, CASCADE.
titletext--Conversation title.
tasktext"summarize"Task type.
statustext"active"active or archived.

message

Individual messages within a conversation.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
conversation_iduuid--FK -> conversation.id, CASCADE.
user_idtext--FK -> user.id, CASCADE.
roletext--system, user, assistant, or tool.
contenttext--Message body.
modeltextnullAI model used.

document

Uploaded user documents.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtext--FK -> user.id, CASCADE.
titletext--Document title.
storage_keytext--Storage reference key, UNIQUE.
content_typetext"text/plain"MIME type.
size_bytesinteger0File size in bytes.
statustext"uploaded"uploaded, processed, or failed.
summarytextnullAI-generated summary.
metadatajsonb{}Arbitrary metadata.

run

AI processing runs (linked to conversations or documents).

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtext--FK -> user.id, CASCADE.
conversation_iduuidnullFK -> conversation.id, SET NULL.
document_iduuidnullFK -> document.id, SET NULL.
featuretext"document-summary"Feature name.
modeltext--AI model used.
statustext"queued"queued, running, succeeded, failed, cancelled.
prompttext--Input prompt.
response_texttextnullAI response.
error_messagetextnullError details.

artifact

Output artifacts produced by AI runs.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtext--FK -> user.id, CASCADE.
run_iduuid--FK -> run.id, CASCADE.
kindtext"summary"summary, rewrite, extraction, file, report.
titletext--Artifact title.
contenttext--Artifact body.
metadatajsonb{}Arbitrary metadata.

usage_event

Usage tracking for billing and analytics.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtext--FK -> user.id, CASCADE.
run_iduuidnullFK -> run.id, SET NULL.
metrictext--ai_tokens, ai_requests, documents, storage_bytes.
quantityinteger--Amount consumed.
modeltextnullAI model.
featuretext"document-summary"Feature name.
cost_usdnumeric(10,4)"0"Cost in USD.

job

Background job queue entries.

ColumnTypeDefaultDescription
iduuidUUID v7PK.
user_idtextnullFK -> user.id, SET NULL.
run_iduuidnullFK -> run.id, SET NULL.
typetext--Job type identifier.
statustext"queued"queued, running, succeeded, failed, cancelled.
attemptsinteger0Retry count.
payloadjsonb{}Job input data.
resultjsonbnullJob output data.
error_messagetextnullError details.
scheduled_attimestamptznow()When to execute.

Conventions

UUID v7 Primary Keys

All app tables use UUID v7 for primary keys. UUID v7 is time-ordered, which provides better index locality than UUID v4:

uuid("id")
  .primaryKey()
  .$defaultFn(() => uuidv7())

The user table uses text for its primary key because Better Auth manages user IDs. All other tables use UUID v7.

Timestamps

All tables include created_at and updated_at columns using timestamptz (timestamp with timezone). The updated_at column auto-updates on every write:

timestamptz("created_at").defaultNow().notNull(),
timestamptz("updated_at")
  .defaultNow()
  .notNull()
  .$onUpdateFn(() => new Date()),

Cascading Deletes

Foreign keys to user.id use onDelete: "cascade". When a user is deleted, all related rows in profiles, conversations, messages, documents, and usage events are automatically removed.

Foreign keys to conversation.id and document.id use onDelete: "set null" for the run table, preserving run history even if the parent resource is deleted.

Text Enums

Enum-like fields are stored as text columns with TypeScript type narrowing:

status: text("status").$type<ConversationStatus>().notNull().default("active")

This avoids PostgreSQL enum types, which are difficult to alter in production.

On this page