Skip to main content

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.

People is a workspace-scoped entity representing an individual contact — an employee, owner, or other relationship a business interacts with. It is the central node for personal contact data, linked to atomic contact details (emails, phones, locations, web links) through dedicated pivot entities. A People record is connected to one or more Company entities via the CompanyPerson pivot, participates in workspace Membership, and tracks its data-source provenance through the PeopleWorkspaceConnector relation. It is a primary records-page root exposed in the data-views pipeline.
NamingValue
ObjectPeople
Resource type (JSON:API type)people
Collection / records rootpeople
REST base/v1/people
Entity classPeople

API operations

OperationMethod & pathStatus
ListGET /v1/people✅ Implemented
RetrieveGET /v1/people/{id}✅ Implemented
CreatePOST /v1/people✅ Implemented
UpdatePATCH /v1/people/{id}✅ Implemented
DeleteDELETE /v1/people/{id}✅ Implemented
EnrichPOST /v1/people/enrich✅ Implemented

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
person_idstring, UUID✅ Yesunique; generated by gen_random_uuid() on insertPublic stable identifier for this person record. Used in all API responses and external references. Never expose the internal pk.
full_namestring✅ Yesvarchar(255), not nullDisplay name for the person. Stored directly on the entity (not derived at query time from first_name + last_name, though both component fields are also persisted). Used as the primary display label across the records UI and composites.
first_namestring✅ Yesvarchar(255), not nullGiven (first) name component. Persisted alongside full_name to enable name-part filtering and salutation formatting.
last_namestring✅ Yesvarchar(255), not nullFamily (last) name component. Persisted alongside full_name.
job_titlestring⚪ Novarchar(100), nullableProfessional role or title of the person at their primary company. Decorated with @Enrichable — the enrichment pipeline may populate or update this field automatically.
external_person_idstring⚪ Nonullable; partial unique index on (external_person_id, workspace_pk) WHERE deleted_at IS NULL — replaces original global unique constraint (Migration20260216120000). Uniqueness is scoped per workspace.Deduplication key from the originating connector (e.g. a CRM contact ID). Used by the reconciliation pipeline for find-or-create matching: if a sync supplies an external_person_id already known in the workspace, the existing record is updated rather than a duplicate created. NULL for manually created records.
created_atDate, 🔒 system✅ Yestimestamptz, not null; set via onCreate lifecycle hookTimestamp of record creation. Set automatically by MikroORM on first persist; never updated.
updated_atDate, 🔒 system⚪ Notimestamptz, nullable; set via onCreate and onUpdate lifecycle hooksTimestamp of last modification. Set on create and updated on every subsequent write by MikroORM.
deleted_atDate⚪ Notimestamptz, nullable; null = active recordSoft-delete timestamp. When set, the record is treated as deleted across all queries and is excluded from the partial unique index on external_person_id. Never hard-deleted. All repositories must filter deleted_at: null.

Relationships

NameTypeRequiredDescription
workspaceto-one (Workspace)⚪ No (nullable ManyToOne)The workspace that owns this person record. Provides multi-tenant scope: all repository queries filter by workspace. Nullable to allow global catalog entries, though in practice all active People records have a workspace.
source_workspace_connectorto-one (WorkspaceConnector)⚪ No (nullable ManyToOne)The WorkspaceConnector instance that created or last synced this record. NULL for manually created people. Used by the pipeline to track provenance and to surface the connector-logo-name composite in the data-views records page.
mediato-one (Media)⚪ No (nullable ManyToOne)Profile photo / avatar for this person. Linked via a direct ManyToOne to the shared Media entity. The overrides.yml marks media.url as editable with display_type: image; write goes through add/delete join-entity mutations, not a scalar PATCH.
emailsto-many (PersonEmail)⚪ NoEmail addresses linked to this person through the PersonEmail pivot entity. Each pivot record carries is_primary, is_verify, and label (work/personal/other). A partial unique index ensures at most one primary email per person (WHERE deleted_at IS NULL AND is_primary IS TRUE).
phonesto-many (PersonPhone)⚪ NoPhone numbers linked through the PersonPhone pivot entity. Each pivot record carries is_primary, is_verify, and label (mobile/work/personal/other). A partial unique index enforces at most one primary phone per person. Decorated @Enrichable on the People side — enrichment pipeline may populate phone data.
locationsto-many (PersonLocation)⚪ NoGeographic locations linked through the PersonLocation pivot entity. Each pivot record carries is_primary, is_legal, and label. A partial unique index enforces at most one primary location per person.
web_linksto-many (PersonWebLink)⚪ NoSocial profile or other web links associated with this person, linked through the PersonWebLink pivot entity. Decorated @Enrichable on the People side — enrichment pipeline may populate social links (e.g. LinkedIn).
companiesto-many (CompanyPerson)⚪ NoCompany associations for this person, modelled through the CompanyPerson pivot entity. Each pivot record carries a relationship_type enum (contact / employee / owner / other, default: other). A person may be associated with multiple companies across workspaces.
membershipsto-many (Membership)⚪ NoWorkspace membership records for this person. The Membership entity links People to a Workspace with role and status information for platform access control.
collectto-many (Collect)⚪ NoCollect (document collection) records associated with this person. Links the People entity into the document collection pipeline.
workspace_connectorsto-many (WorkspaceConnector)⚪ NoWorkspaceConnector records whose person field points to this People row. Used to associate a connector instance with the authenticated platform user who installed or owns it.
people_workspace_connectorsto-many (PeopleWorkspaceConnector)⚪ NoPer-row provenance records linking this People entity to specific WorkspaceConnector instances that have synced it. Each PeopleWorkspaceConnector record carries a direction enum (inbound/outbound) and its own created_at / updated_at / deleted_at. Analogous to CompanyWorkspaceConnector for Companies.

System-computed

  • person_id is generated by PostgreSQL gen_random_uuid() as a column default; unique constraint peoples_person_id_unique enforced at the DB level.
  • created_at is set via MikroORM onCreate lifecycle hook (new Date()); never updated after first persist.
  • updated_at is set on both onCreate and onUpdate via MikroORM lifecycle hooks; reflects the last modification timestamp.
  • deleted_at is null for active records; set to a timestamp on soft-delete. The partial unique index on (external_person_id, workspace_pk) excludes rows where deleted_at IS NOT NULL, allowing soft-deleted records to be re-created with the same external_person_id.
  • external_person_id is the deduplication key for connector-driven sync: if a sync provides an external_person_id already present in the workspace (under the partial unique constraint), the reconciliation pipeline updates the existing record rather than creating a new one.
  • sourceWorkspaceConnector is set by the sync pipeline at creation time to record which WorkspaceConnector produced this record; NULL for manually created people.
  • The @Enrichable decorator on job_title, phones, and webLinks marks these fields as candidates for AI enrichment via the enrichment pipeline (Cloud Tasks workers).
  • Two partial indexes are maintained by migrations for the records-page query path: idx_peoples_workspace_deleted (workspace_pk WHERE deleted_at IS NULL) and idx_peoples_workspace_created_active (workspace_pk, created_at DESC WHERE deleted_at IS NULL) for default sort order.
  • The composite_avatar_fullname composite field (source_fields: person_id, media.url, full_name; display_type: people_avatar_name) is materialized at query time by the data-views pipeline — it is not a persisted column.
  • The sourceWorkspaceConnector.composite_connector_logo_name composite (source_fields: workspace_connector_id, connector.service_id, connector.name; display_type: connector_logo_name) is likewise a query-time composite on the people records root.

Example

{
  "data": {
    "type": "people",
    "id": "a3f1c2d4-7e89-4b10-bcd2-1f234567890a",
    "attributes": {
      "person_id": "a3f1c2d4-7e89-4b10-bcd2-1f234567890a",
      "full_name": "Sophie Marotremy",
      "first_name": "Sophie",
      "last_name": "Marotremy",
      "job_title": "Head of Finance",
      "external_person_id": "crm_contact_0049281",
      "created_at": "2025-11-03T09:14:22.000Z",
      "updated_at": "2026-03-17T14:55:10.000Z",
      "deleted_at": null
    },
    "relationships": {
      "workspace": {
        "data": { "type": "workspace", "id": "f9e2a1b3-0000-4c2d-8888-aabbccddeeff" }
      },
      "source_workspace_connector": {
        "data": { "type": "workspace_connector", "id": "7a123456-dead-beef-cafe-000000000001" }
      },
      "media": {
        "data": { "type": "media", "id": "bb887766-5544-3322-1100-aabbccddeeff" }
      },
      "emails": {
        "data": [
          { "type": "person_email", "id": "11223344-aaaa-bbbb-cccc-000000000001" }
        ]
      },
      "phones": {
        "data": [
          { "type": "person_phone", "id": "55667788-aaaa-bbbb-cccc-000000000001" }
        ]
      },
      "locations": {
        "data": [
          { "type": "person_location", "id": "99aabbcc-aaaa-bbbb-cccc-000000000001" }
        ]
      },
      "web_links": {
        "data": [
          { "type": "person_web_link", "id": "ddeeff00-aaaa-bbbb-cccc-000000000001" }
        ]
      },
      "companies": {
        "data": [
          { "type": "company_person", "id": "fa1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d" }
        ]
      },
      "memberships": {
        "data": []
      }
    }
  }
}
Source: apps/api/src/database/entities/People.ts · domain: financial-graph · tier: Main