Compare commits
No commits in common. "bff24f312466d8f11d5f408278916002a4ab6dd5" and "464730658350ca0af383cd800aaba6a2d024cfa8" have entirely different histories.
bff24f3124
...
4647306583
@ -1,9 +0,0 @@
|
|||||||
**/bin/
|
|
||||||
**/obj/
|
|
||||||
.vs/
|
|
||||||
TestResults/
|
|
||||||
.git/
|
|
||||||
.repo-tasks/
|
|
||||||
.repo-context/
|
|
||||||
.tasks/
|
|
||||||
.agile/
|
|
||||||
63
.gitignore
vendored
63
.gitignore
vendored
@ -1,24 +1,53 @@
|
|||||||
# Repository orchestration folders (local only)
|
# AgileWebs local orchestration
|
||||||
.repo-tasks/
|
|
||||||
.repo-context/
|
|
||||||
.tasks/
|
.tasks/
|
||||||
.agile/
|
.agile/
|
||||||
|
|
||||||
# .NET build outputs
|
# Build artifacts
|
||||||
**/bin/
|
**/[Bb]in/
|
||||||
**/obj/
|
**/[Oo]bj/
|
||||||
|
/**/out/
|
||||||
|
/**/artifacts/
|
||||||
|
|
||||||
|
# IDE and editor files
|
||||||
.vs/
|
.vs/
|
||||||
TestResults/
|
|
||||||
**/TestResults/
|
|
||||||
*.user
|
|
||||||
*.suo
|
|
||||||
*.rsuser
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.idea/
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
*.rsuser
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
# Runtime-local artifacts
|
# NuGet
|
||||||
logs/
|
*.nupkg
|
||||||
|
*.snupkg
|
||||||
|
**/packages/*
|
||||||
|
!**/packages/build/
|
||||||
|
|
||||||
|
# Test output
|
||||||
|
**/TestResults/
|
||||||
|
*.trx
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
.env.local
|
logs/
|
||||||
.env.*.local
|
|
||||||
|
# Local environment files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
.docker/
|
||||||
|
**/.docker/
|
||||||
|
*.pid
|
||||||
|
docker-compose.override.yml
|
||||||
|
docker-compose.*.override.yml
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
<Authors>AgileWebs</Authors>
|
|
||||||
<Company>AgileWebs</Company>
|
|
||||||
<RepositoryType>git</RepositoryType>
|
|
||||||
<RepositoryUrl>https://gitea.dream-views.com/AgileWebs/furniture-service</RepositoryUrl>
|
|
||||||
<PackageProjectUrl>https://gitea.dream-views.com/AgileWebs/furniture-service</PackageProjectUrl>
|
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
23
Dockerfile
23
Dockerfile
@ -1,23 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1.7
|
|
||||||
ARG SDK_IMAGE=mcr.microsoft.com/dotnet/sdk:10.0
|
|
||||||
ARG RUNTIME_IMAGE=mcr.microsoft.com/dotnet/aspnet:10.0
|
|
||||||
|
|
||||||
FROM ${SDK_IMAGE} AS build
|
|
||||||
ARG NUGET_FEED_URL=https://gitea.dream-views.com/api/packages/AgileWebs/nuget/index.json
|
|
||||||
ARG NUGET_FEED_USERNAME=
|
|
||||||
ARG NUGET_FEED_TOKEN=
|
|
||||||
WORKDIR /src
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN if [ -n "$NUGET_FEED_USERNAME" ] && [ -n "$NUGET_FEED_TOKEN" ]; then dotnet nuget add source "$NUGET_FEED_URL" --name gitea-org --username "$NUGET_FEED_USERNAME" --password "$NUGET_FEED_TOKEN" --store-password-in-clear-text --allow-insecure-connections --configfile /root/.nuget/NuGet/NuGet.Config; fi
|
|
||||||
|
|
||||||
RUN dotnet restore "src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj" --configfile /root/.nuget/NuGet/NuGet.Config
|
|
||||||
RUN dotnet publish "src/Furniture.Service.Grpc/Furniture.Service.Grpc.csproj" -c Release -o /app/publish /p:UseAppHost=false --no-restore
|
|
||||||
|
|
||||||
FROM ${RUNTIME_IMAGE} AS runtime
|
|
||||||
WORKDIR /app
|
|
||||||
ENV ASPNETCORE_ENVIRONMENT=Production
|
|
||||||
EXPOSE 8080
|
|
||||||
EXPOSE 8081
|
|
||||||
COPY --from=build /app/publish .
|
|
||||||
ENTRYPOINT ["dotnet", "Furniture.Service.Grpc.dll"]
|
|
||||||
@ -6,7 +6,6 @@
|
|||||||
- Use cases depend on DAL-facing ports, not persistence implementations.
|
- Use cases depend on DAL-facing ports, not persistence implementations.
|
||||||
- Use cases consume BuildingBlock capability contracts through adapter and port boundaries.
|
- Use cases consume BuildingBlock capability contracts through adapter and port boundaries.
|
||||||
- Transport handlers map to use-case contracts and do not own orchestration logic.
|
- Transport handlers map to use-case contracts and do not own orchestration logic.
|
||||||
- Demo/runtime aliases (`demo-context`, `FURN-*`, `PROD-FURN-*`) are normalized at use-case orchestration before port calls.
|
|
||||||
|
|
||||||
## Current Skeleton
|
## Current Skeleton
|
||||||
|
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
# Furniture Service Contract Package Baseline
|
|
||||||
|
|
||||||
## Feed
|
|
||||||
|
|
||||||
- Source: `https://gitea.dream-views.com/api/packages/AgileWebs/nuget/index.json`
|
|
||||||
- Authentication: Gitea login + token
|
|
||||||
- HTTP requirement: `allowInsecureConnections="true"` in `nuget.config`
|
|
||||||
|
|
||||||
## Published Baseline
|
|
||||||
|
|
||||||
| Package | Version | Published On |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Furniture.Service.Contracts | 0.2.0 | 2026-02-25 |
|
|
||||||
|
|
||||||
## Dependency Note
|
|
||||||
|
|
||||||
`Furniture.Service.Contracts` depends on:
|
|
||||||
|
|
||||||
- `Core.Blueprint.Common` version `0.2.0`
|
|
||||||
|
|
||||||
## Consumer Validation
|
|
||||||
|
|
||||||
Restore validation passed using:
|
|
||||||
|
|
||||||
- `TargetFramework`: `net10.0`
|
|
||||||
- `PackageReference`: `Furniture.Service.Contracts` `0.2.0`
|
|
||||||
- Restore flags: `--no-cache --force`
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
# 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
|
|
||||||
- Depend on Domain and DAL boundaries without direct BuildingBlock ownership
|
|
||||||
|
|
||||||
## Prohibited Responsibilities
|
|
||||||
- Owning business decision rules
|
|
||||||
- Owning persistence decision concerns
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
# 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
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
# Feature Epics
|
|
||||||
|
|
||||||
## Repository
|
|
||||||
furniture-service
|
|
||||||
|
|
||||||
## Core Epics
|
|
||||||
- Epic 1: Expand domain-aligned capabilities for restaurant operations.
|
|
||||||
- Epic 2: Stabilize service contracts for containerized runtime integration.
|
|
||||||
- Epic 3: Improve observability and operational readiness for demo compose environments.
|
|
||||||
|
|
||||||
## Domain-Specific Candidate Features
|
|
||||||
- Order lifecycle consistency and state transitions.
|
|
||||||
- Kitchen queue and dispatch optimization hooks.
|
|
||||||
- Operations control-plane policies (flags, service windows, overrides).
|
|
||||||
- POS closeout and settlement summary alignment.
|
|
||||||
|
|
||||||
## Documentation Contract
|
|
||||||
Any code change in this repository must include docs updates in the same branch.
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
# Containerization Runbook
|
|
||||||
|
|
||||||
## Image Build
|
|
||||||
|
|
||||||
If the repo consumes internal packages from Gitea, pass feed credentials as build args.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build --build-arg NUGET_FEED_USERNAME=<gitea-login> --build-arg NUGET_FEED_TOKEN=<gitea-token> -t agilewebs/furniture-service:dev .
|
|
||||||
```
|
|
||||||
|
|
||||||
## Local Run
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run --rm -p 8080:8080 --name furniture-service agilewebs/furniture-service:dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Health Probe
|
|
||||||
|
|
||||||
- Path: `/health`
|
|
||||||
- Fallback path: `/healthz`
|
|
||||||
- Port: `8080`
|
|
||||||
|
|
||||||
## Runtime Notes
|
|
||||||
|
|
||||||
- Exposes internal service endpoint set plus gRPC runtime surface.
|
|
||||||
|
|
||||||
## Health Endpoint Consistency
|
|
||||||
|
|
||||||
- Canonical probe: `/health`
|
|
||||||
- Compatibility probe: `/healthz`
|
|
||||||
- Container port: `8080`
|
|
||||||
|
|
||||||
## Demo Integration
|
|
||||||
|
|
||||||
- Participates in: **furniture** demo compose stack.
|
|
||||||
- Integration artifact path: `greenfield/demo/furniture/docker-compose.yml`
|
|
||||||
## Known Limitations
|
|
||||||
|
|
||||||
- Current runtime adapters are still predominantly in-memory for deterministic local/demo behavior.
|
|
||||||
- Demo PostgreSQL seeds validate integration contracts and smoke determinism, but do not yet imply full persistence implementation parity.
|
|
||||||
@ -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;
|
||||||
|
|
||||||
|
/// <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}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
using Core.Blueprint.Common.DependencyInjection;
|
using Core.Blueprint.Common.DependencyInjection;
|
||||||
using Furniture.DAL.DependencyInjection;
|
using Furniture.DAL.DependencyInjection;
|
||||||
using Furniture.Domain.Decisions;
|
|
||||||
using Furniture.Service.Application.Adapters;
|
using Furniture.Service.Application.Adapters;
|
||||||
using Furniture.Service.Application.Ports;
|
using Furniture.Service.Application.Ports;
|
||||||
using Furniture.Service.Application.UseCases;
|
using Furniture.Service.Application.UseCases;
|
||||||
@ -23,8 +22,8 @@ public static class FurnitureServiceRuntimeServiceCollectionExtensions
|
|||||||
{
|
{
|
||||||
services.AddBlueprintRuntimeCore();
|
services.AddBlueprintRuntimeCore();
|
||||||
services.AddFurnitureDalRuntime();
|
services.AddFurnitureDalRuntime();
|
||||||
services.TryAddSingleton<IFurnitureAvailabilityDecisionService, FurnitureAvailabilityDecisionService>();
|
|
||||||
|
|
||||||
|
services.TryAddSingleton<IFurnitureAvailabilityContractAdapter, FurnitureAvailabilityContractAdapter>();
|
||||||
services.TryAddSingleton<IFurnitureAvailabilityGrpcContractAdapter, FurnitureAvailabilityGrpcContractAdapter>();
|
services.TryAddSingleton<IFurnitureAvailabilityGrpcContractAdapter, FurnitureAvailabilityGrpcContractAdapter>();
|
||||||
services.TryAddSingleton<IFurnitureAvailabilityReadPort, FurnitureAvailabilityReadPortDalAdapter>();
|
services.TryAddSingleton<IFurnitureAvailabilityReadPort, FurnitureAvailabilityReadPortDalAdapter>();
|
||||||
services.TryAddSingleton<ICatalogProductReadPort, CatalogProductReadPortDalAdapter>();
|
services.TryAddSingleton<ICatalogProductReadPort, CatalogProductReadPortDalAdapter>();
|
||||||
|
|||||||
@ -6,8 +6,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
|
||||||
<PackageReference Include="Furniture.Domain" Version="0.2.0" />
|
<ProjectReference Include="..\..\..\building-block-catalog\src\BuildingBlock.Catalog.Contracts\BuildingBlock.Catalog.Contracts.csproj" />
|
||||||
<PackageReference Include="Furniture.DAL" Version="0.2.0" />
|
<ProjectReference Include="..\..\..\building-block-inventory\src\BuildingBlock.Inventory.Contracts\BuildingBlock.Inventory.Contracts.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\furniture-dal\src\Furniture.DAL\Furniture.DAL.csproj" />
|
||||||
<ProjectReference Include="..\Furniture.Service.Contracts\Furniture.Service.Contracts.csproj" />
|
<ProjectReference Include="..\Furniture.Service.Contracts\Furniture.Service.Contracts.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
|
using Furniture.Service.Application.Adapters;
|
||||||
using Furniture.Service.Application.Ports;
|
using Furniture.Service.Application.Ports;
|
||||||
using Furniture.Service.Contracts.UseCases;
|
using Furniture.Service.Contracts.UseCases;
|
||||||
using Furniture.Domain.Contracts;
|
|
||||||
using Furniture.Domain.Decisions;
|
|
||||||
|
|
||||||
namespace Furniture.Service.Application.UseCases;
|
namespace Furniture.Service.Application.UseCases;
|
||||||
|
|
||||||
@ -9,67 +8,25 @@ namespace Furniture.Service.Application.UseCases;
|
|||||||
/// Default orchestration implementation for furniture availability lookup.
|
/// Default orchestration implementation for furniture availability lookup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class GetFurnitureAvailabilityUseCase(
|
public sealed class GetFurnitureAvailabilityUseCase(
|
||||||
IFurnitureAvailabilityDecisionService decisionService,
|
IFurnitureAvailabilityContractAdapter contractAdapter,
|
||||||
ICatalogProductReadPort catalogReadPort,
|
ICatalogProductReadPort catalogReadPort,
|
||||||
IFurnitureAvailabilityReadPort inventoryReadPort)
|
IFurnitureAvailabilityReadPort inventoryReadPort)
|
||||||
: IGetFurnitureAvailabilityUseCase
|
: IGetFurnitureAvailabilityUseCase
|
||||||
{
|
{
|
||||||
private static readonly IReadOnlyDictionary<string, (string InventoryItemCode, string CatalogProductId)> LookupAliases =
|
|
||||||
new Dictionary<string, (string InventoryItemCode, string CatalogProductId)>(StringComparer.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
["demo-context"] = ("FUR-001", "PRD-001"),
|
|
||||||
["FURN-001"] = ("FUR-001", "PRD-001"),
|
|
||||||
["FURN-002"] = ("FUR-002", "PRD-002"),
|
|
||||||
["FURN-003"] = ("FUR-003", "PRD-003"),
|
|
||||||
["PROD-FURN-001"] = ("FUR-001", "PRD-001"),
|
|
||||||
["PROD-FURN-002"] = ("FUR-002", "PRD-002"),
|
|
||||||
["PROD-FURN-003"] = ("FUR-003", "PRD-003"),
|
|
||||||
["FUR-001"] = ("FUR-001", "PRD-001"),
|
|
||||||
["FUR-002"] = ("FUR-002", "PRD-002"),
|
|
||||||
["FUR-003"] = ("FUR-003", "PRD-003"),
|
|
||||||
["PRD-001"] = ("FUR-001", "PRD-001"),
|
|
||||||
["PRD-002"] = ("FUR-002", "PRD-002"),
|
|
||||||
["PRD-003"] = ("FUR-003", "PRD-003")
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<GetFurnitureAvailabilityResponse> HandleAsync(GetFurnitureAvailabilityRequest request)
|
public async Task<GetFurnitureAvailabilityResponse> HandleAsync(GetFurnitureAvailabilityRequest request)
|
||||||
{
|
{
|
||||||
var domainRequest = new FurnitureAvailabilityDecisionRequest(
|
var catalogRequest = contractAdapter.ToCatalogRequest(request);
|
||||||
request.FurnitureId,
|
var inventoryRequest = contractAdapter.ToInventoryRequest(request);
|
||||||
request.CorrelationId);
|
|
||||||
var lookupKeys = ResolveLookupKeys(request.FurnitureId);
|
|
||||||
|
|
||||||
var catalogRequest = decisionService
|
|
||||||
.BuildCatalogRequest(domainRequest)
|
|
||||||
with { ProductId = lookupKeys.CatalogProductId };
|
|
||||||
var inventoryRequest = decisionService
|
|
||||||
.BuildInventoryRequest(domainRequest)
|
|
||||||
with { ItemCode = lookupKeys.InventoryItemCode };
|
|
||||||
|
|
||||||
var catalogTask = catalogReadPort.ReadProductAsync(catalogRequest);
|
var catalogTask = catalogReadPort.ReadProductAsync(catalogRequest);
|
||||||
var inventoryTask = inventoryReadPort.ReadAvailabilityAsync(inventoryRequest);
|
var inventoryTask = inventoryReadPort.ReadAvailabilityAsync(inventoryRequest);
|
||||||
|
|
||||||
await Task.WhenAll(catalogTask, inventoryTask);
|
await Task.WhenAll(catalogTask, inventoryTask);
|
||||||
|
|
||||||
var domainResponse = decisionService.ComposeResponse(
|
return contractAdapter.ToServiceResponse(
|
||||||
domainRequest,
|
request,
|
||||||
await catalogTask,
|
await catalogTask,
|
||||||
await inventoryTask);
|
await inventoryTask);
|
||||||
|
|
||||||
return new GetFurnitureAvailabilityResponse(
|
|
||||||
domainResponse.FurnitureId,
|
|
||||||
domainResponse.DisplayName,
|
|
||||||
domainResponse.QuantityAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (string InventoryItemCode, string CatalogProductId) ResolveLookupKeys(string furnitureId)
|
|
||||||
{
|
|
||||||
if (LookupAliases.TryGetValue(furnitureId, out var mappedKeys))
|
|
||||||
{
|
|
||||||
return mappedKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (furnitureId, furnitureId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,6 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Core.Blueprint.Common" Version="0.2.0" />
|
<ProjectReference Include="..\..\..\blueprint-platform\src\Core.Blueprint.Common\Core.Blueprint.Common.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,16 +1,7 @@
|
|||||||
using Furniture.Service.Application.DependencyInjection;
|
using Furniture.Service.Application.DependencyInjection;
|
||||||
using Furniture.Service.Grpc.Services;
|
using Furniture.Service.Grpc.Services;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
var httpPort = builder.Configuration.GetValue("FurnitureService:HttpPort", 8080);
|
|
||||||
var grpcPort = builder.Configuration.GetValue("FurnitureService:GrpcPort", 8081);
|
|
||||||
|
|
||||||
builder.WebHost.ConfigureKestrel(options =>
|
|
||||||
{
|
|
||||||
options.ListenAnyIP(httpPort, listenOptions => listenOptions.Protocols = HttpProtocols.Http1);
|
|
||||||
options.ListenAnyIP(grpcPort, listenOptions => listenOptions.Protocols = HttpProtocols.Http2);
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddGrpc();
|
builder.Services.AddGrpc();
|
||||||
builder.Services.AddHealthChecks();
|
builder.Services.AddHealthChecks();
|
||||||
@ -20,6 +11,5 @@ var app = builder.Build();
|
|||||||
|
|
||||||
app.MapGrpcService<FurnitureRuntimeGrpcService>();
|
app.MapGrpcService<FurnitureRuntimeGrpcService>();
|
||||||
app.MapHealthChecks("/healthz");
|
app.MapHealthChecks("/healthz");
|
||||||
app.MapHealthChecks("/health");
|
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|||||||
@ -4,11 +4,10 @@ using BuildingBlock.Catalog.Contracts.Responses;
|
|||||||
using BuildingBlock.Inventory.Contracts.Conventions;
|
using BuildingBlock.Inventory.Contracts.Conventions;
|
||||||
using BuildingBlock.Inventory.Contracts.Requests;
|
using BuildingBlock.Inventory.Contracts.Requests;
|
||||||
using BuildingBlock.Inventory.Contracts.Responses;
|
using BuildingBlock.Inventory.Contracts.Responses;
|
||||||
|
using Furniture.Service.Application.Adapters;
|
||||||
using Furniture.Service.Application.Ports;
|
using Furniture.Service.Application.Ports;
|
||||||
using Furniture.Service.Application.UseCases;
|
using Furniture.Service.Application.UseCases;
|
||||||
using Furniture.Service.Contracts.UseCases;
|
using Furniture.Service.Contracts.UseCases;
|
||||||
using Furniture.Domain.Contracts;
|
|
||||||
using Furniture.Domain.Decisions;
|
|
||||||
|
|
||||||
namespace Furniture.Service.Application.UnitTests;
|
namespace Furniture.Service.Application.UnitTests;
|
||||||
|
|
||||||
@ -17,10 +16,10 @@ public class GetFurnitureAvailabilityUseCaseTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task HandleAsync_WhenCalled_DelegatesToReadPort()
|
public async Task HandleAsync_WhenCalled_DelegatesToReadPort()
|
||||||
{
|
{
|
||||||
var decisionService = new FakeFurnitureAvailabilityDecisionService();
|
var adapter = new FakeFurnitureAvailabilityContractAdapter();
|
||||||
var catalogPort = new FakeCatalogProductReadPort();
|
var catalogPort = new FakeCatalogProductReadPort();
|
||||||
var inventoryPort = new FakeFurnitureAvailabilityReadPort();
|
var inventoryPort = new FakeFurnitureAvailabilityReadPort();
|
||||||
var useCase = new GetFurnitureAvailabilityUseCase(decisionService, catalogPort, inventoryPort);
|
var useCase = new GetFurnitureAvailabilityUseCase(adapter, catalogPort, inventoryPort);
|
||||||
|
|
||||||
var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FUR-001", "corr-123"));
|
var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FUR-001", "corr-123"));
|
||||||
|
|
||||||
@ -29,9 +28,9 @@ public class GetFurnitureAvailabilityUseCaseTests
|
|||||||
Assert.Equal(10, response.QuantityAvailable);
|
Assert.Equal(10, response.QuantityAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class FakeFurnitureAvailabilityDecisionService : IFurnitureAvailabilityDecisionService
|
private sealed class FakeFurnitureAvailabilityContractAdapter : IFurnitureAvailabilityContractAdapter
|
||||||
{
|
{
|
||||||
public ProductContract BuildCatalogRequest(FurnitureAvailabilityDecisionRequest request)
|
public ProductContract ToCatalogRequest(GetFurnitureAvailabilityRequest request)
|
||||||
{
|
{
|
||||||
return new ProductContract(
|
return new ProductContract(
|
||||||
new CatalogContractEnvelope("1.0.0", request.CorrelationId),
|
new CatalogContractEnvelope("1.0.0", request.CorrelationId),
|
||||||
@ -39,19 +38,19 @@ public class GetFurnitureAvailabilityUseCaseTests
|
|||||||
string.Empty);
|
string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InventoryItemLookupRequest BuildInventoryRequest(FurnitureAvailabilityDecisionRequest request)
|
public InventoryItemLookupRequest ToInventoryRequest(GetFurnitureAvailabilityRequest request)
|
||||||
{
|
{
|
||||||
return new InventoryItemLookupRequest(
|
return new InventoryItemLookupRequest(
|
||||||
new InventoryContractEnvelope("1.0.0", request.CorrelationId),
|
new InventoryContractEnvelope("1.0.0", request.CorrelationId),
|
||||||
request.FurnitureId);
|
request.FurnitureId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FurnitureAvailabilityDecisionResponse ComposeResponse(
|
public GetFurnitureAvailabilityResponse ToServiceResponse(
|
||||||
FurnitureAvailabilityDecisionRequest request,
|
GetFurnitureAvailabilityRequest request,
|
||||||
ProductContractResponse catalogResponse,
|
ProductContractResponse catalogResponse,
|
||||||
InventoryItemLookupResponse inventoryResponse)
|
InventoryItemLookupResponse inventoryResponse)
|
||||||
{
|
{
|
||||||
return new FurnitureAvailabilityDecisionResponse(
|
return new GetFurnitureAvailabilityResponse(
|
||||||
request.FurnitureId,
|
request.FurnitureId,
|
||||||
catalogResponse.DisplayName,
|
catalogResponse.DisplayName,
|
||||||
inventoryResponse.QuantityAvailable);
|
inventoryResponse.QuantityAvailable);
|
||||||
|
|||||||
@ -21,23 +21,6 @@ public class RuntimeWiringTests
|
|||||||
var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FUR-001", "corr-123"));
|
var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FUR-001", "corr-123"));
|
||||||
|
|
||||||
Assert.Equal("FUR-001", response.FurnitureId);
|
Assert.Equal("FUR-001", response.FurnitureId);
|
||||||
Assert.Equal("Contoso Lounge Chair", response.DisplayName);
|
|
||||||
Assert.Equal(8, response.QuantityAvailable);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task AddFurnitureServiceRuntime_WhenUsingDemoFurnitureAlias_ResolvesMappedAvailability()
|
|
||||||
{
|
|
||||||
var services = new ServiceCollection();
|
|
||||||
services.AddFurnitureServiceRuntime();
|
|
||||||
|
|
||||||
using var provider = services.BuildServiceProvider();
|
|
||||||
var useCase = provider.GetRequiredService<IGetFurnitureAvailabilityUseCase>();
|
|
||||||
|
|
||||||
var response = await useCase.HandleAsync(new GetFurnitureAvailabilityRequest("FURN-001", "corr-123"));
|
|
||||||
|
|
||||||
Assert.Equal("FURN-001", response.FurnitureId);
|
|
||||||
Assert.Equal("Contoso Lounge Chair", response.DisplayName);
|
|
||||||
Assert.Equal(8, response.QuantityAvailable);
|
Assert.Equal(8, response.QuantityAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user