清理: - 删除 34 份过时文档(gap reports/QA临时报告/验收报告/阶段性文档) - 删除 docs/.hermes/skills 第三方 skills 副本(16 文件) - 删除 skills-lock.json 目录归集: - 根目录仅保留 README.md 索引 - product/ — 产品与架构设计(PRD + ARCHITECTURE + P2设计文档 + AI/企业路线图) - tracking/ — Chatwoot parity 开发跟踪 - requirements/ — M01-M12 模块需求 - plans/ — 历史实现计划 - parity/ — 路由 parity 与前端契约 - qa/ — QA 报告与测试计划 - ops/ — 运维部署 命名规范: - 全小写 kebab-case,禁止全大写文件名 - product/tracking/ops 用 NN- 序号前缀 - requirements 用 MNN- 两位零填充模块号 - plans/qa 用 YYYY-MM-DD- 日期前缀 - requirements M1-M9 零填充为 M01-M09(修复字典序) 同步更新: - backend/cmd/route_parity/main.go 路径默认值 - backend/scripts/parity_frontend_smoke.sh 报告路径 - 所有 docs 内部交叉引用 - .gitignore 排除编译产物 (backend/gochat, backend/route_parity) - 新增迁移 000052/000053 - 前端 WS 相关修改
238 lines
6.5 KiB
Markdown
238 lines
6.5 KiB
Markdown
## Code Context
|
|
|
|
**Query:** team, team member, assignment policy, auto assignment, inbox assignment policy, agent capacity policy, inbox capacity limit, round robin assignment
|
|
|
|
### Entry Points
|
|
|
|
- **AutoAssignment::InboxRoundRobinService** (class) - app/services/auto_assignment/inbox_round_robin_service.rb:1
|
|
- **CreateInboxCapacityLimits** (class) - db/migrate/20250806140003_create_inbox_capacity_limits.rb:3
|
|
- **AddAgentCapacityPolicyToAccountUsers** (class) - db/migrate/20250806140004_add_agent_capacity_policy_to_account_users.rb:3
|
|
|
|
### Related Symbols
|
|
|
|
- app/services/auto_assignment/inbox_round_robin_service.rb: clear_queue:5, add_agent_to_queue:10, remove_agent_from_queue:15, reset_queue:19, available_agent:28, get_member_from_allowed_agent_ids:36, pop_push_to_queue:44, validate_queue?:51, queue:55, round_robin_key:59
|
|
|
|
### Code
|
|
|
|
#### AutoAssignment::InboxRoundRobinService (app/services/auto_assignment/inbox_round_robin_service.rb:1)
|
|
|
|
```ruby
|
|
class AutoAssignment::InboxRoundRobinService
|
|
pattr_initialize [:inbox!]
|
|
|
|
# called on inbox delete
|
|
def clear_queue
|
|
::Redis::Alfred.delete(round_robin_key)
|
|
end
|
|
|
|
# called on inbox member create
|
|
def add_agent_to_queue(user_id)
|
|
::Redis::Alfred.lpush(round_robin_key, user_id)
|
|
end
|
|
|
|
# called on inbox member delete
|
|
def remove_agent_from_queue(user_id)
|
|
::Redis::Alfred.lrem(round_robin_key, user_id)
|
|
end
|
|
|
|
def reset_queue
|
|
clear_queue
|
|
add_agent_to_queue(inbox.inbox_members.map(&:user_id))
|
|
end
|
|
|
|
# end of queue management functions
|
|
|
|
# allowed member ids = [assignable online agents supplied by the assignment service]
|
|
# the values of allowed member ids should be in string format
|
|
def available_agent(allowed_agent_ids: [])
|
|
reset_queue unless validate_queue?
|
|
user_id = get_member_from_allowed_agent_ids(allowed_agent_ids)
|
|
inbox.inbox_members.find_by(user_id: user_id)&.user if user_id.present?
|
|
end
|
|
|
|
private
|
|
|
|
def get_member_from_allowed_agent_ids(allowed_agent_ids)
|
|
return nil if allowed_agent_ids.blank?
|
|
|
|
user_id = queue.intersection(allowed_agent_ids).pop
|
|
pop_push_to_queue(user_id)
|
|
user_id
|
|
end
|
|
|
|
def pop_push_to_queue(user_id)
|
|
return if user_id.blank?
|
|
|
|
remove_agent_from_queue(user_id)
|
|
add_agent_to_queue(user_id)
|
|
end
|
|
|
|
def validate_queue?
|
|
return true if inbox.inbox_members.map(&:user_id).sort == queue.map(&:to_i).sort
|
|
end
|
|
|
|
def queue
|
|
::Redis::Alfred.lrange(round_robin_key)
|
|
end
|
|
|
|
def round
|
|
// ... truncated ...
|
|
```
|
|
|
|
#### CreateInboxCapacityLimits (db/migrate/20250806140003_create_inbox_capacity_limits.rb:3)
|
|
|
|
```ruby
|
|
class CreateInboxCapacityLimits < ActiveRecord::Migration[7.1]
|
|
def change
|
|
create_table :inbox_capacity_limits do |t|
|
|
t.references :agent_capacity_policy, null: false, index: true
|
|
t.references :inbox, null: false, index: true
|
|
t.integer :conversation_limit, null: false
|
|
|
|
t.timestamps
|
|
end
|
|
|
|
add_index :inbox_capacity_limits, [:agent_capacity_policy_id, :inbox_id], unique: true
|
|
end
|
|
end
|
|
```
|
|
|
|
#### AddAgentCapacityPolicyToAccountUsers (db/migrate/20250806140004_add_agent_capacity_policy_to_account_users.rb:3)
|
|
|
|
```ruby
|
|
class AddAgentCapacityPolicyToAccountUsers < ActiveRecord::Migration[7.1]
|
|
def change
|
|
add_reference :account_users, :agent_capacity_policy, null: true, index: true
|
|
end
|
|
end
|
|
```
|
|
|
|
#### clear_queue (app/services/auto_assignment/inbox_round_robin_service.rb:5)
|
|
|
|
```ruby
|
|
def clear_queue
|
|
::Redis::Alfred.delete(round_robin_key)
|
|
end
|
|
```
|
|
|
|
#### add_agent_to_queue (app/services/auto_assignment/inbox_round_robin_service.rb:10)
|
|
|
|
```ruby
|
|
def add_agent_to_queue(user_id)
|
|
::Redis::Alfred.lpush(round_robin_key, user_id)
|
|
end
|
|
```
|
|
|
|
#### remove_agent_from_queue (app/services/auto_assignment/inbox_round_robin_service.rb:15)
|
|
|
|
```ruby
|
|
def remove_agent_from_queue(user_id)
|
|
::Redis::Alfred.lrem(round_robin_key, user_id)
|
|
end
|
|
```
|
|
|
|
#### reset_queue (app/services/auto_assignment/inbox_round_robin_service.rb:19)
|
|
|
|
```ruby
|
|
def reset_queue
|
|
clear_queue
|
|
add_agent_to_queue(inbox.inbox_members.map(&:user_id))
|
|
end
|
|
```
|
|
|
|
#### available_agent (app/services/auto_assignment/inbox_round_robin_service.rb:28)
|
|
|
|
```ruby
|
|
def available_agent(allowed_agent_ids: [])
|
|
reset_queue unless validate_queue?
|
|
user_id = get_member_from_allowed_agent_ids(allowed_agent_ids)
|
|
inbox.inbox_members.find_by(user_id: user_id)&.user if user_id.present?
|
|
end
|
|
```
|
|
|
|
#### get_member_from_allowed_agent_ids (app/services/auto_assignment/inbox_round_robin_service.rb:36)
|
|
|
|
```ruby
|
|
def get_member_from_allowed_agent_ids(allowed_agent_ids)
|
|
return nil if allowed_agent_ids.blank?
|
|
|
|
user_id = queue.intersection(allowed_agent_ids).pop
|
|
pop_push_to_queue(user_id)
|
|
user_id
|
|
end
|
|
```
|
|
|
|
#### pop_push_to_queue (app/services/auto_assignment/inbox_round_robin_service.rb:44)
|
|
|
|
```ruby
|
|
def pop_push_to_queue(user_id)
|
|
return if user_id.blank?
|
|
|
|
remove_agent_from_queue(user_id)
|
|
add_agent_to_queue(user_id)
|
|
end
|
|
```
|
|
|
|
#### validate_queue? (app/services/auto_assignment/inbox_round_robin_service.rb:51)
|
|
|
|
```ruby
|
|
def validate_queue?
|
|
return true if inbox.inbox_members.map(&:user_id).sort == queue.map(&:to_i).sort
|
|
end
|
|
```
|
|
|
|
#### queue (app/services/auto_assignment/inbox_round_robin_service.rb:55)
|
|
|
|
```ruby
|
|
def queue
|
|
::Redis::Alfred.lrange(round_robin_key)
|
|
end
|
|
```
|
|
|
|
#### round_robin_key (app/services/auto_assignment/inbox_round_robin_service.rb:59)
|
|
|
|
```ruby
|
|
def round_robin_key
|
|
format(::Redis::Alfred::ROUND_ROBIN_AGENTS, inbox_id: inbox.id)
|
|
end
|
|
```
|
|
|
|
#### round_robin_manage_service (app/services/auto_assignment/agent_assignment_service.rb:31)
|
|
|
|
```ruby
|
|
def round_robin_manage_service
|
|
@round_robin_manage_service ||= AutoAssignment::InboxRoundRobinService.new(inbox: conversation.inbox)
|
|
end
|
|
```
|
|
|
|
#### round_robin_service (app/services/auto_assignment/round_robin_selector.rb:13)
|
|
|
|
```ruby
|
|
def round_robin_service
|
|
@round_robin_service ||= AutoAssignment::InboxRoundRobinService.new(inbox: inbox)
|
|
end
|
|
```
|
|
|
|
#### change (db/migrate/20250806140003_create_inbox_capacity_limits.rb:4)
|
|
|
|
```ruby
|
|
def change
|
|
create_table :inbox_capacity_limits do |t|
|
|
t.references :agent_capacity_policy, null: false, index: true
|
|
t.references :inbox, null: false, index: true
|
|
t.integer :conversation_limit, null: false
|
|
|
|
t.timestamps
|
|
end
|
|
|
|
add_index :inbox_capacity_limits, [:agent_capacity_policy_id, :inbox_id], unique: true
|
|
end
|
|
```
|
|
|
|
#### change (db/migrate/20250806140004_add_agent_capacity_policy_to_account_users.rb:4)
|
|
|
|
```ruby
|
|
def change
|
|
add_reference :account_users, :agent_capacity_policy, null: true, index: true
|
|
end
|
|
``` |