Skip to main content
Concordia’s database uses Drizzle ORM relations to define type-safe relationships between tables. This page documents the key relationships and how they’re structured.

Relationship Patterns

The database uses three main relationship patterns:
  1. One-to-One - Single record references another (e.g., User → Profile)
  2. One-to-Many - One record has multiple children (e.g., User → Sessions)
  3. Many-to-Many - Records relate through join tables (e.g., Posts ↔ Authors)

Authentication Relationships

User Relations

The user table is central to authentication and serves as the root for most relationships:

Session Relations

Foreign Key:
  • session.userIduser.id (CASCADE DELETE)
Each session belongs to exactly one user. Sessions are automatically deleted when the user is removed.

Account Relations

Foreign Key:
  • account.userIduser.id (CASCADE DELETE)
OAuth accounts are linked to a single user. Multiple accounts (Google, GitHub, etc.) can belong to one user.

Organization Relations

Member Relations

Foreign Keys:
  • member.organizationIdorganization.id (CASCADE DELETE)
  • member.userIduser.id (CASCADE DELETE)
Members form a junction between users and organizations:
Deleting either the user or organization removes the membership.

Invitation Relations

Foreign Keys:
  • invitation.organizationIdorganization.id (CASCADE DELETE)
  • invitation.inviterIduser.id (CASCADE DELETE)
Invitations track who invited someone to which organization.

Profile Relationships

User → Profile (One-to-One)

While not explicitly defined with relations in the schema, the profile table has a unique constraint on userId:
Relationship:
Each user has exactly one profile. The userId unique constraint enforces this.

Blog Relationships

Blog Post Relations

Many-to-Many: Posts ↔ Authors

Join Table: blog_post_authors
Relationship:
A post can have multiple authors, and an author can write multiple posts.

Many-to-Many: Posts ↔ Categories

Join Table: blog_post_categories
Relationship:
Posts can belong to multiple categories, and categories contain multiple posts.

Many-to-Many: Posts ↔ Media

Join Table: blog_post_media
Relationship:
Posts can have multiple media attachments (images, videos), with metadata about type and position.

Blog Author Relations

Foreign Keys:
  • blogAuthors.avatarIdblogMedia.id
  • blogAuthors.worksForIdblogOrganizations.id

Blog Category Relations

Hierarchical Categories: Categories support self-referencing hierarchy:

Blog Comments Relations

Self-Referencing Hierarchy: Comments support threading through self-reference:

Blog Translations Relations

Foreign Key:
  • blogTranslations.postIdblogPosts.id
Relationship:
Each post can have multiple translations (French, English, Spanish, etc.).

Services Relationships

Service Listing Relations

Many-to-Many: Services ↔ Media

Join Table: services_media_links
Relationship:

Service Category Relations

Hierarchical Categories: Like blog categories, service categories support hierarchy:

Service Reviews Relations

Foreign Keys:
  • servicesReviews.serviceIdservicesListings.id
  • servicesReviews.parentIdservicesReviews.id (self-reference)
Self-Referencing for Replies:

Service Availability Relations

Foreign Key:
  • servicesAvailability.serviceIdservicesListings.id
Relationship:
A service has multiple availability slots (Monday 9-5, Tuesday 10-3, etc.).

Service Bookings Relations

Foreign Key:
  • servicesBookings.serviceIdservicesListings.id
Additional References (not enforced by FK):
  • servicesBookings.customerIduser.id
  • servicesBookings.providerIduser.id

Service Translations Relations

Foreign Key:
  • servicesTranslations.serviceIdservicesListings.id

Complete Relationship Diagram

Authentication & Users

Blog System

Services Marketplace

Cascade Deletion Rules

User Deletion Cascades

When a user is deleted, these are automatically removed:
  • All sessions
  • All linked accounts (OAuth)
  • All organization memberships
  • All invitations sent by user

Organization Deletion Cascades

When an organization is deleted:
  • All members are removed
  • All pending invitations are removed

Post/Service Deletion

Note that blog posts and services don’t have explicit cascade rules defined at the database level, but should be handled at the application level:
  • Deleting a post should remove translations, comments, and join table entries
  • Deleting a service should remove reviews, bookings, and availability

Querying Relations with Drizzle

Basic Relation Query

Nested Relations

Many-to-Many Query

Self-Referencing Query

Best Practices

1. Always Use Relations for Type Safety

Drizzle relations provide full TypeScript inference:

2. Use Cascade Deletes Carefully

Cascade deletes are powerful but dangerous:
  • Use CASCADE for dependent data (sessions, tokens)
  • Consider soft deletes for user-generated content
  • Always test deletion in development first

3. Optimize Nested Queries

Avoid over-fetching with selective includes:

4. Use Indexes for Foreign Keys

All foreign key columns should be indexed:

5. Handle Soft Deletes for Content

For user-generated content, consider soft deletes:

Next Steps

Schema Reference

View detailed schema documentation

Migrations

Learn how to create and apply migrations