Skip to main content

Tags

πŸ“– Overview​

internal/api/v1/crm/services/tag.service.js exposes CRUD helpers for account-level tags shared between contacts and deals. It handles pagination, case-insensitive uniqueness checks, respects lock flags (preventing non-admin updates), and keeps tag references tidy across CRM entities during deletions. Controllers supply validated inputs; this service executes Mongo queries, permission checks, and cascading updates.

πŸ—„οΈ Collections Used​

πŸ“š Full Schema: See Database Collections Documentation

crm-tag​

  • Operations: All CRUD plus lock flag checks (is_locked)
  • Model: shared/models/crm-tag.js
  • Usage Context: Stores tag text, account ownership, creator, lock state, and metadata

crm.contacts​

  • Operations: $pull / $pullAll cleanup when tags are removed
  • Model: shared/models/contact.js
  • Usage Context: Ensures contacts no longer reference deleted tags

crm.deals​

  • Operations: $pull / $pullAll updates to strip removed tag IDs
  • Model: shared/models/deal.js
  • Usage Context: Keeps deal tag arrays aligned after deletes

πŸ”„ Data Flow​

flowchart TD
Client --> Controller
Controller --> TagService
TagService -->|list/create| Tags[(crm-tag)]
TagService -->|cleanup| Contacts[(crm.contacts)]
TagService -->|cleanup| Deals[(crm.deals)]
Tags --> Response

🧭 Service Entry Points​

Listing & Detail​

  • getTag({ account_id, uid, page, limit, search, sortOrder })

    • Coerces pagination args, applies account scoping, and filters by search using case-insensitive regex
    • Returns sorted results with pagination metadata from utilities.generatePagination
  • getOneTag({ account_id, uid, id })

    • Fetches a single tag by _id and account, raising an error when missing

Creation & Update​

  • postTag({ account_id, uid, tag })

    • Rejects duplicates via regex match and enforces is_locked guard (locked tags ban creation for non-admin contexts)
    • Persists the tag document with creator metadata
  • updateOneTag({ account_id, uid, tag, id })

    • Confirms existence, honors is_locked, then validates uniqueness before updating the tag string

Deletion​

  • deleteOneTag({ account_id, id })

    • Verifies the tag belongs to the account, deletes it, and $pulls the ID from related deals and contacts
  • deleteMultiTag({ account_id, tags })

    • Converts incoming IDs to ObjectId, ensures all exist for the account, and runs deleteMany plus $pullAll cleanup on both contacts and deals

πŸ”— Integration Points​

Internal​

  • utilities.generatePagination delivers consistent paging payloads for list responses
  • mongoose conversions are used before bulk deletes to match stored ObjectId types

External​

  • None directlyβ€”the service strictly manipulates Mongo collections

⚠️ Edge Cases & Guardrails​

  • Lock enforcement: Documents flagged is_locked block create/update attempts, returning ACCESS_DENIED
  • Case-insensitive uniqueness: Regex ensure Tag and tag are treated as duplicates
  • Bulk validation: deleteMultiTag validates every ID belongs to the caller’s account before deleting
  • Cleanup: Both deletion paths remove tag IDs from contact and deal arrays to prevent orphan references
πŸ’¬

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