Skip to main content

Contacts

πŸ“– Overview​

internal/api/v1/crm/services/contact.service.js is the largest CRM surface. It manages people and business records, enforces owner/follower visibility preferences, maps custom fields, handles attachments and exports, and orchestrates background jobs for bulk linking or imports. Controllers mostly validate payloads; this service performs the real liftingβ€”Mongo aggregations, Stripe-style pagination, Wasabi cleanup, queue insertion, and CRM activity fan-out.

πŸ—„οΈ Collections Used​

πŸ“š Full Schema: See Database Collections Documentation

crm.contacts​

  • Operations: Heavy read/write (aggregation, create/update/delete, bulk operations)
  • Model: shared/models/contact.js
  • Usage Context: Stores person/business records, embedded custom fields, attachments, associations

_accounts​

  • Operations: Lookups to resolve sub-account status (aggregations in list endpoints)
  • Model: shared/models/account.js
  • Usage Context: Adds account metadata during list queries and exports

crm.notes​

  • Operations: Create during bulk note association
  • Model: shared/models/crm-note.js
  • Usage Context: Records note content when putAssociateNotesContact runs

crm.activity​

  • Operations: Inserts via addActivity utility when notes are attached in bulk
  • Model: shared/models/activity.js
  • Usage Context: Audit trail for contact interactions

queues​

  • Operations: Inserts linking jobs (putAssociateContact) and CSV processing tasks
  • Model: shared/models/queues.js
  • Usage Context: Asynchronous contact linking and post-checkout workflows

Supporting Collections​

  • crm-tag, crm.pipeline.stages, crm.deals, crm.import.results, crm.attachments (via Wasabi metadata)
  • External integration tokens (hubspot-key, salesforce-key, etc.) resolved by getConnectedContact

πŸ”„ Data Flow​

flowchart TD
A[Request] --> B{Owner visibility?}
B -->|no| C[Build filters from search/filter payload]
B -->|restricted| D[Append owner/follower clause]
C --> E[Aggregate contacts]
D --> E
E --> F[setupContactPromises]
F --> G[expandContacts (currency, totals, associations)]
G --> H[Response]

subgraph Mutations
I[Create/Update Payload] --> J[validateTags + validateEmailOrMobile]
J --> K[Verify associations]
K --> L[Contact.save/update]
L --> M[Assignment helpers + expandContacts]
M --> H
end

subgraph Attachments
N[Add/Delete attachment] --> O[Wasabi upload/delete]
O --> P[Update contact attachments]
P --> H
end

subgraph Bulk Ops
Q[Mass selection/all switch] --> R[Contact.find/count]
R --> S[Queue job or apply loop]
S --> H
end

πŸ”§ Business Logic & Functions​


getContact({ account_id, is_owner, uid, page, limit, search, filter, filters, accountCurrency, auth })​

  • Purpose: Master list endpoint combining search, advanced filters, and pagination.
  • Highlights:
    • Builds regex search across core fields and nested additional_info entries.
    • Enforces owner visibility preferences (owner_followers) when the requester is not the owner.
    • Aggregates _accounts to append sub_account_status before filtering.
    • Expands contacts via setupContactPromises + expandContacts to hydrate computed properties (balances, linked entities, currency formatting).
  • Errors: Returns { success:false, errno:400 } with the thrown message when queries or expansions fail.

getBusinessesContact / getPeopleContact​

  • Purpose: Type-specific list endpoints for businesses and people.
  • Highlights:
    • Support origin, sorting, association toggles, and populate flags.
    • Normalise associated records (linked contacts) and optionally limit expansions.
    • Apply additional filters such as associated boolean, associated_limit, and custom sorts (including stage-based ordering for people linked to deals).
  • Side Effects: Noneβ€”pure read.

postFilterContact​

  • Purpose: JSON-filtered search using the builder in utilities.generateMongoDbQuery.
  • Highlights: Accepts advanced logical expressions, respects visibility rules, and shares the same expansion pipeline as general lists.

postSearchContact​

  • Purpose: Global search across contacts (people/business/both) with optional type filtering.
  • Highlights: Normalises search text, dedupes results, and respects type parameter semantics.

getConnectedContact​

  • Purpose: Report which third-party CRMs (HubSpot, Salesforce, Keap, Zoho, Pipedrive, Constant Contact, Mailchimp, ActiveCampaign) are connected for a given owner.
  • Highlights: Fetches token documents per provider and returns connected/token_id flags.

getBusinessContact, getPersonContact, getBusinessAssociatedContact​

  • Purpose: Detailed views with optional expansions for attachments, associated records, tags, deals, and currencies.
  • Highlights: Use setupBusinessContactPromises/getBusinessAssociatedContacts utilities to hydrate relationships and guard access by visibility rules.

exportBusinessesContact, exportPeopleContact​

  • Purpose: CSV export using json2csv and Wasabi for storage when required.
  • Highlights: Apply same filtering logic as list endpoints, stream formatted data (including expanded custom fields) for download.

getTotalNewContact​

  • Purpose: Return counts per contact type within a date window.
  • Highlights: Aggregates by type after applying owner visibility restrictions.

Creation & Updates​

postBusinessContact, postPersonContact​

  • Purpose: Create business or person contacts.
  • Highlights:
    • Validate tags via validateTags and enforce unique email/phone through validateEmailOrMobile.
    • Resolve relationships (businessAndPersonAssignment, verifyContactIds) before persisting.
    • Store owner defaults (owner fallback to creator) and capture metadata like last_activity, last_contacted.
    • After save, run expansion pipeline to return enriched payload.

putBusinessContact, putPersonContact​

  • Purpose: Update existing contacts.
  • Highlights:
    • Guard against editing locked contacts (limited to follower assignments, deals, etc.).
    • When owner changes, adjust follower lists to avoid duplicates.
    • Resynchronise relationships (business ↔ person) and map custom fields via mapFields.
    • Re-expand response to mirror creation output.

putAttachmentsContact​

  • Purpose: Append attachments to contacts.
  • Highlights: Accepts metadata payloads, pushes attachments to embedded array, ensures Wasabi keys are preserved for later deletions.

deleteAttachmentContact​

  • Purpose: Remove a specific attachment.
  • Highlights: Deletes Wasabi object via Wasabi.deleteByKey then updates contact document.

deleteBusinessContact, deletePersonContact​

  • Purpose: Remove single contacts (soft delete semantics defined by controller).
  • Highlights: Validate ownership/visibility and clean up associations when necessary.

deletePeopleContact, deleteBusinessesContact​

  • Purpose: Bulk deletions using selected IDs or the all switch.
  • Highlights: Validate contact counts before deletion, optionally pull IDs by re-running filters when all is true.

Bulk Associations & Notes​

putAssociateContact​

  • Purpose: Assign owners/followers in bulk.
  • Highlights: Validates visibility scope, supports all vs specific IDs, and queues background linking jobs for cross-contact association when requested.

putAssociateTagContact​

  • Purpose: Add/remove tags in bulk.
  • Highlights: Validates tag IDs via validateTags, applies add/remove semantics, and ensures duplicates are prevented.

putAssociateNotesContact​

  • Purpose: Attach the same note (and optional attachments) to multiple contacts.
  • Highlights: Creates CRMNote entries per contact, pushes attachments, triggers addActivity for each note, and respects visibility filters.

Filtering, Linking & Utilities​

linkCustomers​

  • Purpose: Persist Stripe mapping details for contact bulk linking flows.
  • Highlights: Normalises mapping keys (replace dots with dashes), updates StripeToken, and optionally enqueues a queues job to process linking asynchronously.

removeContactFromDeals, purgeInstasitesAndReports, removeAssociatedAccounts​

  • Purpose: Helper utilities to clean dependent resources when contacts are deleted.

purge helpers & deleteAdditionalData​

  • Purpose: Ensure no orphaned attachments, reports, or associated data remain after deletion.

Attachments & Media​

  • Uses Wasabi utility for upload and deletion whenever attachments are added or removed.
  • Attachment payloads normalised to include id, key, location, and content_type.
  • Cleans up Wasabi objects during contact deletion or attachment removal loops.

Background Jobs & Exports​

  • Queue jobs created for bulk linking (linkCustomers) and for contact note association when executed asynchronously.
  • exportPeopleContact/exportBusinessesContact leverage json2csv and may stream results directly or via Wasabi, depending on controller context.

πŸ”€ Integration Points​

Internal Dependencies​

  • ../utils/contact β†’ utilities for mapping, expansion, tag validation, timezone lookup.
  • shared/utilities/filter β†’ builds MongoDB queries from filter payloads.
  • shared/utilities/wasabi β†’ attachment storage management.
  • shared/utilities/activity β†’ creates CRM activity records.
  • shared/utilities/catch-errors β†’ consistent error envelopes (custom, notAllowed, conflict).

External Services​

  • Wasabi S3 – stores attachments and exported CSV assets.
  • Conversation Socket – authenticated POST to ${CONVERSATION_SOCKET}/emit when notifications must be broadcast (during Stripe mapping updates).

πŸ§ͺ Edge Cases & Special Handling​

  • Visibility rules: Every list/update path enforces owner/follower preferences when is_owner is false.
  • Duplicate prevention: validateEmailOrMobile and fingerprint checks stop duplicates on creation.
  • Bulk all operations: Safe guards ensure the contact count matches before applying updates/deletes.
  • Attachment cleanup: Wasabi keys are always removed before array updates to avoid orphaned files.
  • Cross-link verification: verifyContactIds blocks associating inaccessible contacts across types.

⚠️ Important Notes​

  • 🚨 Do not edit service-level models/utilities – rely on /shared copies.
  • πŸ’‘ Always rerun setupContactPromises after mutating contacts to guarantee parity with UI expectations.
  • πŸ› CSV filter errors: malformed filter payloads return Query Validation Error; controllers should surface error to user intact.
πŸ’¬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM