Phase 6.2 Stream A - LdapGroupRoleMapping entity + migration + CRUD service #84
Reference in New Issue
Block a user
Delete Branch "phase-6-2-stream-a-ldap-role-mapping"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Stream A.1-A.2 per phase-6-2-authorization-runtime.md. Seed migration (A.3) deferred until production LDAP DNs are finalised.
Summary
AdminRoleenum {ConfigViewer, ConfigEditor, FleetAdmin}.LdapGroupRoleMappingentity: Id, LdapGroup (512), Role, ClusterId (nullable FK to ServerCluster), IsSystemWide, CreatedAtUtc, Notes. Unique (LdapGroup, ClusterId) + hot-path IX on LdapGroup.dotnet ef.ILdapGroupRoleMappingService+ EF impl. Control-plane-only surface per decision #150; the OPC UA data-path evaluator MUST NOT depend on it. GetByGroupsAsync is the hot-path sign-in lookup.InvalidLdapGroupRoleMappingException.Test plan
dotnet test: 1051 passing (was 1042, +9).🤖 Generated with Claude Code
Stream A.1-A.2 per docs/v2/implementation/phase-6-2-authorization-runtime.md. Seed-data migration (A.3) is a separate follow-up once production LDAP group DNs are finalised; until then CRUD via the Admin UI handles the fleet set up. Configuration: - New AdminRole enum {ConfigViewer, ConfigEditor, FleetAdmin} — string-stored. - New LdapGroupRoleMapping entity with Id (surrogate PK), LdapGroup (512 chars), Role (AdminRole enum), ClusterId (nullable, FK to ServerCluster), IsSystemWide, CreatedAtUtc, Notes. - EF config: UX_LdapGroupRoleMapping_Group_Cluster unique index on (LdapGroup, ClusterId) + IX_LdapGroupRoleMapping_Group hot-path index on LdapGroup for sign-in lookups. Cluster FK cascades on cluster delete. - Migration 20260419_..._AddLdapGroupRoleMapping generated via `dotnet ef`. Configuration.Services: - ILdapGroupRoleMappingService — CRUD surface. Declared as control-plane only per decision #150; the OPC UA data-path evaluator must NOT depend on this interface (Phase 6.2 compliance check on control/data-plane separation). GetByGroupsAsync is the hot-path sign-in lookup. - LdapGroupRoleMappingService (EF Core impl) enforces the write-time invariant "exactly one of (ClusterId populated, IsSystemWide=true)" and surfaces InvalidLdapGroupRoleMappingException on violation. Create auto-populates Id + CreatedAtUtc when omitted. Tests (9 new, all pass) in Configuration.Tests: - Create sets Id + CreatedAtUtc. - Create rejects empty LdapGroup. - Create rejects IsSystemWide=true with populated ClusterId. - Create rejects IsSystemWide=false with null ClusterId. - GetByGroupsAsync returns matching rows only. - GetByGroupsAsync with empty input returns empty (no full-table scan). - ListAllAsync orders by group then cluster. - Delete removes the target row. - Delete of unknown id is a no-op. Microsoft.EntityFrameworkCore.InMemory 10.0.0 added to Configuration.Tests for the service-level tests (schema-compliance tests still use the live SQL fixture). SchemaComplianceTests updated to expect the new LdapGroupRoleMapping table. Full solution dotnet test: 1051 passing (baseline 906, Phase 6.1 shipped at 1042, Phase 6.2 Stream A adds 9 = 1051). Pre-existing Client.CLI Subscribe flake unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>