From 464730658350ca0af383cd800aaba6a2d024cfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ren=C3=A9=20White=20Enciso?= Date: Sun, 22 Feb 2026 19:20:40 -0600 Subject: [PATCH 1/3] feat(furniture-service): wire grpc runtime and dal port adapters --- .../FurnitureAvailabilityContractAdapter.cs | 56 +++++++++++++++++++ ...urnitureAvailabilityGrpcContractAdapter.cs | 36 ++++++++++++ ...rviceRuntimeServiceCollectionExtensions.cs | 34 +++++++++++ .../Furniture.Service.Application.csproj | 2 + .../Ports/CatalogProductReadPortDalAdapter.cs | 38 +++++++++++++ ...FurnitureAvailabilityReadPortDalAdapter.cs | 39 +++++++++++++ .../Furniture.Service.Grpc.csproj | 10 ++++ src/Furniture.Service.Grpc/Program.cs | 11 +++- .../Protos/furniture_runtime.proto | 20 +++++++ .../Services/FurnitureRuntimeGrpcService.cs | 39 +++++++++++++ ...iture.Service.Application.UnitTests.csproj | 1 + .../RuntimeWiringTests.cs | 51 +++++++++++++++++ 12 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs create mode 100644 src/Furniture.Service.Application/Adapters/FurnitureAvailabilityGrpcContractAdapter.cs create mode 100644 src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs create mode 100644 src/Furniture.Service.Application/Ports/CatalogProductReadPortDalAdapter.cs create mode 100644 src/Furniture.Service.Application/Ports/FurnitureAvailabilityReadPortDalAdapter.cs create mode 100644 src/Furniture.Service.Grpc/Protos/furniture_runtime.proto create mode 100644 src/Furniture.Service.Grpc/Services/FurnitureRuntimeGrpcService.cs create mode 100644 tests/Furniture.Service.Application.UnitTests/RuntimeWiringTests.cs diff --git a/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs new file mode 100644 index 0000000..d53bce9 --- /dev/null +++ b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs @@ -0,0 +1,56 @@ +using BuildingBlock.Catalog.Contracts.Conventions; +using BuildingBlock.Catalog.Contracts.Products; +using BuildingBlock.Catalog.Contracts.Responses; +using BuildingBlock.Inventory.Contracts.Conventions; +using BuildingBlock.Inventory.Contracts.Requests; +using BuildingBlock.Inventory.Contracts.Responses; +using Furniture.Service.Contracts.UseCases; + +namespace Furniture.Service.Application.Adapters; + +/// +/// Default adapter implementation for furniture service contract composition. +/// +public sealed class FurnitureAvailabilityContractAdapter : IFurnitureAvailabilityContractAdapter +{ + private const string ContractVersion = "1.0.0"; + + /// + public InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request) + { + return new InventoryItemLookupRequest( + new InventoryContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)), + request.FurnitureId); + } + + /// + public ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request) + { + return new ProductContract( + new CatalogContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)), + request.FurnitureId, + string.Empty); + } + + /// + public GetFurnitureAvailabilityResponse ToServiceResponse( + GetFurnitureAvailabilityRequest request, + ProductContractResponse catalogResponse, + InventoryItemLookupResponse inventoryResponse) + { + return new GetFurnitureAvailabilityResponse( + request.FurnitureId, + catalogResponse.DisplayName, + inventoryResponse.QuantityAvailable); + } + + private static string ResolveCorrelationId(string correlationId) + { + if (!string.IsNullOrWhiteSpace(correlationId)) + { + return correlationId; + } + + return $"corr-{Guid.NewGuid():N}"; + } +} diff --git a/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityGrpcContractAdapter.cs b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityGrpcContractAdapter.cs new file mode 100644 index 0000000..bbaeb4a --- /dev/null +++ b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityGrpcContractAdapter.cs @@ -0,0 +1,36 @@ +using Furniture.Service.Application.Grpc; +using Furniture.Service.Contracts.UseCases; + +namespace Furniture.Service.Application.Adapters; + +/// +/// Default adapter implementation for furniture service gRPC contract translation. +/// +public sealed class FurnitureAvailabilityGrpcContractAdapter : IFurnitureAvailabilityGrpcContractAdapter +{ + /// + public GetFurnitureAvailabilityGrpcContract ToGrpc(GetFurnitureAvailabilityRequest request) + { + return new GetFurnitureAvailabilityGrpcContract( + request.FurnitureId, + ResolveCorrelationId(request.CorrelationId)); + } + + /// + public GetFurnitureAvailabilityRequest FromGrpc(GetFurnitureAvailabilityGrpcContract contract) + { + return new GetFurnitureAvailabilityRequest( + contract.FurnitureId, + ResolveCorrelationId(contract.CorrelationId)); + } + + private static string ResolveCorrelationId(string correlationId) + { + if (!string.IsNullOrWhiteSpace(correlationId)) + { + return correlationId; + } + + return $"corr-{Guid.NewGuid():N}"; + } +} diff --git a/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs b/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs new file mode 100644 index 0000000..3dd7863 --- /dev/null +++ b/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs @@ -0,0 +1,34 @@ +using Core.Blueprint.Common.DependencyInjection; +using Furniture.DAL.DependencyInjection; +using Furniture.Service.Application.Adapters; +using Furniture.Service.Application.Ports; +using Furniture.Service.Application.UseCases; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Furniture.Service.Application.DependencyInjection; + +/// +/// Registers furniture-service runtime orchestration and DAL adapters. +/// +public static class FurnitureServiceRuntimeServiceCollectionExtensions +{ + /// + /// Adds furniture-service runtime wiring aligned with blueprint runtime and furniture-dal runtime. + /// + /// Service collection. + /// Service collection for fluent chaining. + public static IServiceCollection AddFurnitureServiceRuntime(this IServiceCollection services) + { + services.AddBlueprintRuntimeCore(); + services.AddFurnitureDalRuntime(); + + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + + return services; + } +} diff --git a/src/Furniture.Service.Application/Furniture.Service.Application.csproj b/src/Furniture.Service.Application/Furniture.Service.Application.csproj index 007938b..236c500 100644 --- a/src/Furniture.Service.Application/Furniture.Service.Application.csproj +++ b/src/Furniture.Service.Application/Furniture.Service.Application.csproj @@ -5,8 +5,10 @@ enable + + diff --git a/src/Furniture.Service.Application/Ports/CatalogProductReadPortDalAdapter.cs b/src/Furniture.Service.Application/Ports/CatalogProductReadPortDalAdapter.cs new file mode 100644 index 0000000..35e9bfc --- /dev/null +++ b/src/Furniture.Service.Application/Ports/CatalogProductReadPortDalAdapter.cs @@ -0,0 +1,38 @@ +using BuildingBlock.Catalog.Contracts.Conventions; +using BuildingBlock.Catalog.Contracts.Products; +using BuildingBlock.Catalog.Contracts.Responses; +using Furniture.DAL.Contracts; +using Furniture.DAL.Repositories; + +namespace Furniture.Service.Application.Ports; + +/// +/// Default DAL adapter for catalog product read port. +/// +public sealed class CatalogProductReadPortDalAdapter(ICatalogRepository catalogRepository) : ICatalogProductReadPort +{ + /// + public async Task ReadProductAsync(ProductContract request) + { + var lookupRequest = new CatalogProductLookupRequest( + new FurnitureDalContractEnvelope( + request.Envelope.ContractVersion, + request.Envelope.CorrelationId), + request.ProductId); + + var projectionRecord = await catalogRepository.ReadProductAsync(lookupRequest); + if (projectionRecord is null) + { + return new ProductContractResponse(request.Envelope, request.ProductId, string.Empty); + } + + var responseEnvelope = new CatalogContractEnvelope( + projectionRecord.Envelope.ContractVersion, + projectionRecord.Envelope.CorrelationId); + + return new ProductContractResponse( + responseEnvelope, + projectionRecord.ProductId, + projectionRecord.DisplayName); + } +} diff --git a/src/Furniture.Service.Application/Ports/FurnitureAvailabilityReadPortDalAdapter.cs b/src/Furniture.Service.Application/Ports/FurnitureAvailabilityReadPortDalAdapter.cs new file mode 100644 index 0000000..f30d0b6 --- /dev/null +++ b/src/Furniture.Service.Application/Ports/FurnitureAvailabilityReadPortDalAdapter.cs @@ -0,0 +1,39 @@ +using BuildingBlock.Inventory.Contracts.Conventions; +using BuildingBlock.Inventory.Contracts.Requests; +using BuildingBlock.Inventory.Contracts.Responses; +using Furniture.DAL.Contracts; +using Furniture.DAL.Repositories; + +namespace Furniture.Service.Application.Ports; + +/// +/// Default DAL adapter for furniture availability read port. +/// +public sealed class FurnitureAvailabilityReadPortDalAdapter( + IFurnitureRepository furnitureRepository) : IFurnitureAvailabilityReadPort +{ + /// + public async Task ReadAvailabilityAsync(InventoryItemLookupRequest request) + { + var lookupRequest = new FurnitureAvailabilityLookupRequest( + new FurnitureDalContractEnvelope( + request.Envelope.ContractVersion, + request.Envelope.CorrelationId), + request.ItemCode); + + var availabilityRecord = await furnitureRepository.ReadAvailabilityAsync(lookupRequest); + if (availabilityRecord is null) + { + return new InventoryItemLookupResponse(request.Envelope, request.ItemCode, 0); + } + + var responseEnvelope = new InventoryContractEnvelope( + availabilityRecord.Envelope.ContractVersion, + availabilityRecord.Envelope.CorrelationId); + + return new InventoryItemLookupResponse( + responseEnvelope, + availabilityRecord.FurnitureId, + availabilityRecord.QuantityAvailable); + } +} diff --git a/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj b/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj index d236f97..c391cd2 100644 --- a/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj +++ b/src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj @@ -4,6 +4,16 @@ enable enable + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/src/Furniture.Service.Grpc/Program.cs b/src/Furniture.Service.Grpc/Program.cs index ef5cbdd..4f71e79 100644 --- a/src/Furniture.Service.Grpc/Program.cs +++ b/src/Furniture.Service.Grpc/Program.cs @@ -1,6 +1,15 @@ +using Furniture.Service.Application.DependencyInjection; +using Furniture.Service.Grpc.Services; + var builder = WebApplication.CreateBuilder(args); -// Stage 3 skeleton: keep a single active internal protocol policy (gRPC-first). +builder.Services.AddGrpc(); +builder.Services.AddHealthChecks(); +builder.Services.AddFurnitureServiceRuntime(); + var app = builder.Build(); +app.MapGrpcService(); +app.MapHealthChecks("/healthz"); + app.Run(); diff --git a/src/Furniture.Service.Grpc/Protos/furniture_runtime.proto b/src/Furniture.Service.Grpc/Protos/furniture_runtime.proto new file mode 100644 index 0000000..785ba0f --- /dev/null +++ b/src/Furniture.Service.Grpc/Protos/furniture_runtime.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +option csharp_namespace = "Furniture.Service.Grpc"; + +package furniture.service.grpc; + +service FurnitureRuntime { + rpc GetFurnitureAvailability (GetFurnitureAvailabilityGrpcRequest) returns (GetFurnitureAvailabilityGrpcResponse); +} + +message GetFurnitureAvailabilityGrpcRequest { + string furniture_id = 1; + string correlation_id = 2; +} + +message GetFurnitureAvailabilityGrpcResponse { + string furniture_id = 1; + string display_name = 2; + int32 quantity_available = 3; +} diff --git a/src/Furniture.Service.Grpc/Services/FurnitureRuntimeGrpcService.cs b/src/Furniture.Service.Grpc/Services/FurnitureRuntimeGrpcService.cs new file mode 100644 index 0000000..4d2bb1e --- /dev/null +++ b/src/Furniture.Service.Grpc/Services/FurnitureRuntimeGrpcService.cs @@ -0,0 +1,39 @@ +using Grpc.Core; +using Furniture.Service.Application.Adapters; +using Furniture.Service.Application.Grpc; +using Furniture.Service.Application.UseCases; + +namespace Furniture.Service.Grpc.Services; + +/// +/// Internal gRPC endpoint implementation for furniture runtime operations. +/// +public sealed class FurnitureRuntimeGrpcService( + IGetFurnitureAvailabilityUseCase getFurnitureAvailabilityUseCase, + IFurnitureAvailabilityGrpcContractAdapter grpcContractAdapter) : FurnitureRuntime.FurnitureRuntimeBase +{ + /// + /// Executes furniture availability lookup through service use-case orchestration. + /// + /// gRPC availability request. + /// gRPC server call context. + /// gRPC availability response. + public override async Task GetFurnitureAvailability( + GetFurnitureAvailabilityGrpcRequest request, + ServerCallContext context) + { + var grpcContract = new GetFurnitureAvailabilityGrpcContract( + request.FurnitureId, + request.CorrelationId); + + var useCaseRequest = grpcContractAdapter.FromGrpc(grpcContract); + var useCaseResponse = await getFurnitureAvailabilityUseCase.HandleAsync(useCaseRequest); + + return new GetFurnitureAvailabilityGrpcResponse + { + FurnitureId = useCaseResponse.FurnitureId, + DisplayName = useCaseResponse.DisplayName, + QuantityAvailable = useCaseResponse.QuantityAvailable + }; + } +} diff --git a/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj b/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj index f2fe7f7..a5758c1 100644 --- a/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj +++ b/tests/Furniture.Service.Application.UnitTests/Furniture.Service.Application.UnitTests.csproj @@ -7,6 +7,7 @@ + diff --git a/tests/Furniture.Service.Application.UnitTests/RuntimeWiringTests.cs b/tests/Furniture.Service.Application.UnitTests/RuntimeWiringTests.cs new file mode 100644 index 0000000..18e861e --- /dev/null +++ b/tests/Furniture.Service.Application.UnitTests/RuntimeWiringTests.cs @@ -0,0 +1,51 @@ +using Furniture.Service.Application.Adapters; +using Furniture.Service.Application.DependencyInjection; +using Furniture.Service.Application.Grpc; +using Furniture.Service.Application.UseCases; +using Furniture.Service.Contracts.UseCases; +using Microsoft.Extensions.DependencyInjection; + +namespace Furniture.Service.Application.UnitTests; + +public class RuntimeWiringTests +{ + [Fact] + public async Task AddFurnitureServiceRuntime_WhenInvoked_ResolvesUseCase() + { + var services = new ServiceCollection(); + services.AddFurnitureServiceRuntime(); + + using var provider = services.BuildServiceProvider(); + var useCase = provider.GetRequiredService(); + + var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FUR-001", "corr-123")); + + Assert.Equal("FUR-001", response.FurnitureId); + Assert.Equal(8, response.QuantityAvailable); + } + + [Fact] + public void FurnitureAvailabilityGrpcContractAdapter_WhenMapped_PreservesValues() + { + var adapter = new FurnitureAvailabilityGrpcContractAdapter(); + var request = new GetFurnitureAvailabilityRequest("FUR-002", "corr-456"); + + var grpcContract = adapter.ToGrpc(request); + var roundtrip = adapter.FromGrpc(grpcContract); + + Assert.Equal("FUR-002", roundtrip.FurnitureId); + Assert.Equal("corr-456", roundtrip.CorrelationId); + } + + [Fact] + public void FurnitureAvailabilityGrpcContractAdapter_WhenCorrelationMissing_GeneratesCorrelation() + { + var adapter = new FurnitureAvailabilityGrpcContractAdapter(); + var grpcContract = new GetFurnitureAvailabilityGrpcContract("FUR-003", string.Empty); + + var mapped = adapter.FromGrpc(grpcContract); + + Assert.Equal("FUR-003", mapped.FurnitureId); + Assert.NotEmpty(mapped.CorrelationId); + } +} From 833813ad13118ab8bef6ecc2c03d2ef2d652702c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ren=C3=A9=20White=20Enciso?= Date: Tue, 24 Feb 2026 05:26:54 -0600 Subject: [PATCH 2/3] refactor(furniture-service): delegate to domain --- .../service-orchestration-boundary.md | 13 +++++ docs/migration/domain-delegation-plan.md | 10 ++++ .../orchestration-regression-checks.md | 10 ++++ .../FurnitureAvailabilityContractAdapter.cs | 56 ------------------- .../IFurnitureAvailabilityContractAdapter.cs | 39 ------------- ...rviceRuntimeServiceCollectionExtensions.cs | 3 +- .../Furniture.Service.Application.csproj | 1 + .../GetFurnitureAvailabilityUseCase.cs | 21 +++++-- .../GetFurnitureAvailabilityUseCaseTests.cs | 19 ++++--- 9 files changed, 61 insertions(+), 111 deletions(-) create mode 100644 docs/architecture/service-orchestration-boundary.md create mode 100644 docs/migration/domain-delegation-plan.md create mode 100644 docs/migration/orchestration-regression-checks.md delete mode 100644 src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs delete mode 100644 src/Furniture.Service.Application/Adapters/IFurnitureAvailabilityContractAdapter.cs diff --git a/docs/architecture/service-orchestration-boundary.md b/docs/architecture/service-orchestration-boundary.md new file mode 100644 index 0000000..312edeb --- /dev/null +++ b/docs/architecture/service-orchestration-boundary.md @@ -0,0 +1,13 @@ +# Furniture Service Orchestration Boundary + +## Purpose +Constrain furniture-service to orchestration responsibilities after domain extraction. + +## Service Responsibilities +- Coordinate use-case flow +- Call domain abstractions for decisions +- Adapt transport contracts + +## Prohibited Responsibilities +- Owning business decision rules +- Owning persistence decision concerns diff --git a/docs/migration/domain-delegation-plan.md b/docs/migration/domain-delegation-plan.md new file mode 100644 index 0000000..087b23d --- /dev/null +++ b/docs/migration/domain-delegation-plan.md @@ -0,0 +1,10 @@ +# Domain Delegation Plan + +## Delegation Model +- Use cases invoke furniture-domain abstractions for decision logic. +- Service adapters retain technical mapping responsibilities. + +## Transition Steps +1. Replace in-service decision branches with domain calls. +2. Keep contract shapes stable at service boundary. +3. Validate orchestration-only responsibilities. diff --git a/docs/migration/orchestration-regression-checks.md b/docs/migration/orchestration-regression-checks.md new file mode 100644 index 0000000..902f546 --- /dev/null +++ b/docs/migration/orchestration-regression-checks.md @@ -0,0 +1,10 @@ +# Orchestration Regression Checks + +## Checks +- Service no longer contains domain decision branches. +- Service still orchestrates required dependencies. +- Transport contract outputs remain stable. + +## Evidence +- Updated architecture docs +- Migration mapping confirmation diff --git a/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs b/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs deleted file mode 100644 index d53bce9..0000000 --- a/src/Furniture.Service.Application/Adapters/FurnitureAvailabilityContractAdapter.cs +++ /dev/null @@ -1,56 +0,0 @@ -using BuildingBlock.Catalog.Contracts.Conventions; -using BuildingBlock.Catalog.Contracts.Products; -using BuildingBlock.Catalog.Contracts.Responses; -using BuildingBlock.Inventory.Contracts.Conventions; -using BuildingBlock.Inventory.Contracts.Requests; -using BuildingBlock.Inventory.Contracts.Responses; -using Furniture.Service.Contracts.UseCases; - -namespace Furniture.Service.Application.Adapters; - -/// -/// Default adapter implementation for furniture service contract composition. -/// -public sealed class FurnitureAvailabilityContractAdapter : IFurnitureAvailabilityContractAdapter -{ - private const string ContractVersion = "1.0.0"; - - /// - public InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request) - { - return new InventoryItemLookupRequest( - new InventoryContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)), - request.FurnitureId); - } - - /// - public ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request) - { - return new ProductContract( - new CatalogContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)), - request.FurnitureId, - string.Empty); - } - - /// - public GetFurnitureAvailabilityResponse ToServiceResponse( - GetFurnitureAvailabilityRequest request, - ProductContractResponse catalogResponse, - InventoryItemLookupResponse inventoryResponse) - { - return new GetFurnitureAvailabilityResponse( - request.FurnitureId, - catalogResponse.DisplayName, - inventoryResponse.QuantityAvailable); - } - - private static string ResolveCorrelationId(string correlationId) - { - if (!string.IsNullOrWhiteSpace(correlationId)) - { - return correlationId; - } - - return $"corr-{Guid.NewGuid():N}"; - } -} diff --git a/src/Furniture.Service.Application/Adapters/IFurnitureAvailabilityContractAdapter.cs b/src/Furniture.Service.Application/Adapters/IFurnitureAvailabilityContractAdapter.cs deleted file mode 100644 index 2f501e5..0000000 --- a/src/Furniture.Service.Application/Adapters/IFurnitureAvailabilityContractAdapter.cs +++ /dev/null @@ -1,39 +0,0 @@ -using BuildingBlock.Catalog.Contracts.Products; -using BuildingBlock.Catalog.Contracts.Responses; -using BuildingBlock.Inventory.Contracts.Requests; -using BuildingBlock.Inventory.Contracts.Responses; -using Furniture.Service.Contracts.UseCases; - -namespace Furniture.Service.Application.Adapters; - -/// -/// Defines adapter boundary for furniture service contract composition. -/// -public interface IFurnitureAvailabilityContractAdapter -{ - /// - /// Maps service request into an inventory capability request. - /// - /// Furniture availability request. - /// Inventory lookup request. - InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request); - - /// - /// Maps service request into a catalog capability request. - /// - /// Furniture availability request. - /// Catalog product request. - ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request); - - /// - /// Maps capability responses back into the service response contract. - /// - /// Furniture availability request. - /// Catalog product response. - /// Inventory lookup response. - /// Furniture availability response. - GetFurnitureAvailabilityResponse ToServiceResponse( - GetFurnitureAvailabilityRequest request, - ProductContractResponse catalogResponse, - InventoryItemLookupResponse inventoryResponse); -} diff --git a/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs b/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs index 3dd7863..b22c04b 100644 --- a/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs +++ b/src/Furniture.Service.Application/DependencyInjection/FurnitureServiceRuntimeServiceCollectionExtensions.cs @@ -1,5 +1,6 @@ using Core.Blueprint.Common.DependencyInjection; using Furniture.DAL.DependencyInjection; +using Furniture.Domain.Decisions; using Furniture.Service.Application.Adapters; using Furniture.Service.Application.Ports; using Furniture.Service.Application.UseCases; @@ -22,8 +23,8 @@ public static class FurnitureServiceRuntimeServiceCollectionExtensions { services.AddBlueprintRuntimeCore(); services.AddFurnitureDalRuntime(); + services.TryAddSingleton(); - services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/src/Furniture.Service.Application/Furniture.Service.Application.csproj b/src/Furniture.Service.Application/Furniture.Service.Application.csproj index 236c500..9d14cf9 100644 --- a/src/Furniture.Service.Application/Furniture.Service.Application.csproj +++ b/src/Furniture.Service.Application/Furniture.Service.Application.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Furniture.Service.Application/UseCases/GetFurnitureAvailabilityUseCase.cs b/src/Furniture.Service.Application/UseCases/GetFurnitureAvailabilityUseCase.cs index 52acd3d..a2e4dc2 100644 --- a/src/Furniture.Service.Application/UseCases/GetFurnitureAvailabilityUseCase.cs +++ b/src/Furniture.Service.Application/UseCases/GetFurnitureAvailabilityUseCase.cs @@ -1,6 +1,7 @@ -using Furniture.Service.Application.Adapters; using Furniture.Service.Application.Ports; using Furniture.Service.Contracts.UseCases; +using Furniture.Domain.Contracts; +using Furniture.Domain.Decisions; namespace Furniture.Service.Application.UseCases; @@ -8,7 +9,7 @@ namespace Furniture.Service.Application.UseCases; /// Default orchestration implementation for furniture availability lookup. /// public sealed class GetFurnitureAvailabilityUseCase( - IFurnitureAvailabilityContractAdapter contractAdapter, + IFurnitureAvailabilityDecisionService decisionService, ICatalogProductReadPort catalogReadPort, IFurnitureAvailabilityReadPort inventoryReadPort) : IGetFurnitureAvailabilityUseCase @@ -16,17 +17,25 @@ public sealed class GetFurnitureAvailabilityUseCase( /// public async Task HandleAsync(GetFurnitureAvailabilityRequest request) { - var catalogRequest = contractAdapter.ToCatalogRequest(request); - var inventoryRequest = contractAdapter.ToInventoryRequest(request); + var domainRequest = new FurnitureAvailabilityDecisionRequest( + request.FurnitureId, + request.CorrelationId); + var catalogRequest = decisionService.BuildCatalogRequest(domainRequest); + var inventoryRequest = decisionService.BuildInventoryRequest(domainRequest); var catalogTask = catalogReadPort.ReadProductAsync(catalogRequest); var inventoryTask = inventoryReadPort.ReadAvailabilityAsync(inventoryRequest); await Task.WhenAll(catalogTask, inventoryTask); - return contractAdapter.ToServiceResponse( - request, + var domainResponse = decisionService.ComposeResponse( + domainRequest, await catalogTask, await inventoryTask); + + return new GetFurnitureAvailabilityResponse( + domainResponse.FurnitureId, + domainResponse.DisplayName, + domainResponse.QuantityAvailable); } } diff --git a/tests/Furniture.Service.Application.UnitTests/GetFurnitureAvailabilityUseCaseTests.cs b/tests/Furniture.Service.Application.UnitTests/GetFurnitureAvailabilityUseCaseTests.cs index 3317df7..a36224c 100644 --- a/tests/Furniture.Service.Application.UnitTests/GetFurnitureAvailabilityUseCaseTests.cs +++ b/tests/Furniture.Service.Application.UnitTests/GetFurnitureAvailabilityUseCaseTests.cs @@ -4,10 +4,11 @@ using BuildingBlock.Catalog.Contracts.Responses; using BuildingBlock.Inventory.Contracts.Conventions; using BuildingBlock.Inventory.Contracts.Requests; using BuildingBlock.Inventory.Contracts.Responses; -using Furniture.Service.Application.Adapters; using Furniture.Service.Application.Ports; using Furniture.Service.Application.UseCases; using Furniture.Service.Contracts.UseCases; +using Furniture.Domain.Contracts; +using Furniture.Domain.Decisions; namespace Furniture.Service.Application.UnitTests; @@ -16,10 +17,10 @@ public class GetFurnitureAvailabilityUseCaseTests [Fact] public async Task HandleAsync_WhenCalled_DelegatesToReadPort() { - var adapter = new FakeFurnitureAvailabilityContractAdapter(); + var decisionService = new FakeFurnitureAvailabilityDecisionService(); var catalogPort = new FakeCatalogProductReadPort(); var inventoryPort = new FakeFurnitureAvailabilityReadPort(); - var useCase = new GetFurnitureAvailabilityUseCase(adapter, catalogPort, inventoryPort); + var useCase = new GetFurnitureAvailabilityUseCase(decisionService, catalogPort, inventoryPort); var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FUR-001", "corr-123")); @@ -28,9 +29,9 @@ public class GetFurnitureAvailabilityUseCaseTests Assert.Equal(10, response.QuantityAvailable); } - private sealed class FakeFurnitureAvailabilityContractAdapter : IFurnitureAvailabilityContractAdapter + private sealed class FakeFurnitureAvailabilityDecisionService : IFurnitureAvailabilityDecisionService { - public ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request) + public ProductContract BuildCatalogRequest(FurnitureAvailabilityDecisionRequest request) { return new ProductContract( new CatalogContractEnvelope("1.0.0", request.CorrelationId), @@ -38,19 +39,19 @@ public class GetFurnitureAvailabilityUseCaseTests string.Empty); } - public InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request) + public InventoryItemLookupRequest BuildInventoryRequest(FurnitureAvailabilityDecisionRequest request) { return new InventoryItemLookupRequest( new InventoryContractEnvelope("1.0.0", request.CorrelationId), request.FurnitureId); } - public GetFurnitureAvailabilityResponse ToServiceResponse( - GetFurnitureAvailabilityRequest request, + public FurnitureAvailabilityDecisionResponse ComposeResponse( + FurnitureAvailabilityDecisionRequest request, ProductContractResponse catalogResponse, InventoryItemLookupResponse inventoryResponse) { - return new GetFurnitureAvailabilityResponse( + return new FurnitureAvailabilityDecisionResponse( request.FurnitureId, catalogResponse.DisplayName, inventoryResponse.QuantityAvailable); From a149394cac207ff4b61a788616c42f70d3707a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ren=C3=A9=20White=20Enciso?= Date: Wed, 25 Feb 2026 13:13:56 -0600 Subject: [PATCH 3/3] refactor(furniture-service): remove redundant building-block references --- docs/architecture/service-orchestration-boundary.md | 1 + .../Furniture.Service.Application.csproj | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/architecture/service-orchestration-boundary.md b/docs/architecture/service-orchestration-boundary.md index 312edeb..6821b14 100644 --- a/docs/architecture/service-orchestration-boundary.md +++ b/docs/architecture/service-orchestration-boundary.md @@ -7,6 +7,7 @@ Constrain furniture-service to orchestration responsibilities after domain extra - Coordinate use-case flow - Call domain abstractions for decisions - Adapt transport contracts +- Depend on Domain and DAL boundaries without direct BuildingBlock ownership ## Prohibited Responsibilities - Owning business decision rules diff --git a/src/Furniture.Service.Application/Furniture.Service.Application.csproj b/src/Furniture.Service.Application/Furniture.Service.Application.csproj index 9d14cf9..b9b8386 100644 --- a/src/Furniture.Service.Application/Furniture.Service.Application.csproj +++ b/src/Furniture.Service.Application/Furniture.Service.Application.csproj @@ -6,8 +6,6 @@ - -