IAM Service - Domain Design
1. User sub-domain
Aggregate Root: User
a. Description
The User domain represents individual users in the system—people who can access the platform and be assigned to tenants with specific roles. Users have personal information (name, email) and can have multiple memberships across different tenants.
The User aggregate manages user identity, validates user data, and enforces business rules around user information updates.
Key Properties:
id: Unique identifier for the userfirstName: User's first namelastName: User's last nameemail: User's email address (unique)memberships: Collection of memberships linking user to tenants with roles
Commands and Operations:
| Command | Triggered By | Purpose | Business Logic |
|---|---|---|---|
create() | Human (Admin) or System (Registration) | Create new user account | Validates email format, creates user with required fields |
update() | Human (User/Admin) | Update user information | Validates email format, ensures names are not empty, updates specified fields |
checkCanDelete() | Human (Admin) | Check if user can be deleted | Currently no restrictions (placeholder for future business rules) |
Validation Rules:
- Email Format: Must match standard email regex pattern (
/^[^\s@]+@[^\s@]+\.[^\s@]+$/) - Name Requirements: First name and last name cannot be empty strings
- Email Uniqueness: Email must be unique across all users (enforced at database level)
c. Domain Entry Points
The User aggregate provides a static factory method as its entry point:
| Static Method | Purpose | Triggered By |
|---|---|---|
create() | Initialize User aggregate | User registration or admin user creation |
d. Domain Boundaries and Vision
The User domain manages user identity and personal information while remaining unaware of authorization details (roles, permissions) which are handled through the Membership domain.
Integration boundaries
- ↔ Membership Domain: Users are linked to tenants and roles through Membership entities. User doesn't directly manage memberships, but memberships reference users.
- ← External Systems: User creation can be triggered by external authentication systems (e.g., SuperTokens) during registration.
- → External Systems: User information is consumed by other services for authorization and personalization.
Vision
- User supports multi-tenant access through memberships
- User maintains audit trail through createdAt/updatedAt timestamps
- User supports soft-delete for data retention and compliance
- User validation ensures data quality and prevents invalid user accounts
2. Tenant sub-domain
Aggregate Root: Tenant
a. Description
The Tenant domain represents organizations or tenants in a multi-tenant system—isolated workspaces where users collaborate. Each tenant has a unique name and can have multiple users as members with different roles.
The Tenant aggregate manages tenant identity, enforces tenant uniqueness, and supports tenant lifecycle management.
Key Properties:
id: Unique identifier for the tenantname: Tenant name (unique across all tenants)memberships: Collection of memberships linking users to this tenant with roles
Commands and Operations:
| Command | Triggered By | Purpose | Business Logic |
|---|---|---|---|
create() | Human (Admin) | Create new tenant | Creates tenant with unique name |
rename() | Human (Admin) | Update tenant name | Updates tenant name (uniqueness enforced at database level) |
Business Rules:
- Name Uniqueness: Tenant name must be unique across all tenants (enforced at database level with unique constraint)
- Soft Delete: Tenants can be soft-deleted, preserving data for audit and compliance
c. Domain Entry Points
The Tenant aggregate provides a static factory method as its entry point:
| Static Method | Purpose | Triggered By |
|---|---|---|
create() | Initialize Tenant aggregate | Tenant creation by admin |
d. Domain Boundaries and Vision
The Tenant domain manages tenant identity and isolation while remaining unaware of user details or authorization specifics, which are handled through the Membership domain.
Integration boundaries
- ↔ Membership Domain: Tenants are linked to users and roles through Membership entities. Tenant doesn't directly manage memberships, but memberships reference tenants.
- ← External Systems: Tenant creation can be triggered by external systems during onboarding.
- → External Systems: Tenant information is consumed by other services for multi-tenant data isolation and authorization.
Vision
- Tenant provides data isolation boundaries for multi-tenant architecture
- Tenant maintains audit trail through createdAt/updatedAt timestamps
- Tenant supports soft-delete for data retention and compliance
- Tenant name uniqueness ensures clear tenant identification
3. Role sub-domain
Entity: Role (not an aggregate root)
a. Description
The Role domain represents roles that define sets of permissions—reusable authorization templates that can be assigned to users within tenants. Roles contain a collection of permission IDs that define what actions users with that role can perform.
Current Architecture Note: Role is an entity that can be referenced by multiple memberships. It doesn't have its own lifecycle persistence independent of the IAM service, but it's a first-class domain concept.
b. Structure and business rules
Role
├── Basic Properties
│ ├── id: string
│ ├── name: string
│ ├── description: string | null
│ └── permissionIds: string[]
│
└── Relationships
├── permissions: Permission[] (via permissionIds)
└── memberships: Membership[] (referenced by memberships)Business Rules:
- Permission Assignment: Roles contain an array of permission IDs that define allowed actions
- Reusability: Roles can be assigned to multiple users across different tenants through memberships
- Permission Validation: Permission IDs must reference existing Permission entities (enforced at application level)
Commands and Operations:
| Command | Triggered By | Purpose | Business Logic |
|---|---|---|---|
create() | Human (Admin) | Create new role | Creates role with name, description, and permission IDs |
rename() | Human (Admin) | Update role name | Updates role name |
updateDescription() | Human (Admin) | Update role description | Updates role description |
updatePermissions() | Human (Admin) | Update role permissions | Replaces permission IDs array |
c. Domain Boundaries and Vision
The Role entity is a reusable authorization template that defines permission sets:
🔗 Role ↔ Permission Interface
- Responsibility: Role encapsulates a named set of permissions
- Direction: Role references Permission entities via permissionIds
- Boundary Rule: Role doesn't own Permission entities; it references them
🔗 Role ↔ Membership Interface
- Responsibility: Role is assigned to users within tenants through Membership
- Direction: Membership references Role via roleId
- Boundary Rule: Role doesn't manage memberships; memberships reference roles
Key Encapsulation Rules:
- External actors CANNOT directly manipulate Role permission sets without going through role commands
- All Role operations MUST go through role commands (create, rename, updatePermissions)
- Role entities contain business logic but are referenced by memberships
Vision
- Role provides reusable authorization templates
- Role supports permission composition through permission IDs
- Role enables consistent authorization across tenants
- Role maintains clear separation between role definition and role assignment
4. Permission sub-domain
Entity: Permission (not an aggregate root)
a. Description
The Permission domain represents permissions—granular authorization capabilities that define what actions can be performed in the system. Permissions are the atomic units of authorization that are composed into roles.
Current Architecture Note: Permission is an entity that can be referenced by multiple roles. It doesn't have its own lifecycle persistence independent of the IAM service, but it's a first-class domain concept.
b. Structure and business rules
Permission
├── Basic Properties
│ ├── id: string
│ ├── name: string
│ ├── description: string | null
│ └── deletedAt: Date | null
│
└── Relationships
└── roles: Role[] (referenced by roles via permissionIds)Business Rules:
- Atomic Authorization: Permissions represent single, atomic authorization capabilities
- Reusability: Permissions can be referenced by multiple roles
- Soft Delete: Permissions can be soft-deleted, preserving references but marking as inactive
Commands and Operations:
| Command | Triggered By | Purpose | Business Logic |
|---|---|---|---|
create() | Human (Admin) | Create new permission | Creates permission with name and optional description |
rename() | Human (Admin) | Update permission name | Updates permission name |
updateDescription() | Human (Admin) | Update permission description | Updates permission description |
c. Domain Boundaries and Vision
The Permission entity is an atomic authorization unit that defines individual capabilities:
🔗 Permission ↔ Role Interface
- Responsibility: Permission defines atomic authorization capabilities
- Direction: Role references Permission entities via permissionIds
- Boundary Rule: Permission doesn't own Role entities; roles reference permissions
Key Encapsulation Rules:
- External actors CANNOT directly manipulate Permission definitions without going through permission commands
- All Permission operations MUST go through permission commands (create, rename, updateDescription)
- Permission entities contain business logic but are referenced by roles
Vision
- Permission provides atomic authorization units
- Permission enables fine-grained access control
- Permission supports composition into roles for flexible authorization
- Permission maintains clear separation between permission definition and permission usage
5. Membership sub-domain
Entity: Membership (not an aggregate root)
a. Description
The Membership domain represents the relationship between users, tenants, and roles—the assignment of a user to a tenant with a specific role. Memberships enable multi-tenant access control by linking users to tenants and defining their authorization level through roles.
Current Architecture Note: Membership is an entity that links User, Tenant, and Role aggregates. It doesn't have its own lifecycle persistence independent of these aggregates, but it's a first-class domain concept that enables the authorization model.
b. Structure and business rules
Membership
├── Basic Properties
│ ├── id: string
│ ├── userId: string (references User)
│ ├── tenantId: string (references Tenant)
│ ├── roleId: string (references Role)
│ ├── createdAt: Date
│ ├── updatedAt: Date
│ └── deletedAt: Date | null
│
└── Relationships
├── user: User (via userId)
├── tenant: Tenant (via tenantId)
└── role: Role (via roleId)Business Rules:
- Unique User-Tenant Pair: A user can have at most one membership per tenant (enforced at database level with unique constraint on
[userId, tenantId]) - Role Assignment: Each membership assigns exactly one role to the user within the tenant
- Multi-Tenant Support: Users can have multiple memberships across different tenants with different roles
- Soft Delete: Memberships can be soft-deleted, preserving audit trail while revoking access
Commands and Operations:
| Command | Triggered By | Purpose | Business Logic |
|---|---|---|---|
create() | Human (Admin) | Create new membership | Creates membership linking user, tenant, and role. If membership already exists, returns existing membership ID |
Key Aggregate Invariants:
- User-Tenant Uniqueness: Each user can have only one active membership per tenant
- Role Requirement: Membership must reference an existing role
- User Requirement: Membership must reference an existing user
- Tenant Requirement: Membership must reference an existing tenant
c. Domain Boundaries and Vision
The Membership entity is a relationship entity that links User, Tenant, and Role aggregates:
🔗 Membership ↔ User Interface
- Responsibility: Membership links users to tenants and roles
- Direction: Membership references User via userId
- Boundary Rule: Membership doesn't own User; it references users
🔗 Membership ↔ Tenant Interface
- Responsibility: Membership defines user's access within a tenant
- Direction: Membership references Tenant via tenantId
- Boundary Rule: Membership doesn't own Tenant; it references tenants
🔗 Membership ↔ Role Interface
- Responsibility: Membership assigns role to user within tenant
- Direction: Membership references Role via roleId
- Boundary Rule: Membership doesn't own Role; it references roles
Key Encapsulation Rules:
- External actors CANNOT directly manipulate Membership relationships without going through membership commands
- All Membership operations MUST go through membership commands (create)
- Membership entities enforce business rules around user-tenant-role relationships
Vision
- Membership enables multi-tenant access control
- Membership provides clear user-tenant-role relationships
- Membership supports role-based access control (RBAC) model
- Membership maintains audit trail through timestamps and soft-delete
- Membership ensures data integrity through unique constraints