Skip to content

Identity

Overview

The Identity domain is a default domain in comby. Identities can be linked to accounts, associated with groups, and assigned tokens for secure interactions. The Identity aggregate is at the core of this domain, handling events and maintaining consistency across identity-related operations.

Concept

What is an Identity?

An Identity is the tenant-specific representation of a user. While an Account handles authentication (login/credentials), an Identity handles authorization (permissions/groups) within a specific tenant. A single account can have multiple identities across different tenants.

Key Characteristics:

  • Account-Tenant Bridge: Links an account to a tenant with specific permissions
  • Multi-Tenant Support: One account can have multiple identities in different tenants
  • Profile Information: Each identity has its own profile (name, email, title, avatar)
  • Group Membership: Identities belong to groups that define their permissions
  • Service Account Tokens: Identities can have API tokens for programmatic access
Account (Authentication)
└── Identity 1 (Tenant A)
    ├── Profile (Name, Email, Title, Avatar)
    ├── Groups [Admin, Developer]
    └── Tokens [API Token 1, API Token 2]
└── Identity 2 (Tenant B)
    ├── Profile (Different Name, Email)
    ├── Groups [Viewer]
    └── Tokens []

Architecture

Hierarchy

System
└── Tenant
    └── Identities
        ├── AccountUuid (Link to Account)
        ├── Profile (Name, Email, Title, Avatar)
        ├── GroupUuids (List of assigned groups)
        └── Tokens (Service account tokens)

Location in Codebase

  • Domain: /domain/identity/

    • aggregate/ - Identity aggregate
    • command/ - Identity commands
    • query/ - Identity queries
    • readmodel/ - Identity readmodel
  • API: /api/identity/

    • REST API handlers for identity management

Identity is connected to:

  • Account: One-to-many relationship (one account, many identities)
  • Tenant: Each identity belongs to exactly one tenant
  • Group: Identities are assigned to groups for permissions
  • Auth: Auth domain consumes identity events for authorization
  • Workspace: Identities can be workspace members

Domain Model

go
type Identity struct {
    AggregateUuid string

    // References
    AccountUuid string
    GroupUuids  []string

    // Entities
    Profile *Profile
    Tokens  []*Token
}

type Profile struct {
    Name   string
    Email  string
    Title  string
    Avatar string
}

type Token struct {
    TokenUuid   string
    Name        string
    Description string
    TokenValue  string  // Hashed
    ExpiredAt   int64
}

An Identity can only be associated with a single Tenant. However, an account can have multiple identities, each linked to a different Tenant. This design allows a user to log in to multiple Tenants using a single account.

Account vs Identity

Account

  • Purpose: Authentication (login, sessions, passwords)
  • Scope: System-wide, tenant-independent
  • Stored in: Anonymous tenant
  • One per user: A user has one account

Identity

  • Purpose: Authorization (permissions, groups, roles)
  • Scope: Tenant-specific
  • Stored in: Specific tenant
  • Multiple per user: A user can have identities in multiple tenants

Example Flow

User → Registers → Creates Account
     → Invited to Tenant A → Creates Identity A (with Groups: [Admin])
     → Invited to Tenant B → Creates Identity B (with Groups: [Viewer])

Service Account Tokens

Identities can have service account tokens for programmatic API access:

Characteristics:

  • API Authentication: Use tokens instead of session-based auth
  • Long-lived: Configurable expiration (default: 10 years)
  • Named & Described: Each token has a name and description
  • Hashed Storage: Token values are hashed before storage
  • Multiple per Identity: Each identity can have multiple tokens

Use Cases:

  • CI/CD pipelines
  • Automated scripts
  • Third-party integrations
  • Microservice authentication

Structure

The Identity aggregate extends the BaseAggregate, inheriting core event-sourcing capabilities like event tracking and versioning. It includes fields to represent the identity's relationships, attributes, and associated entities:

The Identity is an aggregate that represents a user within a system holding entities Profile and Token. Profile contains information about the user, such as their name, email address, title, and avatar. Token represents API tokens associated with the identity, each containing a unique UUID, name, description, token value, and expiration. An identity can act as an Service Account - without an associated account.

References:

  • AccountUuid: Link the identity to an existing account in the Account domain (optional).
  • GroupUuids: Tracks the groups to which the identity belongs.

Entities:

  • Profile: Captures personal information about the identity, such as name, email, title, and avatar.
  • Tokens: Represents authentication or API tokens associated with the identity, each containing a unique UUID, name, description, token value, and expiration.

Usage

1. Register Domain

go
import "github.com/gradientzero/comby/v2/domain/identity"

// In application initialization
identity.Register(ctx, facade)

2. Create Identity

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandCreate{
    IdentityUuid: uuid.New().String(),
    AccountUuid:  "account-uuid",
    GroupUuids: []string{
        "developers-group-uuid",
        "viewers-group-uuid",
    },
})

cmd.SetTenantUuid("tenant-uuid")
facade.DispatchCommand(ctx, cmd)

3. Create Identity without Account

go
// For service accounts or system identities
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandCreate{
    IdentityUuid: uuid.New().String(),
    GroupUuids: []string{
        "service-accounts-group-uuid",
    },
})

cmd.SetTenantUuid("tenant-uuid")
facade.DispatchCommand(ctx, cmd)

4. Update Identity Profile

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandUpdateProfile{
    IdentityUuid: "identity-uuid",
    Name:         "John Doe",
    Email:        "john.doe@example.com",
    Title:        "Senior Developer",
    Avatar:       "https://example.com/avatars/johndoe.jpg",
    PatchedFields: []string{"name", "email", "title", "avatar"},
})

facade.DispatchCommand(ctx, cmd)

5. Add Group to Identity

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandAddGroup{
    IdentityUuid: "identity-uuid",
    GroupUuid:    "administrators-group-uuid",
})

facade.DispatchCommand(ctx, cmd)

6. Remove Group from Identity

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandRemoveGroup{
    IdentityUuid: "identity-uuid",
    GroupUuid:    "viewers-group-uuid",
})

facade.DispatchCommand(ctx, cmd)

7. Add Service Account Token

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandAddToken{
    IdentityUuid: "identity-uuid",
    TokenUuid:    uuid.New().String(),
    TokenValue:   "generated-secure-token",
    Name:         "CI/CD Pipeline Token",
    Description:  "Token for automated deployments",
    ExpiredAt:    time.Now().Add(365 * 24 * time.Hour).UnixNano(), // 1 year
})

facade.DispatchCommand(ctx, cmd)

8. Remove Token

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandRemoveToken{
    IdentityUuid: "identity-uuid",
    TokenUuid:    "token-uuid",
})

facade.DispatchCommand(ctx, cmd)

9. List Identities

go
// List all identities in tenant
qry, _ := comby.NewQuery("Identity", &query.IdentityQueryList{
    TenantUuid: "tenant-uuid",
    Page:       0,
    PageSize:   100,
})

res, _ := facade.DispatchQuery(ctx, qry)
identities := res.(*query.IdentityQueryListResponse).Items

10. List Identities for Account

go
// List all identities for a specific account
qry, _ := comby.NewQuery("Identity", &query.IdentityQueryListForAccount{
    AccountUuid: "account-uuid",
    TenantUuid:  "tenant-uuid",
})

res, _ := facade.DispatchQuery(ctx, qry)
identities := res.(*query.IdentityQueryListResponse).Items

11. Get Identity

go
qry, _ := comby.NewQuery("Identity", &query.IdentityQueryGet{
    IdentityUuid: "identity-uuid",
})

res, _ := facade.DispatchQuery(ctx, qry)
identity := res.(*query.IdentityQueryItemResponse).Item

12. Delete Identity

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandRemove{
    IdentityUuid: "identity-uuid",
})

facade.DispatchCommand(ctx, cmd)

13. Set Identity Attribute

go
cmd, _ := comby.NewCommand("Identity", &command.IdentityCommandSetAttribute{
    IdentityUuid: "identity-uuid",
    Key:          "department",
    Value:        "engineering",
})

facade.DispatchCommand(ctx, cmd)

API Endpoints

Identity Management

POST   /api/tenants/{tenantUuid}/identities                         - Create new identity
GET    /api/tenants/{tenantUuid}/identities                         - List all identities
GET    /api/tenants/{tenantUuid}/identities/{identityUuid}          - Get specific identity
PATCH  /api/tenants/{tenantUuid}/identities/{identityUuid}          - Update identity
DELETE /api/tenants/{tenantUuid}/identities/{identityUuid}          - Delete identity

Profile Management

PATCH /api/tenants/{tenantUuid}/identities/{identityUuid}/profile   - Update profile

Group Management

POST /api/tenants/{tenantUuid}/identities/{identityUuid}/add_group    - Add group
POST /api/tenants/{tenantUuid}/identities/{identityUuid}/remove_group - Remove group

Token Management

POST /api/tenants/{tenantUuid}/identities/{identityUuid}/add_token    - Add service account token
POST /api/tenants/{tenantUuid}/identities/{identityUuid}/remove_token - Remove token

Query by Account

GET /api/tenants/{tenantUuid}/identities/account/{accountUuid}        - List identities for account

Attributes

POST   /api/tenants/{tenantUuid}/identities/{identityUuid}/attributes       - Set attribute
DELETE /api/tenants/{tenantUuid}/identities/{identityUuid}/attributes/{key} - Remove attribute

API Example: Create Identity

bash
POST /api/tenants/{tenantUuid}/identities
Content-Type: application/json

{
  "identityUuid": "550e8400-e29b-41d4-a716-446655440001",
  "accountUuid": "account-uuid",
  "groupUuids": [
    "developers-group-uuid",
    "viewers-group-uuid"
  ]
}

API Example: Update Profile

bash
PATCH /api/tenants/{tenantUuid}/identities/{identityUuid}/profile
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john.doe@example.com",
  "title": "Senior Developer",
  "avatar": "https://example.com/avatars/johndoe.jpg",
  "patchedFields": ["name", "email", "title", "avatar"]
}

API Example: Add Service Account Token

bash
POST /api/tenants/{tenantUuid}/identities/{identityUuid}/add_token
Content-Type: application/json

{
  "tokenUuid": "token-uuid",
  "tokenValue": "generated-secure-token",
  "name": "CI/CD Pipeline Token",
  "description": "Token for automated deployments",
  "expiredAt": 1735689600000000000
}

Use Cases

1. Multi-Tenant SaaS User

User: john@example.com
└── Account: john-account-uuid
    ├── Identity in Tenant A (Company A)
    │   ├── Profile: John Doe (CTO)
    │   ├── Groups: [Administrators, Developers]
    │   └── Tokens: []
    └── Identity in Tenant B (Company B)
        ├── Profile: John D. (Consultant)
        ├── Groups: [Consultants, Viewers]
        └── Tokens: []

2. Service Account Integration

Service: CI/CD Pipeline
└── Identity (No Account)
    ├── Profile: CI/CD Service
    ├── Groups: [Service Accounts, Deployers]
    └── Tokens: [Deploy Token (expires: never)]

3. User Joining Multiple Organizations

User Registration Flow:
1. User registers → Account created
2. User accepts invite from Org A → Identity A created (Groups: [Members])
3. User accepts invite from Org B → Identity B created (Groups: [Admins])
4. User switches between orgs → Uses different identities with different permissions

4. Role Changes Over Time

User Career Progression:
Identity: jane-identity-uuid
├── Year 1: Groups [Junior Developers]
├── Year 2: Groups [Developers, Team Leads] (add group)
├── Year 3: Groups [Senior Developers, Team Leads] (remove Junior, add Senior)
└── Year 4: Groups [Engineering Managers] (new role)

Features

  • ✅ Multi-tenant identity support
  • ✅ Account-identity separation
  • ✅ Profile management per identity
  • ✅ Group-based permissions
  • ✅ Service account token support
  • ✅ Token expiration management
  • ✅ Multiple tokens per identity
  • ✅ Custom attributes support
  • ✅ Cross-tenant identity queries

Best Practices

Identity Creation

✅ Always link identities to accounts for human users ✅ Create identities without accounts for service accounts ✅ Assign initial groups during creation ✅ Set meaningful profile information

Profile Management

✅ Keep profiles up-to-date with user information ✅ Use consistent email addresses across tenants when appropriate ✅ Use professional titles that reflect role ✅ Store avatar URLs, not binary data

Group Assignment

✅ Assign minimal required groups (principle of least privilege) ✅ Review group assignments regularly ✅ Remove unnecessary groups promptly ✅ Use group membership to control access, not individual permissions

Service Account Tokens

✅ Use descriptive names for tokens ✅ Set appropriate expiration times ✅ Rotate tokens regularly ✅ Delete unused tokens immediately ✅ Never log or expose token values ✅ Use separate tokens for different purposes

Token Security

go
// ✅ Good: Generate secure random tokens
tokenValue := generateSecureRandomToken(32)

// ✅ Good: Set reasonable expiration
expiredAt := time.Now().Add(90 * 24 * time.Hour).UnixNano() // 90 days

// ❌ Bad: Use predictable tokens
tokenValue := "token-123"

// ❌ Bad: Never expire tokens (for regular use)
expiredAt := 0

Troubleshooting

Identity not found after creation

Check:

  1. Is the identity in the correct tenant?
  2. Was the command successfully dispatched?
  3. Check event store for IdentityCreatedEvent

Debug:

go
// List all identities in tenant
identities, _ := GetIdentityReadmodel().GetModelList(
    readmodel.ListWithTenantUuid(tenantUuid),
)
for _, identity := range identities {
    fmt.Printf("Identity: %s, Account: %s\n", identity.IdentityUuid, identity.AccountUuid)
}

Group assignment not working

Cause: Group doesn't exist in the tenant or invalid group UUID.

Solution: Verify group exists before adding:

go
// Check if group exists in tenant
group, err := GetGroupReadmodel().GetModel(groupUuid)
if err != nil {
    // Group not found
}

Token authentication fails

Check:

  1. Is the token expired?
  2. Is the token value correct (hashed comparison)?
  3. Is the identity active?
  4. Does the identity have required permissions?

Debug:

go
// Validate token via Auth readmodel
tokenCtx, err := auth.GetAuthReadmodel().GetServiceAccount(tokenUuid, tokenValue)
if err != nil {
    // Token not found or invalid
}
if time.Now().Unix() > tokenCtx.ExpiredAt {
    // Token expired
}

Multiple identities causing confusion

Cause: User has multiple identities and doesn't understand context switching.

Solution:

  • Clearly indicate which tenant/identity is active in UI
  • Provide easy tenant switching mechanism
  • Show identity-specific information (profile, groups)

Profile not updating

Cause: Missing fields in PatchedFields parameter.

Solution:

go
// ✅ Correct: Specify which fields to update
cmd := &command.IdentityCommandUpdateProfile{
    IdentityUuid: "identity-uuid",
    Name:         "New Name",
    Email:        "new@email.com",
    PatchedFields: []string{"name", "email"}, // Required!
}

Integration with Other Domains

Account Domain

go
// After account registration, create identity
accountRegistered := // from account event

cmd := &command.IdentityCommandCreate{
    IdentityUuid: uuid.New().String(),
    AccountUuid:  accountRegistered.AccountUuid,
    GroupUuids:   []string{defaultGroupUuid},
}

Tenant Domain

When a tenant is created, you may want to create an initial identity:

go
// Create first identity (owner) for new tenant
cmd := &command.IdentityCommandCreate{
    IdentityUuid: uuid.New().String(),
    AccountUuid:  ownerAccountUuid,
    GroupUuids:   []string{adminGroupUuid},
}
cmd.SetTenantUuid(newTenantUuid)

Auth Domain

The Auth domain consumes identity events:

  • IdentityCreatedEvent → Builds authorization context
  • IdentityAddedGroupEvent → Updates permissions
  • IdentityRemovedGroupEvent → Revokes permissions
  • IdentityAddedTokenEvent → Enables token-based auth

Invitation Domain

Invitations often trigger identity creation:

go
// When invitation is accepted
cmd := &command.IdentityCommandCreate{
    IdentityUuid: uuid.New().String(),
    AccountUuid:  invitation.AccountUuid,
    GroupUuids:   invitation.GroupUuids,
}
cmd.SetTenantUuid(invitation.TenantUuid)

Security Considerations

Token Management

  • Always hash token values before storage
  • Validate token expiration before authentication
  • Implement token rotation policies
  • Monitor token usage for anomalies

Profile Information

  • Validate email addresses
  • Sanitize profile inputs to prevent XSS
  • Don't store sensitive information in profiles
  • Use HTTPS for avatar URLs

Permission Isolation

  • Ensure identities can only access their tenant's resources
  • Validate group memberships before granting permissions
  • Audit identity permission changes
  • Implement multi-factor authentication for sensitive operations

Commands

IdentityCommandAddGroup

Domain Command Struct:

go
type IdentityCommandAddGroup struct {
	IdentityUuid string `json:"identityUuid"`
	GroupUuid    string `json:"groupUuid"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandAddGroup(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandAddGroup) ([]comby.Event, error)

IdentityCommandAddToken

Domain Command Struct:

go
type IdentityCommandAddToken struct {
	IdentityUuid string `json:"identityUuid"`
	TokenUuid    string `json:"tokenUuid"`
	TokenValue   string `json:"tokenValue"`
	Name         string `json:"name,omitempty"`
	Description  string `json:"description,omitempty"`
	ExpiredAt    int64  `json:"expiredAt,omitempty"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandAddToken(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandAddToken) ([]comby.Event, error)

IdentityCommandCreate

Domain Command Struct:

go
type IdentityCommandCreate struct {
	IdentityUuid string   `json:"identityUuid"`
	AccountUuid  string   `json:"accountUuid,omitempty"`
	GroupUuids   []string `json:"groupUuids"`
	Attributes   string   `json:"attributes,omitempty"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandCreate(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandCreate) ([]comby.Event, error)

IdentityCommandRemove

Domain Command Struct:

go
type IdentityCommandRemove struct {
	IdentityUuid string `json:"identityUuid"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandRemove(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandRemove) ([]comby.Event, error)

IdentityCommandRemoveAttribute

Domain Command Struct:

go
type IdentityCommandRemoveAttribute struct {
	IdentityUuid string `json:"identityUuid"`
	Key          string `json:"key"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandRemoveAttribute(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandRemoveAttribute) ([]comby.Event, error)

IdentityCommandRemoveGroup

Domain Command Struct:

go
type IdentityCommandRemoveGroup struct {
	IdentityUuid string `json:"identityUuid"`
	GroupUuid    string `json:"groupUuid"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandRemoveGroup(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandRemoveGroup) ([]comby.Event, error)

IdentityCommandRemoveToken

Domain Command Struct:

go
type IdentityCommandRemoveToken struct {
	IdentityUuid string `json:"identityUuid"`
	TokenUuid    string `json:"tokenUuid"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandRemoveToken(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandRemoveToken) ([]comby.Event, error)

IdentityCommandSetAttribute

Domain Command Struct:

go
type IdentityCommandSetAttribute struct {
	IdentityUuid string `json:"identityUuid"`
	Key          string `json:"key"`
	Value        any    `json:"value"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandSetAttribute(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandSetAttribute) ([]comby.Event, error)

IdentityCommandUpdate

Domain Command Struct:

go
type IdentityCommandUpdate struct {
	IdentityUuid  string   `json:"identityUuid"`
	Attributes    string   `json:"attributes,omitempty"`
	PatchedFields []string `json:"patchedFields"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandUpdate(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandUpdate) ([]comby.Event, error)

IdentityCommandUpdateProfile

Domain Command Struct:

go
type IdentityCommandUpdateProfile struct {
	IdentityUuid  string   `json:"identityUuid"`
	Name          string   `json:"name,omitempty"`
	Email         string   `json:"email,omitempty"`
	Title         string   `json:"title,omitempty"`
	Avatar        string   `json:"avatar,omitempty"`
	PatchedFields []string `json:"patchedFields" doc:"list of fields that should be patched - comma separated" example:"field1,field2"`
}

Domain Command Handling Method:

go
func (cs *commandHandler) IdentityCommandUpdateProfile(ctx context.Context, cmd comby.Command, domainCmd *IdentityCommandUpdateProfile) ([]comby.Event, error)

Queries

Domain Query Structs:

Domain Query Responses:

IdentityQueryListByAccountUuid

Domain Query Struct:

go
type IdentityQueryListByAccountUuid struct {
	AccountUuid string `json:"accountUuid"`
	Page        int64  `json:"page,omitempty"`
	PageSize    int64  `json:"pageSize,omitempty"`
	OrderBy     string `json:"orderBy,omitempty"`
}

Domain Query Handling Method:

go
func (qs *queryHandler) IdentityQueryListByAccountUuid(ctx context.Context, qry comby.Query, domainQry *IdentityQueryListByAccountUuid) (*IdentityQueryListResponse, error)

IdentityQueryListByAccountTenantUuid

Domain Query Struct:

go
type IdentityQueryListByAccountTenantUuid struct {
	TenantUuid  string `json:"tenantUuid"`
	AccountUuid string `json:"accountUuid"`
	Page        int64  `json:"page,omitempty"`
	PageSize    int64  `json:"pageSize,omitempty"`
	OrderBy     string `json:"orderBy,omitempty"`
}

Domain Query Handling Method:

go
func (qs *queryHandler) IdentityQueryListByAccountTenantUuid(ctx context.Context, qry comby.Query, domainQry *IdentityQueryListByAccountTenantUuid) (*IdentityQueryListResponse, error)

IdentityQueryList

Domain Query Struct:

go
type IdentityQueryList struct {
	TenantUuid     string `json:"tenantUuid"`
	Page           int64  `json:"page,omitempty"`
	PageSize       int64  `json:"pageSize,omitempty"`
	OrderBy        string `json:"orderBy,omitempty"`
	Attributes     string `json:"attributes,omitempty"`
	IncludeHistory bool   `json:"includeHistory,omitempty"`
}

Domain Query Handling Method:

go
func (qs *queryHandler) IdentityQueryList(ctx context.Context, qry comby.Query, domainQry *IdentityQueryList) (*IdentityQueryListResponse, error)

IdentityQueryModel

Domain Query Struct:

go
type IdentityQueryModel struct {
	IdentityUuid   string `json:"identityUuid"`
	IncludeHistory bool   `json:"includeHistory,omitempty"`
}

Domain Query Handling Method:

go
func (qs *queryHandler) IdentityQueryModel(ctx context.Context, qry comby.Query, domainQry *IdentityQueryModel) (*IdentityQueryItemResponse, error)

IdentityQueryListResponse

go
type IdentityQueryListResponse struct {
	Items    []*readmodel.IdentityModel `json:"items,omitempty"`
	Total    int64                      `json:"total,omitempty"`
	Page     int64                      `json:"page,omitempty"`
	PageSize int64                      `json:"pageSize,omitempty"`
}

IdentityQueryItemResponse

go
type IdentityQueryItemResponse struct {
	Item *readmodel.IdentityModel `json:"item,omitempty"`
}

Events

IdentityAddedGroupEvent

Domain Event Struct:

go
type IdentityAddedGroupEvent struct {
	GroupUuid string `json:"groupUuid"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityAddedGroupEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityAddedGroupEvent) (error)

IdentityAddedTokenEvent

Domain Event Struct:

go
type IdentityAddedTokenEvent struct {
	TokenUuid   string `json:"tokenUuid"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	TokenValue  string `json:"tokenValue"`
	ExpiredAt   int64  `json:"expiredAt,omitempty"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityAddedTokenEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityAddedTokenEvent) (error)

IdentityCreatedEvent

Domain Event Struct:

go
type IdentityCreatedEvent struct {
	AccountUuid string `json:"accountUuid,omitempty"`
	Attributes  string `json:"attributes,omitempty"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityCreatedEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityCreatedEvent) (error)

IdentityRemovedEvent

Domain Event Struct:

go
type IdentityRemovedEvent struct {
	Reason string `json:"reason,omitempty"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityRemovedEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityRemovedEvent) (error)

IdentityAttributeRemovedEvent

Domain Event Struct:

go
type IdentityAttributeRemovedEvent struct {
	Key string `json:"key"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityAttributeRemovedEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityAttributeRemovedEvent) (error)

IdentityRemovedGroupEvent

Domain Event Struct:

go
type IdentityRemovedGroupEvent struct {
	GroupUuid string `json:"groupUuid"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityRemovedGroupEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityRemovedGroupEvent) (error)

IdentityRemovedTokenEvent

Domain Event Struct:

go
type IdentityRemovedTokenEvent struct {
	TokenUuid string `json:"tokenUuid"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityRemovedTokenEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityRemovedTokenEvent) (error)

IdentityAttributeSetEvent

Domain Event Struct:

go
type IdentityAttributeSetEvent struct {
	Key   string `json:"key"`
	Value any    `json:"value"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityAttributesSetEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityAttributeSetEvent) (error)

IdentityUpdatedEvent

Domain Event Struct:

go
type IdentityUpdatedEvent struct {
	Attributes string `json:"attributes,omitempty"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityUpdatedEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityUpdatedEvent) (error)

IdentityProfileUpdatedEvent

Domain Event Struct:

go
type IdentityProfileUpdatedEvent struct {
	Name   string `json:"name,omitempty"`
	Email  string `json:"email,omitempty"`
	Title  string `json:"title,omitempty"`
	Avatar string `json:"avatar,omitempty"`
}

Domain Event Handling Method:

go
func (agg *Identity) IdentityProfileUpdatedEvent(ctx context.Context, evt comby.Event, domainEvt *IdentityProfileUpdatedEvent) (error)

Aggregate

Aggregate Struct:

go
type Identity struct {
	*comby.BaseAggregate
	// References
	AccountUuid string
	GroupUuids  []string
	// Entities
	Profile *Profile
	Tokens  []*Token
}

Methods

AddGroup

go
func (agg *Identity) AddGroup(opts ) (error)

AddToken

go
func (agg *Identity) AddToken(opts ) (error)

Add

go
func (agg *Identity) Add(opts ) (error)

Remove

go
func (agg *Identity) Remove(opts ) (error)

RemoveAttribute

go
func (agg *Identity) RemoveAttribute(opts ) (error)

RemoveGroup

go
func (agg *Identity) RemoveGroup(opts ) (error)

RemoveToken

go
func (agg *Identity) RemoveToken(opts ) (error)

SetAttribute

go
func (agg *Identity) SetAttribute(opts ) (error)

Update

go
func (agg *Identity) Update(opts ) (error)

UpdateProfile

go
func (agg *Identity) UpdateProfile(opts ) (error)

Event Handlers

IdentityReadmodel

Domain EventMethod
tenantAggregate.TenantCreatedEventTenantCreatedEvent
tenantAggregate.TenantAttributeRemovedEventTenantAttributeRemovedEvent
tenantAggregate.TenantAttributeSetEventTenantAttributeSetEvent
tenantAggregate.TenantUpdatedEventTenantUpdatedEvent
tenantAggregate.TenantRemovedEventTenantRemovedEvent
identityAggregate.IdentityAttributeRemovedEventIdentityAttributeRemovedEvent
identityAggregate.IdentityRemovedTokenEventIdentityRemovedTokenEvent
identityAggregate.IdentityUpdatedEventIdentityUpdatedEvent
identityAggregate.IdentityRemovedEventIdentityRemovedEvent
identityAggregate.IdentityAddedGroupEventIdentityAddedGroupEvent
identityAggregate.IdentityRemovedGroupEventIdentityRemovedGroupEvent
identityAggregate.IdentityAddedTokenEventIdentityAddedTokenEvent
identityAggregate.IdentityCreatedEventIdentityCreatedEvent
identityAggregate.IdentityProfileUpdatedEventIdentityProfileUpdatedEvent
identityAggregate.IdentityAttributeSetEventIdentityAttributeSetEvent
groupAggregate.GroupUpdatedEventGroupUpdatedEvent
groupAggregate.GroupRemovedEventGroupRemovedEvent
groupAggregate.GroupAddedEventGroupAddedEvent
assetAggregate.AssetAddedEventAssetAddedEvent
assetAggregate.AssetRemovedEventAssetRemovedEvent
assetAggregate.AssetUpdatedEventAssetUpdatedEvent

Custom Permissions

NameTypeComment
IdentityCommandAddTokenCommandAdd token for any other identity
IdentityCommandRemoveTokenCommandRemove token of any other identity
IdentityCommandUpdateProfileCommandUpdate profile of any other identity
IdentityCommandSetAttributeCommandSet attributes of any other identity
IdentityQueryModelQueryGet identity model of any identity