From b24d4009ed9e56375354c33b75e27db903c61069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ren=C3=A9=20White=20Enciso?= Date: Sun, 22 Feb 2026 02:57:11 -0600 Subject: [PATCH] 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 --- .../inventory-contract-boundary.puml | 8 ++++++ docs/contracts/inventory-contract-catalog.md | 6 ++++- docs/contracts/inventory-versioning-policy.md | 7 ++++- .../Adapters/IInventoryGrpcContractAdapter.cs | 25 ++++++++++++++++++ .../BuildingBlock.Inventory.Contracts.csproj | 3 +++ .../Conventions/IInventoryContractRequest.cs | 9 +++++++ .../Conventions/InventoryContractEnvelope.cs | 8 ++++++ .../Conventions/InventoryPackageContract.cs | 15 +++++++++++ .../Grpc/InventoryItemLookupGrpcContract.cs | 7 +++++ .../Requests/InventoryItemLookupRequest.cs | 10 +++++-- .../Responses/InventoryItemLookupResponse.cs | 10 +++++-- .../ContractShapeTests.cs | 26 ++++++++++++++++--- 12 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 src/BuildingBlock.Inventory.Contracts/Adapters/IInventoryGrpcContractAdapter.cs create mode 100644 src/BuildingBlock.Inventory.Contracts/Conventions/IInventoryContractRequest.cs create mode 100644 src/BuildingBlock.Inventory.Contracts/Conventions/InventoryContractEnvelope.cs create mode 100644 src/BuildingBlock.Inventory.Contracts/Conventions/InventoryPackageContract.cs create mode 100644 src/BuildingBlock.Inventory.Contracts/Grpc/InventoryItemLookupGrpcContract.cs diff --git a/docs/architecture/inventory-contract-boundary.puml b/docs/architecture/inventory-contract-boundary.puml index b9b5d0d..76c8e6c 100644 --- a/docs/architecture/inventory-contract-boundary.puml +++ b/docs/architecture/inventory-contract-boundary.puml @@ -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 diff --git a/docs/contracts/inventory-contract-catalog.md b/docs/contracts/inventory-contract-catalog.md index 40a05be..36a2403 100644 --- a/docs/contracts/inventory-contract-catalog.md +++ b/docs/contracts/inventory-contract-catalog.md @@ -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. diff --git a/docs/contracts/inventory-versioning-policy.md b/docs/contracts/inventory-versioning-policy.md index fcb862c..0fbd395 100644 --- a/docs/contracts/inventory-versioning-policy.md +++ b/docs/contracts/inventory-versioning-policy.md @@ -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. diff --git a/src/BuildingBlock.Inventory.Contracts/Adapters/IInventoryGrpcContractAdapter.cs b/src/BuildingBlock.Inventory.Contracts/Adapters/IInventoryGrpcContractAdapter.cs new file mode 100644 index 0000000..f6f6d8e --- /dev/null +++ b/src/BuildingBlock.Inventory.Contracts/Adapters/IInventoryGrpcContractAdapter.cs @@ -0,0 +1,25 @@ +using BuildingBlock.Inventory.Contracts.Grpc; +using BuildingBlock.Inventory.Contracts.Requests; +using BuildingBlock.Inventory.Contracts.Responses; + +namespace BuildingBlock.Inventory.Contracts.Adapters; + +/// +/// Defines adapter boundary for gRPC contract translation. +/// +public interface IInventoryGrpcContractAdapter +{ + /// + /// Maps transport-neutral request into gRPC contract shape. + /// + /// Transport-neutral inventory lookup request. + /// gRPC contract request shape. + InventoryItemLookupGrpcContract ToGrpcRequest(InventoryItemLookupRequest request); + + /// + /// Maps gRPC contract response data into transport-neutral response. + /// + /// gRPC contract response shape. + /// Transport-neutral inventory lookup response. + InventoryItemLookupResponse FromGrpcResponse(InventoryItemLookupGrpcContract contract); +} diff --git a/src/BuildingBlock.Inventory.Contracts/BuildingBlock.Inventory.Contracts.csproj b/src/BuildingBlock.Inventory.Contracts/BuildingBlock.Inventory.Contracts.csproj index 6c3a887..04a4bbc 100644 --- a/src/BuildingBlock.Inventory.Contracts/BuildingBlock.Inventory.Contracts.csproj +++ b/src/BuildingBlock.Inventory.Contracts/BuildingBlock.Inventory.Contracts.csproj @@ -4,4 +4,7 @@ enable enable + + + diff --git a/src/BuildingBlock.Inventory.Contracts/Conventions/IInventoryContractRequest.cs b/src/BuildingBlock.Inventory.Contracts/Conventions/IInventoryContractRequest.cs new file mode 100644 index 0000000..b89977a --- /dev/null +++ b/src/BuildingBlock.Inventory.Contracts/Conventions/IInventoryContractRequest.cs @@ -0,0 +1,9 @@ +namespace BuildingBlock.Inventory.Contracts.Conventions; + +/// +/// Defines transport-neutral request contract shape for inventory capability operations. +/// +/// Response contract type. +public interface IInventoryContractRequest +{ +} diff --git a/src/BuildingBlock.Inventory.Contracts/Conventions/InventoryContractEnvelope.cs b/src/BuildingBlock.Inventory.Contracts/Conventions/InventoryContractEnvelope.cs new file mode 100644 index 0000000..c711a2f --- /dev/null +++ b/src/BuildingBlock.Inventory.Contracts/Conventions/InventoryContractEnvelope.cs @@ -0,0 +1,8 @@ +namespace BuildingBlock.Inventory.Contracts.Conventions; + +/// +/// Defines transport-neutral envelope metadata for inventory contract messages. +/// +/// Contract schema version. +/// Correlation identifier for cross-service tracing. +public sealed record InventoryContractEnvelope(string ContractVersion, string CorrelationId); diff --git a/src/BuildingBlock.Inventory.Contracts/Conventions/InventoryPackageContract.cs b/src/BuildingBlock.Inventory.Contracts/Conventions/InventoryPackageContract.cs new file mode 100644 index 0000000..2b09400 --- /dev/null +++ b/src/BuildingBlock.Inventory.Contracts/Conventions/InventoryPackageContract.cs @@ -0,0 +1,15 @@ +using Core.Blueprint.Common.Contracts; + +namespace BuildingBlock.Inventory.Contracts.Conventions; + +/// +/// Defines package descriptor metadata for inventory contracts package. +/// +public sealed class InventoryPackageContract : IBlueprintPackageContract +{ + /// + public BlueprintPackageDescriptor Descriptor { get; } = new( + "BuildingBlock.Inventory.Contracts", + PackageVersionPolicy.Minor, + ["Core.Blueprint.Common"]); +} diff --git a/src/BuildingBlock.Inventory.Contracts/Grpc/InventoryItemLookupGrpcContract.cs b/src/BuildingBlock.Inventory.Contracts/Grpc/InventoryItemLookupGrpcContract.cs new file mode 100644 index 0000000..bacb46c --- /dev/null +++ b/src/BuildingBlock.Inventory.Contracts/Grpc/InventoryItemLookupGrpcContract.cs @@ -0,0 +1,7 @@ +namespace BuildingBlock.Inventory.Contracts.Grpc; + +/// +/// Defines minimal gRPC contract shape for adapter-level translation. +/// +/// External item identifier. +public sealed record InventoryItemLookupGrpcContract(string ItemCode); diff --git a/src/BuildingBlock.Inventory.Contracts/Requests/InventoryItemLookupRequest.cs b/src/BuildingBlock.Inventory.Contracts/Requests/InventoryItemLookupRequest.cs index fceb943..b1728d0 100644 --- a/src/BuildingBlock.Inventory.Contracts/Requests/InventoryItemLookupRequest.cs +++ b/src/BuildingBlock.Inventory.Contracts/Requests/InventoryItemLookupRequest.cs @@ -1,7 +1,13 @@ +using BuildingBlock.Inventory.Contracts.Conventions; + namespace BuildingBlock.Inventory.Contracts.Requests; /// -/// Represents the contract request to lookup an inventory item. +/// Represents the transport-neutral contract request to lookup an inventory item. /// +/// Contract envelope metadata. /// External item identifier. -public sealed record InventoryItemLookupRequest(string ItemCode); +public sealed record InventoryItemLookupRequest( + InventoryContractEnvelope Envelope, + string ItemCode) + : IInventoryContractRequest; diff --git a/src/BuildingBlock.Inventory.Contracts/Responses/InventoryItemLookupResponse.cs b/src/BuildingBlock.Inventory.Contracts/Responses/InventoryItemLookupResponse.cs index c612e5a..643e2ac 100644 --- a/src/BuildingBlock.Inventory.Contracts/Responses/InventoryItemLookupResponse.cs +++ b/src/BuildingBlock.Inventory.Contracts/Responses/InventoryItemLookupResponse.cs @@ -1,8 +1,14 @@ +using BuildingBlock.Inventory.Contracts.Conventions; + namespace BuildingBlock.Inventory.Contracts.Responses; /// -/// Represents the contract response for an inventory item lookup. +/// Represents the transport-neutral contract response for an inventory item lookup. /// +/// Contract envelope metadata. /// External item identifier. /// Current quantity available. -public sealed record InventoryItemLookupResponse(string ItemCode, int QuantityAvailable); +public sealed record InventoryItemLookupResponse( + InventoryContractEnvelope Envelope, + string ItemCode, + int QuantityAvailable); diff --git a/tests/BuildingBlock.Inventory.Contracts.UnitTests/ContractShapeTests.cs b/tests/BuildingBlock.Inventory.Contracts.UnitTests/ContractShapeTests.cs index e1bbe17..999bd66 100644 --- a/tests/BuildingBlock.Inventory.Contracts.UnitTests/ContractShapeTests.cs +++ b/tests/BuildingBlock.Inventory.Contracts.UnitTests/ContractShapeTests.cs @@ -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); + } }