refactor(furniture-service): delegate to domain

This commit is contained in:
José René White Enciso 2026-02-24 05:26:54 -06:00
parent 4647306583
commit 833813ad13
9 changed files with 61 additions and 111 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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;
/// <summary>
/// Default adapter implementation for furniture service contract composition.
/// </summary>
public sealed class FurnitureAvailabilityContractAdapter : IFurnitureAvailabilityContractAdapter
{
private const string ContractVersion = "1.0.0";
/// <inheritdoc />
public InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request)
{
return new InventoryItemLookupRequest(
new InventoryContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)),
request.FurnitureId);
}
/// <inheritdoc />
public ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request)
{
return new ProductContract(
new CatalogContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)),
request.FurnitureId,
string.Empty);
}
/// <inheritdoc />
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}";
}
}

View File

@ -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;
/// <summary>
/// Defines adapter boundary for furniture service contract composition.
/// </summary>
public interface IFurnitureAvailabilityContractAdapter
{
/// <summary>
/// Maps service request into an inventory capability request.
/// </summary>
/// <param name="request">Furniture availability request.</param>
/// <returns>Inventory lookup request.</returns>
InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request);
/// <summary>
/// Maps service request into a catalog capability request.
/// </summary>
/// <param name="request">Furniture availability request.</param>
/// <returns>Catalog product request.</returns>
ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request);
/// <summary>
/// Maps capability responses back into the service response contract.
/// </summary>
/// <param name="request">Furniture availability request.</param>
/// <param name="catalogResponse">Catalog product response.</param>
/// <param name="inventoryResponse">Inventory lookup response.</param>
/// <returns>Furniture availability response.</returns>
GetFurnitureAvailabilityResponse ToServiceResponse(
GetFurnitureAvailabilityRequest request,
ProductContractResponse catalogResponse,
InventoryItemLookupResponse inventoryResponse);
}

View File

@ -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<IFurnitureAvailabilityDecisionService, FurnitureAvailabilityDecisionService>();
services.TryAddSingleton<IFurnitureAvailabilityContractAdapter, FurnitureAvailabilityContractAdapter>();
services.TryAddSingleton<IFurnitureAvailabilityGrpcContractAdapter, FurnitureAvailabilityGrpcContractAdapter>();
services.TryAddSingleton<IFurnitureAvailabilityReadPort, FurnitureAvailabilityReadPortDalAdapter>();
services.TryAddSingleton<ICatalogProductReadPort, CatalogProductReadPortDalAdapter>();

View File

@ -8,6 +8,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<ProjectReference Include="..\..\..\building-block-catalog\src\BuildingBlock.Catalog.Contracts\BuildingBlock.Catalog.Contracts.csproj" />
<ProjectReference Include="..\..\..\building-block-inventory\src\BuildingBlock.Inventory.Contracts\BuildingBlock.Inventory.Contracts.csproj" />
<ProjectReference Include="..\..\..\furniture-domain\src\Furniture.Domain\Furniture.Domain.csproj" />
<ProjectReference Include="..\..\..\furniture-dal\src\Furniture.DAL\Furniture.DAL.csproj" />
<ProjectReference Include="..\Furniture.Service.Contracts\Furniture.Service.Contracts.csproj" />
</ItemGroup>

View File

@ -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.
/// </summary>
public sealed class GetFurnitureAvailabilityUseCase(
IFurnitureAvailabilityContractAdapter contractAdapter,
IFurnitureAvailabilityDecisionService decisionService,
ICatalogProductReadPort catalogReadPort,
IFurnitureAvailabilityReadPort inventoryReadPort)
: IGetFurnitureAvailabilityUseCase
@ -16,17 +17,25 @@ public sealed class GetFurnitureAvailabilityUseCase(
/// <inheritdoc />
public async Task<GetFurnitureAvailabilityResponse> 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);
}
}

View File

@ -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);