Skip to content

Database Schema

The API uses PostgreSQL 17. Auth-related tables live in the auth schema; everything else is in the default public schema.

All tables include created_at and updated_at timestamps. updated_at is maintained automatically by a update_modified_column() trigger.


Auth Schema

auth.users

Core user accounts. One record per registered user.

Column Type Notes
id UUID PK Auto-generated
name TEXT Display name from Discord
email TEXT UNIQUE Primary email from Discord
preferred_email TEXT User-set preferred email
email_verified BOOLEAN Default false
email_consent BOOLEAN Marketing email opt-in
onboarded BOOLEAN Whether onboarding is complete
image TEXT Profile image URL
role auth_user_role user or superuser
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

auth.accounts

OAuth provider associations. A user can have multiple providers (currently only Discord).

Column Type Notes
id UUID PK
user_id UUID FK → auth.users
provider_id TEXT e.g., discord
account_id TEXT Provider's user ID
access_token TEXT
refresh_token TEXT
scope TEXT
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

Unique constraint on (provider_id, account_id).

auth.sessions

Active user sessions. Sessions expire and use rolling expiration.

Column Type Notes
id UUID PK Stored in sh_session_id cookie
user_id UUID FK → auth.users
expires_at TIMESTAMPTZ Extended on use after 24h
ip_address TEXT
user_agent TEXT
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ Used as last_used_at

Public Schema

events

Hackathon events. Drives the application and attendee lifecycle.

Column Type Notes
id UUID PK
name TEXT
description TEXT
location TEXT
location_url TEXT
max_attendees INT Optional cap
application_open TIMESTAMPTZ Applications open
application_close TIMESTAMPTZ Applications close
rsvp_deadline TIMESTAMPTZ
decision_release TIMESTAMPTZ When decisions are released to applicants
start_time TIMESTAMPTZ
end_time TIMESTAMPTZ
website_url TEXT
banner_url TEXT R2 object key for the banner image
is_published BOOLEAN false = draft (only staff+ can see)
application_review_started BOOLEAN Locks in reviewer assignments
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

event_roles

Maps users to their role within a specific event.

Column Type Notes
user_id UUID FK → auth.users
event_id UUID FK → events
role event_role_type admin, staff, attendee, applicant
assigned_at TIMESTAMPTZ

Primary key: (user_id, event_id).

applications

One application per user per event. Stores the form data as JSONB.

Column Type Notes
user_id UUID FK → auth.users
event_id UUID FK → events
status application_status See statuses below
application JSONB Form field data
experience_rating INTEGER Reviewer score (1–5)
passion_rating INTEGER Reviewer score (1–5)
assigned_reviewer_id UUID FK → auth.users Nullable
submitted_by UUID User ID at time of submission
waitlisted_at TIMESTAMPTZ When the applicant was waitlisted
saved_at TIMESTAMPTZ Last draft save
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

Primary key: (user_id, event_id).

application_status enum:

Value Description
started Draft — created but not submitted
submitted Submitted, awaiting review
under_review Assigned to a reviewer
accepted Accepted by BAT run
rejected Rejected by BAT run
waitlisted On waitlist
withdrawn Withdrawn by applicant

bat_runs

Records of BAT (Balanced Admissions Thresher) execution results.

Column Type Notes
id UUID PK
event_id UUID FK → events
accepted_applicants UUID[] Array of user IDs
rejected_applicants UUID[] Array of user IDs
status bat_run_status running, completed, failed
created_at TIMESTAMPTZ
completed_at TIMESTAMPTZ Nullable

teams

Teams within an event.

Column Type Notes
id UUID PK
name TEXT
owner_id UUID FK → auth.users Nullable (SET NULL on delete)
event_id UUID FK → events
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

team_members

Many-to-many membership join table.

Column Type Notes
user_id UUID FK → auth.users
team_id UUID FK → teams
joined_at TIMESTAMPTZ

Primary key: (user_id, team_id).

team_join_requests

Requests from users to join a team.

Column Type Notes
id UUID PK
team_id UUID FK → teams
user_id UUID FK → auth.users
request_message TEXT Optional message
status join_request_status PENDING, APPROVED, REJECTED
processed_by_user_id UUID FK → auth.users Nullable
processed_at TIMESTAMPTZ Nullable
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

Unique partial index: one PENDING request per (team_id, user_id).

event_interest_submissions

Mailing list for event interest (pre-registration).

Column Type Notes
id UUID PK
event_id UUID FK → events
email TEXT
created_at TIMESTAMPTZ

redeemables

Prize or reward items associated with an event.

Column Type Notes
id UUID PK
event_id UUID FK → events
name VARCHAR(255)
amount INT Total available (≥ 0)
max_user_amount INT Per-user limit (≥ 1)
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

user_redemptions

Tracks how many times a user has redeemed a specific redeemable.

Column Type Notes
user_id UUID FK → auth.users
redeemable_id UUID FK → redeemables
amount INT Times redeemed (≥ 0)
created_at TIMESTAMPTZ
updated_at TIMESTAMPTZ

Primary key: (user_id, redeemable_id).