Appearance
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, events, and resources.
Fields:
id- UUID primary keyowner_id- Reference to User who created the organizationname- Organization display nameslug- URL-safe identifier (unique)logo- Optional logo URLmetadata- Additional custom data (JSONB)created_at- Creation timestamp
Indexes:
- Primary key on
id - Index on
owner_idfor owner lookups - Unique index on
slugfor URL routing
Member
Organization membership records with role-based access.
Fields:
id- Membership record IDuser_id- Reference to Userorganization_id- Reference to Organizationrole- Role within organization (owner,admin,member)team_id- Optional team assignmentcreated_at- When user joined organization
Roles:
owner- Organization creator, full permissionsadmin- Administrative permissionsmember- Standard member permissions
Indexes:
- Primary key on
id - Composite index on
(user_id, organization_id)for membership lookups - Index on
organization_idfor listing members - Index on
team_idfor team-specific queries
Team
Sub-groups within organizations for grouping members.
Fields:
id- Team IDorganization_id- Parent organizationname- Team namecreated_at- Creation timestampupdated_at- Last modification timestamp
Indexes:
- Primary key on
id - Index on
organization_idfor listing teams - Composite unique index on
(organization_id, name)
Invitation
Pending organization invitations with expiry.
Fields:
id- Invitation IDorganization_id- Target organizationteam_id- Optional team ID for team-specific invitationsemail- Invitee email addressrole- Role to assign upon acceptanceinvited_by- User ID of member who sent invitationstatus- Invitation status (pending,accepted,declined)expires_at- When invitation expirescreated_at- When invitation was sent
Indexes:
- Primary key on
id - Index on
organization_idfor listing invitations - Index on
emailfor user invitation lookups - Index on
statusfor filtering by status - Index on
expires_atfor expiring invitations
Relationships
Key Relationships:
- User → Organization (as owner, one-to-many)
- User → Member (user can be member of many organizations)
- Organization → Member (organization has many members)
- Organization → Team (organization contains teams)
- Member → Team (members can be assigned to teams)
- Organization → Invitation (organization can send invitations)
Limits & Constraints
These limits are enforced by Better Auth in app/lib/auth.ts:
| Constraint | Limit | Source |
|---|---|---|
| Max organizations per user | 5 | organizationLimit in app/lib/auth.ts |
| Max members per organization | 100 | membershipLimit in app/lib/auth.ts |
Owner Protection
The Member model has a @beforeDelete hook that prevents removing the organization owner:
- Loads the organization to check
ownerId - Throws if
member.userId === member.organization.ownerId - Error message:
"Cannot remove the organization owner... Transfer ownership first."
To remove an owner, transfer ownership to another member first, then remove the old owner's membership.
Invitation Emails
Invitation emails are not implemented
Invitation records are created and stored in the invitations table when an owner invites a user. However, the sendInvitationEmail function in app/lib/auth.ts has an empty body (TODO comment only). Invited users receive no email notification. This is a known TODO.
See Also
- Authentication Data Models — User, Session, Account schemas
- Auth API Reference — Organization management endpoints
- Organizations Feature Backend — Implementation patterns
For actual migration files, see apps/server/database/migrations/