Skip to content

Database Schema

All tables are defined in packages/db/src/schema.ts using Drizzle ORM. The database is PostgreSQL.


These four tables are owned and managed by Better Auth. Never write to them directly — go through the auth instance exported from packages/auth.

ColumnTypeNotes
idtext PKGenerated by Better Auth
nametextDisplay name
emailtext unique
email_verifiedbooleanDefaults to false
imagetextOptional avatar URL
created_attimestamp
updated_attimestampAuto-updated
ColumnTypeNotes
idtext PK
tokentext uniqueBearer token sent by the mobile client
expires_attimestamp
ip_addresstextOptional
user_agenttextOptional
user_idtext FK → userCascade delete

Index on user_id.

Stores credential data per auth provider. For email/password auth, password holds the bcrypt hash.

ColumnTypeNotes
idtext PK
account_idtextProvider-side account ID
provider_idtext"credential" for email/password
user_idtext FK → userCascade delete
passwordtextHashed. Email/password auth only
access_tokentextOAuth only
refresh_tokentextOAuth only

Index on user_id.

Short-lived tokens for email verification and password reset.

ColumnTypeNotes
idtext PK
identifiertextTypically the user’s email address
valuetextThe token
expires_attimestamp

Index on identifier.


ColumnTypeNotes
iduuid PK
nametextDisplay name
colortextHex colour for the UI
creator_idtext FK → userCascade delete
created_attimestamp
updated_attimestampAuto-updated
ColumnTypeNotes
iduuid PK
titletextEvent title
colortextHex colour for the UI
starttimestampEvent start time
endtimestampEvent end time
is_all_dayboolean
is_canceledboolean
organizertext FK → userCurrently the same as creator_id
creator_idtext FK → userCascade delete
descriptiontextOptional notes
locationtextOptional location string
recurrencetextRFC 5545 RRULE string, e.g. FREQ=WEEKLY;BYDAY=MO,WE,FR
urltextOptional link
created_attimestamp
updated_attimestampAuto-updated

An invite record is created when a calendar owner generates a shareable link. The id doubles as the invite token — it’s the value in the deep link URL.

ColumnTypeNotes
iduuid PKAlso the invite token in the URL
calendar_iduuid FK → calendarsCascade delete
expires_attimestampWhen the link stops working
max_usesintegernull = unlimited
created_attimestamp
updated_attimestampAuto-updated

One row per user. Created with defaults on first request if it doesn’t exist.

ColumnTypeDefaultNotes
idtext PK/FK → userSame as user ID
show_kanjibooleantrueShow Japanese characters in calendar header
default_calendar_viewtext"week""day", "week", or "month"
week_starts_ontext"monday""monday" or "sunday"
created_attimestamp
updated_attimestampAuto-updated

Records which users are members of which calendars.

ColumnTypeNotes
iduuid PK
user_idtext FK → userCascade delete
calendar_iduuid FK → calendarsCascade delete
created_attimestamp
updated_attimestampAuto-updated

Links events to calendars. An event can appear in more than one calendar.

ColumnTypeNotes
iduuid PK
event_iduuid FK → eventsCascade delete
calendar_iduuid FK → calendarsCascade delete
created_attimestamp
updated_attimestampAuto-updated

Links events to specific users (attendees or participants beyond calendar membership).

ColumnTypeNotes
iduuid PK
event_iduuid FK → eventsCascade delete
user_idtext FK → userCascade delete
created_attimestamp
updated_attimestampAuto-updated

user ──< session
user ──< account
user ──< verification
user ──1 user_settings
user ──< calendars (creator)
user ──< calendar_members >──── calendars
user ──< events (creator)
user ──< event_users >────────── events
calendars ──< calendar_invites
calendars ──< calendar_events >── events

Terminal window
# After editing packages/db/src/schema.ts, generate a new migration:
pnpm --filter @musubi/db generate
# Apply pending migrations:
pnpm --filter @musubi/db migrate
# or:
pnpm db:migrate

Migration SQL files live in packages/db/drizzle/.