Contexto Delimitado: Autorización
Raíz de Agregado: Profile
Módulo: Ums.Domain.Authorization.Profile
Estado: Producción
El agregado Profile representa una asignación efectiva de autorización para un usuario dentro de un tenant. Vincula un UserId con un RoleId y opcionalmente con un BranchId, y luego materializa permisos efectivos a partir de definiciones publicadas de PermissionTemplate. Es el contenedor padre de las entidades propias ProfilePermission y la fuente operativa usada por los validadores de acceso aguas abajo.
ProfilePermission.Active / Inactive).Profile es la raíz del agregado. El enlace de plantillas, las anulaciones de permisos, la activación/desactivación de permisos y los cambios de estado del agregado deben pasar por Profile.
TenantId, UserId y RoleId son obligatorios para todo Profile.Scope se deriva de BranchId: sin sucursal es OrgWide; con sucursal es BranchScoped.Profile solo puede enlazar instancias de PermissionTemplate del mismo tenant.Profile solo puede enlazar plantillas que ya estén en estado Published.Profile no puede enlazar dos veces la misma plantilla.Profile padre esté activo.ProfilePermission se materializa por cada elemento de plantilla y conserva trazabilidad mediante TemplateId.| Entidad / VO | Tipo | Propiedad | Descripción |
|—|—|—|—|
| ProfilePermission | Entidad | Propia | Permiso efectivo materializado desde un elemento de plantilla |
| ProfileScope | Enumeración | - | OrgWide o BranchScoped |
| TenantId | Objeto de Valor | - | Límite de pertenencia del tenant |
| UserId | Objeto de Valor | - | Usuario que recibe el perfil efectivo |
| RoleId | Objeto de Valor | - | Fuente del rol para seleccionar plantillas |
| BranchId | Objeto de Valor | - | Segmentación opcional por sucursal |
| TemplateId | Objeto de Valor | - | Trazabilidad hacia la plantilla origen |
| Evento | Disparador |
|—|—|
| ProfileCreatedEvent | Nuevo perfil creado |
| TemplateLinkedToProfileEvent | Plantilla publicada enlazada y materializada en permisos |
| PermissionOverriddenEvent | Se aplica allow / deny / neutral / activate / deactivate sobre un permiso |
| ProfileDeactivatedEvent | Perfil desactivado |
| ProfileActivatedEvent | Perfil reactivado |
Profile (Raíz de Agregado)
├── Props: ProfileProps
│ ├── Id: IdValueObject
│ ├── TenantId: TenantId
│ ├── UserId: UserId
│ ├── RoleId: RoleId
│ ├── BranchId?: BranchId
│ ├── Scope: ProfileScope
│ ├── IsActive: bool
│ └── Audit: AuditValueObject
└── Hijos
└── IReadOnlyCollection<ProfilePermission>
└── Props: ProfilePermissionProps
├── Id: IdValueObject
├── ProfileId: ProfileId
├── TemplateId: TemplateId
├── TargetType: ExclusiveArcTarget
├── TargetId: IdValueObject
├── ActionId: ActionId
├── IsAllowed: bool
├── IsDenied: bool
├── IsActive: bool
├── IsOverride: bool
└── Audit: AuditValueObject
classDiagram
direction TB
class Profile {
+Guid Id
+Guid TenantId
+Guid UserId
+Guid RoleId
+Guid? BranchId
+ProfileScope Scope
+bool IsActive
+List~ProfilePermission~ Permissions
+Create(tenantId, userId, roleId, branchId, actor)
+AssignTemplate(template, actor)
+OverridePermissionAllow(permissionId, actor)
+OverridePermissionDeny(permissionId, actor)
+OverridePermissionNeutral(permissionId, actor)
+ActivatePermission(permissionId, actor)
+DeactivatePermission(permissionId, actor)
+Activate(actor)
+Deactivate(actor)
}
class ProfilePermission {
+Guid Id
+Guid ProfileId
+Guid TemplateId
+ExclusiveArcTarget TargetType
+Guid TargetId
+Guid ActionId
+bool IsAllowed
+bool IsDenied
+bool IsActive
+bool IsOverride
}
Profile "1" *-- "0..*" ProfilePermission
sequenceDiagram
participant C as Cliente
participant H as Handler
participant R as IProfileRepository
participant P as Profile (AR)
participant T as PermissionTemplate
C->>H: CreateProfileCommand(tenantId, userId, roleId, branchId)
H->>P: Profile.Create(tenantId, userId, roleId, branchId, actor)
P->>P: Derivar Scope desde BranchId
P->>P: Levantar ProfileCreatedEvent
H->>R: Add(profile)
R-->>H: ok
H->>T: Cargar plantilla publicada para tenant/rol
H->>P: profile.AssignTemplate(template, actor)
P->>P: Validar tenant y estado Published
P->>P: Materializar elementos ProfilePermission
P->>P: Levantar TemplateLinkedToProfileEvent
H->>R: Update(profile)
R-->>H: ok
H-->>C: ProfileId
sequenceDiagram
participant C as Cliente
participant H as Handler
participant R as IProfileRepository
participant P as Profile (AR)
C->>H: OverridePermissionAllow(profileId, permissionId)
H->>R: GetById(profileId)
R-->>H: Profile
H->>P: OverridePermissionAllow(permissionId, actor)
P->>P: Validar perfil activo
P->>P: Marcar permiso como override
P->>P: Levantar PermissionOverriddenEvent
H->>R: Update(profile)
R-->>H: ok
H-->>C: Success
erDiagram
PROFILE ||--o{ PROFILE_PERMISSION : "contiene"
TENANT ||--o{ PROFILE : "posee"
USER_ACCOUNT ||--o{ PROFILE : "recibe"
ROLE ||--o{ PROFILE : "origina"
BRANCH ||--o{ PROFILE : "delimita"
PERMISSION_TEMPLATE ||--o{ PROFILE_PERMISSION : "materializa"
ACTION ||--o{ PROFILE_PERMISSION : "ejecuta"
PROFILE {
uniqueidentifier Id PK
uniqueidentifier TenantId FK
uniqueidentifier UserId FK
uniqueidentifier RoleId FK
uniqueidentifier BranchId FK "Nullable"
int ScopeId "1=OrgWide, 2=BranchScoped"
bit IsActive
nvarchar CreatedBy
datetime2 CreatedAtUtc
nvarchar UpdatedBy "Nullable"
datetime2 UpdatedAtUtc "Nullable"
nvarchar AuditTimeSpan
}
PROFILE_PERMISSION {
uniqueidentifier Id PK
uniqueidentifier ProfileId FK
uniqueidentifier TemplateId FK
int TargetTypeId
uniqueidentifier TargetId
uniqueidentifier ActionId FK
bit IsAllowed
bit IsDenied
bit IsActive
bit IsOverride
nvarchar CreatedBy
datetime2 CreatedAtUtc
nvarchar UpdatedBy "Nullable"
datetime2 UpdatedAtUtc "Nullable"
nvarchar AuditTimeSpan
}
Profile siempre pertenece a un tenant en la implementación actual; TenantId es obligatorio.ScopeId = OrgWide, no con TenantId nulo.PROFILE_PERMISSION hereda el aislamiento desde su Profile padre.TenantId, UserId y BranchId del Contexto de Identidad.RoleId y definiciones publicadas de PermissionTemplate dentro del contexto de Autorización.ActionId y la topología objetivo desde SystemSuite.CreateProfileCommand -> Entradas: TenantId, UserId, RoleId, BranchId? -> Retorna: GuidProfile.[ums_authorization].[Profiles][ums_authorization].[ProfilePermissions]Profile: TenantId, UserId, (TenantId, UserId, RoleId, BranchId)ProfilePermission: ProfileId, (ProfileId, TemplateId, ActionId, TargetId)deny o neutral sin cambiar la plantilla fuente.Profile representa una asignación efectiva de autorización, no un catálogo de roles nombrados.Scope se persiste como identificador de enumeración (ScopeId) y se deriva desde BranchId al crear el agregado.TemplateId, habilitando reevaluación, auditoría y reconstrucción futura.IsOverride y toggles de estado en ProfilePermission, en lugar de mutar PermissionTemplate.