Skip to Content
Trips Enjoy
Data Model (ERD)Domains

Identity and access

Tables and relationships for the identity and access domain.

Part of the data model; conventions and base columns are documented there.

users

(Base +) FR-AUTH-01 to FR-AUTH-10

ColumnTypeNotes
full_nameVARCHAR(200)
emailCITEXTUnique with deleted_at where not null
phone_encBYTEAenc; E.164
phone_hashCHAR(64)Unique with deleted_at where not null
email_verified_at, phone_verified_atTIMESTAMPTZD-20
password_hashVARCHAR(255)Argon2id; null for code-only accounts
country_codeCHAR(2) FK countriesBRL-23
localeVARCHAR(5)en or ar
timezoneVARCHAR(64)
status_idBIGINT FK lookupsaccount_status: active, suspended, deletion_requested, closed
suspended_reason_idBIGINT FK lookupssuspension_reason (D-234)
deletion_requested_at, deletion_due_atTIMESTAMPTZ30-day grace (BRL-15)
failed_signinsSMALLINTReset on success
locked_untilTIMESTAMPTZBRL-21
token_versionINTBump to revoke all tokens
traveler_plan_subscription_idBIGINT FK subscriptionsFree by default

user_roles

(Base +) FR-AUTH-06, FR-AUTH-07

ColumnTypeNotes
user_idBIGINT FK users
role_idBIGINT FK lookupsrole: traveler, organization_owner, organization_employee, platform_driver, platform_photographer, org_driver, org_photographer, moderator, admin_super, admin_operations, admin_finance
organization_idBIGINT FK organizations NULLSet for organization-scoped roles
status_idBIGINT FK lookupsrole_status: pending, active, paused, suspended, ended
started_at, ended_atTIMESTAMPTZ

Unique (user_id, role_id, organization_id, deleted_at).

auth_factors (Base +): user_id FK, factor_type_id FK lookups (auth_factor: totp, sms), secret_enc BYTEA, verified_at TIMESTAMPTZ, last_used_at TIMESTAMPTZ.

otp_challenges

(Base +) BRL-20

ColumnTypeNotes
user_idBIGINT FK users NULLNull before the account exists
channel_idBIGINT FK lookupsotp_channel: sms, whatsapp, email
destination_hashCHAR(64)
purpose_idBIGINT FK lookupsotp_purpose: verify_email, verify_phone, sign_in, staff_code, password_reset
code_hashCHAR(64)
expires_atTIMESTAMPTZ5 minutes
wrong_attemptsSMALLINTPause at 5
paused_untilTIMESTAMPTZ15 minutes
failed_deliveriesSMALLINTSwitch channel at 3 (D-59)
consumed_atTIMESTAMPTZ

sessions (Base +): user_id FK, active_role_id FK user_roles, active_organization_id FK organizations NULL, refresh_token_hash CHAR(64), device_id FK devices NULL, ip INET, user_agent TEXT, expires_at TIMESTAMPTZ (web 12 h, BRL-22), revoked_at TIMESTAMPTZ.

devices (Base +): user_id FK, platform_id FK lookups (device_platform: ios, android, web), push_token TEXT, app_version VARCHAR(20), last_seen_at TIMESTAMPTZ.

consents (immutable) [NFR-DAT-05](/en/docs/srs/quality#85-data-nfr-dat): id, uuid, user_id FK, consent_type_id FK lookups (consent_type: lab_test, background_check, child_tracking, guardianship, marketing, terms, privacy), text_version VARCHAR(20), granted BOOLEAN, occurred_at TIMESTAMPTZ, ip INET, created_at, created_by.

notification_preferences (Base +): user_id FK, category_id FK lookups (notification_category), channel_id FK lookups (notification_channel: email, sms, whatsapp, push, in_app), enabled BOOLEAN. Unique (user_id, category_id, channel_id, deleted_at).

privacy_requests (Base +) FR-TRV-07: user_id FK, type_id FK lookups (privacy_request_type: data_copy, deletion), status_id FK lookups (privacy_request_status: received, verified, in_progress, delivered, cancelled), due_at TIMESTAMPTZ (30 days, D-162), file_path TEXT, completed_at TIMESTAMPTZ.

On this page