feat(contracts): add transport-neutral inventory contracts

- WHY: align inventory capability contracts with protocol-agnostic integration boundaries
- WHAT: add contract conventions, grpc adapter surfaces, and blueprint descriptor consumption
- RULE: enforce building-block to blueprint dependency direction
This commit is contained in:
José René White Enciso 2026-02-22 02:57:11 -06:00
parent c1cef614ba
commit b24d4009ed
12 changed files with 124 additions and 10 deletions

View File

@ -3,15 +3,23 @@ skinparam packageStyle rectangle
package "building-block-inventory" {
package "BuildingBlock.Inventory.Contracts" {
class Conventions
class Requests
class Responses
interface Adapters
class Grpc
interface Abstractions
}
}
package "blueprint-platform" {
interface IBlueprintPackageContract
}
package "furniture-service" as FurnitureService
package "furniture-bff" as FurnitureBff
Conventions ..> IBlueprintPackageContract
FurnitureService --> Requests
FurnitureService --> Responses
FurnitureBff --> Requests

View File

@ -4,14 +4,18 @@
- `BuildingBlock.Inventory.Contracts`
## Current Contract Groups
## Contract Groups
- `Conventions`: transport-neutral request/response and envelope conventions.
- `Requests`: capability request shapes for inventory use cases.
- `Responses`: capability response shapes for inventory use cases.
- `Abstractions`: marker abstractions for inventory contract ownership.
- `Adapters`: protocol adapter boundaries.
- `Grpc`: gRPC contract shapes for adapter translation.
## Ownership Boundary
- This repository owns inventory capability contracts only.
- Contract metadata consumes `Core.Blueprint.Common.Contracts` and does not redefine Blueprint contracts.
- Implementation details stay in furniture-service, furniture-bff, or furniture-dal.
- Identity abstractions are out of scope and remain Thalos-owned.

View File

@ -6,7 +6,12 @@
- Breaking changes require a new major package version.
- Deprecated members should remain for at least one release cycle.
## Blueprint Compatibility
- Package descriptor metadata is implemented via `IBlueprintPackageContract` from `Core.Blueprint.Common.Contracts`.
- Inventory contracts consume Blueprint common contract primitives rather than redefining them.
## Compatibility Notes
- Consumer repositories (`furniture-service`, `furniture-bff`) should update contracts explicitly.
- Transport adapters remain outside this contracts package.
- Protocol adapters remain edge concerns; inventory contracts remain transport-neutral.

View File

@ -0,0 +1,25 @@
using BuildingBlock.Inventory.Contracts.Grpc;
using BuildingBlock.Inventory.Contracts.Requests;
using BuildingBlock.Inventory.Contracts.Responses;
namespace BuildingBlock.Inventory.Contracts.Adapters;
/// <summary>
/// Defines adapter boundary for gRPC contract translation.
/// </summary>
public interface IInventoryGrpcContractAdapter
{
/// <summary>
/// Maps transport-neutral request into gRPC contract shape.
/// </summary>
/// <param name="request">Transport-neutral inventory lookup request.</param>
/// <returns>gRPC contract request shape.</returns>
InventoryItemLookupGrpcContract ToGrpcRequest(InventoryItemLookupRequest request);
/// <summary>
/// Maps gRPC contract response data into transport-neutral response.
/// </summary>
/// <param name="contract">gRPC contract response shape.</param>
/// <returns>Transport-neutral inventory lookup response.</returns>
InventoryItemLookupResponse FromGrpcResponse(InventoryItemLookupGrpcContract contract);
}

View File

@ -4,4 +4,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\blueprint-platform\src\Core.Blueprint.Common\Core.Blueprint.Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,9 @@
namespace BuildingBlock.Inventory.Contracts.Conventions;
/// <summary>
/// Defines transport-neutral request contract shape for inventory capability operations.
/// </summary>
/// <typeparam name="TResponse">Response contract type.</typeparam>
public interface IInventoryContractRequest<out TResponse>
{
}

View File

@ -0,0 +1,8 @@
namespace BuildingBlock.Inventory.Contracts.Conventions;
/// <summary>
/// Defines transport-neutral envelope metadata for inventory contract messages.
/// </summary>
/// <param name="ContractVersion">Contract schema version.</param>
/// <param name="CorrelationId">Correlation identifier for cross-service tracing.</param>
public sealed record InventoryContractEnvelope(string ContractVersion, string CorrelationId);

View File

@ -0,0 +1,15 @@
using Core.Blueprint.Common.Contracts;
namespace BuildingBlock.Inventory.Contracts.Conventions;
/// <summary>
/// Defines package descriptor metadata for inventory contracts package.
/// </summary>
public sealed class InventoryPackageContract : IBlueprintPackageContract
{
/// <inheritdoc />
public BlueprintPackageDescriptor Descriptor { get; } = new(
"BuildingBlock.Inventory.Contracts",
PackageVersionPolicy.Minor,
["Core.Blueprint.Common"]);
}

View File

@ -0,0 +1,7 @@
namespace BuildingBlock.Inventory.Contracts.Grpc;
/// <summary>
/// Defines minimal gRPC contract shape for adapter-level translation.
/// </summary>
/// <param name="ItemCode">External item identifier.</param>
public sealed record InventoryItemLookupGrpcContract(string ItemCode);

View File

@ -1,7 +1,13 @@
using BuildingBlock.Inventory.Contracts.Conventions;
namespace BuildingBlock.Inventory.Contracts.Requests;
/// <summary>
/// Represents the contract request to lookup an inventory item.
/// Represents the transport-neutral contract request to lookup an inventory item.
/// </summary>
/// <param name="Envelope">Contract envelope metadata.</param>
/// <param name="ItemCode">External item identifier.</param>
public sealed record InventoryItemLookupRequest(string ItemCode);
public sealed record InventoryItemLookupRequest(
InventoryContractEnvelope Envelope,
string ItemCode)
: IInventoryContractRequest<Responses.InventoryItemLookupResponse>;

View File

@ -1,8 +1,14 @@
using BuildingBlock.Inventory.Contracts.Conventions;
namespace BuildingBlock.Inventory.Contracts.Responses;
/// <summary>
/// Represents the contract response for an inventory item lookup.
/// Represents the transport-neutral contract response for an inventory item lookup.
/// </summary>
/// <param name="Envelope">Contract envelope metadata.</param>
/// <param name="ItemCode">External item identifier.</param>
/// <param name="QuantityAvailable">Current quantity available.</param>
public sealed record InventoryItemLookupResponse(string ItemCode, int QuantityAvailable);
public sealed record InventoryItemLookupResponse(
InventoryContractEnvelope Envelope,
string ItemCode,
int QuantityAvailable);

View File

@ -1,24 +1,42 @@
using BuildingBlock.Inventory.Contracts.Conventions;
using BuildingBlock.Inventory.Contracts.Requests;
using BuildingBlock.Inventory.Contracts.Responses;
using Core.Blueprint.Common.Contracts;
namespace BuildingBlock.Inventory.Contracts.UnitTests;
public class ContractShapeTests
{
[Fact]
public void InventoryItemLookupRequest_WhenCreated_StoresItemCode()
public void InventoryItemLookupRequest_WhenCreated_StoresTransportNeutralData()
{
var request = new InventoryItemLookupRequest("SKU-001");
var envelope = new InventoryContractEnvelope("1.0.0", "corr-123");
var request = new InventoryItemLookupRequest(envelope, "SKU-001");
Assert.Equal("1.0.0", request.Envelope.ContractVersion);
Assert.Equal("corr-123", request.Envelope.CorrelationId);
Assert.Equal("SKU-001", request.ItemCode);
}
[Fact]
public void InventoryItemLookupResponse_WhenCreated_StoresContractData()
public void InventoryItemLookupResponse_WhenCreated_StoresTransportNeutralData()
{
var response = new InventoryItemLookupResponse("SKU-001", 5);
var envelope = new InventoryContractEnvelope("1.0.0", "corr-123");
var response = new InventoryItemLookupResponse(envelope, "SKU-001", 5);
Assert.Equal("1.0.0", response.Envelope.ContractVersion);
Assert.Equal("corr-123", response.Envelope.CorrelationId);
Assert.Equal("SKU-001", response.ItemCode);
Assert.Equal(5, response.QuantityAvailable);
}
[Fact]
public void InventoryPackageContract_WhenCreated_UsesBlueprintDescriptorContract()
{
IBlueprintPackageContract contract = new InventoryPackageContract();
Assert.Equal("BuildingBlock.Inventory.Contracts", contract.Descriptor.PackageId);
Assert.Equal(PackageVersionPolicy.Minor, contract.Descriptor.VersionPolicy);
Assert.Contains("Core.Blueprint.Common", contract.Descriptor.DependencyPackageIds);
}
}