# CRM: customers, passengers & documents (Phase 03)

All CRM data lives in the tenant database. The central rule is a strict
separation between the **buyer** and the **traveler**.

## Buyer ≠ traveler

- **`customers`** — the buyer/payer (person or company). May never travel.
  Optionally scoped to a brand; searched via normalized name/email/phone columns
  (tenant-local, never global).
- **`passengers`** — the traveler identity. Tenant-wide and **reusable**, so a
  recurring traveler is never recaptured. May never pay.
- **`customer_passenger_relationships`** — the many-to-many link
  (self/familiar/employee/companion/other). One buyer → many passengers; one
  passenger → many legitimate buyers.

"Individual vs group" describes the operation, not the passenger count.

## Derived traveler categories

`TravelerCategoryService` derives adult/child/infant counts from real passenger
birth dates and the age rules in force **at the service date** — the system
never stores raw adult/minor quantities.

## Sensitive documents

`passenger_documents` keeps the ID number **encrypted at rest** (APP_KEY) with
only a masked suffix (`••••4567`) for listings. Files live on the private,
tenant-scoped disk. Access is layered:

- reveal the raw number → requires `documents.sensitive.view`;
- download the file → a **short-lived signed URL** (tamper-proof) **and**
  `documents.sensitive.view`. There is no public path; direct URLs, id changes
  and unauthorized users are all rejected.

## Deduplication (merge)

`MergeService` merges customers or passengers **without deleting**: references
(links, documents, notes, addresses) are repointed to the winner, the loser is
retained with a pointer to the winner, and every merge is written to
`merge_logs` with actor + reason. Requires the `crm.merge` permission.

## Consent, preferences, tags

`consent_records` (append-only), `communication_preferences` (per
channel/purpose), and polymorphic `tags` round out the profile. Notes carry a
visibility for least-privilege display.

## API (under `/api/v1/tenant`, Sanctum + brand)

`GET/POST /customers`, `GET /customers/{uuid}`,
`POST /customers/{uuid}/passengers`, `GET/POST /passengers`,
`GET /passengers/{uuid}`, `POST /passengers/{uuid}/documents`,
`GET /documents/{uuid}/reveal|link`, signed `GET /documents/{uuid}/download`,
and `POST /customers/merge` · `POST /passengers/merge`.
