Location

A Location is a normalized postal address record shared across the financial graph. It captures a structured postal address (address lines, city, region, postal code, and ISO-3166-1 alpha-2 country code) that companies and people reference through pivot entities (CompanyLocation and PersonLocation). A single location row may be linked to multiple companies or people across a workspace, allowing address deduplication. The workspace association scopes it to a tenant and is nullable to allow global or pre-scoping rows.

NamingValue
ObjectLocation
Resource type (JSON:API type)location
Collection / records rootlocations
REST base/v1/locations
Entity classLocation

API operations

OperationMethod & pathStatus
ListGET /v1/locations✅ Implemented
List (nested)GET /v1/companies/{id}/locations · GET /v1/people/{id}/locations✅ Implemented
RetrieveGET /v1/locations/{id}✅ Implemented
Create (nested)POST /v1/companies/{id}/locations✅ Implemented
UpdatePATCH /v1/locations/{id}🟡 Planned
Delete (nested)DELETE /v1/companies/{id}/locations/{subId}✅ Implemented

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
location_idstring, UUID, 🔒 system✅ Yesunique; DEFAULT gen_random_uuid()Public stable identifier for this location. Generated server-side on creation.
full_addressstring✅ Yesno explicit length constraintDenormalized single-line representation of the complete address. Used as the primary display string in the records table.
address_line1string✅ Yesno explicit length constraintPrimary street address line (street number and street name).
address_line2string⚪ Nonullable; no explicit length constraintSecondary address line for suite, floor, building, or apartment information.
citystring✅ Yesno explicit length constraintCity or municipality of the address.
regionstring⚪ Nonullable; no explicit length constraintState, province, département, or region. Nullable because many EU addresses do not carry a region field.
postal_codestring⚪ Nonullable; no explicit length constraintPostal or ZIP code. Nullable to accommodate countries or address forms that do not have postal codes.
countrystring✅ Yesvarchar(2); ISO-3166-1 alpha-2Any valid ISO-3166-1 alpha-2 code (e.g. FR, US, DE, GB)Two-letter country code. The 2-character length constraint is enforced at the database column level via @Property({ length: 2 }).
created_atstring (ISO 8601 datetime), 🔒 system✅ Yestimestamptz; set on insert via onCreate lifecycle hookTimestamp of when the location record was created. Set automatically by MikroORM on first persist.
updated_atstring (ISO 8601 datetime), 🔒 system⚪ Notimestamptz; set on insert and update via onCreate/onUpdate lifecycle hooks; not explicitly nullable at DB levelTimestamp of the last update to this location record. Maintained automatically by MikroORM. Declared as optional TypeScript type but not null in the database.
deleted_atstring (ISO 8601 datetime)⚪ Notimestamptz; nullable; null = not deletedSoft-delete timestamp. When set, the location is considered deleted. All queries must filter deleted_at IS NULL.

Relationships

NameTypeRequiredDescription
workspaceto-one (workspace)⚪ NoOptional tenant scope FK to core_api.workspaces (workspace_pk; ON UPDATE CASCADE ON DELETE SET NULL). Nullable to allow locations created before workspace scoping was retrofitted (Migration20260119180000). When present, restricts the location to the owning workspace.
company_locationsto-many (company_location)Pivot entity CompanyLocation (core_api.company_locations) links this location to one or more companies. Each pivot carries is_primary, is_legal, label, created_at, and deleted_at. A partial unique index (uniq_company_locations_primary_company WHERE deleted_at IS NULL AND is_primary IS TRUE) enforces at most one primary location per company.
person_locationsto-many (person_location)Pivot entity PersonLocation (core_api.person_locations) links this location to one or more people. Each pivot carries is_primary, is_legal, label, created_at, and deleted_at. A partial unique index (uniq_person_locations_primary_person WHERE deleted_at IS NULL AND is_primary IS TRUE) enforces at most one primary location per person.

System-computed

  • location_id is generated server-side via PostgreSQL DEFAULT gen_random_uuid() (Migration20260224100000). The column was added retroactively to all pre-existing rows via NOT NULL DEFAULT, backfilling historical rows on migration.
  • created_at is set on INSERT by the MikroORM @Property({ onCreate: () => new Date() }) lifecycle hook. Not client-settable.
  • updated_at is set on INSERT and on every UPDATE by the @Property({ onCreate/onUpdate }) lifecycle hooks. Not client-settable.
  • deleted_at is the soft-delete sentinel. Null means active. Any non-null value means soft-deleted. All repository queries must include deleted_at: null.
  • workspace FK (workspace_pk) was added in Migration20260119180000 with ON UPDATE CASCADE ON DELETE SET NULL. Locations created before workspace scoping have workspace_pk = NULL; this is a valid legacy state and not a data integrity issue.
  • full_address is a denormalized convenience field written by the ingestion pipeline or enrichment service. It is not computed by a SQL function — it must be maintained by the writer at creation/update time.
  • Bridge-table indexes (idx_company_locations_company_deleted, idx_company_locations_location, idx_person_locations_location, idx_person_locations_person) were added in Migration20260416100000 to support efficient bi-directional array-relationship traversals from Hasura.
  • The primary_location Hasura computed field (Migration20251007135956) resolves the single active primary location for a company via a PostgreSQL function (core_api.company_primary_location) joining company_locations to locations WHERE is_primary = true AND deleted_at IS NULL. Exposed as issuer.primary_location and receiver.primary_location on invoices in overrides.yml.

Example

{"data": {"type": "location", "id": "7e3f9b24-14ac-4a5d-b8e1-c23d0f6a9107", "attributes": {"location_id": "7e3f9b24-14ac-4a5d-b8e1-c23d0f6a9107", "full_address": "12 Rue de la Paix, 75001 Paris, France", "address_line1": "12 Rue de la Paix", "address_line2": "3ème étage", "city": "Paris", "region": "Île-de-France", "postal_code": "75001", "country": "FR", "created_at": "2025-09-14T08:22:31.000Z", "updated_at": "2026-02-03T11:47:15.000Z", "deleted_at": null}, "relationships": {"workspace": {"data": {"type": "workspace", "id": "a1b2c3d4-0000-4abc-8def-112233445566"}}}}}
Source: apps/api/src/database/entities/Location.ts · domain: financial-graph · tier: Supporting