Address API Reference
Complete API contracts for the Address module, including routes, auth, DTOs, responses, errors, examples, and integration notes.
Address - API Reference
Audience: Frontend engineers, mobile engineers, backend engineers, QA, and API consumers. Scope: The customer address book — seven customer-facing endpoints. There is no admin surface.
1. Documentation Evidence
| Area | Files Inspected | What Was Verified |
|---|---|---|
| Controllers | apps/api/src/modules/address/customer/address-customer.controller.ts | Routes, methods, guards, idempotency scopes, status codes |
| DTOs | customer/dto/*.ts | Validation, defaults |
| Services | customer/address-customer.service.ts | Behavior, default invariant, errors |
| Schema | packages/db/src/schema/address/customer-address.ts | CHECKs, partial unique default, CASCADE |
| Error registry | apps/api/src/common/types/error-codes.ts (// CUSTOMER ADDRESS) | CUSTOMER_ADDRESS_* codes |
2. Module Summary
| Field | Value |
|---|---|
| Module name | address |
| Module slug | address |
| Primary actors | customer |
| API surfaces | mobile only |
| Base route prefixes | /api/mobile/addresses |
| Auth model | JwtAuthGuard |
| Persistence | PostgreSQL (customer_address), Redis (shipping serviceability cache, read) |
| Runtime source of truth | customer_address rows |
| Sibling docs | Backend, Features and flows |
3. Concepts and Terminology
| Term | Meaning | Source File | Used By |
|---|---|---|---|
isDefault | The customer's one default delivery address | schema | Create/list/default routes |
archived | Soft-deleted; readable and restorable, not writable | schema | All routes |
serviceable | Live shipping availability for the address's district — computed per read, never stored | service | All responses |
municipality.id | Always null — reference table ships empty by design; municipality.name is free text | schema | Responses |
recipientPhone | Local numbers accepted; stored and returned as E.164 (+977…) | phone util | Create/update |
4. API Surface Map
| Surface | Method | Path | Actor | Auth/Guard | Permission | Controller | Purpose |
|---|---|---|---|---|---|---|---|
| Mobile | POST | /api/mobile/addresses | Customer | JWT + IpThrottle | — | AddressCustomerController | Create (201; idempotent) |
| Mobile | GET | /api/mobile/addresses | Customer | JWT + IpThrottle | — | same | List mine |
| Mobile | GET | /api/mobile/addresses/:id | Customer | JWT + IpThrottle | — | same | Read one (archived readable) |
| Mobile | PATCH | /api/mobile/addresses/:id | Customer | JWT + IpThrottle | — | same | Update (active only) |
| Mobile | DELETE | /api/mobile/addresses/:id | Customer | JWT + IpThrottle | — | same | Archive (active only; 200) |
| Mobile | POST | /api/mobile/addresses/:id/restore | Customer | JWT + IpThrottle | — | same | Restore (archived only; 200; idempotent) |
| Mobile | PUT | /api/mobile/addresses/:id/default | Customer | JWT + IpThrottle | — | same | Set default (active only) |
Row-state requirement per route: GET :id works on any state (a customer must see what to restore); PATCH, DELETE and PUT /default require active (409 on archived); restore requires archived (409 on active).
5. Auth, Identity, and Permissions
| Surface | Guard/Decorator | Identity Shape | Permission | Guest Allowed | Notes |
|---|---|---|---|---|---|
| All | JwtAuthGuard, IpThrottlerGuard | req.user.id | — | No | Every WHERE is scoped to req.user.id |
Rate limits, keyed on the account (keyStrategy: "user"): CUSTOMER_READ 60/min (list/read), CUSTOMER_WRITE 20/min (create/update/archive/restore/default). Idempotency: Idempotency-Key required on create (scope customer-address-create) and restore (scope customer-address-restore).
6. DTO and Model Reference
6.1 CreateAddressDto
| Field | Type | Required | Default | Validation | Example | Source |
|---|---|---|---|---|---|---|
recipientName | string | Yes | N/A | — | "Sita Sharma" | create-address.dto.ts |
recipientPhone | string | Yes | N/A | must normalize to E.164 (NP region) | "9812345678" | |
districtId | UUID v7 | Yes | N/A | @IsUUID("7") | 0198… | |
municipalityName | string | Yes | N/A | — | "Kathmandu Metropolitan City" | |
ward | number | Yes | N/A | int 1..40 | 16 | |
street / landmark / postalCode | string | No | NULL | — | "Jhamsikhel Marg" | |
latitude / longitude | number | No | NULL | both or neither; inside Nepal (26.0–30.6, 79.9–88.3) | 27.6789 / 85.3123 | |
deliveryInstructions | string | No | NULL | — | "call on arrival" | |
isDefault | boolean | No | false | — | true | only matters from the second address |
6.2 UpdateAddressDto
Same fields, all optional; omitted fields unchanged; an explicit null clears a nullable field. Changing the district may change serviceability, which the response reflects.
6.3 Query DTO
ListAddressesQueryDto: status (active default / archived / all), districtId, provinceId, + QueryDto base (pagination, page, size).
6.4 Response DTO
{
"id": "0198…",
"recipient": { "fullName": "Sita Sharma", "phoneNumber": "+9779812345678" },
"location": {
"province": { "id": "0198…", "code": "bagmati", "name": "Bagmati" },
"district": { "id": "0198…", "code": "kathmandu", "name": "Kathmandu" },
"municipality": { "id": null, "name": "Kathmandu Metropolitan City" },
"ward": 16, "street": "Jhamsikhel Marg", "landmark": "opposite the bakery",
"postalCode": "44600", "latitude": 27.6789, "longitude": 85.3123,
"deliveryInstructions": "call on arrival"
},
"status": { "default": true, "archived": false, "serviceable": true },
"timestamps": { "createdAt": "…", "updatedAt": "…", "archivedAt": null }
}7. Enum Reference
None — address state is archived_at + is_default columns.
8. Endpoint Reference
8.1 POST /api/mobile/addresses
Purpose
Add a delivery address. The first address becomes the default automatically. Retries with the same Idempotency-Key never create a duplicate.
Auth and Permissions
JwtAuthGuard, IpThrottlerGuard; CUSTOMER_WRITE 20/min (account-keyed); Idempotency-Key required (scope customer-address-create).
Request
Body per §6.1 — local phone accepted (9812345678 → +9779812345678).
Response
201 — address response per §6.4.
Side Effects
customer_address row; auto-default when it is the first active address; serviceability computed from shipping.
Error Cases
| HTTP | Code | Condition |
|---|---|---|
| 400 | CUSTOMER_ADDRESS_RECIPIENT_PHONE_INVALID | Phone will not normalize to E.164 |
| 400 | CUSTOMER_ADDRESS_COORDINATES_INCOMPLETE | One coordinate without the other |
| 400 | CUSTOMER_ADDRESS_COORDINATES_OUT_OF_RANGE | Outside Nepal — usually latitude/longitude swapped |
| 400 | IDEMPOTENCY_KEY_REQUIRED | Missing header |
| 404 | CUSTOMER_ADDRESS_DISTRICT_NOT_FOUND | District uuid names nothing |
| 409 | CUSTOMER_ADDRESS_LIMIT_REACHED | 20 active addresses already |
| 409 | idempotency conflicts | Key replayed differently / in flight |
8.2 GET /api/mobile/addresses
Purpose
List my addresses — default first, then newest. Unpaginated by default (the active set is capped at 20).
Request
?status=active|archived|all&districtId=&provinceId=&pagination=&page=&size
Response
200 — array of address responses.
8.3 GET /api/mobile/addresses/:id
Purpose
Read one address — archived rows are readable, so a customer can see what to restore.
Error Cases
| HTTP | Code | Condition |
|---|---|---|
| 404 | CUSTOMER_ADDRESS_NOT_FOUND | No such address for this customer — also the answer for someone else's address (a 403 would be an existence oracle) |
8.4 PATCH /api/mobile/addresses/:id
Purpose
Update an address. Omitted fields are unchanged; explicit null clears a nullable field.
Error Cases
| HTTP | Code | Condition |
|---|---|---|
| 409 | CUSTOMER_ADDRESS_ALREADY_ARCHIVED | Write attempted on an archived row — offer restore |
| 404 | CUSTOMER_ADDRESS_NOT_FOUND | Not this customer's address |
8.5 DELETE /api/mobile/addresses/:id
Purpose
Archive (soft delete). Archiving the default promotes the newest remaining active address. Restorable via 8.6.
Response
200 message-only.
Error Cases
| HTTP | Code | Condition |
|---|---|---|
| 409 | CUSTOMER_ADDRESS_ALREADY_ARCHIVED | Already archived |
| 404 | CUSTOMER_ADDRESS_NOT_FOUND | Not this customer's address |
8.6 POST /api/mobile/addresses/:id/restore
Purpose
Restore an archived address. The default flag is recomputed, never carried over — it becomes the default only if the customer has no other active addresses. Idempotency-Key required (scope customer-address-restore).
Response
200 — address response.
Error Cases
| HTTP | Code | Condition |
|---|---|---|
| 409 | CUSTOMER_ADDRESS_NOT_ARCHIVED | Restore attempted on an active row |
| 404 | CUSTOMER_ADDRESS_NOT_FOUND | Not this customer's address |
8.7 PUT /api/mobile/addresses/:id/default
Purpose
Make this my default address. Clears the previous default in the same transaction; archived addresses cannot be made default. Concurrent calls are serialized per customer.
Response
200 — address response.
Error Cases
| HTTP | Code | Condition |
|---|---|---|
| 409 | CUSTOMER_ADDRESS_ALREADY_ARCHIVED | Archived row |
| 404 | CUSTOMER_ADDRESS_NOT_FOUND | Not this customer's address |
9. Flow Diagrams
9.1 Route Ownership
9.2 Request Sequence (create)
9.3 Error Branch (write on archived)
10. Pagination, Sorting, Filtering, and Search
| Endpoint | Pagination Type | Default Size | Max Size | Sort Fields | Filters | Result Cap |
|---|---|---|---|---|---|---|
GET /api/mobile/addresses | offset (opt-in) | 20 | 100 | default first, then newest (fixed) | status, districtId, provinceId | 20 active / unbounded with status=all |
11. Caching, Jobs, and External Integrations
| Integration | Used? | Details |
|---|---|---|
| Redis cache | Read-only | Shipping serviceability (one key in the shipping domain); address rows never cached (PII) |
| BullMQ | No | — |
| External API | No | — |
13. Mandatory Deep API Documentation Pack
13.1 Route-by-Route Completeness Matrix
| Route | Controller Method | DTOs | Service Method | Guards | Permissions | Cache | Jobs | DB Touches | Errors | Documented? |
|---|---|---|---|---|---|---|---|---|---|---|
POST /api/mobile/addresses | create | CreateAddressDto | AddressCustomerService.create | JWT+IpThrottle+Idempotency | — | — | — | customer_address, district, shipping | 400/404/409 | Yes |
GET /api/mobile/addresses | list | ListAddressesQueryDto | …list | JWT+IpThrottle | — | shipping (read) | — | customer_address, shipping | — | Yes |
GET /api/mobile/addresses/:id | findOne | AddressParamsDto | …findOne | JWT+IpThrottle | — | — | — | customer_address | 404 | Yes |
PATCH /api/mobile/addresses/:id | update | UpdateAddressDto | …update | JWT+IpThrottle | — | — | — | customer_address | 404/409 | Yes |
DELETE /api/mobile/addresses/:id | archive | AddressParamsDto | …archive | JWT+IpThrottle | — | — | — | customer_address (default promotion) | 404/409 | Yes |
POST /:id/restore | restore | AddressParamsDto | …restore | JWT+IpThrottle+Idempotency | — | — | — | customer_address (flag recompute) | 404/409 | Yes |
PUT /:id/default | setDefault | AddressParamsDto | …setDefault | JWT+IpThrottle | — | — | — | customer_address (lock + flags) | 404/409 | Yes |
13.2 Request/Response Exhaustiveness
Covered in §8: minimal/full create payloads (§6.1/8.1), success responses (§8.1/8.6), the municipality.id: null response shape (§6.4), domain errors per endpoint (§8 error tables), rate-limit behavior (account-keyed 429), permission-free surface (403 impossible — JWT only).
13.3 API Diagram Pack
Route ownership (§9.1), sequence per endpoint family (§9.2, backend §7), error decision tree (§9.3), serviceability flow (backend §7.2).
13.4 Consumer Integration Notes
| Consumer | Required Knowledge | Failure Handling | Contract Stability |
|---|---|---|---|
| Web frontend | municipality.id always null; render municipality.name; phone always E.164 in responses | 409 on archived → offer restore | Stable |
| Mobile app | Idempotency-Key on create/restore; account-keyed rate limits | 429 → back off; retry create with same key | Stable |
| QA | Default-flag recompute, zero-active = legal, serviceability-on-read | Reproduce via exact codes | Stable |
| Orders (future) | Snapshot the address, never FK to it | CASCADE erases addresses with the customer | Stable |
| Admin panel | No admin surface exists | — | Stable |
13.5 API Tradeoffs and Rationale
| Decision | Chosen Behavior | Alternatives Considered | Why This Tradeoff | Risk | Mitigation |
|---|---|---|---|---|---|
| CASCADE + snapshot rule | Addresses die with the customer | No-cascade | PII must not outlive owner | Orders lose references | Snapshot contract documented |
| Default invariant | Partial unique index + advisory lock | Application check only | Concurrent set-default safe | Rare contention | Lock is per-customer |
| Restore flag recompute | Never carry the old flag | Restore as-was | Default is a choice, not history | Surprise restores | Documented |
municipality.id null | Free-text name | Full reference | No 753-row memory game | No ids | Documented |
| Local phone accepted | NP default region | Strict E.164 | Easier entry | Ambiguity | Documented |
13.6 API Change Impact
| Change | Affected Consumers | Backend Impact | Data Impact | Migration Needed? | Compatibility Plan |
|---|---|---|---|---|---|
| Serviceability change | Any consumer caching it | None | None | No | Never stored — computed per read |
| Repricing a district | Address lists | None | None | No | Shipping cache domain |
14. Zero-Omission API Checklist
- Every controller route is documented (§4, §8, §13.1).
- Every parent route prefix and runtime URL is documented (§2, §4).
- Every DTO field, enum, default, transform and validator is documented (§6).
- Every response field and nullable field is documented (§6.4, §8).
- Every auth, guard, permission and guest identity branch is documented (§5).
- Every success, validation, not-found, conflict, rate-limit and server-error branch is documented (§8).
- Every DB read/write, cache read and external call is documented (§11, backend §8).
- Every route has examples for minimal request, success response and representative failures (§8).
- Every endpoint family has route, sequence and error diagrams (§9, backend §7).
- Every tradeoff and compatibility risk is documented (§13.5, §13.6).
- The API doc links to backend and features/flows (§1, See Also).
15. Integration Checklist
- Every route from controllers is documented.
- Every DTO field is documented.
- Every response envelope is documented.
- Every error code is documented.
- Every auth guard and permission is documented.
- Every cache key, queue job and external call is documented.
- Every diagram matches the current code.
- The API doc links to backend and features/flows.
See Also
- Backend doc: /docs/developer/address/backend
- Features and flows doc: /docs/developer/address/feature
- TDD: not yet published