backend phase 4: geography, addresses & nurse service areas

Adds the province -> city -> district reference hierarchy (geo schema,
seeded with 31 provinces + capital cities + Tehran's 22 districts),
nurse service areas (district_id NULL = whole city, filtered-index-pair
uniqueness -> 409), and encrypted, geocoded customer addresses with a
single-primary invariant. Introduces the IGeocoder seam (mocked) and
409 Conflict on the result envelope. Public cascading lookups are cached
behind a generation-token scheme with invalidate-on-admin-write.

One EF migration (GeographyAddressesServiceAreas, applied). Contract +
swagger snapshot + handoff/report/registry updated. 103 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamid
2026-07-02 16:06:12 +03:30
parent 39a979b1a7
commit 82561c4cc6
113 changed files with 9817 additions and 5 deletions
@@ -12,6 +12,28 @@ One block per completed backend phase. Newest at the top. Backend lane writes he
- **Notes for frontend:** <anything load-bearing>
-->
## backend-phase-4 — Geography, addresses & nurse service areas — 2026-07-02
- **Shipped:** five tables via one migration (`GeographyAddressesServiceAreas`) — new **`geo`** schema
`Provinces` 1:N `Cities` 1:N `Districts` (+ `NurseServiceAreas`) and `usr.CustomerAddresses`; seed
(31 provinces + capital cities + Tehran's 22 مناطق via `HasData`); 20 CQRS slices across 4 controllers
(`geo` public lookups incl. `/tree`, `admin_geo` CRUD + set_active, `nurse_service_areas`,
`customer_addresses`); new **`IGeocoder`** seam (deterministic mock, `Seams:Geocoding`); per-domain
repos on `IUnitOfWork`; enc value converters for the address PII columns; **`409 Conflict`** added to
`OperationResult`/`BaseController`. Whole-city (`district_id NULL`) uniqueness via a **filtered-index
pair**; single-primary address via filtered `UNIQUE(customer_id) WHERE is_primary=1`; geo reads cached
behind a generation-token scheme with invalidate-on-admin-write.
- **Contracts:** dev/contracts/domains/geography-addresses.md + openapi snapshot refreshed (yes — 20 new
geo/service-area/address paths).
- **Mocked:** `IGeocoder` → 🟡 (see reports/mocks-registry.md).
- **Gate:** build clean (0 new code warnings) / tests green (103 pass: +16 `Baya.Test.Api` integration,
+12 handler unit tests). Migration `GeographyAddressesServiceAreas` applies on startup; swagger exposes
all b4 paths.
- **Handoff:** backend/handoff/after-backend-phase-4.md
- **Notes for frontend:** `districtId=null` means **whole city** (a real choice) everywhere. Duplicate
service area → **409**. Addresses come back **decrypted for the owner** with `latitude`/`longitude`
(nullable when ungeocoded — geocoding is mocked). Routes are action-style (`admin_geo/create_city`,
`nurse_service_areas/add`, `customer_addresses/create`, …). Admin geo needs an admin token.
## backend-phase-3 — Identity: profiles, patients & nurse bank accounts — 2026-07-02
- **Shipped:** four `usr` tables via one migration (`IdentityProfilesPatientsBankAccounts`) —
`NurseProfiles` (1:1 `Users`; guarded `is_verified` **no public setter**; read-only aggregates;