Contact
The contact module manages caller identities across the platform. When a call comes in, the system automatically resolves the caller’s phone number to a contact — creating a stub if needed. After the call, GPT-5 extracts the caller’s name and email from the transcription to enrich the record.
How It Works
Section titled “How It Works”Inbound call from +15551234567 → resolve_contact("+15551234567", org_id) Match in contact_phone? → Return contact ID No match? → Create stub contact + link phone → Return new ID
Call ends → Transcription saved → enrich_contact(call_id) Stub contact? → GPT-5 extracts name/email from transcription → Update recordData Model
Section titled “Data Model”Contact
Section titled “Contact”pub struct Contact { pub id: Uuid, pub first_name: String, pub last_name: String, pub phones: Vec<ContactPhone>, pub emails: Vec<ContactEmail>, pub created_at: String,}ContactPhone
Section titled “ContactPhone”pub struct ContactPhone { pub id: Uuid, pub phone_number: String, // E.164 format pub label: Option<String>, // e.g. "Work", "Mobile" pub is_preferred: bool,}ContactEmail
Section titled “ContactEmail”pub struct ContactEmail { pub id: Uuid, pub email: String, pub label: Option<String>, pub is_preferred: bool,}A contact has many phone numbers and many email addresses. The is_preferred flag marks the primary entry for each type — used by other modules (e.g. the todo system uses the preferred email when sending follow-up emails).
Contact Resolution
Section titled “Contact Resolution”resolve_contact runs when an inbound call arrives, linking the caller to a contact record.
pub async fn resolve_contact( caller_phone: &str, organization_id: Uuid,) -> Result<Uuid, AppError>Flow:
- Search
contact_phonefor a matching phone number - If found: verify the contact belongs to the same org → return contact ID
- If not found: create a stub contact (
first_name: "",last_name: "") → add the phone number as preferred → return new contact ID
Each phone number exists once in the system — no duplicates across contacts.
Contact Enrichment
Section titled “Contact Enrichment”enrich_contact runs after a call is transcribed, filling in stub contacts with real data.
pub async fn enrich_contact(call_id: Uuid) -> Result<(), AppError>Flow:
- Load the call — skip if no
contact_idor no transcription - Load the contact — skip if already enriched (either name field is non-empty)
- Send transcription to GPT-5 with structured output to extract:
first_name(empty string if not mentioned)last_name(empty string if not mentioned)email(null if not mentioned)
- Update contact name if either field was extracted
- Create a
contact_emailrecord if an email was found (lowercased, marked as preferred)
API Endpoints
Section titled “API Endpoints”All endpoints require an authenticated session.
Contacts
Section titled “Contacts”| Route | Method | Description |
|---|---|---|
/api/contacts | GET | List all org contacts (newest first) |
/api/contacts/{id} | GET | Get contact with phones and emails |
/api/contacts | POST | Create a contact (first_name, last_name) |
/api/contacts/{id} | PUT | Update name fields |
/api/contacts/{id} | DELETE | Delete a contact |
Phone Numbers
Section titled “Phone Numbers”| Route | Method | Description |
|---|---|---|
/api/contacts/{contact_id}/phones | POST | Add a phone number |
/api/contacts/{contact_id}/phones/{phone_id} | PUT | Update a phone number |
/api/contacts/{contact_id}/phones/{phone_id} | DELETE | Remove a phone number |
Email Addresses
Section titled “Email Addresses”| Route | Method | Description |
|---|---|---|
/api/contacts/{contact_id}/emails | POST | Add an email address |
/api/contacts/{contact_id}/emails/{email_id} | PUT | Update an email address |
/api/contacts/{contact_id}/emails/{email_id} | DELETE | Remove an email address |
Module Structure
Section titled “Module Structure”src/mods/contact/├── api/ # CRUD for contacts, phones, emails├── components/ # UI: contact list, card, details, phone/email cards, create form├── services/ # resolve_contact, enrich_contact├── types/ # Contact, ContactPhone, ContactEmail + data DTOs└── views/ # ContactListView, ContactDetailsView, CreateContactViewRelated Modules
Section titled “Related Modules”- Call — calls link to contacts via
contact_id; enrichment runs post-transcription - Todos —
SendEmailToCallertool uses the contact’s preferred email - Supporting Modules — dashboard shows active/total contact counts