# addresses — customer addresses

> Client seam `client/src/services/addresses/` · `USE_ADDRESSES_MOCK = false` (**real**) · 5 server ops
> Last verified: 2026-07-30 against commit `d3ec723` and swagger.v1.json (2026-07-29).

The customer's saved addresses. One address is primary; the rest are ordered by recency. The address a
booking uses is **snapshotted** onto the booking, so editing an address later never rewrites history.

## Endpoints

| Method | Path | Auth | Verdict |
| --- | --- | --- | --- |
| GET | `/api/v1/customer_addresses/list` | `[Authorize]` | wired · paginated (`Page`/`PageSize`) |
| POST | `/api/v1/customer_addresses/create` | `[Authorize]` | wired |
| POST | `/api/v1/customer_addresses/update/{id}` | `[Authorize]` | wired |
| POST | `/api/v1/customer_addresses/set_primary/{id}` | `[Authorize]` | wired |
| DELETE | `/api/v1/customer_addresses/delete/{id}` | `[Authorize]` | wired · **soft delete** |

No phantoms. The domain maps 1:1.

## Shape rules the JSON does not express

- **`provinceId` is on `CustomerAddressDto`** (REQ-009, delivered). The client needs it to preselect the
  province in the city cascade without a reverse lookup.
- **The client-picked map pin is accepted on create and update** (REQ-008, delivered) — the server does
  **not** re-geocode over a pin the user placed. When no pin is given, `IGeocoder` resolves one.
- **`latitude`/`longitude` are nullable.** Null means the geocoder could not resolve the address and the
  user placed no pin; the UI shows "saved without a map pin" rather than an error. `IGeocoder`'s mock
  forces this path for any address whose text contains `NO_GEO`
  (`Seams:Geocoding:LowConfidenceMarker`).
- **The full address line is encrypted at rest** and returned decrypted only to its owner. A *booking
  request* sees a city/district-coarse mask instead — see [booking-requests.md](booking-requests.md).
- **`set_primary` touches two rows** (demote the old, promote the new) in one transaction. The client
  invalidates the whole list key rather than patching one item.
- Delete is a soft delete behind the entity's global query filter; a booking that snapshotted the address
  is unaffected.

## Enums

None of its own. `provinceId` / `cityId` / `districtId` are geography ids — see
[geography.md](geography.md), where **`districtId = null` means whole-city**.

## Open REQs

None. REQ-008 and REQ-009 were both delivered in refinement-phase-3 and are folded into the rules above.
