Files
gochat/docs/requirements/M05-codegraph-context.md
rogee 0dabb8cfa5 docs: 整理文档目录结构 — 清理过时文档、归集功能子目录、统一命名规范
清理:
- 删除 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 相关修改
2026-07-09 14:53:27 +08:00

6.5 KiB

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
  • 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)

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)

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)

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)

  def clear_queue
    ::Redis::Alfred.delete(round_robin_key)
  end

add_agent_to_queue (app/services/auto_assignment/inbox_round_robin_service.rb:10)

  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)

  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)

  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)

  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)

  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)

  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)

  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)

  def queue
    ::Redis::Alfred.lrange(round_robin_key)
  end

round_robin_key (app/services/auto_assignment/inbox_round_robin_service.rb:59)

  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)

  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)

  def round_robin_service
    @round_robin_service ||= AutoAssignment::InboxRoundRobinService.new(inbox: inbox)
  end

change (db/migrate/20250806140003_create_inbox_capacity_limits.rb:4)

  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)

  def change
    add_reference :account_users, :agent_capacity_policy, null: true, index: true
  end