Skip to main content

Database Schema

Complete reference for the PostgreSQL database schema used in Qubital backend.


Entity Relationship Diagram


Tables Overview

TablePurpose
usersAuthenticated users from WorkOS
organizationsOrganizations from WorkOS
roomsLiveKit meeting rooms
user_sessionsUser login sessions with refresh tokens
user_organizationsMany-to-many: users ↔ organizations
user_integrationsMany-to-many: users ↔ integrations
integrationsThird-party integrations (Google Calendar, etc.)
valid_room_combinationsWhitelist of valid room layouts
subscription_linkPilot program invitation links

Detailed Table Descriptions

users

Stores authenticated users synced from WorkOS.

Columns:

  • id (BIGSERIAL PK) - Auto-incrementing primary key
  • workos_id (VARCHAR UK) - Unique WorkOS user identifier
  • invitation_link (VARCHAR) - Optional pilot invitation link
  • last_logged_org (VARCHAR) - Last organization user logged into
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • One-to-many with user_sessions (CASCADE delete)
  • Many-to-many with organizations via user_organizations (CASCADE delete)
  • Many-to-many with integrations via user_integrations (CASCADE delete)

organizations

Stores organizations synced from WorkOS.

Columns:

  • id (BIGSERIAL PK) - Auto-incrementing primary key
  • org_name (VARCHAR) - Organization name (NOT unique - WorkOS is source of truth)
  • invite_id (VARCHAR UK) - Unique invite link ID for member invitations
  • workos_org_id (VARCHAR UK) - Unique WorkOS organization identifier
  • initialized (BOOLEAN) - Whether organization setup is complete
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • One-to-many with rooms (CASCADE delete)
  • Many-to-many with users via user_organizations (CASCADE delete)

rooms

Stores LiveKit room metadata.

Columns:

  • id (BIGSERIAL PK) - Auto-incrementing primary key
  • name (VARCHAR) - Room name
  • description (TEXT) - Room description
  • room_id (UUID UK) - Unique LiveKit room identifier
  • layout, dimension, style (VARCHAR) - Room configuration (validated by valid_room_combinations)
  • org_id (BIGINT FK) - Foreign key to organizations.id
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • Many-to-one with organizations (CASCADE delete when org deleted)
  • Many-to-one with valid_room_combinations (SET NULL if combination deleted)

user_sessions

Stores user authentication sessions.

Columns:

  • id (BIGSERIAL PK) - Auto-incrementing primary key
  • user_id (BIGINT FK) - Foreign key to users.id
  • session_id (VARCHAR UK) - Unique session identifier
  • refresh_token (TEXT) - WorkOS refresh token (encrypted at rest)
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • Many-to-one with users (CASCADE delete when user deleted)

user_organizations

Junction table for many-to-many relationship between users and organizations.

Columns:

  • user_id (BIGINT PK/FK) - Composite primary key + foreign key to users.id
  • org_id (BIGINT PK/FK) - Composite primary key + foreign key to organizations.id
  • role (VARCHAR) - User role in organization (admin, moderator, member)
  • status (VARCHAR) - Membership status (active, suspended, pending)
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • Many-to-one with users (CASCADE delete)
  • Many-to-one with organizations (CASCADE delete)

integrations

Stores types of third-party integrations available.

Columns:

  • id (BIGSERIAL PK) - Auto-incrementing primary key
  • integration (VARCHAR UK) - Unique integration name (e.g., "google-calendar")
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • One-to-many with user_integrations

user_integrations

Junction table tracking which integrations users have enabled.

Columns:

  • user_id (BIGINT PK/FK) - Composite primary key + foreign key to users.id
  • integration_id (BIGINT PK/FK) - Composite primary key + foreign key to integrations.id
  • refresh_token (TEXT) - OAuth refresh token for the integration
  • is_enabled (BOOLEAN) - Whether integration is currently active
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • Many-to-one with users (CASCADE delete)
  • Many-to-one with integrations (CASCADE delete)

valid_room_combinations

Whitelist of valid room configuration combinations.

Columns:

  • layout (VARCHAR PK) - Part of composite primary key
  • dimension (VARCHAR PK) - Part of composite primary key
  • style (VARCHAR PK) - Part of composite primary key
  • created_at (TIMESTAMP) - Auto-managed timestamp

Relationships:

  • One-to-many with rooms (SET NULL if combination deleted)

Stores pilot program invitation links.

Columns:

  • id (BIGSERIAL PK) - Auto-incrementing primary key
  • special_link (VARCHAR UK) - Unique invitation link
  • enabled (BOOLEAN) - Whether link is currently active
  • consumed_by_workos_id (VARCHAR UK) - WorkOS ID of user who used the link (one-time use)
  • created_at, updated_at (TIMESTAMP) - Auto-managed timestamps

Relationships:

  • None (standalone table)

Key Relationships Summary

users (1) ──────< (N) user_sessions

│ (M)
└─────< user_organizations >─────┐
│ (N)
organizations (1) ──────< (N) rooms │

users (M) ──────< user_integrations >───── integrations (N)

valid_room_combinations (1) ──────< (N) rooms

subscription_link (1) ────── (0..1) users

Legend:

  • (1) = One
  • (N) = Many
  • (M) = Many-to-Many
  • PK = Primary Key
  • FK = Foreign Key
  • UK = Unique Key

Foreign Key Behaviors

RelationshipDelete Behavior
user_sessions.user_idusers.idCASCADE (delete sessions when user deleted)
user_organizations.user_idusers.idCASCADE
user_organizations.org_idorganizations.idCASCADE
rooms.org_idorganizations.idCASCADE (delete rooms when org deleted)
user_integrations.user_idusers.idCASCADE
user_integrations.integration_idintegrations.idCASCADE
rooms.(layout,dimension,style)valid_room_combinations.(layout,dimension,style)SET NULL

Constraints

TableConstraint TypeColumnsDescription
usersUNIQUEworkos_idEnsures unique WorkOS user identifiers
organizationsUNIQUEinvite_idEnsures unique invitation IDs (when not null)
organizationsUNIQUEworkos_org_idEnsures unique WorkOS org identifiers (when not null)
roomsUNIQUEroom_idEnsures unique LiveKit room identifiers
user_sessionsUNIQUEsession_idEnsures unique session identifiers
integrationsUNIQUEintegrationEnsures unique integration names
subscription_linkUNIQUEspecial_linkEnsures unique invitation links
subscription_linkUNIQUEconsumed_by_workos_idOne-time use per user (when not null)
user_organizationsPRIMARY KEY(user_id, org_id)Prevents duplicate user-org memberships
user_integrationsPRIMARY KEY(user_id, integration_id)Prevents duplicate user-integration links
valid_room_combinationsPRIMARY KEY(layout, dimension, style)Ensures unique room configuration combinations

Indexes

users

  • idx_users_workos_id (UNIQUE) on workos_id - Fast WorkOS ID lookups
  • idx_users_created_at on created_at DESC - Sorting by creation date
  • idx_users_invitation_link on invitation_link WHERE NOT NULL - Pilot invite lookups

organizations

  • idx_organizations_org_name on org_name - Organization name searches
  • idx_organizations_invite_id (UNIQUE) on invite_id WHERE NOT NULL - Invite link lookups
  • idx_organizations_workos_org_id (UNIQUE) on workos_org_id WHERE NOT NULL - WorkOS org lookups
  • idx_organizations_created_at on created_at DESC - Sorting by creation date
  • idx_organizations_initialized on initialized WHERE TRUE - Active org filtering

rooms

  • idx_rooms_name on name - Room name searches
  • idx_rooms_name_lower on LOWER(name) - Case-insensitive name searches
  • idx_rooms_room_code (UNIQUE) on room_id - LiveKit room ID lookups
  • idx_rooms_org_id on org_id WHERE NOT NULL - Filtering by organization
  • idx_rooms_layout on layout WHERE NOT NULL - Layout filtering
  • idx_rooms_dimension on dimension WHERE NOT NULL - Dimension filtering
  • idx_rooms_style on style WHERE NOT NULL - Style filtering
  • idx_rooms_combination on (layout, dimension, style) WHERE ALL NOT NULL - Composite configuration lookup

user_sessions

  • idx_user_sessions_user_id on user_id - User's sessions lookup
  • idx_user_sessions_session_id (UNIQUE) on session_id - Session ID lookup
  • idx_user_sessions_created_at on created_at DESC - Session age sorting
  • idx_user_sessions_updated_at on updated_at DESC - Last activity sorting

user_organizations

  • idx_user_organizations_user_id on user_id - User's organizations lookup
  • idx_user_organizations_org_id on org_id - Organization's members lookup
  • idx_user_organizations_role on role - Role filtering
  • idx_user_organizations_status on status - Status filtering
  • idx_user_organizations_role_status on (role, status) - Composite role+status filtering

integrations

  • idx_integrations_integration (UNIQUE) on integration - Integration name lookups
  • idx_integrations_created_at on created_at DESC - Sorting by creation date

user_integrations

  • idx_user_integrations_user_id on user_id - User's integrations lookup
  • idx_user_integrations_integration_id on integration_id - Integration's users lookup
  • idx_user_integrations_enabled on is_enabled WHERE TRUE - Active integrations filtering

valid_room_combinations

  • idx_valid_room_combinations_layout on layout - Layout filtering
  • idx_valid_room_combinations_dimension on dimension - Dimension filtering
  • idx_valid_room_combinations_style on style - Style filtering
  • idx_subscription_link_special_link (UNIQUE) on special_link - Link lookups
  • idx_subscription_link_created_at on created_at DESC - Sorting by creation date
  • idx_subscription_link_enabled on enabled WHERE TRUE - Active links filtering
  • idx_subscription_link_consumed_by (UNIQUE) on consumed_by_workos_id WHERE NOT NULL - User consumption tracking

Cardinality

Users ↔ Organizations: Many-to-Many (through user_organizations)

  • One user can be a member of multiple organizations
  • One organization can have multiple users
  • Junction table stores role and status for each membership

Users → Sessions: One-to-Many

  • One user can have multiple active sessions
  • Each session belongs to exactly one user

Users ↔ Integrations: Many-to-Many (through user_integrations)

  • One user can enable multiple integrations
  • One integration type can be enabled by multiple users
  • Junction table stores OAuth tokens and enabled status

Organizations → Rooms: One-to-Many

  • One organization can own multiple rooms
  • Each room belongs to at most one organization (nullable)

Valid Room Combinations → Rooms: One-to-Many

  • One valid combination can be used by multiple rooms
  • Each room references at most one valid combination (nullable)

Subscription Links → Users: One-to-One (optional)

  • One link can be consumed by at most one user
  • One user can consume multiple links (but each link is single-use)

Sample SQL Queries

Creating a User with Session (Transaction)

BEGIN;

-- Insert user
INSERT INTO users (workos_id, created_at, updated_at)
VALUES ('user_123', NOW(), NOW())
RETURNING id;

-- Insert session (use returned id)
INSERT INTO user_sessions (user_id, session_id, refresh_token, created_at, updated_at)
VALUES (1, 'session_abc', 'refresh_token_xyz', NOW(), NOW());

COMMIT;

Getting User's Organizations with Roles

SELECT
o.id,
o.org_name,
o.workos_org_id,
uo.role,
uo.status,
uo.created_at as joined_at
FROM users u
INNER JOIN user_organizations uo ON u.id = uo.user_id
INNER JOIN organizations o ON uo.org_id = o.id
WHERE u.workos_id = 'user_123'
AND uo.status = 'active'
ORDER BY o.org_name;

Listing Rooms in an Organization

SELECT
r.id,
r.name,
r.description,
r.room_id,
r.layout,
r.dimension,
r.style,
r.created_at
FROM rooms r
INNER JOIN organizations o ON r.org_id = o.id
WHERE o.workos_org_id = 'org_456'
ORDER BY r.created_at DESC
LIMIT 20 OFFSET 0;

Searching Rooms by Name (Case-Insensitive)

SELECT
r.id,
r.name,
r.description,
r.room_id
FROM rooms r
INNER JOIN organizations o ON r.org_id = o.id
WHERE o.workos_org_id = 'org_456'
AND r.name ILIKE '%conference%'
ORDER BY r.name;

Getting User's Active Integrations

SELECT
i.id,
i.integration,
ui.is_enabled,
ui.created_at as enabled_at
FROM users u
INNER JOIN user_integrations ui ON u.id = ui.user_id
INNER JOIN integrations i ON ui.integration_id = i.id
WHERE u.workos_id = 'user_123'
AND ui.is_enabled = true;

Adding User to Organization with Role

INSERT INTO user_organizations (user_id, org_id, role, status, created_at, updated_at)
VALUES (
(SELECT id FROM users WHERE workos_id = 'user_123'),
(SELECT id FROM organizations WHERE workos_org_id = 'org_456'),
'member',
'active',
NOW(),
NOW()
)
ON CONFLICT (user_id, org_id) DO UPDATE
SET role = EXCLUDED.role, status = EXCLUDED.status, updated_at = NOW();

Deleting an Organization (Cascades to Rooms and Memberships)

-- This automatically:
-- - Deletes all rooms in the organization
-- - Deletes all user_organizations entries
DELETE FROM organizations WHERE workos_org_id = 'org_456';
UPDATE subscription_link
SET consumed_by_workos_id = 'user_123',
enabled = false,
updated_at = NOW()
WHERE special_link = 'pilot-invite-abc'
AND enabled = true
AND consumed_by_workos_id IS NULL;

Checking if Room Configuration is Valid

SELECT EXISTS (
SELECT 1
FROM valid_room_combinations
WHERE layout = 'grid'
AND dimension = 'medium'
AND style = 'modern'
) as is_valid;

Getting Organization Member Count

SELECT
o.id,
o.org_name,
COUNT(uo.user_id) as member_count
FROM organizations o
LEFT JOIN user_organizations uo ON o.id = uo.org_id AND uo.status = 'active'
WHERE o.workos_org_id = 'org_456'
GROUP BY o.id, o.org_name;