Skip to main content
The identity module is a low-level shared primitive, not a CRM. It owns three generic records, contact points, addresses, and named contacts, that any entity in the system can attach by reference. A Person, an organization, a supplier, or a facility does not store its own phone columns and address columns. It points at identity records instead, so contact data stays canonical and consistent across every consumer. It ships as @voyant-travel/identity with Drizzle schema, Zod validation, a sync and hydration service, and Hono routes.

Key concepts

  • Generic attachment. Every identity record carries an entityType and entityId pair, not a typed foreign key. A contact point belongs to whatever entity those two columns name, so identity never depends on its consumers and any module can attach to it.
  • Contact points. A contact point is one reachable channel for an entity: an email, phone, mobile, whatsapp, website, sms, fax, social, or other value, with an optional label, a normalized value for matching, and an isPrimary flag.
  • Addresses. A structured postal address with line1, line2, city, region, postalCode, and country, plus optional latitude, longitude, and timezone. Each address carries a label such as primary, billing, shipping, mailing, meeting, service, or legal.
  • Named contacts. A person of contact attached to an entity, such as a reservations or accounting contact at a supplier, with a name, optional title, inline email and phone, and a role such as reservations, operations, front_desk, sales, accounting, or emergency.
Identity is contact data, not relationship history. It owns reachable channels, postal addresses, and named points of contact. Customer records, pipelines, and timelines belong to the relationships module, which is a consumer of identity, not the other way around.

What it owns

The module owns three Drizzle tables, each with a TypeID prefix: All three share the same shape: an entityType and entityId pair, an isPrimary flag, free-form notes, a metadata JSON column, and timestamps. The tables are indexed by (entityType, entityId) so listing an entity’s contact data is a single fast lookup.

Working with it

Standard modules are not registered by hand. @voyant-travel/identity is part of the standard product graph, so its routes, services, subscribers, and jobs are resolved into the application at build time. See Configuration. Call the service directly to attach a contact point to any entity by its type and id:
Read every contact point, address, or named contact for an entity in one call:
The schema and validation surfaces are available on their own subpaths for consumers that need the tables (@voyant-travel/identity/schema) or the Zod insert and update schemas (@voyant-travel/identity/validation).
  • Relationships. A Person create or update syncs inline contact fields (email, phone, website, address, city, country) into identity records, keeping the relationships module’s contact data canonical here rather than duplicated on its own tables.
  • Distribution. Suppliers attach contact points, addresses, and named contacts (reservations, operations, accounting) by reference rather than carrying their own contact columns.
  • Operations. Facilities and venues use identity addresses and named contacts for their physical location and on-site points of contact.

Next steps

Relationships

The People and organizations that sync inline contact data into identity.

Distribution

Suppliers that attach contact points and named contacts by reference.

Links

How modules associate records without hard foreign keys.

Glossary

The canonical vocabulary for entities and contact data.