chore(furniture-dal): merge contract integration branch
This commit is contained in:
commit
20cbe1bb3b
@ -2,14 +2,28 @@
|
||||
skinparam packageStyle rectangle
|
||||
|
||||
package "furniture-dal" {
|
||||
class FurnitureAvailabilityLookupRequest
|
||||
class FurnitureAvailabilityRecord
|
||||
class CatalogProductLookupRequest
|
||||
class CatalogProductProjectionRecord
|
||||
interface IFurnitureDalGrpcContractAdapter
|
||||
interface ICatalogProjectionContractAdapter
|
||||
interface IFurnitureDataProvider
|
||||
interface ICatalogDataProvider
|
||||
interface IFurnitureRepository
|
||||
interface ICatalogRepository
|
||||
interface ICacheInvalidationPolicy
|
||||
|
||||
IFurnitureDalGrpcContractAdapter --> FurnitureAvailabilityLookupRequest
|
||||
IFurnitureDalGrpcContractAdapter --> CatalogProductLookupRequest
|
||||
ICatalogProjectionContractAdapter --> CatalogProductLookupRequest
|
||||
ICatalogProjectionContractAdapter --> CatalogProductProjectionRecord
|
||||
IFurnitureRepository --> IFurnitureDataProvider
|
||||
IFurnitureRepository --> FurnitureAvailabilityLookupRequest
|
||||
IFurnitureRepository --> FurnitureAvailabilityRecord
|
||||
ICatalogRepository --> ICatalogDataProvider
|
||||
ICatalogRepository --> CatalogProductLookupRequest
|
||||
ICatalogRepository --> CatalogProductProjectionRecord
|
||||
IFurnitureRepository --> ICacheInvalidationPolicy
|
||||
ICatalogRepository --> ICacheInvalidationPolicy
|
||||
}
|
||||
|
||||
@ -5,8 +5,10 @@
|
||||
- Repositories coordinate provider calls for aggregate persistence.
|
||||
- Cache invalidation policy is owned by DAL.
|
||||
- Service layer does not implement persistence or cache invalidation details.
|
||||
- Cache invalidation boundaries are expressed through DAL contract interfaces.
|
||||
|
||||
## Policy
|
||||
|
||||
- Persistence writes must define cache invalidation triggers.
|
||||
- Cache keys and invalidation behavior are centralized in DAL policy definitions.
|
||||
- This stage defines contracts, ports, and adapters only; no persistence implementation is introduced.
|
||||
|
||||
@ -4,9 +4,14 @@
|
||||
|
||||
- `IFurnitureDataProvider`: furniture persistence provider boundary.
|
||||
- `ICatalogDataProvider`: catalog persistence provider boundary.
|
||||
- `IFurnitureRepository`: furniture DAL composition boundary.
|
||||
- `ICatalogRepository`: catalog DAL composition boundary.
|
||||
- `ICatalogProjectionContractAdapter`: building-block catalog to DAL contract adapter boundary.
|
||||
- `IFurnitureDalGrpcContractAdapter`: gRPC translation boundary for DAL contracts.
|
||||
|
||||
## Rules
|
||||
|
||||
- Providers encapsulate datastore-specific access.
|
||||
- Providers do not contain orchestration concerns.
|
||||
- Provider contracts are consumed by DAL repositories.
|
||||
- Repository and adapter boundaries expose contracts only in this stage.
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
using BuildingBlock.Catalog.Contracts.Products;
|
||||
using BuildingBlock.Catalog.Contracts.Responses;
|
||||
using Furniture.DAL.Contracts;
|
||||
|
||||
namespace Furniture.DAL.Adapters;
|
||||
|
||||
/// <summary>
|
||||
/// Defines adapter boundary between catalog building block contracts and furniture dal contracts.
|
||||
/// </summary>
|
||||
public interface ICatalogProjectionContractAdapter
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps catalog capability product contract into dal lookup request.
|
||||
/// </summary>
|
||||
/// <param name="contract">Catalog product contract.</param>
|
||||
/// <returns>Catalog product lookup request contract.</returns>
|
||||
CatalogProductLookupRequest ToDalRequest(ProductContract contract);
|
||||
|
||||
/// <summary>
|
||||
/// Maps dal catalog projection record into catalog capability response contract.
|
||||
/// </summary>
|
||||
/// <param name="record">Catalog product projection record.</param>
|
||||
/// <returns>Catalog product response contract.</returns>
|
||||
ProductContractResponse ToCatalogResponse(CatalogProductProjectionRecord record);
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
using Furniture.DAL.Contracts;
|
||||
using Furniture.DAL.Grpc;
|
||||
|
||||
namespace Furniture.DAL.Adapters;
|
||||
|
||||
/// <summary>
|
||||
/// Defines adapter boundary for furniture dal gRPC contract translation.
|
||||
/// </summary>
|
||||
public interface IFurnitureDalGrpcContractAdapter
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps transport-neutral availability lookup request to gRPC contract shape.
|
||||
/// </summary>
|
||||
/// <param name="request">Furniture availability lookup request contract.</param>
|
||||
/// <returns>gRPC availability request contract.</returns>
|
||||
FurnitureAvailabilityDalGrpcContract ToGrpcAvailabilityRequest(FurnitureAvailabilityLookupRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Maps gRPC availability contract shape to transport-neutral request.
|
||||
/// </summary>
|
||||
/// <param name="contract">gRPC availability request contract.</param>
|
||||
/// <returns>Furniture availability lookup request contract.</returns>
|
||||
FurnitureAvailabilityLookupRequest FromGrpcAvailabilityRequest(FurnitureAvailabilityDalGrpcContract contract);
|
||||
|
||||
/// <summary>
|
||||
/// Maps transport-neutral catalog lookup request to gRPC contract shape.
|
||||
/// </summary>
|
||||
/// <param name="request">Catalog product lookup request contract.</param>
|
||||
/// <returns>gRPC catalog request contract.</returns>
|
||||
CatalogProductDalGrpcContract ToGrpcCatalogRequest(CatalogProductLookupRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Maps gRPC catalog contract shape to transport-neutral request.
|
||||
/// </summary>
|
||||
/// <param name="contract">gRPC catalog request contract.</param>
|
||||
/// <returns>Catalog product lookup request contract.</returns>
|
||||
CatalogProductLookupRequest FromGrpcCatalogRequest(CatalogProductDalGrpcContract contract);
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
using Furniture.DAL.Contracts;
|
||||
|
||||
namespace Furniture.DAL.Caching;
|
||||
|
||||
/// <summary>
|
||||
@ -5,4 +7,17 @@ namespace Furniture.DAL.Caching;
|
||||
/// </summary>
|
||||
public interface ICacheInvalidationPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds cache key for a furniture availability request.
|
||||
/// </summary>
|
||||
/// <param name="request">Furniture availability lookup request contract.</param>
|
||||
/// <returns>Cache key string.</returns>
|
||||
string BuildAvailabilityKey(FurnitureAvailabilityLookupRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Resolves cache invalidation keys for a mutation request boundary.
|
||||
/// </summary>
|
||||
/// <param name="request">Cache invalidation request contract.</param>
|
||||
/// <returns>Cache keys to invalidate.</returns>
|
||||
IReadOnlyList<string> ResolveInvalidationKeys(FurnitureCacheInvalidationRequest request);
|
||||
}
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Furniture.DAL.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request contract for catalog product lookup.
|
||||
/// </summary>
|
||||
/// <param name="Envelope">Contract envelope metadata.</param>
|
||||
/// <param name="ProductId">Catalog product identifier.</param>
|
||||
public sealed record CatalogProductLookupRequest(FurnitureDalContractEnvelope Envelope, string ProductId);
|
||||
@ -0,0 +1,12 @@
|
||||
namespace Furniture.DAL.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Response contract representing catalog product projection data.
|
||||
/// </summary>
|
||||
/// <param name="Envelope">Contract envelope metadata.</param>
|
||||
/// <param name="ProductId">Catalog product identifier.</param>
|
||||
/// <param name="DisplayName">Catalog display name.</param>
|
||||
public sealed record CatalogProductProjectionRecord(
|
||||
FurnitureDalContractEnvelope Envelope,
|
||||
string ProductId,
|
||||
string DisplayName);
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Furniture.DAL.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request contract for furniture availability lookup.
|
||||
/// </summary>
|
||||
/// <param name="Envelope">Contract envelope metadata.</param>
|
||||
/// <param name="FurnitureId">Furniture aggregate identifier.</param>
|
||||
public sealed record FurnitureAvailabilityLookupRequest(FurnitureDalContractEnvelope Envelope, string FurnitureId);
|
||||
12
src/Furniture.DAL/Contracts/FurnitureAvailabilityRecord.cs
Normal file
12
src/Furniture.DAL/Contracts/FurnitureAvailabilityRecord.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace Furniture.DAL.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Response contract representing persisted furniture availability data.
|
||||
/// </summary>
|
||||
/// <param name="Envelope">Contract envelope metadata.</param>
|
||||
/// <param name="FurnitureId">Furniture aggregate identifier.</param>
|
||||
/// <param name="QuantityAvailable">Current quantity available.</param>
|
||||
public sealed record FurnitureAvailabilityRecord(
|
||||
FurnitureDalContractEnvelope Envelope,
|
||||
string FurnitureId,
|
||||
int QuantityAvailable);
|
||||
@ -0,0 +1,12 @@
|
||||
namespace Furniture.DAL.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Request contract for cache invalidation boundaries.
|
||||
/// </summary>
|
||||
/// <param name="Envelope">Contract envelope metadata.</param>
|
||||
/// <param name="FurnitureId">Furniture aggregate identifier that changed.</param>
|
||||
/// <param name="Reason">Invalidation reason code.</param>
|
||||
public sealed record FurnitureCacheInvalidationRequest(
|
||||
FurnitureDalContractEnvelope Envelope,
|
||||
string FurnitureId,
|
||||
string Reason);
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Furniture.DAL.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Defines transport-neutral envelope metadata for furniture dal contract messages.
|
||||
/// </summary>
|
||||
/// <param name="ContractVersion">Contract schema version.</param>
|
||||
/// <param name="CorrelationId">Correlation identifier for cross-layer tracing.</param>
|
||||
public sealed record FurnitureDalContractEnvelope(string ContractVersion, string CorrelationId);
|
||||
15
src/Furniture.DAL/Contracts/FurnitureDalPackageContract.cs
Normal file
15
src/Furniture.DAL/Contracts/FurnitureDalPackageContract.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Core.Blueprint.Common.Contracts;
|
||||
|
||||
namespace Furniture.DAL.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Defines package descriptor metadata for furniture dal contracts.
|
||||
/// </summary>
|
||||
public sealed class FurnitureDalPackageContract : IBlueprintPackageContract
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public BlueprintPackageDescriptor Descriptor { get; } = new(
|
||||
"Furniture.DAL.Contracts",
|
||||
PackageVersionPolicy.Minor,
|
||||
["Core.Blueprint.Common", "BuildingBlock.Catalog.Contracts"]);
|
||||
}
|
||||
@ -4,4 +4,8 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\blueprint-platform\src\Core.Blueprint.Common\Core.Blueprint.Common.csproj" />
|
||||
<ProjectReference Include="..\..\..\building-block-catalog\src\BuildingBlock.Catalog.Contracts\BuildingBlock.Catalog.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
7
src/Furniture.DAL/Grpc/CatalogProductDalGrpcContract.cs
Normal file
7
src/Furniture.DAL/Grpc/CatalogProductDalGrpcContract.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Furniture.DAL.Grpc;
|
||||
|
||||
/// <summary>
|
||||
/// Defines minimal gRPC contract shape for catalog projection dal translation.
|
||||
/// </summary>
|
||||
/// <param name="ProductId">Catalog product identifier.</param>
|
||||
public sealed record CatalogProductDalGrpcContract(string ProductId);
|
||||
@ -0,0 +1,7 @@
|
||||
namespace Furniture.DAL.Grpc;
|
||||
|
||||
/// <summary>
|
||||
/// Defines minimal gRPC contract shape for furniture availability dal translation.
|
||||
/// </summary>
|
||||
/// <param name="FurnitureId">Furniture aggregate identifier.</param>
|
||||
public sealed record FurnitureAvailabilityDalGrpcContract(string FurnitureId);
|
||||
@ -1,3 +1,5 @@
|
||||
using Furniture.DAL.Contracts;
|
||||
|
||||
namespace Furniture.DAL.Providers;
|
||||
|
||||
/// <summary>
|
||||
@ -5,4 +7,13 @@ namespace Furniture.DAL.Providers;
|
||||
/// </summary>
|
||||
public interface ICatalogDataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads catalog projection data for furniture scope.
|
||||
/// </summary>
|
||||
/// <param name="request">Catalog product lookup request contract.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Catalog product projection when found; otherwise null.</returns>
|
||||
Task<CatalogProductProjectionRecord?> ReadProductAsync(
|
||||
CatalogProductLookupRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
using Furniture.DAL.Contracts;
|
||||
|
||||
namespace Furniture.DAL.Providers;
|
||||
|
||||
/// <summary>
|
||||
@ -5,4 +7,13 @@ namespace Furniture.DAL.Providers;
|
||||
/// </summary>
|
||||
public interface IFurnitureDataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads furniture availability persistence data.
|
||||
/// </summary>
|
||||
/// <param name="request">Furniture availability lookup request contract.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Furniture availability record when found; otherwise null.</returns>
|
||||
Task<FurnitureAvailabilityRecord?> ReadAvailabilityAsync(
|
||||
FurnitureAvailabilityLookupRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
using Furniture.DAL.Contracts;
|
||||
|
||||
namespace Furniture.DAL.Repositories;
|
||||
|
||||
/// <summary>
|
||||
@ -5,4 +7,13 @@ namespace Furniture.DAL.Repositories;
|
||||
/// </summary>
|
||||
public interface ICatalogRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads catalog product projection for furniture scope.
|
||||
/// </summary>
|
||||
/// <param name="request">Catalog product lookup request contract.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Catalog product projection when found; otherwise null.</returns>
|
||||
Task<CatalogProductProjectionRecord?> ReadProductAsync(
|
||||
CatalogProductLookupRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
using Furniture.DAL.Contracts;
|
||||
|
||||
namespace Furniture.DAL.Repositories;
|
||||
|
||||
/// <summary>
|
||||
@ -5,4 +7,13 @@ namespace Furniture.DAL.Repositories;
|
||||
/// </summary>
|
||||
public interface IFurnitureRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads availability for a furniture aggregate.
|
||||
/// </summary>
|
||||
/// <param name="request">Furniture availability lookup request contract.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Furniture availability record when found; otherwise null.</returns>
|
||||
Task<FurnitureAvailabilityRecord?> ReadAvailabilityAsync(
|
||||
FurnitureAvailabilityLookupRequest request,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
using Furniture.DAL.Caching;
|
||||
using Furniture.DAL.Adapters;
|
||||
using Furniture.DAL.Providers;
|
||||
using Furniture.DAL.Repositories;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Furniture.DAL.UnitTests;
|
||||
|
||||
@ -20,4 +22,35 @@ public class BoundaryShapeTests
|
||||
Assert.True(typeof(ICatalogRepository).IsInterface);
|
||||
Assert.True(typeof(ICacheInvalidationPolicy).IsInterface);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RepositoryBoundaries_WhenReflected_ExposeReadOnlyContracts()
|
||||
{
|
||||
Assert.Equal("ReadAvailabilityAsync", typeof(IFurnitureRepository).GetMethods().Single().Name);
|
||||
Assert.Equal("ReadProductAsync", typeof(ICatalogRepository).GetMethods().Single().Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProviderBoundaries_WhenReflected_ExposeReadOnlyContracts()
|
||||
{
|
||||
Assert.Equal("ReadAvailabilityAsync", typeof(IFurnitureDataProvider).GetMethods().Single().Name);
|
||||
Assert.Equal("ReadProductAsync", typeof(ICatalogDataProvider).GetMethods().Single().Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AdapterBoundaries_WhenReflected_AreInterfaces()
|
||||
{
|
||||
Assert.True(typeof(IFurnitureDalGrpcContractAdapter).IsInterface);
|
||||
Assert.True(typeof(ICatalogProjectionContractAdapter).IsInterface);
|
||||
|
||||
var grpcMethodNames = typeof(IFurnitureDalGrpcContractAdapter)
|
||||
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Select(method => method.Name)
|
||||
.OrderBy(name => name)
|
||||
.ToArray();
|
||||
|
||||
Assert.Equal(
|
||||
["FromGrpcAvailabilityRequest", "FromGrpcCatalogRequest", "ToGrpcAvailabilityRequest", "ToGrpcCatalogRequest"],
|
||||
grpcMethodNames);
|
||||
}
|
||||
}
|
||||
|
||||
41
tests/Furniture.DAL.UnitTests/ContractShapeTests.cs
Normal file
41
tests/Furniture.DAL.UnitTests/ContractShapeTests.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Core.Blueprint.Common.Contracts;
|
||||
using Furniture.DAL.Contracts;
|
||||
|
||||
namespace Furniture.DAL.UnitTests;
|
||||
|
||||
public class ContractShapeTests
|
||||
{
|
||||
[Fact]
|
||||
public void FurnitureAvailabilityLookupRequest_WhenCreated_StoresTransportNeutralData()
|
||||
{
|
||||
var envelope = new FurnitureDalContractEnvelope("1.0.0", "corr-123");
|
||||
var request = new FurnitureAvailabilityLookupRequest(envelope, "FUR-001");
|
||||
|
||||
Assert.Equal("1.0.0", request.Envelope.ContractVersion);
|
||||
Assert.Equal("corr-123", request.Envelope.CorrelationId);
|
||||
Assert.Equal("FUR-001", request.FurnitureId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CatalogProductProjectionRecord_WhenCreated_StoresTransportNeutralData()
|
||||
{
|
||||
var envelope = new FurnitureDalContractEnvelope("1.0.0", "corr-123");
|
||||
var record = new CatalogProductProjectionRecord(envelope, "PRD-001", "Chair");
|
||||
|
||||
Assert.Equal("1.0.0", record.Envelope.ContractVersion);
|
||||
Assert.Equal("corr-123", record.Envelope.CorrelationId);
|
||||
Assert.Equal("PRD-001", record.ProductId);
|
||||
Assert.Equal("Chair", record.DisplayName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FurnitureDalPackageContract_WhenCreated_UsesBlueprintDescriptorContract()
|
||||
{
|
||||
IBlueprintPackageContract contract = new FurnitureDalPackageContract();
|
||||
|
||||
Assert.Equal("Furniture.DAL.Contracts", contract.Descriptor.PackageId);
|
||||
Assert.Equal(PackageVersionPolicy.Minor, contract.Descriptor.VersionPolicy);
|
||||
Assert.Contains("Core.Blueprint.Common", contract.Descriptor.DependencyPackageIds);
|
||||
Assert.Contains("BuildingBlock.Catalog.Contracts", contract.Descriptor.DependencyPackageIds);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user