Files
gochat/internal/autoassignment/model.go
T
2026-06-04 15:44:48 +08:00

102 lines
4.6 KiB
Go

package autoassignment
// GORM models for the auto-assignment system.
//
// Reference: Chatwoot AutoAssignment pattern
// - AssignmentPolicy: global policy for how conversations are assigned
// (round_robin, longest_waiting). Has fair_distribution_limit and
// fair_distribution_window for rate limiting per agent.
// - InboxAssignmentPolicy: per-inbox override of the global policy.
// Each inbox can have its own assignment policy and rate limits.
//
// Pattern: gochat models embed model.Base (ID, CreatedAt, UpdatedAt, DeletedAt),
// use TableName() method, and use gorm struct tags.
import (
"github.com/gochat/gochat/internal/model"
)
// AssignmentPolicyType defines the type of auto-assignment policy.
type AssignmentPolicyType string
const (
// PolicyRoundRobin assigns conversations to agents in round-robin order.
// Reference: Chatwoot InboxRoundRobinService
PolicyRoundRobin AssignmentPolicyType = "round_robin"
// PolicyLongestWaiting assigns conversations to the agent with the
// longest idle time since their last assignment.
// Reference: Chatwoot "longest_waiting" policy (planned feature)
PolicyLongestWaiting AssignmentPolicyType = "longest_waiting"
// PolicyLowestLoad assigns conversations to the agent with the
// fewest currently open conversations.
// Reference: Chatwoot "least_busy" concept — agent with lowest workload.
PolicyLowestLoad AssignmentPolicyType = "lowest_load"
)
// AssignmentPolicy represents the global auto-assignment policy for an account.
// Reference: Chatwoot AssignmentPolicy model
// - Defines how unassigned conversations are distributed among agents
// - fair_distribution_limit: max assignments per agent per window (default 5)
// - fair_distribution_window: time window in seconds for rate limiting (default 300 = 5 min)
type AssignmentPolicy struct {
model.Base
AccountID uint `gorm:"index;not null" json:"account_id"`
Policy AssignmentPolicyType `gorm:"size:50;default:round_robin" json:"policy"`
FairDistributionLimit int `gorm:"default:5" json:"fair_distribution_limit"`
FairDistributionWindow int `gorm:"default:300" json:"fair_distribution_window"` // seconds
Active bool `gorm:"default:true" json:"active"`
}
func (AssignmentPolicy) TableName() string { return "assignment_policies" }
// InboxAssignmentPolicy represents a per-inbox override of the global assignment policy.
// Reference: Chatwoot InboxAssignmentPolicy model
// - Each inbox can override the account-level policy
// - If no inbox-specific policy exists, the account policy is used
type InboxAssignmentPolicy struct {
model.Base
AccountID uint `gorm:"index;not null" json:"account_id"`
InboxID uint `gorm:"uniqueIndex;not null" json:"inbox_id"`
Policy AssignmentPolicyType `gorm:"size:50;default:round_robin" json:"policy"`
FairDistributionLimit int `gorm:"default:5" json:"fair_distribution_limit"`
FairDistributionWindow int `gorm:"default:300" json:"fair_distribution_window"` // seconds
Active bool `gorm:"default:true" json:"active"`
}
func (InboxAssignmentPolicy) TableName() string { return "inbox_assignment_policies" }
// EffectivePolicy returns the effective assignment policy for a given inbox.
// If the inbox has a specific policy, it is used; otherwise the account policy is used.
func EffectivePolicy(accountPolicy *AssignmentPolicy, inboxPolicy *InboxAssignmentPolicy) AssignmentPolicyType {
if inboxPolicy != nil && inboxPolicy.Active {
return inboxPolicy.Policy
}
if accountPolicy != nil && accountPolicy.Active {
return accountPolicy.Policy
}
return PolicyRoundRobin // default
}
// EffectiveLimit returns the effective fair distribution limit for a given inbox.
func EffectiveLimit(accountPolicy *AssignmentPolicy, inboxPolicy *InboxAssignmentPolicy) int {
if inboxPolicy != nil && inboxPolicy.Active && inboxPolicy.FairDistributionLimit > 0 {
return inboxPolicy.FairDistributionLimit
}
if accountPolicy != nil && accountPolicy.FairDistributionLimit > 0 {
return accountPolicy.FairDistributionLimit
}
return 5 // default
}
// EffectiveWindow returns the effective fair distribution window (in seconds).
func EffectiveWindow(accountPolicy *AssignmentPolicy, inboxPolicy *InboxAssignmentPolicy) int {
if inboxPolicy != nil && inboxPolicy.Active && inboxPolicy.FairDistributionWindow > 0 {
return inboxPolicy.FairDistributionWindow
}
if accountPolicy != nil && accountPolicy.FairDistributionWindow > 0 {
return accountPolicy.FairDistributionWindow
}
return 300 // default (5 minutes)
}