# Phase 5B-D2 — Business Customers, Contact Persons & Relationships (proposed model)

Reusable, additive extension of the customer domain. Individual customers are unaffected; business-only
data lives in separate 1:1 / child tables so an individual record never carries organization fields.

## Tables (all tenant-scoped, UUIDv7, composite `(tenant_id, …)` FKs — cross-tenant is structurally impossible)

### customer_business_profiles (1:1 with a business-type customer)
Organization info kept OFF the `customers` table so individuals stay clean. The trading name stays
`customers.display_name`; the org's own email/phone stay `customers.email/phone`.
- `legal_name`, `business_reference` (internal account code) — both nullable.
- `tax_identifiers` — **encrypted JSON** list of `{label, value}` (registration/tax numbers). Country-agnostic,
  never universally required. PROTECTED: returned only to a `customers.manage` holder (redacted otherwise).
- `unique(tenant_id, customer_id)` enforces the 1:1.

### customer_contact_persons (N per business customer)
Named people at the organization — NOT customers themselves (no customer UUID). Distinct from the org's own
contact channels (`customer_contacts`): a contact person's email/phone are the person's, stored on this row.
- `name`, `position`, `email`, `phone`, `preferred_contact_method` (email|phone|none, CHECK), `notes`.
- `is_primary` — at most ONE per customer via a stored generated key `primary_key` + `unique(tenant_id, primary_key)`.
- `is_active` — archived (soft), never hard-deleted; history preserved.

### customer_relationship_types (configurable, tenant-level — `customers.configure`)
- `key` (slug, per-tenant unique), `label`, `inverse_label` (nullable), `is_directional`, `is_active`.
- Directional e.g. Parent→Branch (`inverse_label` "Branch of"); symmetric e.g. "Related organization"
  (`is_directional=false`, no inverse). Not hardcoded — admins define them (empty by default).

### customer_relationships (edges — `customers.manage`)
- `from_customer_id`, `to_customer_id`, `relationship_type_id`, `note`.
- `unique(tenant_id, from, to, type)` — no duplicate edge. `from != to` — no self-link. For a DIRECTIONAL
  type, a cycle (A→…→A) is rejected. Edges carry **NO authorization** — they never grant access to orders,
  payments, invoices or private profile data, and never change order visibility / location scope.

## Authorization & audit
Reuse `customers.view` (read), `customers.manage` (business profile, contact persons, relationship edges),
`customers.configure` (relationship TYPES). No new permission. Every mutation is transactional and audited
(`customers.business.updated`, `customers.contact_person.*`, `customers.relationship.*`,
`customers.relationship_type.*`). Tax identifiers redacted server-side for non-managers.

## Profile / POS / performance
`GET customers/{id}` gains the small 1:1 `business` block (tax redacted) for business customers only; contact
persons and relationships load through their OWN paginated endpoints (the full hierarchy is never loaded in an
ordinary profile response). POS: selecting a business customer sets the order's `customer_id` to the ORG and
lets staff pick a contact person whose details populate the order's contact SNAPSHOT — the org remains the
order's customer; the contact person is never treated as a separate customer. No order-engine change.

## Data integrity
Additive migrations only; existing customers, contacts, addresses, orders, payments and group/tag/custom-field
data are untouched. Archiving preserves historical references. No automatic merging of contacts or customers.
