From 9f1790ef11df9f7b8ad7fd9643340a5747df0bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ren=C3=A9=20White=20Enciso?= Date: Sun, 22 Feb 2026 01:30:02 -0600 Subject: [PATCH] feat(stage3): scaffold task-001 baseline - WHY: establish Stage 3 task-001 execution baseline per repo intent - WHAT: add minimal solution/project skeleton and boundary docs - RULE: apply stage3 execution runtime and repository workflow directives --- Thalos.Service.slnx | 10 +++++++ docs/architecture/thalos-service-modules.puml | 29 +++++++++++++++++++ docs/identity/abstraction-ownership.md | 12 ++++++++ docs/identity/token-policy-and-use-cases.md | 12 ++++++++ .../Ports/IIdentityTokenReadPort.cs | 16 ++++++++++ .../Thalos.Service.Application.csproj | 10 +++++++ .../UseCases/IIssueIdentityTokenUseCase.cs | 16 ++++++++++ .../UseCases/IssueIdentityTokenUseCase.cs | 17 +++++++++++ src/Thalos.Service.Grpc/Program.cs | 6 ++++ .../Thalos.Service.Grpc.csproj | 11 +++++++ .../Contracts/IssueIdentityTokenRequest.cs | 8 +++++ .../Contracts/IssueIdentityTokenResponse.cs | 8 +++++ .../Ownership/IdentityAbstractionBoundary.cs | 8 +++++ ...halos.Service.Identity.Abstractions.csproj | 7 +++++ .../IssueIdentityTokenUseCaseTests.cs | 28 ++++++++++++++++++ ...halos.Service.Application.UnitTests.csproj | 21 ++++++++++++++ 16 files changed, 219 insertions(+) create mode 100644 Thalos.Service.slnx create mode 100644 docs/architecture/thalos-service-modules.puml create mode 100644 docs/identity/abstraction-ownership.md create mode 100644 docs/identity/token-policy-and-use-cases.md create mode 100644 src/Thalos.Service.Application/Ports/IIdentityTokenReadPort.cs create mode 100644 src/Thalos.Service.Application/Thalos.Service.Application.csproj create mode 100644 src/Thalos.Service.Application/UseCases/IIssueIdentityTokenUseCase.cs create mode 100644 src/Thalos.Service.Application/UseCases/IssueIdentityTokenUseCase.cs create mode 100644 src/Thalos.Service.Grpc/Program.cs create mode 100644 src/Thalos.Service.Grpc/Thalos.Service.Grpc.csproj create mode 100644 src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenRequest.cs create mode 100644 src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenResponse.cs create mode 100644 src/Thalos.Service.Identity.Abstractions/Ownership/IdentityAbstractionBoundary.cs create mode 100644 src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj create mode 100644 tests/Thalos.Service.Application.UnitTests/IssueIdentityTokenUseCaseTests.cs create mode 100644 tests/Thalos.Service.Application.UnitTests/Thalos.Service.Application.UnitTests.csproj diff --git a/Thalos.Service.slnx b/Thalos.Service.slnx new file mode 100644 index 0000000..3187108 --- /dev/null +++ b/Thalos.Service.slnx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/architecture/thalos-service-modules.puml b/docs/architecture/thalos-service-modules.puml new file mode 100644 index 0000000..bc81619 --- /dev/null +++ b/docs/architecture/thalos-service-modules.puml @@ -0,0 +1,29 @@ +@startuml +skinparam packageStyle rectangle + +package "thalos-service" { + package "Thalos.Service.Identity.Abstractions" { + class IssueIdentityTokenRequest + class IssueIdentityTokenResponse + interface IdentityAbstractionBoundary + } + + package "Thalos.Service.Application" { + interface IIssueIdentityTokenUseCase + class IssueIdentityTokenUseCase + interface IIdentityTokenReadPort + } + + package "Thalos.Service.Grpc" { + class Program + } + + IssueIdentityTokenUseCase ..|> IIssueIdentityTokenUseCase + IssueIdentityTokenUseCase --> IIdentityTokenReadPort + IIssueIdentityTokenUseCase --> IssueIdentityTokenRequest + IIssueIdentityTokenUseCase --> IssueIdentityTokenResponse +} + +package "thalos-dal" as ThalosDal +IIdentityTokenReadPort ..> ThalosDal +@enduml diff --git a/docs/identity/abstraction-ownership.md b/docs/identity/abstraction-ownership.md new file mode 100644 index 0000000..567c85c --- /dev/null +++ b/docs/identity/abstraction-ownership.md @@ -0,0 +1,12 @@ +# Identity Abstraction Ownership + +## Ownership Rule + +- Identity-specific abstractions are owned by `thalos-service`. +- `Thalos.Service.Identity.Abstractions` is the canonical abstraction package. +- Blueprint and non-Thalos repositories must not own identity abstractions. + +## Guardrails + +- Identity token and authorization contracts remain in Thalos scope. +- Cross-repo consumers reference abstractions, not Thalos internals. diff --git a/docs/identity/token-policy-and-use-cases.md b/docs/identity/token-policy-and-use-cases.md new file mode 100644 index 0000000..15559fe --- /dev/null +++ b/docs/identity/token-policy-and-use-cases.md @@ -0,0 +1,12 @@ +# Token Policy and Use Cases + +## Use-Case Boundaries + +- `IIssueIdentityTokenUseCase`: orchestrates token issuance behavior. +- `IIdentityTokenReadPort`: DAL-facing identity token boundary. + +## Policy Baseline + +- Token issuance policy is orchestrated in service use cases. +- Data retrieval and persistence details remain in thalos-dal. +- Protocol adaptation remains outside use-case logic. diff --git a/src/Thalos.Service.Application/Ports/IIdentityTokenReadPort.cs b/src/Thalos.Service.Application/Ports/IIdentityTokenReadPort.cs new file mode 100644 index 0000000..c513044 --- /dev/null +++ b/src/Thalos.Service.Application/Ports/IIdentityTokenReadPort.cs @@ -0,0 +1,16 @@ +using Thalos.Service.Identity.Abstractions.Contracts; + +namespace Thalos.Service.Application.Ports; + +/// +/// Defines DAL-facing boundary for issuing identity tokens. +/// +public interface IIdentityTokenReadPort +{ + /// + /// Issues an identity token from persistence-backed policy data. + /// + /// Token request contract. + /// Token response contract. + Task IssueTokenAsync(IssueIdentityTokenRequest request); +} diff --git a/src/Thalos.Service.Application/Thalos.Service.Application.csproj b/src/Thalos.Service.Application/Thalos.Service.Application.csproj new file mode 100644 index 0000000..032d28e --- /dev/null +++ b/src/Thalos.Service.Application/Thalos.Service.Application.csproj @@ -0,0 +1,10 @@ + + + net10.0 + enable + enable + + + + + diff --git a/src/Thalos.Service.Application/UseCases/IIssueIdentityTokenUseCase.cs b/src/Thalos.Service.Application/UseCases/IIssueIdentityTokenUseCase.cs new file mode 100644 index 0000000..a7a4a06 --- /dev/null +++ b/src/Thalos.Service.Application/UseCases/IIssueIdentityTokenUseCase.cs @@ -0,0 +1,16 @@ +using Thalos.Service.Identity.Abstractions.Contracts; + +namespace Thalos.Service.Application.UseCases; + +/// +/// Defines orchestration boundary for identity token issuance. +/// +public interface IIssueIdentityTokenUseCase +{ + /// + /// Handles identity token issuance use case. + /// + /// Token request contract. + /// Token response contract. + Task HandleAsync(IssueIdentityTokenRequest request); +} diff --git a/src/Thalos.Service.Application/UseCases/IssueIdentityTokenUseCase.cs b/src/Thalos.Service.Application/UseCases/IssueIdentityTokenUseCase.cs new file mode 100644 index 0000000..a94c145 --- /dev/null +++ b/src/Thalos.Service.Application/UseCases/IssueIdentityTokenUseCase.cs @@ -0,0 +1,17 @@ +using Thalos.Service.Application.Ports; +using Thalos.Service.Identity.Abstractions.Contracts; + +namespace Thalos.Service.Application.UseCases; + +/// +/// Default orchestration implementation for identity token issuance. +/// +public sealed class IssueIdentityTokenUseCase(IIdentityTokenReadPort readPort) + : IIssueIdentityTokenUseCase +{ + /// + public Task HandleAsync(IssueIdentityTokenRequest request) + { + return readPort.IssueTokenAsync(request); + } +} diff --git a/src/Thalos.Service.Grpc/Program.cs b/src/Thalos.Service.Grpc/Program.cs new file mode 100644 index 0000000..5af6dbd --- /dev/null +++ b/src/Thalos.Service.Grpc/Program.cs @@ -0,0 +1,6 @@ +var builder = WebApplication.CreateBuilder(args); + +// Stage 3 skeleton: single active internal protocol policy is gRPC-first. +var app = builder.Build(); + +app.Run(); diff --git a/src/Thalos.Service.Grpc/Thalos.Service.Grpc.csproj b/src/Thalos.Service.Grpc/Thalos.Service.Grpc.csproj new file mode 100644 index 0000000..b7f7de2 --- /dev/null +++ b/src/Thalos.Service.Grpc/Thalos.Service.Grpc.csproj @@ -0,0 +1,11 @@ + + + net10.0 + enable + enable + + + + + + diff --git a/src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenRequest.cs b/src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenRequest.cs new file mode 100644 index 0000000..6298d1b --- /dev/null +++ b/src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenRequest.cs @@ -0,0 +1,8 @@ +namespace Thalos.Service.Identity.Abstractions.Contracts; + +/// +/// Request contract for issuing an identity token. +/// +/// Identity subject identifier. +/// Tenant scope identifier. +public sealed record IssueIdentityTokenRequest(string SubjectId, string TenantId); diff --git a/src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenResponse.cs b/src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenResponse.cs new file mode 100644 index 0000000..df510d9 --- /dev/null +++ b/src/Thalos.Service.Identity.Abstractions/Contracts/IssueIdentityTokenResponse.cs @@ -0,0 +1,8 @@ +namespace Thalos.Service.Identity.Abstractions.Contracts; + +/// +/// Response contract for identity token issuance. +/// +/// Issued access token value. +/// Token expiration in seconds. +public sealed record IssueIdentityTokenResponse(string Token, int ExpiresInSeconds); diff --git a/src/Thalos.Service.Identity.Abstractions/Ownership/IdentityAbstractionBoundary.cs b/src/Thalos.Service.Identity.Abstractions/Ownership/IdentityAbstractionBoundary.cs new file mode 100644 index 0000000..fdf293d --- /dev/null +++ b/src/Thalos.Service.Identity.Abstractions/Ownership/IdentityAbstractionBoundary.cs @@ -0,0 +1,8 @@ +namespace Thalos.Service.Identity.Abstractions.Ownership; + +/// +/// Marker boundary for abstractions owned by thalos-service. +/// +public interface IdentityAbstractionBoundary +{ +} diff --git a/src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj b/src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj new file mode 100644 index 0000000..6c3a887 --- /dev/null +++ b/src/Thalos.Service.Identity.Abstractions/Thalos.Service.Identity.Abstractions.csproj @@ -0,0 +1,7 @@ + + + net10.0 + enable + enable + + diff --git a/tests/Thalos.Service.Application.UnitTests/IssueIdentityTokenUseCaseTests.cs b/tests/Thalos.Service.Application.UnitTests/IssueIdentityTokenUseCaseTests.cs new file mode 100644 index 0000000..50685bf --- /dev/null +++ b/tests/Thalos.Service.Application.UnitTests/IssueIdentityTokenUseCaseTests.cs @@ -0,0 +1,28 @@ +using Thalos.Service.Application.Ports; +using Thalos.Service.Application.UseCases; +using Thalos.Service.Identity.Abstractions.Contracts; + +namespace Thalos.Service.Application.UnitTests; + +public class IssueIdentityTokenUseCaseTests +{ + [Fact] + public async Task HandleAsync_WhenCalled_DelegatesToReadPort() + { + var port = new FakeIdentityTokenReadPort(); + var useCase = new IssueIdentityTokenUseCase(port); + + var response = await useCase.HandleAsync(new IssueIdentityTokenRequest("user-1", "tenant-1")); + + Assert.Equal("token-123", response.Token); + Assert.Equal(3600, response.ExpiresInSeconds); + } + + private sealed class FakeIdentityTokenReadPort : IIdentityTokenReadPort + { + public Task IssueTokenAsync(IssueIdentityTokenRequest request) + { + return Task.FromResult(new IssueIdentityTokenResponse("token-123", 3600)); + } + } +} diff --git a/tests/Thalos.Service.Application.UnitTests/Thalos.Service.Application.UnitTests.csproj b/tests/Thalos.Service.Application.UnitTests/Thalos.Service.Application.UnitTests.csproj new file mode 100644 index 0000000..a887a0c --- /dev/null +++ b/tests/Thalos.Service.Application.UnitTests/Thalos.Service.Application.UnitTests.csproj @@ -0,0 +1,21 @@ + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + +