domain tier

domain-contact

Contact channels (phone, email, website) for parties and places

Contact channels (phone, email, website) for parties and places

Tierdomain
Roleunclassified (baselined)
Pathcrates/domain/contact
Edition2021
Targetsdomain_contact
Public items52 across 1 module
Tests28

What it is for

# domain-contact

Contact channels (phone, email, website, social) for parties and places.

Design Philosophy

A Contact answers: "How do I reach this party, optionally at this place?"

Contacts can be attached to:

Key Relationships

Party (Organization/Person)
│
├── Contact (org-level)
│      - main phone
│      - info@ email
│      - primary website
│
└── Place (from domain-geo)
│
└── Contact (place-level)
- local phone
- branch website
- store email

Example

use domain_contact::{Contact, ContactType, ContactPurpose, PartyType};
use uuid::Uuid;

// Org-level contact (no place_id)
let main_phone = Contact::builder()
.tenant_id(Uuid::new_v4())
.party_type(PartyType::Organization)
.party_id(Uuid::new_v4())
.contact_type(ContactType::Phone)
.value("+1-800-555-0199")
.purpose(ContactPurpose::Main)
.label("Toll-Free")
.is_primary(true)
.build()
.unwrap();

// Location-specific contact
let branch_phone = Contact::builder()
.tenant_id(Uuid::new_v4())
.party_type(PartyType::Organization)
.party_id(Uuid::new_v4())
.place_id(Uuid::new_v4())  // Specific branch
.contact_type(ContactType::Phone)
.value("+1-623-555-1234")
.purpose(ContactPurpose::Dispatch)
.build()
.unwrap();

Capabilities

Contact:Contact

# domain-contact

Item
pub struct Contact

Contact:as

# domain-contact

Item
Contact :: fn as_primary(mut self) -> Self

Contact:at

# domain-contact

Item
Contact :: fn at_place(mut self, place_id : Uuid) -> Self

Contact:builder

# domain-contact

Item
Contact :: fn builder() -> ContactBuilder

Contact:created

# domain-contact

Item
Contact :: fn created_at(& self) -> DateTime <Utc>

Contact:deleted

# domain-contact

Item
Contact :: fn deleted_at(& self) -> Option <DateTime <Utc>>

Contact:display

# domain-contact

Item
Contact :: fn display_value(& self) -> String

Contact:email

# domain-contact

Item
Contact :: fn email(tenant_id : Uuid, party_type : PartyType, party_id : Uuid, address : impl Into <String>,) -> Self

Contact:id

# domain-contact

Item
Contact :: fn id(& self) -> Uuid

Contact:is

# domain-contact

Item
Contact :: fn is_org_level(& self) -> bool
Contact :: fn is_place_level(& self) -> bool
Contact :: fn is_verified(& self) -> bool
Contact :: fn is_phone(& self) -> bool
Contact :: fn is_email(& self) -> bool
Contact :: fn is_web(& self) -> bool

Contact:phone

# domain-contact

Item
Contact :: fn phone(tenant_id : Uuid, party_type : PartyType, party_id : Uuid, number : impl Into <String>,) -> Self

Contact:updated

# domain-contact

Item
Contact :: fn updated_at(& self) -> DateTime <Utc>

Contact:verify

# domain-contact

Item
Contact :: fn verify(mut self, verified_by : impl Into <String>) -> Self

Contact:website

# domain-contact

Item
Contact :: fn website(tenant_id : Uuid, party_type : PartyType, party_id : Uuid, url : impl Into <String>,) -> Self

Contact:with

# domain-contact

Item
Contact :: fn with_purpose(mut self, purpose : ContactPurpose) -> Self
Contact :: fn with_label(mut self, label : impl Into <String>) -> Self

ContactBuilder:ContactBuilder

# domain-contact

Item
pub struct ContactBuilder

ContactBuilder:build

# domain-contact

Item
ContactBuilder :: fn build(self) -> Result <Contact, ContactError>

ContactBuilder:contact

# domain-contact

Item
ContactBuilder :: fn contact_type(mut self, contact_type : ContactType) -> Self

ContactBuilder:is

# domain-contact

Item
ContactBuilder :: fn is_primary(mut self, is_primary : bool) -> Self

ContactBuilder:label

# domain-contact

Item
ContactBuilder :: fn label(mut self, label : impl Into <String>) -> Self

ContactBuilder:new

# domain-contact

Item
ContactBuilder :: fn new() -> Self

ContactBuilder:notes

# domain-contact

Item
ContactBuilder :: fn notes(mut self, notes : impl Into <String>) -> Self

ContactBuilder:party

# domain-contact

Item
ContactBuilder :: fn party_type(mut self, party_type : PartyType) -> Self
ContactBuilder :: fn party_id(mut self, party_id : Uuid) -> Self

ContactBuilder:place

# domain-contact

Item
ContactBuilder :: fn place_id(mut self, place_id : Uuid) -> Self

ContactBuilder:purpose

# domain-contact

Item
ContactBuilder :: fn purpose(mut self, purpose : ContactPurpose) -> Self

ContactBuilder:tenant

# domain-contact

Item
ContactBuilder :: fn tenant_id(mut self, tenant_id : Uuid) -> Self

ContactBuilder:value

# domain-contact

Item
ContactBuilder :: fn value(mut self, value : impl Into <String>) -> Self

ContactBuilder:verified

# domain-contact

Item
ContactBuilder :: fn verified(mut self, verified_by : impl Into <String>) -> Self

ContactError

# domain-contact

Item
pub enum ContactError

ContactPurpose

# domain-contact

Item
pub enum ContactPurpose
ContactPurpose :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
ContactPurpose :: fn from_str(s : & str) -> Result <Self, Self::Err>

ContactType

# domain-contact

Item
pub enum ContactType
ContactType :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
ContactType :: fn from_str(s : & str) -> Result <Self, Self::Err>

PartyType

# domain-contact

Item
pub enum PartyType
PartyType :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
PartyType :: fn from_str(s : & str) -> Result <Self, Self::Err>

ContactRepoError

Tenant-scoped repository for contacts.

Item
pub enum ContactRepoError
async fn create_contact_for_tenant(pool : & PgPool, tenant_id : Uuid, contact : & Contact,) -> Result <Contact, ContactRepoError>
async fn find_contact_by_id_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid,) -> Result <Option <Contact>, ContactRepoError>
async fn list_contacts_for_party_for_tenant(pool : & PgPool, tenant_id : Uuid, party_id : Uuid,) -> Result <Vec <Contact>, ContactRepoError>
async fn update_contact_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid, contact_type : ContactType, purpose : Option <ContactPurpose>, value : & str, label : Option <& str>, notes : Option <& str>,) -> Result <Option <Contact>, ContactRepoError>
async fn soft_delete_contact_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid,) -> Result <(), ContactRepoError>
async fn set_primary_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid,) -> Result <Option <Contact>, ContactRepoError>

How to use it

From this crate's own rustdoc:


## Example

From this crate's own rustdoc:

Tenant-scoped `sqlx` repository over the `contacts` table (sprint 3.83 —
this crate previously shipped the domain model with no persistence layer
at all, see the crate's own module doc history).
Contact-related errors.
Missing required field.
The name of the missing field.
Invalid contact value.
The type of contact.
Description of the validation error.
Contact not found.
Duplicate primary contact.
Type of contact channel.
Landline or general phone number.
Mobile/cell phone number.
Fax number.
Email address.
Website URL.
Generic URL (Google Maps, Yelp profile, etc.).
Social media profile.
Purpose/role of the contact.
Primary/main contact.
Dispatch or service scheduling.
Emergency contact.
Billing inquiries.
Customer support.
Sales inquiries.
Appointment scheduling.
Receiving/deliveries.
Unspecified purpose.
Type of party this contact belongs to.
A person.
An organization/company.
A group (household, team).
A contact channel for reaching a party or place.

Represents any method of communication: phone, email, website, social media, etc.
Unique identifier.
Tenant this contact belongs to.
When this contact was created.
When this contact was last updated.
When this contact was soft-deleted (None if active).
Type of party this contact belongs to.
The party (Person, Organization, Group) this contact belongs to.
Optional place (location) this contact is specific to.
If None, this is an org/person-level contact.
Type of contact channel.
Purpose/role of this contact.
The actual contact value (phone number, email, URL, etc.).
Human-readable label (e.g., "Main", "Dispatch", "After Hours").
Whether this is the primary contact for its type+purpose+scope.
When this contact was verified.
Who/what verified this contact.
Additional notes about this contact.
Create a new contact builder.
Check if this is an org/person-level contact (not place-specific).
Check if this is a place-specific contact.
Check if this contact has been verified.
Check if this is a phone-type contact (Phone, Mobile, or Fax).
Check if this is an email contact.
Check if this is a web-type contact (Website, URL, or Social).
Mark this contact as verified.
Get a display-friendly representation.
Builder for `Contact`.
Create a new builder.
Set the tenant ID.
Set the party type.
Set the party ID.
Set the place ID (for location-specific contacts).
Set the contact type.
Set the contact purpose.
Set the contact value.
Set the label.
Set whether this is the primary contact.
Mark as verified.
Set notes.
Build the contact.

# Errors
Returns `ContactError::MissingField` if required fields are missing.
Create a phone contact.

# Example

Module structure

domain_contact

Public surface

`crate root`

ItemWhat it is
pub enum ContactErrorContact-related errors.
pub enum ContactTypeType of contact channel.
ContactType :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
ContactType :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub enum ContactPurposePurpose/role of the contact.
ContactPurpose :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
ContactPurpose :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub enum PartyTypeType of party this contact belongs to.
PartyType :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
PartyType :: fn from_str(s : & str) -> Result <Self, Self::Err>
pub struct ContactA contact channel for reaching a party or place
Contact :: fn builder() -> ContactBuilderCreate a new contact builder.
Contact :: fn is_org_level(& self) -> boolCheck if this is an org/person-level contact (not place-specific).
Contact :: fn is_place_level(& self) -> boolCheck if this is a place-specific contact.
Contact :: fn is_verified(& self) -> boolCheck if this contact has been verified.
Contact :: fn is_phone(& self) -> boolCheck if this is a phone-type contact (Phone, Mobile, or Fax).
Contact :: fn is_email(& self) -> boolCheck if this is an email contact.
Contact :: fn is_web(& self) -> boolCheck if this is a web-type contact (Website, URL, or Social).
Contact :: fn verify(mut self, verified_by : impl Into <String>) -> SelfMark this contact as verified.
Contact :: fn display_value(& self) -> StringGet a display-friendly representation.
Contact :: fn id(& self) -> Uuid
Contact :: fn created_at(& self) -> DateTime <Utc>
Contact :: fn updated_at(& self) -> DateTime <Utc>
Contact :: fn deleted_at(& self) -> Option <DateTime <Utc>>
pub struct ContactBuilderBuilder for Contact.
ContactBuilder :: fn new() -> SelfCreate a new builder.
ContactBuilder :: fn tenant_id(mut self, tenant_id : Uuid) -> SelfSet the tenant ID.
ContactBuilder :: fn party_type(mut self, party_type : PartyType) -> SelfSet the party type.
ContactBuilder :: fn party_id(mut self, party_id : Uuid) -> SelfSet the party ID.
ContactBuilder :: fn place_id(mut self, place_id : Uuid) -> SelfSet the place ID (for location-specific contacts).
ContactBuilder :: fn contact_type(mut self, contact_type : ContactType) -> SelfSet the contact type.
ContactBuilder :: fn purpose(mut self, purpose : ContactPurpose) -> SelfSet the contact purpose.
ContactBuilder :: fn value(mut self, value : impl Into <String>) -> SelfSet the contact value.
ContactBuilder :: fn label(mut self, label : impl Into <String>) -> SelfSet the label.
ContactBuilder :: fn is_primary(mut self, is_primary : bool) -> SelfSet whether this is the primary contact.
ContactBuilder :: fn verified(mut self, verified_by : impl Into <String>) -> SelfMark as verified.
ContactBuilder :: fn notes(mut self, notes : impl Into <String>) -> SelfSet notes.
ContactBuilder :: fn build(self) -> Result <Contact, ContactError>Build the contact
Contact :: fn phone(tenant_id : Uuid, party_type : PartyType, party_id : Uuid, number : impl Into <String>,) -> SelfCreate a phone contact
Contact :: fn email(tenant_id : Uuid, party_type : PartyType, party_id : Uuid, address : impl Into <String>,) -> SelfCreate an email contact.
Contact :: fn website(tenant_id : Uuid, party_type : PartyType, party_id : Uuid, url : impl Into <String>,) -> SelfCreate a website contact.
Contact :: fn at_place(mut self, place_id : Uuid) -> SelfSet the place ID (makes this a location-specific contact).
Contact :: fn with_purpose(mut self, purpose : ContactPurpose) -> SelfSet the purpose.
Contact :: fn with_label(mut self, label : impl Into <String>) -> SelfSet the label.
Contact :: fn as_primary(mut self) -> SelfMark as primary.

`repo`

ItemWhat it is
pub enum ContactRepoErrorErrors from the repository layer
async fn create_contact_for_tenant(pool : & PgPool, tenant_id : Uuid, contact : & Contact,) -> Result <Contact, ContactRepoError>Insert a new contact channel
async fn find_contact_by_id_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid,) -> Result <Option <Contact>, ContactRepoError>One contact by id, scoped to tenant_id
async fn list_contacts_for_party_for_tenant(pool : & PgPool, tenant_id : Uuid, party_id : Uuid,) -> Result <Vec <Contact>, ContactRepoError>Every non-deleted contact for one party, scoped to tenant_id
async fn update_contact_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid, contact_type : ContactType, purpose : Option <ContactPurpose>, value : & str, label : Option <& str>, notes : Option <& str>,) -> Result <Option <Contact>, ContactRepoError>Apply a field update — contact_type/purpose/value/label/notes
async fn soft_delete_contact_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid,) -> Result <(), ContactRepoError>Soft-delete
async fn set_primary_for_tenant(pool : & PgPool, tenant_id : Uuid, id : Uuid,) -> Result <Option <Contact>, ContactRepoError>Demote every other primary contact in the same (party_id, contact_type) scope, then promote id, atomically

No pub use re-exports: every item above is declared in this crate.

Boundary

Reaches into foundation.

Shares tier domain with 41 other crates: domain-agreements, domain-ai-report, domain-billing, domain-catalog, domain-classify, domain-comments, domain-competitive-intel, domain-conversation-engine, … (41 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)domain
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/domain/contact
Vocabulary in force (lexicon)current

Tier flow. Which tiers this crate's own edges cross.

flowchart LR
  n_domain["domain"] --> n_foundation["foundation"]

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`foundation-basemodels`foundationnoalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
chrono^0.4serdenoalways
serde^1derivenoalways
serde_json^1noalways
sqlx^0.8runtime-tokio, postgres, chrono, uuid, jsonnoalways
thiserror^2noalways
tokio^1fullnoalways
uuid^1v4, v7, serde, jsnoalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
tokio-test^0.4noalways

Build. None.

Depended on by. 4 workspace crates.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  n_application_contact["application-contact"] -->|uses| SELF
  n_application_party_discovery["application-party-discovery"] -->|uses| SELF
  n_domain_sender_reputation["domain-sender-reputation"] -->|uses| SELF
  n_infrastructure_web_contact_extractor["infrastructure-web-contact-extractor"] -->|uses| SELF
  SELF["domain-contact"]
  SELF -->|runtime| n_foundation_basemodels["foundation-basemodels"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
libdomain_contact`src/lib.rs`

Error model

Error typeNamed by
ContactErrordeclared, no public signature returns it
ContactRepoErrorcreate_contact_for_tenant, find_contact_by_id_for_tenant, list_contacts_for_party_for_tenant, set_primary_for_tenant, soft_delete_contact_for_tenant, update_contact_for_tenant

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimeyes
database accessyes
network I/Onone detected
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

4 workspace crates depend on this one: application-contact, application-party-discovery, domain-sender-reputation, infrastructure-web-contact-extractor.

Verification

KindCount
Unit tests28
Integration tests0
Examples0
Doctests2

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
crate root6011
repo707

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc4252
Public modules with a //! block11
pie showData
    title Public items with rustdoc
    "Documented" : 42
    "No rustdoc detected" : 10

Metrics

MetricValue
Rust source files2
Source lines1488
Code lines1016
Public API items52
Public modules1
Tests28
Examples0
Cargo features0
Direct runtime dependencies8
Workspace reverse dependencies4
pie showData
    title Public API by kind
    "enum" : 5
    "function" : 6
    "method" : 39
    "struct" : 2
pie showData
    title Rust source composition
    "Code" : 1016
    "Blank or comment" : 472

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All domain · Manual