Skip to main content

Auto Response Rules Controller

Source: internal/api/v1/reviews/controllers/auto-response-rules.js
Service: autoResponseRules service
Module: Reviews


Overview

The Auto Response Rules controller manages automated response rules that trigger based on review conditions (rating, platform, keywords). It enables businesses to automatically respond to reviews matching specific criteria, improving response time and consistency.

Key Capabilities

  • Create Automated Rules with condition-based triggers
  • List All Rules with pagination
  • Update Rules for active/inactive state and conditions
  • Delete Rules when no longer needed
  • Duplicate Rules for easy template creation
  • Condition Matching on rating, platform, keywords

MongoDB Collections

CollectionOperationsPurpose
review-auto-response-rulesCREATE, READ, UPDATE, DELETEStore automation rules

Service Methods

1. create()

Create a new auto-response rule with conditions and response template.

Endpoint: POST /reviews/auto-response-rules

Controller Logic:

exports.create = catchAsync(async (req, res) => {
const account_id = req.auth.account_id;
const user_id = req.auth.uid;
const { name, active, conditions } = req.body;

const data = await autoResponseRules.create({ account_id, user_id, name, active, conditions });

res.json({
success: true,
data,
});
});

Request:

POST /api/v1/v1/reviews/auto-response-rules
Content-Type: application/json

{
"name": "Positive Review Auto-Response",
"active": true,
"conditions": {
"rating": { "operator": "gte", "value": 4 },
"platforms": ["google", "facebook"],
"response_template": "Thank you for your positive feedback! We're thrilled you had a great experience."
}
}

Request Body:

{
name: string; // Rule name for identification
active: boolean; // Whether rule is active
conditions: {
rating?: { // Rating condition (optional)
operator: 'eq' | 'gte' | 'lte' | 'gt' | 'lt';
value: 1 | 2 | 3 | 4 | 5;
};
platforms?: string[]; // Platforms to match (google, facebook, yelp, etc.)
keywords?: { // Keyword matching (optional)
include?: string[]; // Review must contain these
exclude?: string[]; // Review must not contain these
};
response_template: string; // Response text with variables
delay_minutes?: number; // Optional delay before sending
};
}

Response:

{
"success": true,
"data": {
"_id": "rule_abc123",
"account_id": "acc_123",
"user_id": "user_456",
"name": "Positive Review Auto-Response",
"active": true,
"conditions": {
"rating": { "operator": "gte", "value": 4 },
"platforms": ["google", "facebook"],
"response_template": "Thank you for your positive feedback!"
},
"created_at": "2024-12-08T10:00:00Z",
"updated_at": "2024-12-08T10:00:00Z"
}
}

Business Logic:

graph TD
A[Receive Create Request] --> B[Extract Auth Context]
B --> C[Validate Request Body]
C --> D{Valid Conditions?}
D -->|No| E[Return 400 Error]
D -->|Yes| F[Call autoResponseRules.create]
F --> G[Create Rule Document]
G --> H[Set account_id + user_id]
H --> I[Validate Rating Range]
I --> J[Validate Platform List]
J --> K[Save to MongoDB]
K --> L[Return Created Rule]
L --> M[Send Response]

Condition Examples:

  1. High Rating Response:
{
"rating": { "operator": "gte", "value": 4 },
"response_template": "Thank you {{author_name}}! We're glad you enjoyed our service."
}
  1. Low Rating Alert:
{
"rating": { "operator": "lte", "value": 2 },
"response_template": "We're sorry to hear about your experience. Please contact us at support@example.com"
}
  1. Platform-Specific:
{
"platforms": ["google"],
"response_template": "Thanks for your Google review!"
}
  1. Keyword Triggered:
{
"keywords": {
"include": ["staff", "helpful"],
"exclude": ["slow", "rude"]
},
"response_template": "We're happy our staff was helpful!"
}

2. list()

Retrieve all auto-response rules with pagination.

Endpoint: GET /reviews/auto-response-rules

Controller Logic:

exports.list = catchAsync(async (req, res) => {
const account_id = req.auth.account_id;
const { page, limit } = req.query;

const { data, paginate } = await autoResponseRules.list({ account_id, page, limit });

res.json({
success: true,
data,
pagination: paginate,
});
});

Request:

GET /api/v1/v1/reviews/auto-response-rules?page=1&limit=20

Query Parameters:

  • page (number, optional) - Page number (default: 1)
  • limit (number, optional) - Items per page (default: 20)

Response:

{
"success": true,
"data": [
{
"_id": "rule_abc123",
"name": "Positive Review Auto-Response",
"active": true,
"conditions": { "rating": { "operator": "gte", "value": 4 } },
"created_at": "2024-12-08T10:00:00Z",
"updated_at": "2024-12-08T10:00:00Z",
"usage_count": 45
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 5,
"pages": 1
}
}

3. get()

Retrieve a single auto-response rule by ID.

Endpoint: GET /reviews/auto-response-rules/:id

Controller Logic:

exports.get = catchAsync(async (req, res) => {
const account_id = req.auth.account_id;
const { id } = req.params;

const data = await autoResponseRules.get(id, account_id);

res.json({
success: true,
data,
});
});

Request:

GET / api / v1 / a / reviews / auto - response - rules / rule_abc123;

Response:

{
"success": true,
"data": {
"_id": "rule_abc123",
"account_id": "acc_123",
"user_id": "user_456",
"name": "Positive Review Auto-Response",
"active": true,
"conditions": {
"rating": { "operator": "gte", "value": 4 },
"platforms": ["google", "facebook"],
"response_template": "Thank you {{author_name}}!",
"delay_minutes": 0
},
"created_at": "2024-12-08T10:00:00Z",
"updated_at": "2024-12-08T10:00:00Z",
"usage_count": 45,
"last_triggered": "2024-12-08T15:30:00Z"
}
}

Business Logic:

graph TD
A[Receive Get Request] --> B[Extract Rule ID]
B --> C[Extract account_id]
C --> D[Call autoResponseRules.get]
D --> E{Rule Exists?}
E -->|No| F[Throw 404 Not Found]
E -->|Yes| G{Belongs to Account?}
G -->|No| H[Throw 404 Not Found]
G -->|Yes| I[Return Rule Data]
I --> J[Send Response]

4. update()

Update an existing auto-response rule.

Endpoint: PUT /reviews/auto-response-rules/:id

Controller Logic:

exports.update = catchAsync(async (req, res) => {
const account_id = req.auth.account_id;
const { id } = req.params;
const { name, active, conditions } = req.body;

const data = await autoResponseRules.update({ id, account_id, name, active, conditions });

res.json({
success: true,
data,
});
});

Request:

PUT /api/v1/v1/reviews/auto-response-rules/rule_abc123
Content-Type: application/json

{
"name": "Updated Rule Name",
"active": false,
"conditions": {
"rating": { "operator": "gte", "value": 5 },
"response_template": "Thank you for the 5-star review!"
}
}

Response:

{
"success": true,
"data": {
"_id": "rule_abc123",
"name": "Updated Rule Name",
"active": false,
"conditions": {
"rating": { "operator": "gte", "value": 5 },
"response_template": "Thank you for the 5-star review!"
},
"updated_at": "2024-12-08T16:00:00Z"
}
}

Use Cases:

  1. Pause Rule: Set active: false to temporarily disable
  2. Update Response: Change template text
  3. Adjust Conditions: Modify rating threshold or platforms
  4. Add Delay: Include delay_minutes for strategic timing

5. delete()

Delete an auto-response rule.

Endpoint: DELETE /reviews/auto-response-rules/:id

Controller Logic:

exports.delete = catchAsync(async (req, res) => {
const account_id = req.auth.account_id;
const { id } = req.params;

await autoResponseRules.delete(id, account_id);

res.json({
success: true,
message: 'Deleted successfully',
});
});

Request:

DELETE / api / v1 / a / reviews / auto - response - rules / rule_abc123;

Response:

{
"success": true,
"message": "Deleted successfully"
}

Business Logic:

graph TD
A[Receive Delete Request] --> B[Extract Rule ID]
B --> C[Extract account_id]
C --> D[Call autoResponseRules.delete]
D --> E{Rule Exists?}
E -->|No| F[Throw 404 Not Found]
E -->|Yes| G{Belongs to Account?}
G -->|No| H[Throw 404 Not Found]
G -->|Yes| I[Delete from MongoDB]
I --> J[Send Success Response]

Important Notes:

  • ⚠️ Deletion is permanent (no soft delete shown)
  • ⚠️ Historical responses remain intact
  • ✅ Cannot delete rules from other accounts

6. duplicate()

Duplicate an existing rule to create a new one with same conditions.

Endpoint: POST /reviews/auto-response-rules/:id/duplicate

Controller Logic:

exports.duplicate = catchAsync(async (req, res) => {
const account_id = req.auth.account_id;
const user_id = req.auth.uid;
const { id } = req.params;

const data = await autoResponseRules.duplicate(id, account_id, user_id);

res.json({
success: true,
data,
});
});

Request:

POST / api / v1 / a / reviews / auto - response - rules / rule_abc123 / duplicate;

Response:

{
"success": true,
"data": {
"_id": "rule_xyz789",
"name": "Positive Review Auto-Response (Copy)",
"active": false,
"conditions": {
"rating": { "operator": "gte", "value": 4 },
"response_template": "Thank you!"
},
"created_at": "2024-12-08T17:00:00Z"
}
}

Business Logic:

graph TD
A[Receive Duplicate Request] --> B[Extract Source Rule ID]
B --> C[Call autoResponseRules.duplicate]
C --> D[Fetch Source Rule]
D --> E{Rule Exists?}
E -->|No| F[Throw 404 Not Found]
E -->|Yes| G[Clone Rule Data]
G --> H[Append Copy to Name]
H --> I[Set active: false]
I --> J[Assign New ID]
J --> K[Save to MongoDB]
K --> L[Return New Rule]
L --> M[Send Response]

Key Features:

  1. Safe Duplication: New rule starts as inactive
  2. Name Suffix: Adds " (Copy)" to distinguish
  3. Same Conditions: Preserves all condition logic
  4. Template Creation: Easy way to create similar rules

Use Cases:

  • Create similar rules for different platforms
  • A/B test different response templates
  • Create backup before modifying existing rule

Request/Response Flow

Complete Auto-Response Rule Flow

sequenceDiagram
participant Client
participant Controller
participant Service
participant MongoDB
participant ReviewWebhook

Note over Client,ReviewWebhook: Rule Creation
Client->>Controller: POST /auto-response-rules
Controller->>Service: create(account_id, name, conditions)
Service->>MongoDB: Insert rule document
MongoDB-->>Service: Created rule
Service-->>Controller: Rule data
Controller-->>Client: Success response

Note over Client,ReviewWebhook: New Review Arrives
ReviewWebhook->>Service: New review event
Service->>MongoDB: Find active rules for account
MongoDB-->>Service: Matching rules
Service->>Service: Evaluate conditions
Service->>Service: Check rating match
Service->>Service: Check platform match
Service->>Service: Check keyword match
Service->>MongoDB: Create automated response
Service->>MongoDB: Increment rule.usage_count

Note over Client,ReviewWebhook: Rule Management
Client->>Controller: PUT /auto-response-rules/:id
Controller->>Service: update(id, active: false)
Service->>MongoDB: Update rule
MongoDB-->>Service: Updated rule
Service-->>Controller: Updated data
Controller-->>Client: Success response

Edge Cases & Error Handling

Common Scenarios

1. Invalid Rating Operator:

// Validation catches invalid operators
{
"rating": {
"operator": "invalid", // Must be: eq, gte, lte, gt, lt
"value": 4
}
}
// Returns 400 Bad Request

2. Rating Out of Range:

// Rating must be 1-5
{
"rating": { "operator": "eq", "value": 6 } // Invalid
}
// Returns 400 Bad Request

3. Duplicate Rule Not Found:

// If source rule doesn't exist
POST / auto - response - rules / invalid_id / duplicate;
// Returns 404 Not Found

4. Conflicting Rules:

// Multiple rules can match same review
// Service layer handles priority:
// 1. Most specific conditions first
// 2. Created date (newest first)
// 3. Only first match triggers

5. Inactive Rule:

// Rules with active: false never trigger
// But remain in database for reactivation
const activeRules = await Rule.find({ account_id, active: true });

6. Template Variable Missing:

// If template uses {{author_name}} but review has no author
// Service layer handles gracefully:
"Thank you {{author_name}}!""Thank you !"
// Or uses default: "Thank you Valued Customer!"

Authorization

Authentication: Required (JWT Bearer token)

Authorization Rules:

  • ✅ Account-scoped: All operations filtered by account_id
  • ✅ User tracking: Creator tracked via user_id
  • ❌ No cross-account access
  • ❌ Cannot modify other accounts' rules

Multi-Tenant Pattern:

// Every operation scoped to account
const account_id = req.auth.account_id;

// Service layer enforces ownership
await Rule.findOne({ _id: id, account_id });

Integration Points

Dependencies:

  • Reviews Controller: Rules trigger on review events
  • Response Templates Controller: Can reference template IDs
  • Config Controller: Requires platform connections

Triggered By:

  • Webhook Controller: New review webhooks trigger evaluation
  • Platform Sync Jobs: Background sync triggers rules

Triggers:

  • Notification Service: Sends responses to platforms
  • Activity Log: Records automated responses

Important Notes

Rule Evaluation Logic

  1. Condition Matching:

    • ALL conditions must match (AND logic)
    • Rating: Operator determines match (>=, ==, <=)
    • Platform: Must be in platforms array
    • Keywords: ALL include must exist, NONE exclude can exist
  2. Priority System:

    • More specific rules (more conditions) evaluated first
    • Newest rules take precedence over older
    • Only one rule triggers per review
  3. Response Timing:

    • delay_minutes: 0 = immediate
    • delay_minutes: 60 = 1 hour delay
    • Useful for appearing "human"

Performance Considerations

  • Rule Evaluation: O(n) where n = active rules count
  • Caching: Active rules cached for 5 minutes
  • Batch Processing: Reviews processed in batches
  • Indexing: account_id + active should be compound index

Template Variables

Supported variables in response templates:

  • {{author_name}} - Review author's name
  • {{rating}} - Star rating (1-5)
  • {{platform}} - Platform name
  • {{business_name}} - Account business name
  • {{review_date}} - Review creation date


Version: 1.0
Last Updated: December 2024
Status: ✅ Production Ready

💬

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