email resource is a canonically-stored email address shared across the financial graph. It functions as an atomic contact channel rather than a top-level business entity: a single Email row holds exactly one RFC 5321 address and is linked to companies via the CompanyEmail pivot and to people via the PersonEmail pivot — both pivots carry metadata (is_primary, is_verify, label). The record is workspace-scoped through an optional @ManyToOne to Workspace, and is deduplicated per workspace via a find-or-create pattern keyed on (email, workspace_pk, deleted_at IS NULL).
Read access today: this object is readable via the universal
POST /v1/records/query endpoint with root: "emails". A dedicated GET /v1/emails endpoint is Planned.API operations
Data model
Attributes
Relationships
System-computed
- email_id is generated by gen_random_uuid() at the database default level and also explicitly set in EmailRepository.findOrCreate() via Node.js randomUUID() to ensure the value is available before flush.
- created_at is set on insert by MikroORM onCreate: () => new Date().
- updated_at is set on both insert and update by MikroORM onCreate/onUpdate lifecycle hooks.
- deleted_at is null on creation; set to the current timestamp by EmailRepository.delete() as a soft-delete operation. Live queries must always filter deleted_at: null.
- Find-or-create deduplication: EmailRepository.findOrCreate() normalizes the input address via .trim().toLowerCase(), then queries (email, workspace, deleted_at: null). When a workspace is not provided the scope falls back to (email, deleted_at: null) globally. A new Email row is only created when no matching live record is found.
- Composite views: the
emailsrecords root exposes two composites —composite_companies_list(relation_list of company_id + company.name, via company_emails reverse) andcomposite_people_list(relation_list of person_id + full_name, via person_emails reverse). These are defined in composites.yml and reconstructed at query time. - Hasura RLS for the user role filters deleted_at IS NULL and resolves workspace tenancy indirectly: an email is visible if any linked company_email or person_email traces to a workspace matching X-Hasura-Workspace-Id (direct or parent-workspace cascade via workspace_group).
Example
apps/api/src/database/entities/Email.ts · domain: financial-graph · tier: Supporting