Skip to main content
Version: v1.0.0(int)

Contacts

Shared contacts pool — people linked polymorphically to customers, vendors, locations, etc. Each contact can carry multiple methods (email / phone) and can be linked to multiple entities.

Tables owned

TablePurpose
org.contactsContact records (first/last name, title, notes).
org.contact_methodsEmail / phone methods attached to a contact, with label.
org.entity_contactsPolymorphic linker. (entity_type, entity_id, contact_id) with role + notes. entity_id is application-enforced (no DB FK).

contact_methods is owned here too — it's a subordinate of contacts with no independent consumers. Implicit in the table list above.

Operations

Writes — Contacts

  • createContact(conn, input)Contact. input: { firstName, lastName?, title?, notes? }.
  • updateContact(conn, contactId, patch)Contact. Partial update.
  • deleteContact(conn, contactId)void. Cascades to methods and entity_contact links.

Writes — Contact methods

  • addMethod(conn, contactId, { type, value, label? })ContactMethod. type: 'email' | 'phone'.
  • updateMethod(conn, methodId, patch)ContactMethod.
  • deleteMethod(conn, methodId)void.
  • linkToEntity(conn, { contactId, entityType, entityId, role?, notes? })EntityContact. entityType is the entity_type enum.
  • updateLink(conn, linkId, patch)EntityContact. Edits role / notes.
  • unlink(conn, linkId)void. Removes the association without deleting the contact.

Reads — Contacts

  • listContacts(conn, filters?)Contact[]. Filters: { q? } (name/email search).
  • getContactById(conn, contactId)Contact | null.
  • getContactsByIds(conn, contactIds)Contact[]. Batch hydration.

Reads — Methods

  • listMethodsForContact(conn, contactId)ContactMethod[].
  • listContactsByEntity(conn, entityType, entityId)Array<{ link: EntityContact, contact: Contact, methods: ContactMethod[] }>. The hydrated view used on Customer/Vendor detail pages.
  • listEntityContactsByEntity(conn, entityType, entityId)EntityContact[]. Link rows only (for L3 to compose its own hydration).
  • getLinkById(conn, linkId)EntityContact | null.

Notes

  • The component never resolves entity_id back to its source table. That's L3's job (it knows which component owns the entity).
  • entity_type values are enum-controlled. Adding a new entity type requires a migration on the enum, not a code change here.