Bounded Context: Identity
Aggregate Root: Tenant
Module: Ums.Domain.Identity.Tenant
Status: Production
The Tenant aggregate represents the top-level organizational unit in the UMS multi-tenant model. Every resource in the system is scoped to a Tenant. It governs onboarding, lifecycle status, hierarchical structure (parent/child tenants), the strategy used to authenticate its users (local, federated, or hybrid), and whether it is the management owner for its own internal UMS portal scope. It also fully owns and manages Branch, Branding, and IdentityProvider configurations.
Branch, Branding, IdentityProvider — all owned by and accessed through the Tenant aggregate root.The internal UMS portal uses its own authorization path for tenant administrators. This path is separate from the external API authentication flow and is governed by tenant scope, roles, permissions, and IsManagementOwner.
This boundary is formalized in ADR-0077.
| Scenario | Rule |
|---|---|
| Tenant admin opens the UMS portal | Allowed only if the user belongs to the tenant and has the required role/permission set |
| Tenant admin changes data inside their own tenant | Allowed only within the tenant scope and only when IsManagementOwner = true |
| Tenant admin changes another tenant’s data | Rejected regardless of portal access |
| External API client authenticates | Uses the tenant IDP resolution flow and the auth graph |
| Audit trail | Every internal tenant mutation must be recorded |
Tenant is the aggregate root. All operations on Branch, Branding, and IdentityProvider must go through Tenant commands. No external aggregate should hold a direct reference to Branch — only a BranchId value object.
Code must be unique across the platform.Branding record (1:1 relationship).IdpStrategy must be consistent with the registered IdentityProvider records (e.g., FEDERATED requires at least one active IdentityProvider).ParentTenantId IS NOT NULL) inherits the top-level Tenant’s compliance policies.Status transitions follow: Active → Suspended → Active or Active → Inactive (terminal).Code must be unique within the owning Tenant.Branch cannot be removed if active UserAccount or Profile records are scoped to it.GeofencingMetadata must be valid JSON when provided.CustomDomain must be a valid hostname when provided.DnsVerificationStatus starts as PENDING when CustomDomain is set and cannot be manually set to VERIFIED — only the DNS verification service may do so.LogoFormat must match the actual format of the uploaded Logo URI.Code must be unique within the owning Tenant.IdentityProvider must be deactivated before it can be removed.IdentityProvider that is the sole active IdP for a Federated tenant is not allowed unless the tenant’s IdpStrategy is changed first.Strategy cannot be changed after registration — it is immutable once set.IsManagementOwner identifies tenants that can manage their own internal UMS scope without depending on the external API IDP flow.| Entity / VO | Type | Ownership |
|—|—|—|
| Branch | Entity | Owned — child of Tenant |
| Branding | Entity | Owned — child of Tenant (1:1) |
| IdentityProvider | Entity | Owned — child of Tenant |
| Code | Value Object | Identifier code |
| Name | Value Object | Display name |
| OrganizationType | Enum | ENTERPRISE · SMB · GOVERNMENT · PARTNER |
| IdpStrategy | Enum | LOCAL · FEDERATED · HYBRID |
| TenantStatus | Enum | Active · Suspended · Inactive |
| IsManagementOwner | Flag | Identifies the tenant responsible for internal UMS management access |
| Logo | Value Object | URI storage path |
| LogoFormat | Enum | PNG · SVG · JPEG |
| HexColor | Value Object | Validated hex color |
| BackgroundStyle | Enum | Glassmorphism · SleekDark |
| CustomDomain | Value Object | Nullable hostname |
| DnsVerificationStatus | Enum | Pending · Verified · Failed |
| AuditValueObject | Value Object | CreatedAt/By, UpdatedAt/By |
| Event | Trigger |
|—|—|
| TenantCreatedEvent | New tenant registered |
| TenantSuspendedEvent | Tenant moved to Suspended status |
| TenantActivatedEvent | Tenant re-activated from Suspended |
| BranchCreatedEvent | A new Branch added to the Tenant |
| BranchDeactivatedEvent | A Branch deactivated |
| BranchReactivatedEvent | A Branch reactivated |
| BranchRemovedEvent | A Branch hard-removed |
| BrandingCreatedEvent | Branding configured for the first time |
| BrandingUpdatedEvent | Branding attributes updated |
| BrandingRemovedEvent | Branding configuration removed |
| BrandingDnsVerifiedEvent | Custom domain DNS verified successfully |
| BrandingDnsFailedEvent | DNS verification failed |
| IdentityProviderRegisteredEvent | New IdP registered |
| IdentityProviderActivatedEvent | IdP activated |
| IdentityProviderDeactivatedEvent | IdP deactivated |
| IdentityProviderRemovedEvent | IdP removed |
| Command | Description |
|—|—|
| RegisterTenantCommand | Onboard a new organization onto the platform |
| SuspendTenantCommand | Suspend a tenant (blocks all user auth) |
| ActivateTenantCommand | Reactivate a suspended tenant |
| AddBranchCommand | Create a new branch within the tenant |
| UpdateBranchCommand | Update name or geofencing metadata of a branch |
| DeactivateBranchCommand | Deactivate an existing branch |
| ReactivateBranchCommand | Reactivate a branch |
| RemoveBranchCommand | Remove a branch |
| ConfigureBrandingCommand | Set the tenant’s visual identity |
| UpdateBrandingCommand | Update branding attributes |
| SetCustomDomainCommand | Add or replace the custom domain |
| RemoveBrandingCommand | Remove the branding configuration |
| MarkDnsVerifiedCommand | Internal — called by DNS verification service |
| MarkDnsFailedCommand | Internal — called by DNS verification service |
| RegisterIdentityProviderCommand | Register an external IdP |
| ActivateIdentityProviderCommand | Activate a registered IdP |
| DeactivateIdentityProviderCommand | Deactivate an IdP |
| RemoveIdentityProviderCommand | Hard-remove an inactive IdP |
ITenantRepository — persists the Tenant aggregate including owned children.IIdpStrategyValidationService / IIdpStrategyConsistencyService — domain service that validates IdpStrategy consistency when IdP records are added/removed.IBranchDependencyChecker — domain service that verifies no UserAccount or Profile depends on the branch before removal.IDnsVerificationService — infrastructure service that performs CNAME lookups.Tenant (Aggregate Root)
├── Props: TenantProps
│ ├── Id: IdValueObject
│ ├── Code: Code
│ ├── Name: Name
│ ├── Type: OrganizationType
│ ├── IdpStrategy: IdpStrategy
│ ├── IsManagementOwner: bool
│ ├── CompanyReference?: CompanyReference
│ ├── ParentTenantId?: TenantId
│ ├── Status: TenantStatus
│ └── Audit: AuditValueObject
├── Children
│ ├── IReadOnlyList<Branch>
│ │ └── Props: BranchProps (Id, TenantId, Code, Name, GeofencingMetadata?, IsActive)
│ ├── Branding? (0..1)
│ │ └── Props: BrandingProps (Id, TenantId, Logo, LogoFormat, PrimaryColor, BackgroundStyle, Texts, CustomDomain?, DnsVerificationStatus, DnsCnameTarget, MagicLinkFallbackEnabled)
│ └── IReadOnlyList<IdentityProvider>
│ └── Props: IdentityProviderProps (Id, TenantId, Code, Name, Description, Strategy, IsActive)
└── DomainEvents: TenantDomainEventsManager
| Attribute | Entity | Type | Notes |
|—|—|—|—|
| Id | Tenant | Guid | PK, generated on creation |
| Code | Tenant | string | Unique tenant identifier code |
| Name | Tenant | string | Display name |
| Type | Tenant | OrganizationType | Organization classification |
| IdpStrategy | Tenant | IdpStrategy | Authentication strategy |
| Status | Tenant | TenantStatus | Active / Suspended / Inactive |
| IsManagementOwner | Tenant | bool | Internal management access flag |
| Code | Branch | string | Unique per tenant |
| Name | Branch | string | Display name |
| GeofencingMetadata | Branch | string? | JSON polygon/coordinates |
| IsActive | Branch | bool | Soft activation flag |
| Logo | Branding | string | URI to uploaded logo |
| LogoFormat | Branding | LogoFormat | PNG / SVG / JPEG |
| PrimaryColor | Branding | string | Hex color |
| CustomDomain | Branding | string? | Optional FQDN |
| DnsVerificationStatus | Branding| Enum | Pending / Verified / Failed |
| Code | IdentityProvider | string | Unique within tenant |
| Strategy | IdentityProvider | IdpStrategy| OIDC / SAML2 / WS_FED — immutable |
| IsActive | IdentityProvider | bool | Routing availability |
(Consolidated view covering core flows)
sequenceDiagram
participant C as Client
participant H as RegisterTenantHandler
participant R as ITenantRepository
participant T as Tenant (AR)
C->>H: RegisterTenantCommand(...)
H->>R: ExistsByCode(code)
R-->>H: false
H->>T: Tenant.Create(...)
T->>T: Raise TenantCreatedEvent
H->>R: Add(tenant)
H-->>C: TenantId
sequenceDiagram
participant C as Client
participant H as AddBranchHandler
participant R as ITenantRepository
participant T as Tenant (AR)
C->>H: AddBranchCommand(tenantId, code, name, geofencing?)
H->>R: GetById(tenantId)
R-->>H: Tenant
H->>T: tenant.AddBranch(branchId, code, name, geofencing, createdBy)
T->>T: Guard: code unique within tenant
T->>T: Raise BranchCreatedEvent
H->>R: Update(tenant)
H-->>C: BranchId
sequenceDiagram
participant C as Client
participant H as ConfigureBrandingHandler
participant R as ITenantRepository
participant T as Tenant (AR)
participant DNS as IDnsVerificationService
C->>H: ConfigureBrandingCommand(tenantId, logo, ...)
H->>R: GetById(tenantId)
R-->>H: Tenant
H->>T: tenant.ConfigureBranding(...)
T->>T: Guard: no existing Branding
T->>T: Raise BrandingCreatedEvent
H->>R: Update(tenant)
alt customDomain provided
H->>DNS: ScheduleVerification(tenantId, cnameTarget)
end
H-->>C: BrandingId
sequenceDiagram
participant C as Client
participant H as RegisterIdpHandler
participant R as ITenantRepository
participant T as Tenant (AR)
C->>H: RegisterIdentityProviderCommand(tenantId, code, name, description, strategy, createdBy)
H->>R: GetById(tenantId)
R-->>H: Tenant
H->>T: tenant.RegisterIdentityProvider(...)
T->>T: Guard: code unique within tenant
T->>T: Raise IdentityProviderRegisteredEvent
H->>R: Update(tenant)
H-->>C: IdpId
erDiagram
TENANT ||--o{ BRANCH : "operates"
TENANT ||--o| BRANDING : "configures"
TENANT ||--o{ IDENTITY_PROVIDER : "registers"
TENANT }o--o| TENANT : "parent_of"
TENANT {
uniqueidentifier TenantId PK
nvarchar Code "Unique platform-wide"
nvarchar Name
nvarchar Type "ENTERPRISE-SMB-GOVERNMENT-PARTNER"
nvarchar IdpStrategy "LOCAL-FEDERATED-HYBRID"
nvarchar CompanyReference "Nullable"
uniqueidentifier ParentTenantId FK "Nullable Self-Ref"
nvarchar Status "ACTIVE-SUSPENDED-INACTIVE"
datetime2 CreatedAt
uniqueidentifier CreatedBy
datetime2 UpdatedAt
uniqueidentifier UpdatedBy
}
BRANCH {
uniqueidentifier BranchId PK
uniqueidentifier TenantId FK
nvarchar Code "Unique per TenantId"
nvarchar Name
nvarchar GeofencingMetadata "Nullable JSON"
bit IsActive
datetime2 CreatedAt
uniqueidentifier CreatedBy
datetime2 UpdatedAt
uniqueidentifier UpdatedBy
}
BRANDING {
uniqueidentifier BrandingId PK
uniqueidentifier TenantId FK "Unique - One-to-One"
nvarchar Logo "URI Storage Path"
nvarchar LogoFormat "PNG-SVG-JPEG"
nvarchar PrimaryColor "Hex Color"
nvarchar BackgroundStyle "Glassmorphism-SleekDark"
nvarchar HeadlineText
nvarchar SecondaryText
nvarchar PrimaryButtonLabel
nvarchar FooterText
nvarchar CustomDomain "Nullable FQDN"
nvarchar DnsVerificationStatus "PENDING-VERIFIED-FAILED"
nvarchar DnsCnameTarget "Platform CNAME"
bit MagicLinkFallbackEnabled
datetime2 CreatedAt
uniqueidentifier CreatedBy
datetime2 UpdatedAt
uniqueidentifier UpdatedBy
}
IDENTITY_PROVIDER {
uniqueidentifier IdpId PK
uniqueidentifier TenantId FK
nvarchar Code "Unique per TenantId"
nvarchar Name
nvarchar Description
nvarchar Strategy "OIDC-SAML2-WS_FED"
bit IsActive
datetime2 CreatedAt
uniqueidentifier CreatedBy
datetime2 UpdatedAt
uniqueidentifier UpdatedBy
}
flowchart TD
subgraph Identity["Identity BC"]
T[Tenant AR]
B[Branch]
BR[Branding]
IP[IdentityProvider]
T --> B
T --> BR
T --> IP
end
subgraph Authorization["Authorization BC"]
SS[SystemSuite]
ROLE[Role]
PROF[Profile]
end
subgraph Configuration["Configuration BC"]
IDPC[IdpConfiguration]
AC[AppConfiguration]
end
subgraph Infrastructure["Infrastructure"]
DNS[DNS Verification Service]
STORE[File Storage - Logo URI]
end
T -->|TenantId scopes| SS
T -->|TenantId scopes| ROLE
T -->|TenantCreatedEvent| IDPC
T -->|TenantCreatedEvent| AC
B -->|BranchId optional scope| PROF
IP -->|IdentityProviderRegisteredEvent| IDPC
DNS -->|MarkDnsVerifiedCommand| BR
STORE -->|Logo URI stored| BR
(Includes consolidated commands and queries for Tenant, Branch, Branding, and IdP).
| Command | Output |
|—|—|
| RegisterTenantCommand | Guid tenantId |
| SuspendTenantCommand | void |
| ActivateTenantCommand | void |
| AddBranchCommand | Guid branchId |
| UpdateBranchCommand | void |
| DeactivateBranchCommand | void |
| ReactivateBranchCommand | void |
| RemoveBranchCommand | void |
| ConfigureBrandingCommand | Guid brandingId |
| UpdateBrandingCommand | void |
| SetCustomDomainCommand | void |
| RemoveBrandingCommand | void |
| RegisterIdentityProviderCommand | Guid idpId |
| ActivateIdentityProviderCommand | void |
| DeactivateIdentityProviderCommand | void |
| RemoveIdentityProviderCommand | void |
| Query | Returns |
|—|—|
| GetTenantByIdQuery | TenantDetailDto |
| ListTenantsQuery | PagedList<TenantSummaryDto> |
| GetTenantBranchesQuery | List<BranchDto> |
| GetBranchByIdQuery | BranchDto? |
| GetTenantBrandingQuery | BrandingDto? |
| GetBrandingByDomainQuery | BrandingDto? |
| GetTenantIdentityProvidersQuery | List<IdentityProviderDto> |
The entire Tenant aggregate (including Branch, Branding, IdentityProvider) is persisted within a single EF Core DbContext.SaveChanges() call. No partial saves across owned entities.
| Index | Columns | Type |
|—|—|—|
| IX_Tenant_Code | Code | Unique |
| IX_Branch_TenantId_Code | TenantId, Code | Unique |
| IX_Branding_TenantId | TenantId | Unique |
| IX_Branding_CustomDomain | CustomDomain | Unique (partial — not null) |
| IX_IdentityProvider_TenantId_Code | TenantId, Code | Unique |
Tenant itself is the isolation boundary.BRANCH, BRANDING, IDENTITY_PROVIDER) are filtered by TenantId.CustomDomain is a cross-tenant unique key.| Operation | Required Role / Policy |
|—|—|
| Register / Suspend / Activate Tenant | Platform:Admin |
| Add / Update / Remove Branch | Tenant:Admin (own tenant only) |
| Configure / Update Branding | Tenant:Admin |
| Set Custom Domain | Tenant:Admin |
| Register / Activate / Deactivate IdP | Tenant:Admin |
All state-changing commands produce immutable AuditRecord entries:
TENANT_REGISTERED, TENANT_SUSPENDED, TENANT_ACTIVATEDBRANCH_CREATED, BRANCH_DEACTIVATED, BRANCH_REACTIVATED, BRANCH_REMOVEDBRANDING_CONFIGURED, BRANDING_UPDATED, BRANDING_REMOVED, DNS_VERIFIED, DNS_FAILEDIDP_REGISTERED, IDP_ACTIVATED, IDP_DEACTIVATED, IDP_REMOVEDThe UMS supports a special tenant called INTERNAL_ADMIN (ID: 11111111-1111-1111-1111-111111111111) that is reserved for internal platform administrators. Users belonging to this tenant have elevated privileges that allow them to:
| Mode | Description | Isolation |
|---|---|---|
| Tenant Access (Regular) | Users can only access data within their own tenant | Full tenant isolation via query filters |
| Internal Admin Access | Users in INTERNAL_ADMIN tenant can access multiple tenants |
Cross-tenant access via ITenantContext.EnableCrossTenantAccess() |
INTERNAL_ADMIN tenant code, the system sets isInternalAdmin=true in the JWT claimsis_internal_admin claim is added to the tokenITenantContext.Initialize() is called with isInternalAdmin=truePOST /api/v1/auth/switch-tenant to:
{ "tenantId": "...", "enableCrossTenantAccess": false }{ "tenantId": "...", "enableCrossTenantAccess": true }public interface ITenantContext
{
Guid? OrganizationId { get; }
Guid? OriginalTenantId { get; }
bool IsInternalAdmin { get; }
void Initialize(Guid userTenantId, bool isInternalAdmin);
void EnableCrossTenantAccess(); // Sets OrganizationId = null (bypasses filters)
void DisableCrossTenantAccess(); // Resets to user's original tenant
void SetOrganizationId(Guid organizationId);
}
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/login |
Returns isInternalAdmin flag in response |
| POST | /api/v1/auth/switch-tenant |
Switch tenant context (admins only) |
| GET | /api/v1/auth/session |
Returns current session with admin flag |
OrganizationId — enforced in TenantContext.SetOrganizationId()INTERNAL_ADMIN tenant can call switch-tenant endpointAuditRecord entriesOrganizationId is null (shows all tenants to admins)GraphQL Query (Recommended)
The GraphQL endpoint tenantBranches(tenantId: UUID!) is the recommended way to access branch data for any tenant. Internal admins can query branches for any tenant by passing the tenantId parameter directly. This approach works correctly without requiring tenant context switching.
REST Endpoint /api/v1/auth/switch-tenant
Authentication:Enabled may be falseITenantContext from JWT claims after validationis_internal_admin=true claimEF Core Query Splitting (SQLite)
EF Core 7+ defaults to split query mode when multiple Include() statements are used. This causes SQLite Error: 'near "EXEC": syntax error' because split queries use EXEC statements not supported by SQLite. Use .AsSingleQuery() to force single-query mode:
var record = await dbContext.Tenants
.AsSingleQuery() // Forces single query instead of split
.Include(x => x.Branches)
.Include(x => x.IdentityProviders)
.Include(x => x.Branding)
.FirstOrDefaultAsync(x => x.Id == id);
| Component | Status | Notes |
|---|---|---|
Login with INTERNAL_ADMIN |
Working | Returns isInternalAdmin: true in response |
GraphQL tenantBranches query |
Working | Admin can query any tenant’s branches |
REST switch-tenant endpoint |
Working (with fix) | JWT validated directly, TenantContext initialized manually |
GraphQL getTenants query |
Not available | Use REST endpoint or alternate query |
| Branch CRUD via GraphQL | Working | Single query mode prevents SQLite issues |
Administrators with appropriate permissions can reset user passwords and modify user account validity periods. The scope of these operations is determined by the administrator’s type and tenant association.
| Admin Type | Tenant Association | Operational Scope |
|---|---|---|
| Internal Platform Admin | Belongs to INTERNAL_ADMIN tenant |
Can operate on users in any tenant |
| Tenant Admin | Belongs to a specific tenant | Can operate on users in their own tenant only |
CAN_RESET_PASSWORD permission assigned to their roleCAN_MODIFY_VALIDITY_PERIOD permission assigned to their roleCAN_RESET_PASSWORD and/or CAN_MODIFY_VALIDITY_PERIOD)targetUser.TenantId == OrganizationId)AUTH_010 errorThese capabilities are controlled by feature flags (configurable at system or tenant level):
| Feature Flag | Description | Default |
|---|---|---|
ALLOW_PASSWORD_RESET_BY_ADMIN |
Enables password reset by admin | true |
ALLOW_VALIDITY_PERIOD_MODIFICATION |
Enables validity period modification | true |
Every password reset and validity period modification MUST generate an audit record with:
| Field | Description |
|---|---|
adminUserId |
ID of the administrator who performed the action |
targetUserId |
ID of the user affected by the action |
targetTenantId |
Tenant ID of the affected user |
timestamp |
Date and time of the action (UTC) |
operationType |
PASSWORD_RESET or VALIDITY_PERIOD_MODIFIED |
previousExpiresAt |
Previous validity expiration (for validity changes) |
newExpiresAt |
New validity expiration (for validity changes) |
reason |
Administrator-provided reason for the action |
| Method | Endpoint | Description | Scope |
|---|---|---|---|
| POST | /user-accounts/{userAccountId}/passwords/reset |
Reset password for target user | Based on admin type |
| PATCH | /user-accounts/{userAccountId}/validity |
Modify user validity period | Based on admin type |
| Code | Description |
|---|---|
AUTH_009 |
Administrator lacks required permission |
AUTH_010 |
Target user outside administrator’s scope |
USER_015 |
Federated user cannot have local password reset |
CONFIG_003 |
Requested validity period exceeds maximum allowed |
| Parameter | Config Location | Default | Description |
|---|---|---|---|
MAX_VALIDITY_PERIOD_DAYS |
AppConfiguration |
365 | Maximum allowed validity period |
MIN_PASSWORD_LENGTH |
AppConfiguration |
12 | Minimum password length requirement |
PASSWORD_RESET_NOTIFICATION_CHANNEL |
AppConfiguration |
Channel for notifying users |
UMS provides a centralized system parameter management capability through the AppConfiguration aggregate. Parameters can be scoped as Global (system-wide), Tenant (tenant-specific), Suite (system-suite-specific), or Module (module-specific).
| Scope | Description | Who Can Manage |
|---|---|---|
| Global | System-wide parameters with no tenant association | Internal admins only |
| Tenant | Tenant-specific parameters | Internal admins (any tenant), Tenant admins (own tenant only) |
| Suite | Parameters scoped to a specific system suite | Internal admins only |
| Module | Parameters scoped to a specific module | Internal admins only |
IsInternalAdmin=true can access global configurations403 Forbidden403 ForbiddenITenantContext.IsInternalAdmin determines if user has cross-tenant accessITenantContext.OrganizationId determines the user’s tenant scopeTenantId, SystemSuiteId, and ModuleId presencepublic class AppConfiguration : AggregateRoot<AppConfiguration, AppConfigurationProps>
{
public TenantId? TenantId { get; } // Null = global/system-wide
public SystemSuiteId? SystemSuiteId { get; } // Null if not suite-specific
public IdValueObject? ModuleId { get; } // Null if not module-specific
public Code Code { get; } // Unique parameter key
public ConfigurationValue Value { get; } // Parameter value
public Description Description { get; } // Human-readable description
public ConfigurationScope Scope { get; } // Auto-derived: Global/Tenant/Suite/Module
public bool IsInheritable { get; } // Can child configs override?
public bool IsEncrypted { get; } // Is value encrypted at rest?
public string Version { get; } // Semantic versioning
public ConfigStatus Status { get; } // Draft/Published/Archived
}
Draft → Published → Archived
↑
└── Can only be modified in Draft status
| Current Hardcode | Parameter Code | Default Value |
|---|---|---|
Frontend ACCESS_TOKEN_DURATION |
ACCESS_TOKEN_DURATION_MS |
3600000 (1 hour) |
Frontend REFRESH_TOKEN_DURATION |
REFRESH_TOKEN_DURATION_MS |
604800000 (7 days) |
MIN_PASSWORD_LENGTH constant |
MIN_PASSWORD_LENGTH |
12 |
MAX_VALIDITY_PERIOD_DAYS constant |
MAX_VALIDITY_PERIOD_DAYS |
365 |
| Method | Endpoint | Description | Authorization |
|---|---|---|---|
| GET | /app-configurations |
List configurations (filtered by scope and permissions) | Based on scope |
| GET | /app-configurations/{id} |
Get single configuration | Based on scope and ownership |
| POST | /app-configurations |
Create new configuration | Internal admin or tenant admin (own tenant) |
| PUT | /app-configurations/{id} |
Update draft configuration | Same as create |
| POST | /app-configurations/{id}/publish |
Publish configuration | Same as create |
| POST | /app-configurations/{id}/archive |
Archive configuration | Same as create |
| Event Type | Description |
|---|---|
APP_CONFIG_CREATED |
New configuration created |
APP_CONFIG_UPDATED |
Configuration value or description modified |
APP_CONFIG_PUBLISHED |
Configuration moved from Draft to Published |
APP_CONFIG_ARCHIVED |
Configuration archived |
| Flag | Description | Default |
|---|---|---|
ALLOW_GLOBAL_CONFIG_MANAGEMENT |
Enable global configuration management | true |
ALLOW_TENANT_CONFIG_MANAGEMENT |
Enable tenant configuration management | true |
IsInheritable=true can be overridden by child scopes