diff --git a/docs/architecture/dal-domain-alignment.md b/docs/architecture/dal-domain-alignment.md new file mode 100644 index 0000000..1261cc9 --- /dev/null +++ b/docs/architecture/dal-domain-alignment.md @@ -0,0 +1,13 @@ +# Thalos DAL Domain Alignment + +## Goal +Align DAL with thalos-domain abstractions while keeping DAL technical. + +## DAL Responsibilities +- Identity persistence and retrieval +- Technical data translation +- Provider/repository boundaries + +## Prohibited +- Identity policy decision ownership +- Service orchestration concerns diff --git a/docs/migration/dal-port-alignment-map.md b/docs/migration/dal-port-alignment-map.md new file mode 100644 index 0000000..dbbc0be --- /dev/null +++ b/docs/migration/dal-port-alignment-map.md @@ -0,0 +1,6 @@ +# Thalos DAL Port Alignment Map + +## Alignment Areas +- DAL read/write ports map to domain contracts. +- Technical DTO translation remains in DAL adapters. +- Domain policy semantics are not reimplemented in DAL. diff --git a/docs/migration/technical-mapping-rules.md b/docs/migration/technical-mapping-rules.md new file mode 100644 index 0000000..98161ed --- /dev/null +++ b/docs/migration/technical-mapping-rules.md @@ -0,0 +1,6 @@ +# Thalos DAL Technical Mapping Rules + +## Rules +- Mapping logic remains technical and deterministic. +- No policy evaluation branching in DAL mapping layer. +- Correlation and metadata pass-through remains unchanged. diff --git a/src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs index 8e6d4e4..9c5117f 100644 --- a/src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs +++ b/src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs @@ -5,4 +5,5 @@ namespace Thalos.DAL.Contracts; /// /// Contract envelope metadata. /// Identity subject identifier. -public sealed record IdentityUserLookupRequest(IdentityContractEnvelope Envelope, string SubjectId); +/// Tenant identifier. +public sealed record IdentityUserLookupRequest(IdentityContractEnvelope Envelope, string SubjectId, string TenantId); diff --git a/src/Thalos.DAL/Contracts/IdentityUserRecord.cs b/src/Thalos.DAL/Contracts/IdentityUserRecord.cs index aa364ac..095f3c5 100644 --- a/src/Thalos.DAL/Contracts/IdentityUserRecord.cs +++ b/src/Thalos.DAL/Contracts/IdentityUserRecord.cs @@ -7,8 +7,14 @@ namespace Thalos.DAL.Contracts; /// Identity subject identifier. /// Tenant scope identifier. /// Current user status. +/// Persisted token projection for subject/tenant. +/// Persisted token expiration in seconds. +/// Persisted policy context projection. public sealed record IdentityUserRecord( IdentityContractEnvelope Envelope, string SubjectId, string TenantId, - string Status); + string Status, + string Token, + int ExpiresInSeconds, + bool ContextSatisfied); diff --git a/src/Thalos.DAL/Providers/InMemory/InMemoryUserDataProvider.cs b/src/Thalos.DAL/Providers/InMemory/InMemoryUserDataProvider.cs index 4d54c23..66cd15d 100644 --- a/src/Thalos.DAL/Providers/InMemory/InMemoryUserDataProvider.cs +++ b/src/Thalos.DAL/Providers/InMemory/InMemoryUserDataProvider.cs @@ -20,8 +20,11 @@ public sealed class InMemoryUserDataProvider : IUserDataProvider var record = new IdentityUserRecord( request.Envelope, request.SubjectId, - "tenant-default", - "active"); + request.TenantId, + "active", + $"{request.SubjectId}:{request.TenantId}:token", + 1800, + true); return Task.FromResult(record); } diff --git a/src/Thalos.DAL/Repositories/IdentityRepository.cs b/src/Thalos.DAL/Repositories/IdentityRepository.cs index 8725a0d..bbe768c 100644 --- a/src/Thalos.DAL/Repositories/IdentityRepository.cs +++ b/src/Thalos.DAL/Repositories/IdentityRepository.cs @@ -15,15 +15,19 @@ public sealed class IdentityRepository( IdentityTokenLookupRequest request, CancellationToken cancellationToken = default) { - var userRequest = new IdentityUserLookupRequest(request.Envelope, request.SubjectId); + var userRequest = new IdentityUserLookupRequest(request.Envelope, request.SubjectId, request.TenantId); var userRecord = await userDataProvider.ReadUserAsync(userRequest, cancellationToken); if (userRecord is null) { return null; } - var token = $"{request.SubjectId}:{request.TenantId}:token"; - return new IdentityTokenRecord(request.Envelope, request.SubjectId, request.TenantId, token, 1800); + return new IdentityTokenRecord( + request.Envelope, + request.SubjectId, + request.TenantId, + userRecord.Token, + userRecord.ExpiresInSeconds); } /// @@ -31,15 +35,18 @@ public sealed class IdentityRepository( IdentityPolicyLookupRequest request, CancellationToken cancellationToken = default) { - var userRequest = new IdentityUserLookupRequest(request.Envelope, request.SubjectId); + var userRequest = new IdentityUserLookupRequest(request.Envelope, request.SubjectId, request.TenantId); var userRecord = await userDataProvider.ReadUserAsync(userRequest, cancellationToken); if (userRecord is null) { return null; } - var contextSatisfied = string.Equals(userRecord.Status, "active", StringComparison.OrdinalIgnoreCase); - return new IdentityPolicyRecord(request.Envelope, request.SubjectId, request.PermissionCode, contextSatisfied); + return new IdentityPolicyRecord( + request.Envelope, + request.SubjectId, + request.PermissionCode, + userRecord.ContextSatisfied); } ///