Contexto Acotado: Approvals
Raíz del Agregado: Sí
Módulo: Ums.Domain.Approvals.AccessEnforcementPolicy
Estado: Producción
El agregado raíz AccessEnforcementPolicy establece reglas generales de restricción de acceso a nivel de inquilino (tenant). Determina qué privilegios de acceso (como un perfil o mapeo de rol) se bloquean, degradan o restringen cuando un usuario entra en estado de incumplimiento (por ejemplo, falta de credenciales válidas obligatorias o documentos críticos vencidos).
AccessEnforcementPolicy actúa como una raíz de agregado independiente de DocumentType para separar las definiciones de credenciales de las reglas de reacción de seguridad.
ProfileId o a un RoleId (o a ambos). Está prohibido crear una política sin especificar al menos un objetivo (DomainErrors.Approvals.PolicyRequiresProfileOrRole).DomainErrors.Approvals.PolicyAlreadyInactive).TenantId para garantizar la seguridad de la partición de inquilinos.| Entidad / VO | Tipo | Descripción |
|—|—|—|
| AccessEnforcementPolicyId | Objeto de Valor | Identificador único del agregado |
| TenantId | Objeto de Valor | Identificador del inquilino propietario |
| ProfileId | Objeto de Valor | Perfil de autorización de destino (opcional) |
| RoleId | Objeto de Valor | Rol de autorización de destino (opcional) |
| AccessEnforcementAction | Enumerado/VO | BLOCK_ACCESS · DEGRADE_ROLE · RESTRICT_API |
| AuditValueObject | Objeto de Valor | Historial de auditoría multiusuario |
AccessEnforcementPolicy (Aggregate Root)
└── Props: AccessEnforcementPolicyProps
├── Id: AccessEnforcementPolicyId
├── TenantId: TenantId
├── ProfileId: ProfileId?
├── RoleId: RoleId?
├── EnforcementAction: AccessEnforcementAction
├── IsActive: bool
└── Audit: AuditValueObject
classDiagram
direction TB
class AccessEnforcementPolicy {
+AccessEnforcementPolicyProps Props
+Create(TenantId, ProfileId?, RoleId?, AccessEnforcementAction, ActorId) Result~AccessEnforcementPolicy~
+Deactivate(ActorId) Result
+UpdateAction(AccessEnforcementAction, ActorId) Result
}
class AccessEnforcementPolicyProps {
+IdValueObject Id
+TenantId TenantId
+ProfileId ProfileId
+RoleId RoleId
+AccessEnforcementAction EnforcementAction
+bool IsActive
+AuditValueObject Audit
}
class AccessEnforcementAction {
<<enumeration>>
BLOCK_ACCESS
DEGRADE_ROLE
RESTRICT_API
}
AccessEnforcementPolicy *-- AccessEnforcementPolicyProps
AccessEnforcementPolicyProps --> AccessEnforcementAction
sequenceDiagram
autonumber
actor Admin as Administrador del Inquilino
participant Portal as Cliente Web
participant App as Servicio de Aplicación
participant Policy as AccessEnforcementPolicy [Agregado]
participant Repo as AccessEnforcementPolicyRepository
participant DB as SQL Server
Admin->>Portal: Configura nueva regla de aplicación
Portal->>App: CreateAccessEnforcementPolicyCommand(ProfileId, Action)
App->>Policy: Create(TenantId, ProfileId, null, Action, AdminId)
note over Policy: Validar INV-AEP1<br/>(Se debe definir ProfileId o RoleId)
Policy-->>App: AccessEnforcementPolicy [Éxito]
App->>Repo: SaveAsync(Policy)
Repo->>DB: INSERT INTO ACCESS_ENFORCEMENT_POLICY
DB-->>Repo: Acknowledge
Repo-->>App: Done
App-->>Portal: CreateAccessEnforcementPolicyResponse(Éxito)
erDiagram
ACCESS_ENFORCEMENT_POLICY {
uniqueidentifier PolicyId PK
uniqueidentifier TenantId FK "Contexto de Configuración"
uniqueidentifier ProfileId FK "Contexto de Autorización"
uniqueidentifier RoleId FK "Contexto de Autorización"
nvarchar EnforcementAction
bit IsActive
nvarchar CreatedBy
datetime2 CreatedAt
nvarchar UpdatedBy
datetime2 UpdatedAt
}
TenantId. Los filtros de inquilino deben aplicarse a todas las lecturas y escrituras para garantizar las fronteras operativas.flowchart TD
subgraph ConfigContext [Contexto de Configuración]
T[Tenant]
end
subgraph AuthContext [Contexto de Autorización]
P[Profile]
R[Role]
end
subgraph ApprovalsContext [Contexto de Approvals]
AEP[AccessEnforcementPolicy]
end
AEP -->|restringe| T
AEP -.->|hace referencia a| P
AEP -.->|hace referencia a| R
public class AccessEnforcementPolicyConfiguration : IEntityTypeConfiguration<AccessEnforcementPolicy>
{
public void Configure(EntityTypeBuilder<AccessEnforcementPolicy> builder)
{
builder.ToTable("ACCESS_ENFORCEMENT_POLICY");
builder.HasKey(e => e.Id);
builder.OwnsOne(e => e.Props, props =>
{
props.Property(p => p.Id).HasColumnName("PolicyId");
props.Property(p => p.TenantId).HasColumnName("TenantId");
props.Property(p => p.ProfileId).HasColumnName("ProfileId");
props.Property(p => p.RoleId).HasColumnName("RoleId");
props.Property(p => p.EnforcementAction).HasConversion<string>().HasColumnName("EnforcementAction");
props.Property(p => p.IsActive).HasColumnName("IsActive");
props.OwnsOne(p => p.Audit);
});
}
}