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:
@@ -55,6 +55,15 @@ Fields unchanged from baseline: `id`, `email` (enc, nullable), `phone` (enc, uni
|
||||
### `customer_addresses` [CORE]
|
||||
**Role:** Saved service locations; the encrypted address + coordinates for EVV distance checks. **Why coordinates:** EVV check-in compares the nurse's GPS against the booking address within tolerance. Unchanged fields, plus: **filtered `UNIQUE(customer_id) WHERE is_primary=1`** so exactly one primary exists (prevents ambiguous default). **Relations:** N:1 → `customer_profiles`, `cities`, `districts`; referenced by `booking_requests`/`bookings`.
|
||||
|
||||
> **As-built (backend-phase-4):** `usr.CustomerAddresses` — `address_line`, `postal_code`,
|
||||
> `recipient_name` and `recipient_phone` are **encrypted at rest** via `IFieldEncryptor` and returned only
|
||||
> in the owning customer's own read (decrypted); `title` and coordinates (`decimal(9,6)`, nullable until
|
||||
> geocoded) stay plaintext. The **first** address is primary by default; `set_primary` thereafter clears
|
||||
> the prior primary and sets the new one in one transaction, with the filtered
|
||||
> `UNIQUE(customer_id) WHERE is_primary=1 AND deleted_at IS NULL` index as the DB backstop. Coordinates are
|
||||
> produced by the mocked **`IGeocoder`** seam on create/update (nullable when the address can't be
|
||||
> resolved) and are consumed by the EVV distance check only later (b9), never for coverage matching.
|
||||
|
||||
### `nurse_bank_accounts` [CORE]
|
||||
**Role:** Payout destination (IBAN/Sheba). **Why hardened:** the IBAN is the single place real money leaves the platform — the original "admin eyeballs the IBAN" check is exactly the forgeable, money-mule-risk link the research warns about.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user