diff --git a/docs/architecture/thalos-service-modules.puml b/docs/architecture/thalos-service-modules.puml
index bc81619..e168b89 100644
--- a/docs/architecture/thalos-service-modules.puml
+++ b/docs/architecture/thalos-service-modules.puml
@@ -5,25 +5,32 @@ package "thalos-service" {
package "Thalos.Service.Identity.Abstractions" {
class IssueIdentityTokenRequest
class IssueIdentityTokenResponse
+ class EvaluateIdentityPolicyRequest
+ class EvaluateIdentityPolicyResponse
+ class IdentityPolicyContextRequest
+ class IdentityPolicyContextResponse
+ class ThalosIdentityPackageContract
interface IdentityAbstractionBoundary
}
package "Thalos.Service.Application" {
interface IIssueIdentityTokenUseCase
class IssueIdentityTokenUseCase
+ interface IEvaluateIdentityPolicyUseCase
+ class EvaluateIdentityPolicyUseCase
interface IIdentityTokenReadPort
+ interface IIdentityPolicyContextReadPort
+ interface IIdentityCapabilityContractAdapter
+ interface IIdentityPolicyGrpcContractAdapter
}
package "Thalos.Service.Grpc" {
class Program
}
-
- IssueIdentityTokenUseCase ..|> IIssueIdentityTokenUseCase
- IssueIdentityTokenUseCase --> IIdentityTokenReadPort
- IIssueIdentityTokenUseCase --> IssueIdentityTokenRequest
- IIssueIdentityTokenUseCase --> IssueIdentityTokenResponse
}
package "thalos-dal" as ThalosDal
+
+IIdentityPolicyContextReadPort ..> ThalosDal
IIdentityTokenReadPort ..> ThalosDal
@enduml
diff --git a/docs/identity/token-policy-and-use-cases.md b/docs/identity/token-policy-and-use-cases.md
index 15559fe..0469f0d 100644
--- a/docs/identity/token-policy-and-use-cases.md
+++ b/docs/identity/token-policy-and-use-cases.md
@@ -3,10 +3,18 @@
## Use-Case Boundaries
- `IIssueIdentityTokenUseCase`: orchestrates token issuance behavior.
+- `IEvaluateIdentityPolicyUseCase`: orchestrates policy evaluation behavior.
- `IIdentityTokenReadPort`: DAL-facing identity token boundary.
+- `IIdentityPolicyContextReadPort`: DAL/integration-facing identity policy context boundary.
+
+## Contract Integration
+
+- Policy orchestration uses Thalos-owned transport-neutral identity contracts.
+- gRPC translation boundaries are isolated behind `IIdentityPolicyGrpcContractAdapter`.
+- Service contracts remain transport-neutral at the application boundary.
## Policy Baseline
-- Token issuance policy is orchestrated in service use cases.
-- Data retrieval and persistence details remain in thalos-dal.
+- Token issuance and policy evaluation are orchestrated in service use cases.
+- Data retrieval and persistence details remain in thalos-dal and identity adapters.
- Protocol adaptation remains outside use-case logic.
diff --git a/src/Thalos.Service.Application/Adapters/IIdentityCapabilityContractAdapter.cs b/src/Thalos.Service.Application/Adapters/IIdentityCapabilityContractAdapter.cs
new file mode 100644
index 0000000..8ac98a7
--- /dev/null
+++ b/src/Thalos.Service.Application/Adapters/IIdentityCapabilityContractAdapter.cs
@@ -0,0 +1,26 @@
+using Thalos.Service.Identity.Abstractions.Contracts;
+
+namespace Thalos.Service.Application.Adapters;
+
+///
+/// Defines adapter boundary for integrating identity contracts into policy use cases.
+///
+public interface IIdentityCapabilityContractAdapter
+{
+ ///
+ /// Creates a transport-neutral context request for policy evaluation.
+ ///
+ /// Identity policy request.
+ /// Identity policy context request.
+ IdentityPolicyContextRequest CreatePolicyContext(EvaluateIdentityPolicyRequest identityRequest);
+
+ ///
+ /// Maps policy context response into identity policy response.
+ ///
+ /// Identity policy request.
+ /// Identity policy context response.
+ /// Identity policy response.
+ EvaluateIdentityPolicyResponse MapPolicyResponse(
+ EvaluateIdentityPolicyRequest identityRequest,
+ IdentityPolicyContextResponse contextResponse);
+}
diff --git a/src/Thalos.Service.Application/Adapters/IIdentityPolicyGrpcContractAdapter.cs b/src/Thalos.Service.Application/Adapters/IIdentityPolicyGrpcContractAdapter.cs
new file mode 100644
index 0000000..1eee486
--- /dev/null
+++ b/src/Thalos.Service.Application/Adapters/IIdentityPolicyGrpcContractAdapter.cs
@@ -0,0 +1,24 @@
+using Thalos.Service.Application.Grpc;
+using Thalos.Service.Identity.Abstractions.Contracts;
+
+namespace Thalos.Service.Application.Adapters;
+
+///
+/// Defines adapter boundary for gRPC contract translation of identity policy flows.
+///
+public interface IIdentityPolicyGrpcContractAdapter
+{
+ ///
+ /// Maps transport-neutral request into gRPC contract shape.
+ ///
+ /// Identity policy request.
+ /// gRPC policy contract.
+ EvaluateIdentityPolicyGrpcContract ToGrpc(EvaluateIdentityPolicyRequest request);
+
+ ///
+ /// Maps gRPC contract into transport-neutral request.
+ ///
+ /// gRPC policy contract.
+ /// Identity policy request.
+ EvaluateIdentityPolicyRequest FromGrpc(EvaluateIdentityPolicyGrpcContract contract);
+}
diff --git a/src/Thalos.Service.Application/Grpc/EvaluateIdentityPolicyGrpcContract.cs b/src/Thalos.Service.Application/Grpc/EvaluateIdentityPolicyGrpcContract.cs
new file mode 100644
index 0000000..8fd286d
--- /dev/null
+++ b/src/Thalos.Service.Application/Grpc/EvaluateIdentityPolicyGrpcContract.cs
@@ -0,0 +1,9 @@
+namespace Thalos.Service.Application.Grpc;
+
+///
+/// Defines minimal gRPC contract shape for identity policy adapter translation.
+///
+/// Identity subject identifier.
+/// Tenant scope identifier.
+/// Permission code to evaluate.
+public sealed record EvaluateIdentityPolicyGrpcContract(string SubjectId, string TenantId, string PermissionCode);
diff --git a/src/Thalos.Service.Application/Ports/IIdentityPolicyContextReadPort.cs b/src/Thalos.Service.Application/Ports/IIdentityPolicyContextReadPort.cs
new file mode 100644
index 0000000..45f8b4e
--- /dev/null
+++ b/src/Thalos.Service.Application/Ports/IIdentityPolicyContextReadPort.cs
@@ -0,0 +1,16 @@
+using Thalos.Service.Identity.Abstractions.Contracts;
+
+namespace Thalos.Service.Application.Ports;
+
+///
+/// Defines DAL/integration read boundary for identity policy context contracts.
+///
+public interface IIdentityPolicyContextReadPort
+{
+ ///
+ /// Reads identity policy context for policy evaluation.
+ ///
+ /// Identity policy context request.
+ /// Identity policy context response.
+ Task ReadPolicyContextAsync(IdentityPolicyContextRequest request);
+}
diff --git a/src/Thalos.Service.Application/UseCases/EvaluateIdentityPolicyUseCase.cs b/src/Thalos.Service.Application/UseCases/EvaluateIdentityPolicyUseCase.cs
new file mode 100644
index 0000000..4255e88
--- /dev/null
+++ b/src/Thalos.Service.Application/UseCases/EvaluateIdentityPolicyUseCase.cs
@@ -0,0 +1,23 @@
+using Thalos.Service.Application.Adapters;
+using Thalos.Service.Application.Ports;
+using Thalos.Service.Identity.Abstractions.Contracts;
+
+namespace Thalos.Service.Application.UseCases;
+
+///
+/// Default orchestration implementation for identity policy evaluation.
+///
+public sealed class EvaluateIdentityPolicyUseCase(
+ IIdentityCapabilityContractAdapter contractAdapter,
+ IIdentityPolicyContextReadPort policyContextReadPort)
+ : IEvaluateIdentityPolicyUseCase
+{
+ ///
+ public async Task HandleAsync(EvaluateIdentityPolicyRequest request)
+ {
+ var policyContextRequest = contractAdapter.CreatePolicyContext(request);
+ var policyContextResponse = await policyContextReadPort.ReadPolicyContextAsync(policyContextRequest);
+
+ return contractAdapter.MapPolicyResponse(request, policyContextResponse);
+ }
+}
diff --git a/src/Thalos.Service.Application/UseCases/IEvaluateIdentityPolicyUseCase.cs b/src/Thalos.Service.Application/UseCases/IEvaluateIdentityPolicyUseCase.cs
new file mode 100644
index 0000000..e503608
--- /dev/null
+++ b/src/Thalos.Service.Application/UseCases/IEvaluateIdentityPolicyUseCase.cs
@@ -0,0 +1,16 @@
+using Thalos.Service.Identity.Abstractions.Contracts;
+
+namespace Thalos.Service.Application.UseCases;
+
+///
+/// Defines orchestration boundary for identity policy evaluation.
+///
+public interface IEvaluateIdentityPolicyUseCase
+{
+ ///
+ /// Handles identity policy evaluation.
+ ///
+ /// Identity policy request contract.
+ /// Identity policy response contract.
+ Task HandleAsync(EvaluateIdentityPolicyRequest request);
+}
diff --git a/src/Thalos.Service.Identity.Abstractions/Contracts/EvaluateIdentityPolicyRequest.cs b/src/Thalos.Service.Identity.Abstractions/Contracts/EvaluateIdentityPolicyRequest.cs
new file mode 100644
index 0000000..1f8be61
--- /dev/null
+++ b/src/Thalos.Service.Identity.Abstractions/Contracts/EvaluateIdentityPolicyRequest.cs
@@ -0,0 +1,9 @@
+namespace Thalos.Service.Identity.Abstractions.Contracts;
+
+///
+/// Transport-neutral request contract for identity policy evaluation.
+///
+/// Identity subject identifier.
+/// Tenant scope identifier.
+/// Permission code to evaluate.
+public sealed record EvaluateIdentityPolicyRequest(string SubjectId, string TenantId, string PermissionCode);
diff --git a/src/Thalos.Service.Identity.Abstractions/Contracts/EvaluateIdentityPolicyResponse.cs b/src/Thalos.Service.Identity.Abstractions/Contracts/EvaluateIdentityPolicyResponse.cs
new file mode 100644
index 0000000..e32eb0a
--- /dev/null
+++ b/src/Thalos.Service.Identity.Abstractions/Contracts/EvaluateIdentityPolicyResponse.cs
@@ -0,0 +1,9 @@
+namespace Thalos.Service.Identity.Abstractions.Contracts;
+
+///
+/// Transport-neutral response contract for identity policy evaluation.
+///
+/// Identity subject identifier.
+/// Permission code evaluated.
+/// Policy result.
+public sealed record EvaluateIdentityPolicyResponse(string SubjectId, string PermissionCode, bool IsAllowed);
diff --git a/src/Thalos.Service.Identity.Abstractions/Contracts/IdentityPolicyContextRequest.cs b/src/Thalos.Service.Identity.Abstractions/Contracts/IdentityPolicyContextRequest.cs
new file mode 100644
index 0000000..3041628
--- /dev/null
+++ b/src/Thalos.Service.Identity.Abstractions/Contracts/IdentityPolicyContextRequest.cs
@@ -0,0 +1,9 @@
+namespace Thalos.Service.Identity.Abstractions.Contracts;
+
+///
+/// Transport-neutral request contract for identity policy context retrieval.
+///
+/// Identity subject identifier.
+/// Tenant scope identifier.
+/// Permission code to evaluate.
+public sealed record IdentityPolicyContextRequest(string SubjectId, string TenantId, string PermissionCode);
diff --git a/src/Thalos.Service.Identity.Abstractions/Contracts/IdentityPolicyContextResponse.cs b/src/Thalos.Service.Identity.Abstractions/Contracts/IdentityPolicyContextResponse.cs
new file mode 100644
index 0000000..05baa75
--- /dev/null
+++ b/src/Thalos.Service.Identity.Abstractions/Contracts/IdentityPolicyContextResponse.cs
@@ -0,0 +1,9 @@
+namespace Thalos.Service.Identity.Abstractions.Contracts;
+
+///
+/// Transport-neutral response contract for identity policy context retrieval.
+///
+/// Identity subject identifier.
+/// Permission code evaluated.
+/// Indicates whether context satisfies policy preconditions.
+public sealed record IdentityPolicyContextResponse(string SubjectId, string PermissionCode, bool ContextSatisfied);
diff --git a/src/Thalos.Service.Identity.Abstractions/Contracts/ThalosIdentityPackageContract.cs b/src/Thalos.Service.Identity.Abstractions/Contracts/ThalosIdentityPackageContract.cs
new file mode 100644
index 0000000..160aacd
--- /dev/null
+++ b/src/Thalos.Service.Identity.Abstractions/Contracts/ThalosIdentityPackageContract.cs
@@ -0,0 +1,15 @@
+using Core.Blueprint.Common.Contracts;
+
+namespace Thalos.Service.Identity.Abstractions.Contracts;
+
+///
+/// Defines package descriptor metadata for Thalos identity abstractions.
+///
+public sealed class ThalosIdentityPackageContract : IBlueprintPackageContract
+{
+ ///
+ public BlueprintPackageDescriptor Descriptor { get; } = new(
+ "Thalos.Service.Identity.Abstractions",
+ PackageVersionPolicy.Minor,
+ ["Core.Blueprint.Common"]);
+}
diff --git a/src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj b/src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj
index 6c3a887..04a4bbc 100644
--- a/src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj
+++ b/src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj
@@ -4,4 +4,7 @@
enable
enable
+
+
+
diff --git a/tests/Thalos.Service.Application.UnitTests/EvaluateIdentityPolicyUseCaseTests.cs b/tests/Thalos.Service.Application.UnitTests/EvaluateIdentityPolicyUseCaseTests.cs
new file mode 100644
index 0000000..8cb71a9
--- /dev/null
+++ b/tests/Thalos.Service.Application.UnitTests/EvaluateIdentityPolicyUseCaseTests.cs
@@ -0,0 +1,49 @@
+using Thalos.Service.Application.Adapters;
+using Thalos.Service.Application.Ports;
+using Thalos.Service.Application.UseCases;
+using Thalos.Service.Identity.Abstractions.Contracts;
+
+namespace Thalos.Service.Application.UnitTests;
+
+public class EvaluateIdentityPolicyUseCaseTests
+{
+ [Fact]
+ public async Task HandleAsync_WhenCalled_UsesIdentityContractsAndReturnsMappedResponse()
+ {
+ var useCase = new EvaluateIdentityPolicyUseCase(
+ new FakeIdentityCapabilityContractAdapter(),
+ new FakeIdentityPolicyContextReadPort());
+
+ var response = await useCase.HandleAsync(new EvaluateIdentityPolicyRequest("subject-1", "tenant-1", "perm.read"));
+
+ Assert.Equal("subject-1", response.SubjectId);
+ Assert.Equal("perm.read", response.PermissionCode);
+ Assert.True(response.IsAllowed);
+ }
+
+ private sealed class FakeIdentityCapabilityContractAdapter : IIdentityCapabilityContractAdapter
+ {
+ public IdentityPolicyContextRequest CreatePolicyContext(EvaluateIdentityPolicyRequest identityRequest)
+ {
+ return new IdentityPolicyContextRequest(identityRequest.SubjectId, identityRequest.TenantId, identityRequest.PermissionCode);
+ }
+
+ public EvaluateIdentityPolicyResponse MapPolicyResponse(
+ EvaluateIdentityPolicyRequest identityRequest,
+ IdentityPolicyContextResponse contextResponse)
+ {
+ return new EvaluateIdentityPolicyResponse(
+ identityRequest.SubjectId,
+ identityRequest.PermissionCode,
+ contextResponse.ContextSatisfied);
+ }
+ }
+
+ private sealed class FakeIdentityPolicyContextReadPort : IIdentityPolicyContextReadPort
+ {
+ public Task ReadPolicyContextAsync(IdentityPolicyContextRequest request)
+ {
+ return Task.FromResult(new IdentityPolicyContextResponse(request.SubjectId, request.PermissionCode, true));
+ }
+ }
+}