Add Tag Automation Processor
Overview
The Add Tag automation adds CRM tags to deals when they enter a specific pipeline stage. It validates tag existence, prevents duplicates, and tracks automation status with retry logic.
Source File: queue-manager/queues/deals/automations/add-tag.js
Triggered By: queue-manager/services/deals/automations.js
Business Impact: MEDIUM - Deal organization
Processing Logic
sequenceDiagram
participant AUTO as Automation Service
participant QUEUE as Add Tag Queue
participant DEAL as Deals Collection
participant TAG as CRM Tags
AUTO->>QUEUE: Add automation job
QUEUE->>TAG: Validate tag exists
TAG-->>QUEUE: Tag valid
QUEUE->>DEAL: Find eligible deals<br/>(stage + time window)
loop For Each Deal
QUEUE->>DEAL: Check if tag exists
alt Tag Not Present
QUEUE->>DEAL: Add tag to deal.tags[]
QUEUE->>DEAL: Mark automation triggered
else Tag Exists
QUEUE->>DEAL: Skip (already tagged)
end
end
QUEUE->>AUTO: Update automation status
Key Features
Validation
- Tag ID Validation: Checks if tag is valid ObjectId
- Tag Existence: Verifies tag exists in account
- Duplicate Prevention: Skips deals already having the tag
Deal Eligibility
Deals must meet ALL criteria:
stage_idmatches automation stageautomation_startsless than or equal to delayed date (now - delay)automation_startsgreater than or equal to automation creation date- NOT in
skip_automationsarray - NOT in
automation_triggeredarray - OR in
retry_automationsarray
Delayed Execution
const delayedDate = moment().subtract(automation.delay, 'seconds');
Allows configurable delay after deal enters stage.
Core Code Pattern
// Validate tag
if (!tag || !mongoose.Types.ObjectId.isValid(tag)) {
throw new Error('Invalid tag id provided');
}
const validTag = await CrmTag.countDocuments({ _id: tag, account: accountID });
if (!validTag) {
throw new Error('Tag not found.');
}
// Find eligible deals
let dealData = await Deal.find({
stage_id: automation.stage_id,
$and: [
{ automation_starts: { $lte: delayedDate.toDate() } },
{ automation_starts: { $gte: automation.createdAt } },
],
$or: [
{ retry_automations: automationId },
{
$and: [
{ skip_automations: { $ne: automationId } },
{ automation_triggered: { $ne: automationId } },
],
},
],
}).exec();
// Add tag to each deal
for (const deal of dealData) {
const tags = deal._doc.tags || [];
if (tags.find(t => t.toString() === tag.toString())) {
throw new Error('Tag already associated.');
}
if (deal.tags) {
deal.tags.push(new mongoose.Types.ObjectId(tag));
} else {
deal.tags = [new mongoose.Types.ObjectId(tag)];
}
await deal.save();
}
Collections Used
Input: deal-automation
- Automation configuration
Validation: crm-tag
- Tag existence verification
Update: deal
- Add tag to deal.tags array
- Update automation tracking fields
Automation Tracking
Success Tracking
{
automation_triggered: [automationId],
retry_automations: [], // Removed after success
skip_automations: [] // Not added
}
Failure Tracking
{
retry_automations: [automationId], // Added on failure for retry
skip_automations: [], // Can be manually added to skip
automation_triggered: [] // Not added until success
}
Error Handling
Common Errors
- Invalid Tag ID: Not a valid ObjectId
- Tag Not Found: Tag doesn't exist in account
- Tag Already Associated: Deal already has this tag
- Deal Not Found: Deal was deleted
Error Response
{
deal: dealID,
tag_id: ObjectId,
message: "Tag already associated.",
additional_info: {...}
}
Use Cases
Example 1: Lead Qualification
// Automation
{
stage_id: "hot_leads",
action: "add_tag",
data: { tag: "qualified" },
delay: 0
}
// Result: All deals in "hot_leads" stage get "qualified" tag
Example 2: Delayed Tagging
// Automation
{
stage_id: "new_lead",
action: "add_tag",
data: { tag: "needs_follow_up" },
delay: 86400 // 24 hours
}
// Result: Tag added 24 hours after deal enters stage
Performance
Execution Time: 100-500ms per automation
Batch Size: All eligible deals in one run
Retry Strategy: 3 attempts with exponential backoff
Complexity: LOW
Lines of Code: 163