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:
@@ -12,4 +12,16 @@ One block per completed backend phase. Newest at the top. Backend lane writes he
|
||||
- **Notes for frontend:** <anything load-bearing>
|
||||
-->
|
||||
|
||||
_(no phases completed yet)_
|
||||
## backend-phase-0 — Foundation, cross-cutting seams & starter cleanup — 2026-06-28
|
||||
- **Shipped:** removed the `Order` demo (entity/feature/repo/config/gRPC) + 3 old migrations; fresh
|
||||
`InitialBaseline` migration; REST surface (`PingController` + `System/Ping` CQRS); `ICurrentUser` +
|
||||
`AuditFieldInterceptor`; five cross-cutting seams (`IDateTimeProvider`, `IFieldEncryptor`,
|
||||
`ICacheService`, `IObjectStorage`, `INotificationDispatcher`) with mocks; `LoggingBehavior` +
|
||||
rate limiter (per-IP global + `otp`/`auth`/`sensitive`).
|
||||
- **Contracts:** `dev/contracts/openapi/swagger.v1.json` published (envelope + ping schemas).
|
||||
- **Mocked:** the 5 seams above → 🟡 (see reports/mocks-registry.md).
|
||||
- **Gate:** build clean (0 new warnings) / tests green (10 pass). Live API verified vs `192.168.100.14`
|
||||
(migration applied + seeded; ping `200`; rate-limit `429`).
|
||||
- **Handoff:** backend/handoff/after-backend-phase-0.md
|
||||
- **Notes for frontend:** `ApiResult` envelope is fixed (camelCase body, snake_case URLs);
|
||||
`GET /api/v1/ping/get_status` is live to wire types against; `429` on over-limit.
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# After backend-phase-0 — what f0/b1 can rely on
|
||||
|
||||
**The spine is clean and REST works.** The inherited `Order` demo (entity/feature/repo/config/gRPC) and
|
||||
the three pre-marketplace migrations are gone; Identity + JWE auth + dynamic permissions + the CQRS
|
||||
behaviors + observability are untouched and the existing tests stay green. A real REST controller is
|
||||
live and proves the full pipeline.
|
||||
|
||||
## What the frontend (f0) can rely on now
|
||||
- **The response envelope is fixed.** Every endpoint returns the server's `ApiResult` envelope, not a
|
||||
bare body. Success shape:
|
||||
```json
|
||||
{ "isSuccess": true, "statusCode": 0, "message": "Success", "requestId": "<trace>", "data": <T> }
|
||||
```
|
||||
Failure returns `400/401/403/404` with the same envelope (field-level errors for validation). This is
|
||||
what `clientFetch`/`serverFetch` must unwrap. JSON casing is the server default (camelCase for the
|
||||
envelope/body properties; **URL segments are snake_case**).
|
||||
- **A working endpoint to wire the type pipeline against:**
|
||||
`GET /api/v1/ping/get_status` → `ApiResult<{ service, status, serverTimeUtc }>`.
|
||||
- **Rate limiting exists.** Over-limit requests get `429`; `get_status_rate_limited` demonstrates it
|
||||
(first 5/10s OK, then 429).
|
||||
- **swagger.json is published:** `dev/contracts/openapi/swagger.v1.json` (envelope schemas
|
||||
`ApiResult`, `ApiResultStatusCode`, `PingQueryResult`). Generate frontend types from it.
|
||||
|
||||
## What b1 can rely on now
|
||||
- **Audit base type:** `BaseEntity`/`IAuditableEntity` (`Domain/Common/BaseEntity.cs`) with
|
||||
`CreatedAt`/`ModifiedAt` (`DateTimeOffset`) + `CreatedById`/`ModifiedById` (`int?`). New entities that
|
||||
derive `BaseEntity` get audit stamping for free.
|
||||
- **Audit interceptor:** `AuditFieldInterceptor` (`Infrastructure.Persistence/Interceptors/`) stamps
|
||||
those fields on save from `ICurrentUser` + `IDateTimeProvider`. **b1 extends this** to also write the
|
||||
append-only `audit_logs` rows — the stamping plumbing and the clean extension point are in place.
|
||||
- **Cross-cutting seams (DI-registered, mocked):** `IDateTimeProvider`, `IFieldEncryptor` (use it for
|
||||
every encrypted PII column — phone/national_id/IBAN/addresses/clinical notes; deterministic `Hash`
|
||||
for `*_hash` lookup columns), `ICacheService` (cache `platform_configs` / read-heavy data through it),
|
||||
`IObjectStorage`, `INotificationDispatcher`. Contracts in `Application/Contracts/Common`; mocks in
|
||||
`Infrastructure.CrossCutting/Seams/`; registered by `AddCrossCuttingSeams`.
|
||||
- **Money rule:** IRR is `long`/`BIGINT`, integer-only, no floats (CONVENTIONS §6).
|
||||
- **Migration baseline:** `20260628191947_InitialBaseline`. Add the marketplace schema on top of it;
|
||||
generate with the documented `dotnet ef migrations add` command.
|
||||
- **Rate-limit policies** `otp`/`auth`/`sensitive` are defined and ready to apply via
|
||||
`[EnableRateLimiting("...")]` on the relevant endpoints (b2 auth/OTP).
|
||||
|
||||
## Known caveat
|
||||
Non-Development environments route Serilog to the `logDb` connection (`Server=sql_server2022`); if that
|
||||
host isn't reachable, the API won't start there. Development logs to console/file and boots cleanly
|
||||
against the configured `SqlServer` DB. This is pre-existing infra config, unrelated to phase-0 code.
|
||||
Reference in New Issue
Block a user