Memberships
The Membership entity represents the relationship between users and organizations, defining roles and access levels within specific contexts. It is a crucial component of Wrkbelt's multi-tenant architecture and role-based access control (RBAC) system.
Schema Definition
type Membership = {
// Base Properties
_id: string; // MongoDB ObjectId
user_id: string; // Required, Reference to User
roles: string[]; // Required, Array of Role ObjectIds
context_id: string; // Required, Reference to Organization
context_type: MembershipType; // Required, Currently only 'organization'
is_default: boolean; // Optional, Default: false
// Timestamps
createdAt: Date; // Auto-generated
updatedAt: Date; // Auto-updated
} & BaseEntity;
Field Descriptions
Base Properties
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
_id | ObjectId | Yes | - | Unique identifier for the membership |
user_id | ObjectId | Yes | - | Reference to the associated user |
roles | ObjectId[] | Yes | - | Array of role references defining user permissions |
context_id | ObjectId | Yes | - | Reference to the organization this membership belongs to |
context_type | MembershipType | Yes | - | Type of membership context (currently only 'organization') |
is_default | boolean | No | false | Indicates if this is the user's default membership |
Timestamps
| Field | Type | Description |
|---|---|---|
createdAt | Date | Automatically set when the membership is created |
updatedAt | Date | Automatically updated when the membership changes |
Type Variations
MembershipPopulated
A fully populated version with resolved references:
type MembershipPopulated = Omit<Membership, 'roles' | 'user_id'> & {
roles: RolePopulated[]; // Full role objects with permissions
user_id: User; // Full user object
};
MembershipLeanWithRoleNames
A lightweight version with just role names:
type MembershipLeanWithRoleNames = {
roles: Pick<Role, 'name'>[];
};
Relationships
Primary Relationships
-
Membership → User (Many-to-One)
- Each membership belongs to exactly one user
- Users can have multiple memberships
- Referenced via
user_idfield
-
Membership → Roles (Many-to-Many)
- Each membership can have multiple roles
- Roles can be assigned to multiple memberships
- Referenced via
rolesarray field
-
Membership → Organization (Many-to-One)
- Each membership belongs to exactly one organization
- Organizations can have multiple memberships
- Referenced via
context_idfield withcontext_type: 'organization'
Context Types
Currently, the only supported context type is:
enum MembershipType {
Organization = 'organization'
}
This design allows for future expansion to support other context types while maintaining proper type safety.
Validation
user_id: Required ObjectId reference to Userroles: Required array of ObjectId references to Rolecontext_id: Required ObjectId reference to Organizationcontext_type: Required enum value (currently only 'organization')is_default: Optional boolean, defaults to false
Security Considerations
-
Access Control
- Memberships define user access within organizations
- Role assignments determine available permissions
- Default membership affects initial context selection
-
Multi-tenancy
- Memberships enforce proper tenant isolation
- Users can only access resources within their membership context
- Organizations can only manage their own memberships
-
Role-Based Security
- Roles must be valid for the organization context
- Permission checks are performed through role assignments
- Role changes require proper authorization
Usage Examples
Creating a Basic Membership
const membership = {
user_id: "user123",
roles: ["role456"],
context_id: "org789",
context_type: MembershipType.Organization,
is_default: true
};
Common Operations
-
Default Membership Management
// Only one membership can be default per user
await Membership.updateMany(
{ user_id: userId },
{ is_default: false }
);
await Membership.updateOne(
{ _id: membershipId },
{ is_default: true }
); -
Role Assignment
// Add roles to membership
await Membership.updateOne(
{ _id: membershipId },
{ $addToSet: { roles: newRoleId } }
);