Skip to main content

Database Tables Reference

Derived from server/app/models/ via scripts/generate_db_docs.py. For the ERD see erd.md. Do not hand-edit the generated sections below this line — run python3 scripts/generate_db_docs.py instead.

All tables use MariaDB. Schema is auto-created at startup — see migrations.md.

Known issue: app.models.devices.Device (table device) declares id without primary_key=True. SQLAlchemy raises ArgumentError: could not assemble any primary key columns the moment its module is imported, so it cannot be mapped at all in its current form. It is not imported anywhere in server/app and does not appear below.


blacklistedtoken

ColumnTypeNotes
jtiCHAR(32)PK, indexed
expires_atDATETIMEnot null

conversation

ColumnTypeNotes
created_atBIGINTnot null, has default
updated_atBIGINTindexed, not null, has default
is_deletedBOOLEANindexed, not null, has default
idCHAR(32)PK, unique, indexed, has default
titleVARCHAR(100)not null
conversation_typeVARCHAR(6)not null

device_key

ColumnTypeNotes
idCHAR(32)PK, has default
user_idCHAR(32)indexed, not null
device_fingerprintVARCHAR(64)indexed, not null
public_key_b64VARCHAR(64)not null
bound_atDATETIMEnot null, has default
last_seenDATETIMEnot null, has default

email_recovery_token

ColumnTypeNotes
idINTEGERPK
user_idCHAR(32)indexed, not null
token_hashVARCHARunique, indexed, not null
expires_atDATETIMEnot null
usedBOOLEANnot null, has default
created_atDATETIMEnot null, has default

guest_sessions

ColumnTypeNotes
session_idVARCHARunique, indexed, not null
first_nameVARCHAR(100)not null
last_nameVARCHAR(100)not null
mac_addressVARCHAR(17)
ip_addressVARCHAR(45)
hotspot_nameVARCHAR(100)
idINTEGERPK
statusVARCHAR(12)not null, has default
login_atDATETIMEnot null, has default
disconnect_atDATETIME

interfacetraffic

ColumnTypeNotes
idINTEGERPK
interfaceVARCHARnot null
rx_bpsINTEGERnot null
tx_bpsINTEGERnot null
created_atDATETIMEnot null, has default

login_attempt

ColumnTypeNotes
idCHAR(32)PK, has default
user_idCHAR(32)indexed, not null
device_fingerprintVARCHAR(64)indexed, not null
device_typeVARCHAR(20)not null
attempt_countINTEGERnot null, has default
lockout_countINTEGERnot null, has default
locked_untilDATETIME
last_attempt_atDATETIME

passwordresetcode

ColumnTypeNotes
idINTEGERPK
emailVARCHARindexed, not null
codeVARCHARindexed, not null
expires_atDATETIMEnot null
usedBOOLEANnot null, has default
attemptsINTEGERnot null, has default

passwordresettoken

ColumnTypeNotes
idINTEGERPK
user_idCHAR(32)indexed
token_hashVARCHARunique, indexed, not null
expires_atDATETIMEnot null
created_atDATETIMEnot null, has default

phone_password_reset_code

ColumnTypeNotes
idINTEGERPK
phone_numberVARCHARindexed, not null
codeVARCHARindexed, not null
expires_atDATETIMEnot null
usedBOOLEANnot null, has default
attemptsINTEGERnot null, has default

recovery_attempt

ColumnTypeNotes
idCHAR(32)PK, has default
user_idCHAR(32)indexed, not null
device_fingerprintVARCHAR(64)indexed, not null
recovery_methodVARCHAR(30)indexed, not null
device_typeVARCHAR(20)not null
attempt_countINTEGERnot null, has default
lockout_countINTEGERnot null, has default
locked_untilDATETIME
last_attempt_atDATETIME

recovery_session

ColumnTypeNotes
idINTEGERPK
user_idCHAR(32)indexed, not null
token_hashVARCHARunique, indexed, not null
methodVARCHARnot null
expires_atDATETIMEnot null
usedBOOLEANnot null, has default
created_atDATETIMEnot null, has default

recoverykey

ColumnTypeNotes
user_idCHAR(32)unique, indexed
key_hashVARCHARnot null
created_atDATETIMEnot null, has default
updated_atDATETIMEnot null, has default
idCHAR(32)PK, indexed, has default

routerhealth

ColumnTypeNotes
idINTEGERPK
cpu_loadFLOATnot null
free_memoryINTEGERnot null
total_memoryINTEGERnot null
uptimeVARCHARnot null
created_atDATETIMEnot null, has default

user

ColumnTypeNotes
usernameVARCHAR(50)unique, indexed, not null
first_nameVARCHAR(50)indexed, not null
last_nameVARCHAR(50)indexed, not null
phone_numberVARCHARunique
emailVARCHARunique
idCHAR(32)PK, indexed, has default
hashed_passwordVARCHARnot null
email_verifiedBOOLEANnot null, has default
terms_accepted_atDATETIME
must_change_passwordBOOLEANnot null, has default

activity_logs

ColumnTypeNotes
idCHAR(32)PK, has default
user_idCHAR(32)FK -> user.id, indexed, not null
actionVARCHARnot null
entity_idCHAR(32)
metadata_jsonJSON
created_atDATETIMEnot null, has default

admin

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
user_idCHAR(32)FK -> user.id, unique, indexed, not null
created_atDATETIMEindexed, not null, has default

announcement

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
user_idCHAR(32)FK -> user.id, indexed, not null
titleVARCHARnot null
contentVARCHARnot null
priorityVARCHAR(6)not null
statusVARCHAR(7)not null
expires_atDATETIMEnot null
target_audienceVARCHAR(7)not null
created_atDATETIMEindexed, not null, has default

banneduser

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
user_idCHAR(32)FK -> user.id, unique, indexed, not null
created_atDATETIMEindexed, not null, has default
untilDATETIMEindexed, not null

call

ColumnTypeNotes
created_atBIGINTnot null, has default
updated_atBIGINTindexed, not null, has default
is_deletedBOOLEANindexed, not null, has default
idCHAR(32)PK, indexed, has default
call_typeVARCHAR(5)not null
statusVARCHAR(9)not null
start_timeBIGINTnot null, has default
end_timeBIGINTnot null
conversation_idCHAR(32)FK -> conversation.id
initiator_idCHAR(32)FK -> user.id

contact_key

ColumnTypeNotes
idINTEGERPK
owner_idCHAR(32)FK -> user.id, indexed, not null
peer_idVARCHARindexed, not null
encrypted_public_keyVARCHARnot null

conversationparticipant

ColumnTypeNotes
created_atBIGINTnot null, has default
updated_atBIGINTindexed, not null, has default
idCHAR(32)PK, unique, indexed, has default
conversation_idCHAR(32)FK -> conversation.id, indexed
user_idCHAR(32)FK -> user.id, indexed, not null
joined_atBIGINTnot null, has default
is_deletedBOOLEANnot null, has default

email_verifications

ColumnTypeNotes
user_idCHAR(32)FK -> user.id, not null
tokenVARCHARunique, indexed, not null
emailVARCHAR
expires_atDATETIMEnot null
idINTEGERPK
created_atDATETIMEnot null, has default

guest

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
user_idCHAR(32)FK -> user.id, unique, indexed, not null
created_atDATETIMEindexed, not null, has default

message

ColumnTypeNotes
created_atBIGINTnot null, has default
updated_atBIGINTindexed, not null, has default
idCHAR(32)PK, indexed, has default
message_typeVARCHAR(8)not null, has default
contentTEXTnot null
is_deletedBOOLEANnot null, has default
conversation_idCHAR(32)FK -> conversation.id, indexed
sender_idCHAR(32)FK -> user.id, indexed

peer_key

ColumnTypeNotes
idINTEGERPK
user_idCHAR(32)FK -> user.id, unique, indexed, not null
ecdh_public_keyVARCHARnot null
issued_atDATETIMEnot null
expires_atDATETIMEnot null
signatureVARCHARnot null

phone_verification

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
user_idCHAR(32)FK -> user.id, indexed, not null
phone_numberVARCHAR(20)indexed, not null
verification_codeVARCHAR(6)indexed, not null
is_usedBOOLEANindexed, not null, has default
attemptsINTEGERnot null, has default
expires_atBIGINTindexed, not null
created_atBIGINTnot null, has default

phone_verified

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
user_idCHAR(32)FK -> user.id, indexed, not null

queue

ColumnTypeNotes
idCHAR(32)PK, unique, indexed
toCHAR(32)FK -> user.id
payload_typeVARCHAR(6000)
data_idVARCHARindexed, not null
dataVARCHAR(6000)

rescuer

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
user_idCHAR(32)FK -> user.id, unique, indexed, not null
created_atDATETIMEindexed, not null, has default

user_activity

ColumnTypeNotes
user_idCHAR(32)PK, FK -> user.id
last_activeDATETIMEnot null, has default
statusVARCHARnot null, has default
ip_addressVARCHAR
user_agentVARCHAR

userlocation

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
latitudeFLOATnot null
longitudeFLOATnot null
timestampDATETIMEindexed, not null, has default
user_idCHAR(32)FK -> user.id, indexed, not null

userprofilepicture

ColumnTypeNotes
idCHAR(32)PK, has default
filenameVARCHARindexed, not null
created_atDATETIMEnot null, has default
is_activeBOOLEANnot null, has default
user_idCHAR(32)FK -> user.id, indexed, not null

usersecurityquestion

ColumnTypeNotes
idINTEGERPK
user_idCHAR(32)FK -> user.id, not null
questionVARCHARnot null
answer_hashVARCHARnot null
created_atDATETIMEnot null, has default
is_burnedBOOLEANnot null, has default

wrapped_key

ColumnTypeNotes
idINTEGERPK
user_idCHAR(32)FK -> user.id, unique, indexed, not null
wrapped_blobVARCHARnot null
created_atDATETIMEnot null, has default
updated_atDATETIMEnot null, has default

wrapped_key_recovery

ColumnTypeNotes
idINTEGERPK
user_idCHAR(32)FK -> user.id, indexed, not null
methodVARCHARindexed, not null
wrapped_blobVARCHARnot null
recovery_metadataVARCHAR
created_atDATETIMEnot null, has default
updated_atDATETIMEnot null, has default

attachment

ColumnTypeNotes
idCHAR(32)PK, indexed, has default
message_idCHAR(32)FK -> message.id, not null
file_pathVARCHAR(255)not null
file_nameVARCHAR(200)not null
file_sizeINTEGERnot null
mime_typeVARCHAR(255)not null

callparticipant

ColumnTypeNotes
created_atBIGINTnot null, has default
updated_atBIGINTindexed, not null, has default
is_deletedBOOLEANindexed, not null, has default
idCHAR(32)PK, indexed, has default
joined_atBIGINTnot null, has default
left_atINTEGER
call_idCHAR(32)FK -> call.id, indexed
user_idCHAR(32)FK -> user.id, indexed

messagereceipt

ColumnTypeNotes
created_atBIGINTnot null, has default
updated_atBIGINTindexed, not null, has default
is_deletedBOOLEANindexed, not null, has default
idCHAR(32)PK, indexed, has default
statusVARCHAR(9)not null
message_idCHAR(32)FK -> message.id, not null
user_idCHAR(32)FK -> user.id, not null

Mobile App Tables (WatermelonDB)

Not introspectable from server/app/models/ (different language/ORM) — hand-maintained here from mobile-app/sapot-mobile-app/features/shared/core/database/schema.ts (schema version 11). All tables use WatermelonDB's implicit id primary key (framework-managed, not declared in tableSchema()). For migration history per column, see migrations.md.

guest_user

ColumnTypeNotes
first_namestring
last_namestring
usernamestring

peers

ColumnTypeNotes
usernamestring
is_onlineboolean
first_namestring
last_namestringoptional
emailstringoptional; current authenticated user's own profile mirror
phone_numberstringoptional
email_verifiedbooleanoptional (added v4)
phone_number_verifiedbooleanoptional (added v7) — declared twice in schema.ts's column array; a source-level duplicate, not a docs error
rolestringoptional (added v9)
is_guestbooleanoptional (added v10)
last_seen_atnumberoptional (added v11)

messages

ColumnTypeNotes
conversationstringFK to conversations.id
senderstringFK to peers.id
message_typestring
contentstring
created_atnumberms epoch
updated_atnumberms epoch
is_deletedbooleansoft-delete
linked_message_idstringoptional (added v8) — formerly paired a P2P message with its SMS duplicate for the dual-send UX (removed); column retained unused, no longer read or written
is_encryptedbooleanoptional (added v9)

calls

ColumnTypeNotes
conversationstringFK to conversations.id
initiatorstringFK to peers.id
call_typestring
statusstring
start_timenumberms epoch
end_timenumberoptional, ms epoch
updated_atnumberms epoch
created_atnumberms epoch
is_deletedbooleansoft-delete

call_participants

ColumnTypeNotes
callstringFK to calls.id
userstringFK to peers.id
joined_atnumberms epoch
left_atnumberoptional, ms epoch
updated_atnumberms epoch
created_atnumberms epoch
is_deletedbooleansoft-delete

message_receipts

ColumnTypeNotes
messagestringFK to messages.id
userstringFK to peers.id
statusstring
created_atnumberms epoch
updated_atnumberms epoch
is_deletedbooleansoft-delete

conversations

ColumnTypeNotes
typestring
titlestringoptional
created_atnumberms epoch
updated_atnumberms epoch
is_deletedbooleansoft-delete

conversation_participants

ColumnTypeNotes
conversationstringFK to conversations.id
userstringFK to peers.id
joined_atnumberms epoch
is_deletedbooleansoft-delete
created_atnumberms epoch
updated_atnumberms epoch