> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# PersonLocation

> PersonLocation is a pivot (bridge) entity that links a `People` record to a `Location` record, recording whether that address is the person's primary address an

PersonLocation is a pivot (bridge) entity that links a `People` record to a `Location` record, recording whether that address is the person's primary address and whether it serves a legal purpose. It mirrors the `company_locations` pattern applied to individuals. The entity is workspace-scoped indirectly through its owning `People` record, carries soft-delete semantics via `deleted_at`, and enforces a partial-unique constraint ensuring at most one primary address per person among non-deleted rows.

| Naming                          | Value                             |
| ------------------------------- | --------------------------------- |
| Object                          | PersonLocation                    |
| Resource type (JSON:API `type`) | `person_location`                 |
| Collection / records root       | — <sub>(not a records root)</sub> |
| REST base                       | `/v1/person-locations`            |
| Entity class                    | `PersonLocation`                  |

<Note>
  **Internal object.** Not currently exposed on the public REST API. The operations below describe the intended contract.
</Note>

## API operations

| Operation | Method & path                      | Status     |
| --------- | ---------------------------------- | ---------- |
| List      | `GET /v1/person-locations`         | 🟡 Planned |
| Retrieve  | `GET /v1/person-locations/{id}`    | 🟡 Planned |
| Create    | `POST /v1/person-locations`        | 🟡 Planned |
| Update    | `PATCH /v1/person-locations/{id}`  | 🟡 Planned |
| Delete    | `DELETE /v1/person-locations/{id}` | 🟡 Planned |

## Data model

### Attributes

| Field       | Type             | Required | Constraints                                                                                                                                              | Allowed values | Description                                                                                                                                 |
| ----------- | ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| is\_primary | boolean          | ✅ Yes    | Partial unique index: only one row per person\_pk may have is\_primary = TRUE where deleted\_at IS NULL (index uniq\_person\_locations\_primary\_person) | true \| false  | Marks this address as the person's primary (canonical) address. At most one non-deleted PersonLocation per person may be primary.           |
| is\_legal   | boolean          | ✅ Yes    | Not null                                                                                                                                                 | true \| false  | Indicates whether this address is the person's legal domicile (registered address for official/legal purposes).                             |
| label       | string           | ✅ Yes    | varchar(255), not null                                                                                                                                   | —              | Human-readable label categorising the address (e.g. 'Home', 'Work', 'Billing'). Free-form text up to 255 characters.                        |
| created\_at | 🔒 system — Date | ✅ Yes    | timestamptz, set on insert via onCreate hook, never updated                                                                                              | —              | Timestamp when this pivot row was created. System-set on insert; not writable by the user.                                                  |
| deleted\_at | Date \| null     | ⚪ No     | timestamptz, nullable; NULL means active; partial indexes filter WHERE deleted\_at IS NULL                                                               | —              | Soft-delete timestamp. When set, the row is logically deleted and excluded from all active queries. System-managed; not directly patchable. |

### Relationships

| Name     | Type               | Required | Description                                                                                                                                                                        |
| -------- | ------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| person   | to-one (ManyToOne) | ✅ Yes    | The People record this address is attached to. Foreign key person\_pk → core\_api.people.pk. Indexed via partial index idx\_person\_locations\_person (WHERE deleted\_at IS NULL). |
| location | to-one (ManyToOne) | ✅ Yes    | The Location record (address details) associated with this pivot. Foreign key location\_pk → core\_api.locations.pk. Indexed via idx\_person\_locations\_location.                 |

### System-computed

* pk — auto-increment serial integer, internal join key only; never exposed on the public API.
* created\_at — set to new Date() via @Property({ onCreate }) on insert; no subsequent updates (no updated\_at column on this entity).
* deleted\_at — soft-delete sentinel; null on creation; set by the application soft-delete service, never by user PATCH.
* Partial unique index uniq\_person\_locations\_primary\_person enforces at most one is\_primary = TRUE row per person\_pk among non-deleted rows — maintained by the database, not application code.
* The entity has no updated\_at column; mutations that change is\_primary or label do not produce a timestamp trail beyond created\_at.
* No UUID public id column — PersonLocation does not carry a \*\_id UUID field; it is identified externally via the combination of person relationship + location relationship.
* No workspace\_pk column — tenant isolation is inherited transitively through the person → workspace path; Hasura RLS walks this relationship chain.

## Example

```json theme={null}
{
  "data": {
    "type": "person_location",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "attributes": {
      "is_primary": true,
      "is_legal": false,
      "label": "Home",
      "created_at": "2025-09-14T10:23:00.000Z",
      "deleted_at": null
    },
    "relationships": {
      "person": {
        "data": { "type": "people", "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
      },
      "location": {
        "data": { "type": "location", "id": "f9e8d7c6-b5a4-3210-fedc-ba9876543210" }
      }
    }
  }
}
```

<sub>Source: `apps/api/src/database/entities/PersonLocation.ts` · domain: financial-graph · tier: Supporting</sub>
