backend phase 0: foundation, cross-cutting seams & starter cleanup

Remove the Order demo (entity/feature/repo/config/gRPC/proto) and the three
pre-marketplace migrations; regenerate a fresh InitialBaseline migration.

Stand up the REST surface (PingController + System/Ping CQRS) proving the
Mediator -> behaviors -> OperationResult -> ApiResult envelope end to end.

Close wiring gaps: register LoggingBehavior (outermost) and add the built-in
rate limiter (per-IP global + otp/auth/sensitive policies), placed before
authentication.

Add current-user + audit plumbing: ICurrentUser (HttpContext + null impls),
rename BaseEntity audit fields to CreatedAt/ModifiedAt (DateTimeOffset) +
CreatedById/ModifiedById, stamped by a new AuditFieldInterceptor.

Introduce five cross-cutting seams (IDateTimeProvider, IFieldEncryptor,
ICacheService, IObjectStorage, INotificationDispatcher) with in-memory/local
mocks registered via AddCrossCuttingSeams.

Add Baya.Test.Foundation (encryptor, audit interceptor, ping handler) and
update docs, contracts (swagger.v1.json), handoff, report, and mocks registry.
This commit is contained in:
hamid
2026-06-30 22:48:41 +03:30
parent 53a40dc51d
commit 765cc632d5
75 changed files with 1539 additions and 1418 deletions
@@ -0,0 +1,28 @@
namespace Baya.Infrastructure.CrossCutting.Seams;
/// <summary>
/// Options bound from the <c>Seams</c> configuration section. The mock seams read non-secret defaults
/// from here; production keys/paths come from environment variables or user-secrets, never committed.
/// </summary>
public sealed class SeamOptions
{
public const string SectionName = "Seams";
public FieldEncryptionOptions FieldEncryption { get; set; } = new();
public ObjectStorageOptions ObjectStorage { get; set; } = new();
}
public sealed class FieldEncryptionOptions
{
/// <summary>Base64 32-byte AES key. Local-dev default only; override per environment.</summary>
public string Key { get; set; } = string.Empty;
/// <summary>Base64 HMAC key used for deterministic lookup hashes.</summary>
public string HashKey { get; set; } = string.Empty;
}
public sealed class ObjectStorageOptions
{
/// <summary>Filesystem root the local-disk mock writes blobs under.</summary>
public string RootPath { get; set; } = string.Empty;
}