Files
chatwoot/assignment_v2_feature.md
T

29 KiB

Assignment v2 Feature Documentation

Overview

Assignment v2 is an intelligent, automated conversation distribution system that ensures conversations are fairly and efficiently assigned to available agents. It replaces the legacy assignment mechanism with a more sophisticated approach that considers multiple factors like agent capacity, availability, and conversation priority.

Purpose

Instead of conversations sitting unassigned or being manually assigned one-by-one, Assignment v2 automatically distributes them across your team based on configurable rules and policies. This ensures:

  • No conversations are left unassigned — Open conversations get assigned to agents automatically
  • Fair workload distribution — Conversations are spread evenly across the team
  • Respects agent capacity — Agents don't get overloaded with too many conversations
  • Flexible prioritization — You control how conversations are prioritized (oldest first vs. longest waiting)

How It Works: The Auto-Assignment Flow

Assignment v2 operates through two parallel mechanisms:

1. Real-time Assignment Trigger (AutoAssignmentHandler)

The system monitors conversation changes in real-time through the AutoAssignmentHandler concern:

  • Triggers on: Every conversation save operation
  • Assignment occurs when:
    • A conversation transitions to status: 'open' with no assignee
    • A conversation has an assignee who is no longer an inbox member
  • Action: Immediately enqueues an AutoAssignment::AssignmentJob for that inbox
  • Fallback: If assignment_v2 is not enabled, falls back to legacy AgentAssignmentService

This ensures conversations get assigned immediately when they become eligible, without waiting for the periodic job.

2. Periodic Assignment Cycle

The system also runs a 30-minute cycle through an automated job (AutoAssignment::PeriodicAssignmentJob) configured in config/schedule.yml:

  1. Discovery Phase: The system checks all accounts in batches

    • Only accounts with the assignment_v2 feature flag enabled are processed
    • Uses find_in_batches for memory efficiency with large datasets
  2. Queue Phase: For each inbox in those accounts:

    • Only inboxes with an assignment_policy linked are considered
    • The inbox must have enable_auto_assignment set to true
    • The linked assignment policy must be enabled
    • An AutoAssignment::AssignmentJob is queued for each eligible inbox
  3. Processing Phase: Each assignment job:

    • Fetches up to 100 unassigned, open conversations (configurable via AUTO_ASSIGNMENT_BULK_LIMIT env var)
    • Processes conversations one at a time in the order determined by the priority policy
  4. Assignment Phase: For each conversation, the system:

    • Checks if the conversation is assignable (open status, no current assignee)
    • Finds agents who are available (online status) and have capacity
    • Filters agents by rate limiting rules
    • Selects one agent using the configured selection strategy
    • Assigns the conversation to that agent
    • Tracks the assignment in Redis for rate limiting
    • Dispatches an ASSIGNEE_CHANGED event

Key Architectural Details

  • Job Queues:

    • PeriodicAssignmentJob runs in the scheduled_jobs queue
    • AssignmentJob runs in the default queue
  • Batched Processing: Uses find_in_batches for accounts and inboxes to handle large-scale deployments efficiently

  • Error Handling:

    • Errors are logged with the inbox ID
    • In test environments, errors are re-raised for debugging
    • In production, errors don't crash the entire job cycle
  • Conversation Limits: Default is 100 conversations per job run, preventing memory issues and long-running jobs


Prerequisites & Feature Enablement

Assignment v2 requires all of the following conditions to be met:

  1. Account-Level Feature Flag: The account must have the assignment_v2 feature enabled (configured in config/features.yml)
  2. Assignment Policy: An AssignmentPolicy must exist and be linked to the inbox via InboxAssignmentPolicy
  3. Policy Enabled: The AssignmentPolicy must have enabled: true (acts as a soft switch)
  4. Inbox Auto-Assignment: The inbox must have enable_auto_assignment: true

If any of these conditions is not met, the inbox is skipped entirely and no assignments occur. The system checks these conditions via the Inbox#auto_assignment_v2_enabled? method.


Assignment Policies

Policies determine HOW conversations are selected and assigned. Here are the main policies:

1. Conversation Priority Policy

What it does: Controls which conversations get assigned first

Options:

  • Longest Waiting Mode (longest_waiting):

    • Prioritizes conversations based on last_activity_at (oldest first)
    • Uses last_activity_at ASC, created_at ASC ordering
    • Ensures customers waiting longest for a response get priority
    • Ideal for support teams focused on response time SLAs
  • Default Mode (or any other value):

    • Conversations are assigned in the order they were created
    • Uses created_at ASC ordering
    • First In, First Out (FIFO) approach
    • Ideal for teams that want to clear backlogs chronologically

Example:

Conversation A: Created 2 hours ago, last activity 2 hours ago
Conversation B: Created 1 hour ago, last activity 30 minutes ago
Conversation C: Created 30 minutes ago, last activity 30 minutes ago

Longest Waiting: A → B → C (prioritizes least recent activity)
Default: A → B → C (prioritizes creation order)

2. Fair Distribution / Rate Limiting Policy

What it does: Prevents any single agent from being overwhelmed by too many assignments in a short time window

Configuration:

  • fair_distribution_limit: Maximum number of assignments per agent within the time window (integer)
  • fair_distribution_window: Time window in seconds (integer, defaults to 3600 seconds / 1 hour)

How it works:

  • When enabled, the system tracks each assignment in Redis
  • Redis key pattern: chatwoot:assignment:{inbox_id}:{agent_id}:{conversation_id}
  • Each key has a TTL (Time To Live) equal to the configured window
  • Before assigning, the system counts existing keys for that agent
  • If count >= limit, the agent is filtered out from eligible agents
  • After assignment, a new Redis key is created with the window TTL

Behavior:

  • If fair_distribution_limit is not set or is 0, rate limiting is disabled
  • Rate limiting is applied per inbox per agent
  • Once the time window expires, old assignments are automatically removed from Redis
  • Agents become eligible again once their count drops below the limit

Example:

Configuration: limit=5, window=3600 (1 hour)

Agent A is assigned 5 conversations between 10:00-10:15am
At 10:16am, Agent A is filtered out (at limit)
At 11:01am (after the first assignment expires), Agent A is eligible again

Edge Cases:

  • If ALL agents hit their rate limit, no assignments occur (0 assignments returned)
  • Rate limits are checked AFTER agent availability but BEFORE capacity checks
  • Rate limiting tracks assignments, not current workload (different from capacity)

3. Agent Availability Policy

What it does: Ensures only agents who are actually available get new conversations

How it works:

  • Uses OnlineStatusTracker to check real-time agent status
  • Fetches all users with their status from Redis
  • Only agents with status exactly equal to 'online' are eligible
  • Agents with status 'busy', 'offline', or any other value are filtered out

Integration:

  • The system calls inbox.available_agents which:
    1. Fetches online agent IDs from OnlineStatusTracker
    2. Filters inbox members to only those with online status
    3. Returns InboxMember records (not User records)

Edge Cases:

  • If no agents are online for an inbox, 0 assignments occur
  • Agent availability is checked at the time of assignment (not when the job starts)
  • If an agent goes offline mid-job, they won't receive more assignments

Important: The system does NOT check:

  • Agent's working hours
  • Agent's timezone
  • Agent's custom availability settings (these would need to be handled separately)

4. Capacity Management Policy (Enterprise Feature)

What it does: Advanced workload balancing based on agent's current load and conversation history

How it works:

  • Each agent can be assigned to an AgentCapacityPolicy
  • The policy defines InboxCapacityLimit records (one per inbox)
  • Each limit specifies a conversation_limit (integer)
  • The system counts the agent's current open conversations in that specific inbox
  • If current_count >= conversation_limit, the agent is filtered out

Key Characteristics:

  • Inbox-specific: Limits apply per inbox, so an agent can have different limits for different inboxes
  • Open conversations only: Only counts conversations with status: 'open'
  • Optional: If an agent has no AgentCapacityPolicy, they have unlimited capacity
  • Per-inbox limits: If a capacity policy exists but has no InboxCapacityLimit for a specific inbox, the agent has unlimited capacity for that inbox

Example:

Agent A has a capacity policy with:
- Inbox 1 (Support): limit = 10
- Inbox 2 (Sales): limit = 20

Agent A currently has:
- 10 open conversations in Inbox 1
- 5 open conversations in Inbox 2

Result:
- Agent A is at capacity for Inbox 1 (10 >= 10) → filtered out
- Agent A has capacity for Inbox 2 (5 < 20) → eligible

Edge Cases:

  • Resolved/closed conversations do NOT count toward capacity
  • Capacity is checked at assignment time, not continuously
  • If an agent goes over capacity manually (outside auto-assignment), they're still filtered out

5. Exclusion Rules (Enterprise Feature)

What it does: Allows excluding certain conversations from auto-assignment based on labels or age

Configuration (on AgentCapacityPolicy):

exclusion_rules = {
  'excluded_labels' => ['VIP', 'Escalation', 'Manual'],
  'exclude_older_than_hours' => 24
}

Behavior:

Label-Based Exclusions:

  • Conversations tagged with any of the excluded labels are skipped
  • Uses the tagged_with method with exclude: true
  • Multiple labels are treated as OR (conversation with ANY excluded label is skipped)
  • Label matching is exact (case-sensitive)

Age-Based Exclusions:

  • Conversations older than the specified hours are skipped
  • Age is calculated from created_at, not last_activity_at
  • Uses where('conversations.created_at >= ?', hours.hours.ago)
  • If set to 24, conversations created more than 24 hours ago are excluded

Combined Exclusions:

  • Both rules are applied together (AND logic)
  • A conversation must pass both checks to be eligible
  • Example: Must be less than 24 hours old AND not have an excluded label

Edge Cases:

  • If exclusion_rules is nil or empty, no exclusions apply
  • If there's no capacity policy linked to the inbox, exclusion rules don't apply
  • Exclusions are applied BEFORE agent selection (reduces conversations to assign)

Selection Strategies

Once eligible agents are identified (after availability, rate limiting, and capacity checks), the system uses a selection strategy to pick the agent:

Round-Robin (Default)

Implementation: Uses AutoAssignment::RoundRobinSelector which delegates to AutoAssignment::InboxRoundRobinService

How it works:

  • Maintains a Redis-based queue of agent IDs for the inbox
  • Each time an agent is selected, they're moved to the back of the queue
  • The next agent in the queue is always selected
  • Ensures even distribution over time

Characteristics:

  • Fair over time: Each agent gets an equal turn
  • Stateful: Uses Redis to maintain queue state across jobs
  • Inbox-specific: Each inbox has its own round-robin queue

Example:

Queue: [Agent A, Agent B, Agent C]

Assignment 1: Agent A (queue becomes [Agent B, Agent C, Agent A])
Assignment 2: Agent B (queue becomes [Agent C, Agent A, Agent B])
Assignment 3: Agent C (queue becomes [Agent A, Agent B, Agent C])

Edge Cases:

  • If an agent is removed from the inbox, they're removed from the queue
  • If a new agent is added, they're added to the queue
  • The queue is validated and reset if it becomes inconsistent (membership drift)
  • The InboxRoundRobinService validates the queue and resets it when agent membership changes

Balanced / Workload-Based (Enterprise)

Implementation: Uses Enterprise::AutoAssignment::BalancedSelector

How it works:

  • For each eligible agent, counts their current open conversations in the inbox
  • Selects the agent with the minimum count
  • Uses min_by which returns the first agent if there's a tie

Characteristics:

  • Real-time balancing: Based on current workload, not historical assignments
  • Inbox-specific: Only counts conversations in the specific inbox
  • Open conversations only: Ignores resolved/closed conversations
  • Prioritizes new agents: Agents with 0 conversations are always selected first

Example:

Agent A: 5 open conversations
Agent B: 3 open conversations
Agent C: 8 open conversations

Selection: Agent B (has the least workload)

After assignment:
Agent A: 5, Agent B: 4, Agent C: 8
Next selection: Agent B again (still has least)

Comparison:

Aspect Round-Robin Balanced
Goal Equal distribution over time Equal workload at any moment
State Redis queue Database query
Speed Very fast (Redis lookup) Slower (DB count query)
Accuracy Equal turns, not equal workload Equal workload
Best for High-volume, fast assignments Teams where agents have varying resolve rates

Configuration:

  • In OSS: Always uses Round-Robin
  • In Enterprise: Can set balanced: true on the assignment policy to use Balanced strategy

Important Behaviors & Edge Cases

Conversation Eligibility

A conversation is only eligible for auto-assignment if ALL of the following are true:

  1. Status is 'open': Resolved, pending, or snoozed conversations are never assigned
  2. No current assignee: Conversations with an existing assignee are never reassigned
  3. Passes exclusion rules (if Enterprise): Must not have excluded labels and must be within age threshold
  4. In an eligible inbox: The inbox must have auto-assignment v2 enabled

Edge Cases:

  • If a conversation is manually assigned mid-job, it's skipped (already has assignee)
  • If a conversation is resolved mid-job, it's skipped (no longer open)
  • Assignment v2 NEVER reassigns conversations (even if the current agent goes offline)

Agent Eligibility

An agent is only eligible for assignment if ALL of the following are true:

  1. Member of the inbox: Agent must be an InboxMember
  2. Status is 'online': Checked via OnlineStatusTracker at assignment time
  3. Within rate limit (if configured): Agent hasn't exceeded assignments in the current window
  4. Has capacity (if Enterprise): Agent's open conversation count is below their limit for this inbox

Edge Cases:

  • If an agent meets all criteria but goes offline between the eligibility check and assignment, they may still receive the conversation (race condition)
  • If ALL agents are filtered out, the conversation remains unassigned until the next cycle

Zero-Assignment Scenarios

The system may assign 0 conversations if:

  1. No unassigned, open conversations exist in the inbox
  2. All conversations are excluded by exclusion rules
  3. No agents are online
  4. All online agents are at their rate limit
  5. All online agents are at capacity (Enterprise)
  6. The assignment policy is disabled mid-job

Assignment Events

When a conversation is successfully assigned, the system:

  1. Updates the conversation's assignee_id in the database
  2. Creates a Redis key to track the assignment (for rate limiting)
  3. Dispatches an Events::Types::ASSIGNEE_CHANGED event with:
    • conversation: The conversation object
    • user: The assigned agent
    • Timestamp of the assignment

Event Integration:

  • Webhooks subscribed to ASSIGNEE_CHANGED will be triggered
  • The conversation model also dispatches a conversation.updated event
  • These events can be used for notifications, integrations, or analytics

Error Handling

Job-Level Errors:

  • If an AssignmentJob encounters an error, it logs the error with the inbox ID
  • In production, the error is caught and logged, allowing other jobs to continue
  • In test environment, errors are re-raised for debugging

Service-Level Errors:

  • If a single conversation assignment fails, it's skipped and the job continues
  • The assigned_count only includes successful assignments
  • Database errors (like constraint violations) are logged but don't stop the job

Graceful Degradation:

  • If Redis is unavailable, rate limiting is skipped (all assignments proceed)
  • If OnlineStatusTracker fails, no agents are considered online (0 assignments)
  • If the inbox is deleted mid-job, the job exits early

Performance Considerations

Batch Processing:

  • Accounts are processed in batches to avoid loading all accounts into memory
  • Inboxes are processed in batches to avoid loading all inboxes into memory
  • Conversations are limited to 100 per job to prevent long-running jobs

Redis Usage:

  • Rate limiting creates one Redis key per assignment
  • Keys automatically expire based on the configured window
  • Pattern matching (keys_count) is used to count assignments (can be expensive with many agents)

Database Queries:

  • Uses includes(:user) in InboxAgentAvailability#available_agents to preload users and avoid N+1 queries
  • Falls back to inbox_members.none when no agents are online to avoid unnecessary database hits
  • Uses group(:assignee_id).count for balanced selector (efficient aggregation)
  • Uses limit(100) to prevent loading thousands of conversations at once

Scaling Recommendations:

  • For high-volume inboxes, increase AUTO_ASSIGNMENT_BULK_LIMIT (e.g., 200-500)
  • Consider shorter rate limiting windows for faster cycling (e.g., 1800 seconds instead of 3600)
  • Use balanced selector for teams where workload balance is critical

API Endpoints

Assignment v2 provides REST API endpoints for managing assignment policies:

Policy Management

  • CRUD Operations: Api::V1::Accounts::AssignmentPoliciesController
    • GET /api/v1/accounts/:account_id/assignment_policies - List all policies
    • POST /api/v1/accounts/:account_id/assignment_policies - Create a policy
    • PUT /api/v1/accounts/:account_id/assignment_policies/:id - Update a policy
    • DELETE /api/v1/accounts/:account_id/assignment_policies/:id - Delete a policy
    • Accepts: assignment_order, conversation_priority, fair_distribution_limit, fair_distribution_window, enabled

Inbox-Policy Linking

  • Link/Unlink: Api::V1::Accounts::Inboxes::AssignmentPoliciesController
    • POST /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy - Attach policy to inbox
    • DELETE /api/v1/accounts/:account_id/inboxes/:inbox_id/assignment_policy - Detach policy from inbox
    • Note: Only one policy can be linked to an inbox at a time

Policy-Inbox Queries

  • List Linked Inboxes: Api::V1::Accounts::AssignmentPolicies::InboxesController
    • GET /api/v1/accounts/:account_id/assignment_policies/:policy_id/inboxes - List all inboxes using a policy

Authorization

  • All endpoints require proper account scoping
  • Requires AssignmentPolicy authorization for the requesting user

Configuration & Flexibility

Assignment v2 is designed to be flexible at multiple levels:

Account Level

  • Feature Flag: assignment_v2 must be enabled on the account
  • Enterprise Features: Capacity and exclusion rules require Enterprise

Policy Level

  • Assignment Order: round_robin (default) or balanced (Enterprise only)
  • Conversation Priority: longest_waiting or earliest_created (default/FIFO)
  • Fair Distribution Limit: Integer (e.g., 5)
  • Fair Distribution Window: Integer in seconds (defaults to 3600 when omitted)
  • Enabled: Boolean soft switch to enable/disable the policy

Inbox Level

  • Auto-Assignment: enable_auto_assignment boolean
  • Policy Link: InboxAssignmentPolicy links inbox to a policy (one-to-one relationship)
  • Capacity Limits (Enterprise): Per-inbox conversation limits
  • Configuration Overrides:
    • OSS: The inbox.auto_assignment_config JSONB field can override policy settings for per-inbox customization
    • Enterprise: Policy settings take precedence over inbox.auto_assignment_config - edit the policy directly

Agent Level

  • Capacity Policy (Enterprise): Optional AgentCapacityPolicy per agent
  • Availability: Real-time online status tracked by OnlineStatusTracker

Environment Level

  • Bulk Limit: AUTO_ASSIGNMENT_BULK_LIMIT env var (default: 100)
  • Job Schedule: Configurable via job scheduler (default: 30 minutes)

System Architecture

Components

  1. Jobs:

    • AutoAssignment::PeriodicAssignmentJob: Scheduled job that discovers eligible inboxes
    • AutoAssignment::AssignmentJob: Per-inbox job that performs assignments
  2. Services:

    • AutoAssignment::AssignmentService: Core assignment logic (OSS)
    • Enterprise::AutoAssignment::AssignmentService: Extended with capacity and exclusion rules
    • AutoAssignment::RateLimiter: Rate limiting logic using Redis
    • Enterprise::AutoAssignment::CapacityService: Capacity checking logic
  3. Selectors:

    • AutoAssignment::RoundRobinSelector: Round-robin selection strategy
    • Enterprise::AutoAssignment::BalancedSelector: Workload-based selection strategy
  4. Models:

    • AssignmentPolicy: Configures assignment behavior
    • InboxAssignmentPolicy: Links inbox to policy
    • AgentCapacityPolicy (Enterprise): Defines capacity rules
    • InboxCapacityLimit (Enterprise): Per-inbox limits
  5. Concerns:

    • InboxAgentAvailability: Provides available_agents method for inboxes

Data Flow

1. PeriodicAssignmentJob (every 30 min)
   ↓
2. For each Account with assignment_v2
   ↓
3. For each Inbox with auto_assignment_v2_enabled?
   ↓
4. Queue AssignmentJob(inbox_id)
   ↓
5. AssignmentService.perform_bulk_assignment(limit: 100)
   ↓
6. Fetch unassigned conversations (with priority ordering)
   ↓
7. For each conversation:
   a. Check assignable? (open + no assignee)
   b. Find available agents (online + rate limit + capacity)
   c. Select agent (round-robin or balanced)
   d. Assign conversation
   e. Track in Redis
   f. Dispatch event
   ↓
8. Return assigned_count

Redis Keys

Rate Limiting:

  • Pattern: chatwoot:assignment:{inbox_id}:{agent_id}:*
  • Key: chatwoot:assignment:{inbox_id}:{agent_id}:{conversation_id}
  • TTL: Equal to fair_distribution_window (default 3600 seconds)

Round-Robin Queue:

  • Key: chatwoot:round_robin:{inbox_id}
  • Type: List (LPUSH/RPOP operations)
  • Persistent (no TTL)

Advantages Over Manual Assignment

Aspect Manual Assignment v2
Speed Slow (requires human action) Instant (automatic every 30 min)
Consistency Variable (depends on person) Consistent (follows rules)
Fairness Prone to bias Fair and data-driven
Scalability Doesn't scale (1 person = bottleneck) Scales infinitely
Workload Balance Hard to maintain Automatically balanced
Priority Manual judgment Configurable policies
24/7 Operation Requires shifts Automated
Onboarding New agents may be overlooked New agents automatically included
Audit Trail Limited Full event log

Integration Points

Assignment v2 integrates with several Chatwoot systems:

  1. Conversation Model:

    • Reads: status, assignee_id, last_activity_at, created_at
    • Writes: assignee_id
    • Scopes: unassigned, open
  2. OnlineStatusTracker:

    • Reads: Real-time agent online status from Redis
    • Returns: Hash of {user_id => status}
  3. Redis:

    • Rate limiting: Stores assignment keys with TTL
    • Round-robin: Maintains agent queues
    • Performance: All Redis operations are non-blocking
  4. Events System:

    • Dispatches: Events::Types::ASSIGNEE_CHANGED
    • Consumers: Webhooks, notifications, analytics
  5. Assignment Policy:

    • Reads: Priority, limits, windows, balanced mode
    • Links: Via InboxAssignmentPolicy
  6. Capacity Policy (Enterprise):

    • Reads: Per-inbox limits, exclusion rules
    • Links: Via AccountUser and InboxCapacityLimit
  7. Labels (Enterprise):

    • Reads: Conversation labels for exclusion rules
    • Uses: ActsAsTaggableOn gem for label filtering

For Non-Technical Stakeholders

Think of Assignment v2 as an intelligent dispatcher at a taxi company:

Without Assignment v2

  • Customers (conversations) call in and wait on hold
  • Someone manually decides which driver (agent) should take each ride
  • Some drivers get overloaded while others sit idle
  • Customers who called first might not get picked up first
  • The dispatcher becomes a bottleneck

With Assignment v2

  • The system automatically dispatches rides to available drivers
  • Drivers who are online and not at capacity get new rides
  • The system balances workload so no driver gets too many rides at once
  • You can set rules: "Prioritize customers waiting longest" or "No driver gets more than 5 rides per hour"
  • Drivers with VIP rides (excluded labels) can be handled separately
  • Everything happens automatically every 30 minutes

Benefits

  • Faster: Customers get assigned immediately
  • Fairer: All drivers get equal opportunities
  • Scalable: Works with 5 drivers or 500
  • Configurable: Rules can be adjusted based on business needs
  • Reliable: Runs 24/7 without human intervention

Troubleshooting

"Conversations aren't being assigned"

Check the following in order:

  1. Feature flag: Is assignment_v2 enabled for the account?
  2. Assignment policy: Does the inbox have a linked, enabled assignment policy?
  3. Inbox setting: Is enable_auto_assignment true for the inbox?
  4. Agent availability: Are any agents online?
  5. Rate limiting: Are all agents at their rate limit? Check Redis keys
  6. Capacity (Enterprise): Are all agents at capacity? Check open conversation counts
  7. Exclusion rules (Enterprise): Are all conversations being excluded by labels or age?
  8. Job running: Is PeriodicAssignmentJob scheduled and running?

"Assignments are uneven"

  • If using round-robin: Check the Redis queue for the inbox
  • If some agents never get assignments: Check their online status
  • If using balanced selector: Check open conversation counts per agent
  • If rate limiting is too strict: Increase the limit or window

"Too many/too few assignments"

  • Check AUTO_ASSIGNMENT_BULK_LIMIT (default 100)
  • Check rate limiting configuration
  • Check capacity limits (Enterprise)
  • Check conversation priority (longest_waiting vs. FIFO)

"Redis keys not expiring"

  • Verify fair_distribution_window is set correctly
  • Check Redis configuration for key eviction policies
  • Manually inspect keys: Redis::Alfred.keys('chatwoot:assignment:*')

Testing Guidelines

Test Coverage Touchpoints

Core Spec Files:

  • spec/services/auto_assignment/assignment_service_spec.rb - Verifies open-only assignment, respect for limits, conversation priority, fair distribution, and event dispatching
  • spec/services/auto_assignment/rate_limiter_spec.rb - Covers Redis key semantics, limit/window handling, and edge cases when configuration is absent
  • spec/services/auto_assignment/round_robin_selector_spec.rb - Ensures proper Redis-backed round robin queue and handles empty agent pools
  • spec/jobs/auto_assignment/* - Covers both immediate job and periodic scheduler behavior
  • spec/enterprise/services/enterprise/auto_assignment/* - Asserts balanced selection, capacity filtering, and exclusion rule behavior

Key Test Scenarios

  1. Basic Assignment:

    • Create unassigned, open conversation
    • Create online agent
    • Run assignment service
    • Verify conversation is assigned
  2. Rate Limiting:

    • Configure rate limit (e.g., 2 per hour)
    • Assign 2 conversations to an agent
    • Verify 3rd conversation goes to a different agent
  3. Capacity Management:

    • Set capacity limit (e.g., 5 conversations)
    • Create 5 open conversations for an agent
    • Verify agent is filtered out of eligibility
  4. Exclusion Rules:

    • Configure excluded labels
    • Create conversation with excluded label
    • Verify conversation is not assigned
  5. Priority:

    • Create multiple conversations with different last_activity_at
    • Configure longest_waiting priority
    • Verify oldest last_activity_at is assigned first
  6. Agent Availability:

    • Set agent status to 'busy' or 'offline'
    • Verify agent is not eligible
    • Set status to 'online'
    • Verify agent is now eligible
  7. Zero Assignments:

    • Disable assignment policy
    • Verify 0 assignments occur
    • Set all agents offline
    • Verify 0 assignments occur

Next Steps / Additional Reading

  • To enable Assignment v2 for your account, contact your Chatwoot administrator
  • For Enterprise features, see the Enterprise-specific capacity policies documentation
  • For webhook integrations, refer to the Assignment Events documentation
  • For performance tuning, consult the Scaling Chatwoot guide

Last Updated: November 2024 Feature Status: Stable (v2 final) Related PR: #12320 Architecture: Modular with Enterprise extensions via prepend_mod_with