Database Schema
Purpose
Defines the current StudyBoost public schema shape used by backend services and feature modules.
Core Notes
- Primary database: PostgreSQL (Neon)
- ORM: Prisma (
backend/prisma/schema.prisma) - Migration source of truth:
backend/prisma/migrations/* - Auth/session data currently lives in
public(no separateauthschema yet)
Auth Tables (Public Schema)
users
Core identity table used across documents, subscriptions, notifications, and auth.
Important columns:
user_id(UUID, PK)email(unique)username(unique)password(hashed)onboarding_draft(JSONB) - Stores volatile AI/Wizard onboarding state.onboarding_completed(Boolean) - Tracks final readiness status.university,major_focus,study_goal- Canonicalized profile fields.is_active,is_verified
Institutions Catalog (Public Schema)
institutions
A master catalog of 100k+ global universities and schools used for profile canonicalization.
Columns:
institution_id(UUID, PK)institution_name(unique)slug(unique, URL-friendly name)is_active
Indexes:
idx_institution_name_trgm: GIN Trigram index oninstitution_namefor high-performance fuzzy matching.idx_institution_slug: B-tree index for rapid URL lookups.
Notes:
- Trigram index added via migration
202605030322_onboarding_overhaul. - Enabled by the
pg_trgmextension.
auth_sessions
Stores active refresh-session state per device/login.
Columns:
session_id(UUID, PK)user_id(FK ->users.user_id)refresh_token_hash(unique)user_agentip_addressexpires_atcreated_at
Indexes:
idx_auth_sessions_useridx_auth_sessions_expires_atuk_auth_sessions_refresh_token_hash
email_verification_tokens
Stores one-time email verification tokens (hashed).
Columns:
id(UUID, PK)user_id(FK ->users.user_id)token_hash(unique)expires_atcreated_atused_at
Indexes:
idx_email_verification_tokens_useridx_email_verification_tokens_expires_atidx_email_verification_tokens_used_atuk_email_verification_tokens_token_hash
Queue Infrastructure Tables (Public Schema)
background_jobs
Tracks lifecycle state for asynchronous queue jobs processed by FEAT-33 workers.
Columns:
id(UUID, PK)queue_name(ocr_queue,ai_processing_queue,indexing_queue,email_queue,notification_queue)job_type(logical task type)bull_job_id(BullMQ job identifier)status(pending|processing|completed|failed)payload_jsonresult_jsonerror_messageattempts_mademax_attemptsidempotency_key(unique when present)created_atstarted_atfinished_atupdated_at
Indexes:
idx_background_jobs_queue_nameidx_background_jobs_statusidx_background_jobs_created_atidx_background_jobs_queue_statusuk_background_jobs_idempotency_key(partial unique index for non-null keys)
Notes:
- Added via migration
202604272230_add_background_jobs_table. - Used by queue producers and worker processors for retry-safe status tracking.
Structured Notes Tables (Public Schema)
structured_notes
Stores user-owned note records for FEAT-59.
Columns:
id(UUID, PK)user_id(FK ->users.user_id)titlebodystatus(active|archived|deleted)deadline_atreminder_atarchived_atdeleted_atcreated_atupdated_at
Indexes:
idx_structured_notes_user_status_updatedidx_structured_notes_user_deadlineidx_structured_notes_user_created
structured_note_references
Stores typed note references to catalog entities.
Columns:
id(UUID, PK)note_id(FK ->structured_notes.id)reference_type(document|course|institution)document_id(nullable FK ->documents.document_id)course_id(nullable FK ->courses.course_id)institution_id(nullable FK ->institutions.institution_id)contextaccess_state_snapshotdeadline_atreminder_atposition_orderarchived_atcreated_atupdated_at
Indexes:
idx_structured_note_references_noteidx_structured_note_references_typeidx_structured_note_references_documentidx_structured_note_references_courseidx_structured_note_references_institution
structured_note_canvas_items
Stores persisted card coordinates/layout metadata per note.
Columns:
id(UUID, PK)note_id(FK ->structured_notes.id)x,y,width,heightgroup_labelcreated_atupdated_at
Indexes:
idx_structured_note_canvas_note
Notes:
- Added via migration
202605021540_add_structured_notes_tables. - Migration is additive and guard-safe (
IF NOT EXISTS).
Referral Ledger Tables (Public Schema)
referral_settings
Global referral configuration row (settings_key = 'global').
Columns:
enable_referralscommission_percentagefraud_window_daysmin_payout_amountcreated_at,updated_at
referral_codes
One auto-generated referral code per user.
Columns:
id(UUID, PK)user_id(unique FK ->users.user_id)code(case-insensitive unique viaLOWER(code)index)is_activecreated_at,updated_at
referrals
Attribution mapping between referrer and referred users.
Columns:
id(UUID, PK)referrer_user_id(FK ->users.user_id)referred_user_id(unique FK ->users.user_id)attribution_source(registration|checkout)locked_atcreated_at
payment_events
Payment ledger rows used as commission source records for subscriptions now and future paid features later.
Columns:
id(UUID, PK)user_id(FK ->users.user_id)source_type,source_id(unique pair)amount,currencystripe_payment_intent_id,stripe_charge_id,payment_fingerprintstatus(confirmed|refunded|fraud_flagged)paid_at,metadata,created_at
commissions
Commission ledger rows (source of truth for earnings state; no balance field).
Columns:
id(UUID, PK)referral_id(FK ->referrals.id)payment_event_id(unique nullable FK ->payment_events.id)amount,currency,percentagestatus(pending|locked|ready_for_payout|paid|cancelled)available_atpayout_batch_id(nullable FK ->payout_batches.id)created_at,updated_at
commission_status_events
Trace table for explicit commission status transitions.
Columns:
commission_id(FK ->commissions.id)from_status,to_statusreasonactor_user_id(nullable FK ->users.user_id)created_at
payout_batches
Future payout grouping placeholder; no disbursement logic yet.
Columns:
id(UUID, PK)total_amountstatus(pending|processing|completed|failed)created_at,updated_at
Notes:
- Added via migration
202605120900_add_referral_ledger_system. - Includes default disabled referral settings and default
enable_referralsfeature flag insertion.
Relationship Highlights
users 1 -> many auth_sessionsusers 1 -> many email_verification_tokensusers 1 -> many structured_notesusers 1 -> 1 referral_codesusers 1 -> many referrals(as referrer) andusers 1 -> 0..1 referrals(as referred)users 1 -> many payment_eventsreferrals 1 -> many commissionscommissions 1 -> many commission_status_eventspayout_batches 1 -> many commissionsstructured_notes 1 -> many structured_note_referencesstructured_notes 1 -> many structured_note_canvas_itemsbackground_jobsis standalone in v1 (no FK dependency to domain tables)- Existing feature tables (
documents,notifications,user_subscriptions, etc.) continue to referenceusers.user_id
Schema Change Rules
- Follow mandatory migration controls in
/docs/database-schema/migration-convention:- required intent header (
PURPOSE,IMPACT,DATA RISK,ROLLBACK STRATEGY) - dangerous migration classification and required destructive checklist evidence
- migration rationale/changelog block in the PR
- required intent header (
- Additive auth/security migrations must include QA docs updates in
docs/features/* - Never push schema changes directly to
main; use PR flow todev