Database Schema¶
Complete reference for the PostgreSQL database schema used in Qubital backend.
Entity Relationship Diagram¶
erDiagram
users ||--o{ user_sessions : "has"
users ||--o{ user_integrations : "has"
users }o--o{ organizations : "member of"
organizations ||--o{ rooms : "owns"
integrations ||--o{ user_integrations : "used by"
valid_room_combinations ||--o{ rooms : "validates"
subscription_link ||--o| users : "consumed by"
users {
bigserial id PK
varchar workos_id UK "NOT NULL"
varchar invitation_link
varchar last_logged_org
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
organizations {
bigserial id PK
varchar org_name "NOT NULL"
varchar invite_id UK "NULLABLE"
varchar workos_org_id UK "NULLABLE"
boolean initialized "DEFAULT false"
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
rooms {
bigserial id PK
varchar name "NOT NULL"
text description "DEFAULT ''"
uuid room_id UK "NOT NULL"
varchar layout
varchar dimension
varchar style
bigint org_id FK "NULLABLE"
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
user_sessions {
bigserial id PK
bigint user_id FK "NOT NULL"
varchar session_id UK "NOT NULL"
text refresh_token "NOT NULL"
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
user_organizations {
bigint user_id PK "NOT NULL, FK"
bigint org_id PK "NOT NULL, FK"
varchar role "DEFAULT member"
varchar status "DEFAULT active"
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
integrations {
bigserial id PK
varchar integration UK "NOT NULL"
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
user_integrations {
bigint user_id PK "NOT NULL, FK"
bigint integration_id PK "NOT NULL, FK"
text refresh_token "NULLABLE"
boolean is_enabled "DEFAULT false"
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
valid_room_combinations {
varchar layout PK "NOT NULL"
varchar dimension PK "NOT NULL"
varchar style PK "NOT NULL"
timestamp created_at "DEFAULT NOW()"
}
subscription_link {
bigserial id PK
varchar special_link UK "NOT NULL"
boolean enabled "DEFAULT false"
varchar consumed_by_workos_id UK "NULLABLE"
timestamp created_at "DEFAULT NOW()"
timestamp updated_at "DEFAULT NOW()"
}
Tables Overview¶
| Table | Purpose |
|---|---|
users |
Authenticated users from WorkOS |
organizations |
Organizations from WorkOS |
rooms |
LiveKit meeting rooms |
user_sessions |
User login sessions with refresh tokens |
user_organizations |
Many-to-many: users ↔ organizations |
user_integrations |
Many-to-many: users ↔ integrations |
integrations |
Third-party integrations (Google Calendar, etc.) |
valid_room_combinations |
Whitelist of valid room layouts |
subscription_link |
Pilot 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)
subscription_link¶
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¶
| Relationship | Delete Behavior |
|---|---|
user_sessions.user_id → users.id |
CASCADE (delete sessions when user deleted) |
user_organizations.user_id → users.id |
CASCADE |
user_organizations.org_id → organizations.id |
CASCADE |
rooms.org_id → organizations.id |
CASCADE (delete rooms when org deleted) |
user_integrations.user_id → users.id |
CASCADE |
user_integrations.integration_id → integrations.id |
CASCADE |
rooms.(layout,dimension,style) → valid_room_combinations.(layout,dimension,style) |
SET NULL |
Constraints¶
| Table | Constraint Type | Columns | Description |
|---|---|---|---|
users |
UNIQUE | workos_id |
Ensures unique WorkOS user identifiers |
organizations |
UNIQUE | invite_id |
Ensures unique invitation IDs (when not null) |
organizations |
UNIQUE | workos_org_id |
Ensures unique WorkOS org identifiers (when not null) |
rooms |
UNIQUE | room_id |
Ensures unique LiveKit room identifiers |
user_sessions |
UNIQUE | session_id |
Ensures unique session identifiers |
integrations |
UNIQUE | integration |
Ensures unique integration names |
subscription_link |
UNIQUE | special_link |
Ensures unique invitation links |
subscription_link |
UNIQUE | consumed_by_workos_id |
One-time use per user (when not null) |
user_organizations |
PRIMARY KEY | (user_id, org_id) |
Prevents duplicate user-org memberships |
user_integrations |
PRIMARY KEY | (user_id, integration_id) |
Prevents duplicate user-integration links |
valid_room_combinations |
PRIMARY KEY | (layout, dimension, style) |
Ensures unique room configuration combinations |
Indexes¶
users¶
idx_users_workos_id(UNIQUE) onworkos_id- Fast WorkOS ID lookupsidx_users_created_atoncreated_at DESC- Sorting by creation dateidx_users_invitation_linkoninvitation_linkWHERE NOT NULL - Pilot invite lookups
organizations¶
idx_organizations_org_nameonorg_name- Organization name searchesidx_organizations_invite_id(UNIQUE) oninvite_idWHERE NOT NULL - Invite link lookupsidx_organizations_workos_org_id(UNIQUE) onworkos_org_idWHERE NOT NULL - WorkOS org lookupsidx_organizations_created_atoncreated_at DESC- Sorting by creation dateidx_organizations_initializedoninitializedWHERE TRUE - Active org filtering
rooms¶
idx_rooms_nameonname- Room name searchesidx_rooms_name_loweronLOWER(name)- Case-insensitive name searchesidx_rooms_room_code(UNIQUE) onroom_id- LiveKit room ID lookupsidx_rooms_org_idonorg_idWHERE NOT NULL - Filtering by organizationidx_rooms_layoutonlayoutWHERE NOT NULL - Layout filteringidx_rooms_dimensionondimensionWHERE NOT NULL - Dimension filteringidx_rooms_styleonstyleWHERE NOT NULL - Style filteringidx_rooms_combinationon(layout, dimension, style)WHERE ALL NOT NULL - Composite configuration lookup
user_sessions¶
idx_user_sessions_user_idonuser_id- User's sessions lookupidx_user_sessions_session_id(UNIQUE) onsession_id- Session ID lookupidx_user_sessions_created_atoncreated_at DESC- Session age sortingidx_user_sessions_updated_atonupdated_at DESC- Last activity sorting
user_organizations¶
idx_user_organizations_user_idonuser_id- User's organizations lookupidx_user_organizations_org_idonorg_id- Organization's members lookupidx_user_organizations_roleonrole- Role filteringidx_user_organizations_statusonstatus- Status filteringidx_user_organizations_role_statuson(role, status)- Composite role+status filtering
integrations¶
idx_integrations_integration(UNIQUE) onintegration- Integration name lookupsidx_integrations_created_atoncreated_at DESC- Sorting by creation date
user_integrations¶
idx_user_integrations_user_idonuser_id- User's integrations lookupidx_user_integrations_integration_idonintegration_id- Integration's users lookupidx_user_integrations_enabledonis_enabledWHERE TRUE - Active integrations filtering
valid_room_combinations¶
idx_valid_room_combinations_layoutonlayout- Layout filteringidx_valid_room_combinations_dimensionondimension- Dimension filteringidx_valid_room_combinations_styleonstyle- Style filtering
subscription_link¶
idx_subscription_link_special_link(UNIQUE) onspecial_link- Link lookupsidx_subscription_link_created_atoncreated_at DESC- Sorting by creation dateidx_subscription_link_enabledonenabledWHERE TRUE - Active links filteringidx_subscription_link_consumed_by(UNIQUE) onconsumed_by_workos_idWHERE 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';
Consuming a Subscription Link¶
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;