Skip to content

Organization Data Models

Multi-tenant organization system models managed by Better Auth's organization plugin.

Overview

Organizations provide multi-tenant workspace functionality, allowing users to belong to multiple organizations with different roles. All organization data is managed through Better Auth's organization plugin integrated with AdonisJS and PostgreSQL.

Models

Organization

Multi-tenant workspaces that group users and events. Events are currently organization-owned; additional organization-owned resource types remain planned.

Fields:

  • id - UUID primary key
  • owner_id - Stored user reference maintained by Jubiloop's organization hooks. It is separate from Better Auth's membership role used for organization authorization.
  • name - Organization display name
  • slug - URL-safe identifier (unique)
  • logo - Optional logo URL
  • metadata - Optional serialized custom data stored in a text column
  • created_at - Creation timestamp

Indexes:

  • Primary key on id
  • Index on owner_id for owner lookups
  • Unique index on slug for URL routing

Member

Organization membership records with role-based access.

Fields:

  • id - Membership record ID
  • user_id - Reference to User
  • organization_id - Reference to Organization
  • role - Role within organization (owner, admin, member)
  • created_at - When user joined organization

Roles:

  • owner - Better Auth membership role with full organization-management permissions
  • admin - Administrative permissions
  • member - Standard member permissions

Indexes:

  • Primary key on id
  • Unique constraint on (user_id, organization_id) for membership lookups
  • Index on organization_id for listing members

Team

Sub-groups within organizations for grouping members.

Fields:

  • id - Team ID
  • organization_id - Parent organization
  • name - Team name
  • created_at - Creation timestamp
  • updated_at - Last modification timestamp

Indexes:

  • Primary key on id
  • Index on organization_id for listing teams
  • Composite unique index on (organization_id, name)

TeamMember

Team membership is a separate many-to-many link. A user may belong to more than one team without changing their organization membership record.

Indexes and constraints:

  • Primary key on id
  • Unique constraint on (team_id, user_id)
  • Indexes on team_id and user_id

Invitation

Pending organization invitations with expiry.

Fields:

  • id - Invitation ID
  • organization_id - Target organization
  • team_id - Optional team ID for team-specific invitations
  • email - Invitee email address
  • role - Role to assign upon acceptance
  • inviter_id - User ID of the inviter
  • status - Better Auth invitation status
  • expires_at - When invitation expires
  • created_at - When the invitation record was created

Indexes:

  • Primary key on id
  • Index on organization_id for listing invitations
  • Index on email for user invitation lookups
  • Index on status for filtering by status
  • Index on expires_at for expiring invitations

Relationships

Key Relationships:

  • User → Organization (stored owner_id reference, one-to-many)
  • User → Member (user can be member of many organizations)
  • Organization → Member (organization has many members)
  • Organization → Team (organization contains teams)
  • User → TeamMember → Team (users can join multiple teams)
  • Organization → Invitation (organization can send invitations)
  • Organization → Event (organization owns current event records)

Persistence Constraints

  • Organization slugs are unique.
  • (user_id, organization_id) is unique, so a user has at most one membership per organization.
  • (organization_id, name) is unique for teams.
  • (team_id, user_id) is unique for team memberships.
  • Foreign keys cascade membership, team, and invitation cleanup where defined by the migrations.

Runtime limits, owner protection, and role behavior belong to the organization backend guide.

See Also

For actual migration files, see apps/server/database/migrations/

Built with ❤️ by the Jubiloop team