Files
gochat/docs/requirements/M1-accounts-and-users.md
T
2026-06-04 15:44:48 +08:00

790 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M1 账户与用户管理 — Chatwoot 功能梳理文档
> 基于 Chatwoot 源码深度阅读 + CodeGraph 上下文梳理
> 生成日期:2026-05-22
> 参照仓库:chatwoot-reference
---
## 1. 账户 CRUD + 设置 + 品牌
### 账户创建(注册时自动建账)
- 功能描述:用户注册时同步创建其第一个 Account,Account 与 User 通过 AccountUser 关联。AccountBuilder 事务性地创建 Account + User + AccountUser(角色默认 administrator)。
- 用户操作流程:
1. 用户在注册页面填写账户名、用户名、邮箱、密码
2. 系统验证邮箱有效性( disposable / blocked domain 检测)
3. 如通过 CAPTCHA 校验,事务性地创建 Account 和 User
4. 发送确认邮件;API-only 模式下直接返回 auth token
5. 已登录用户点击"添加账户"可创建新账户,自动成为该账户 administrator
- 涉及的API端点:
- `POST /api/v1/accounts` — 创建账户(无需认证)
- 请求参数:`{ account_name, user_full_name, email, password, locale }`
- 响应(已认证/API-only):`{ data: { id, email, ... }, meta: { access_token, ... } }`
- 响应(未确认注册):`{ email: "user@example.com" }`
- 涉及的数据模型:
- **Account**(`accounts` 表):`id, name, domain, locale, status, feature_flags, settings, custom_attributes, limits, support_email, auto_resolve_duration, internal_attributes`
- `status` enum:active(0), suspended(1)
- `settings` jsonb:包含 auto_resolve_after, auto_resolve_message, auto_resolve_ignore_waiting, audio_transcriptions 等大量配置项(参见 AccountSettingsSchema)
- `feature_flags` bigint:位运算存储(FlagShihTzu)
- 涉及的业务逻辑:
- **AccountBuilder**(`app/builders/account_builder.rb`):事务性创建 Account → User → AccountUser
- **Account::SignUpEmailValidationService**:邮箱验证(valid_email2 + blocked domain)
- **Account::BrandingEnrichmentJob**:注册后异步从邮箱域名拉取品牌信息(logo/favicon)
- 涉及的自动化/规则/事件:
- `before_create :enable_default_features` — 根据 InstallationConfig 启用默认 feature flags
- `after_create_commit :notify_creation` — ActionCable 通知
- `Account::BrandingEnrichmentJob.perform_later` — 品牌信息异步填充
- `AccountSettingsSchema` — JSON Schema 校验 settings 字段合法性
- CAPTCHA 验证(`validate_captcha` before_action)
- 邮件域名黑名单(`SignUpEmailValidationService.blocked_domains`)
- Chatwoot原实现关键代码文件路径:
- `app/controllers/api/v1/accounts_controller.rb`
- `app/builders/account_builder.rb`
- `app/services/account/sign_up_email_validation_service.rb`
- `app/jobs/account/branding_enrichment_job.rb`
- `app/models/account.rb`
- `app/models/concerns/account_settings_schema.rb`
- `app/models/concerns/featurable.rb`
- 版本标注:**社区版**
### 账户查看(Show)
- 功能描述:返回当前账户详情,包含 feature flags、settings、limits、品牌信息等。
- 用户操作流程:用户切换到某账户后,前端自动请求账户数据以渲染侧边栏和设置页。
- 涉及的API端点:
- `GET /api/v1/accounts/:id`
- 响应:`{ id, name, domain, locale, features, settings, limits, ... }`
- 涉及的数据模型:Account 全字段 + `latest_chatwoot_version`(Redis::Alfred)
- 涉及的业务逻辑:`AccountsController#show` — 查 Redis 获取最新 Chatwoot 版本号用于版本提示
- 涉及的自动化/规则/事件:Pundit 授权(AccountPolicy#show? → administrator || agent)
- Chatwoot原实现关键代码文件路径:
- `app/controllers/api/v1/accounts_controller.rb`
- `app/policies/account_policy.rb`
- 版本标注:**社区版**
### 账户更新(Update)
- 功能描述:管理员更新账户名称、域名、语言、支持邮箱、settings(自动解决配置等)、custom_attributes。
- 用户操作流程:
1. 管理员进入 Settings → Account Settings
2. 编辑账户名称/域名/locale/support_email
3. 编辑 auto_resolve_after、auto_resolve_message 等会话自动解决配置
4. 保存
- 涉及的API端点:
- `PUT /api/v1/accounts/:id`
- 请求参数:`{ name, locale, domain, support_email, settings: { auto_resolve_after, ... }, custom_attributes: { ... } }`
- 涉及的数据模型:Account 的 `name, locale, domain, support_email, settings, custom_attributes`
- 涉及的业务逻辑:
- 合并 `custom_attributes` 和 `settings`(merge! 策略,非覆盖)
- JSON Schema 校验 settings(`AccountSettingsSchema`)
- onboarding_step 步进逻辑:account_details → invite_team
- 涉及的自动化/规则/事件:Pundit(AccountPolicy#update? → 仅 administrator)
- Chatwoot原实现关键代码文件路径:
- `app/controllers/api/v1/accounts_controller.rb`
- `app/models/concerns/account_settings_schema.rb`
- `app/policies/account_policy.rb`
- 版本标注:**社区版**
### 账户激活时间更新(Update Active At)
- 功能描述:用户切换账户时更新 AccountUser 的 `active_at`,用于前端判断当前活跃账户。
- 涉及的API端点:`POST /api/v1/accounts/:id/update_active_at`
- 涉及的数据模型:AccountUser `active_at`
- 涉及的业务逻辑:直接更新 `active_at = Time.now.utc`
- Chatwoot原实现关键代码文件路径:`app/controllers/api/v1/accounts_controller.rb`
- 版本标注:**社区版**
### 账户缓存键(Cache Keys)
- 功能描述:前端轮询获取账户级别缓存键,用于判断数据是否需要刷新。
- 涉及的API端点:`GET /api/v1/accounts/:id/cache_keys`
- 涉及的业务逻辑:`CacheKeysHelper#cache_keys_for_account` 生成多维缓存键
- Chatwoot原实现关键代码文件路径:`app/controllers/api/v1/accounts_controller.rb`, `app/helpers/cache_keys_helper.rb`
- 版本标注:**社区版**
---
## 2. 用户注册 / 登录 / OAuth
### 用户注册(邮箱+密码)
- 功能描述:通过 AccountBuilder 创建账户时同步注册用户;独立注册仅通过账户创建入口。Devise Confirmable 模块要求邮箱确认后才能登录。
- 用户操作流程:
1. 填写邮箱、密码、全名
2. 系统调用 AccountBuilder → User.create! + Account.create! + AccountUser.create!
3. 发送确认邮件
4. 用户点击邮件链接确认邮箱
5. 确认后可正常登录
- 涉及的API端点:
- `POST /api/v1/accounts`(注册入口与账户创建合一)
- `GET /auth/confirmation?confirmation_token=xxx`(Devise 确认回调)
- `POST /api/v1/resend_confirmation`(重发确认邮件)
- 涉及的数据模型:
- **User**(`users` 表):`id, name, email, display_name, encrypted_password, provider, uid, confirmation_token, confirmed_at, confirmation_sent_at, unconfirmed_email, reset_password_token, reset_password_sent_at, sign_in_count, current_sign_in_at, current_sign_in_ip, last_sign_in_at, last_sign_in_ip, availability, message_signature, custom_attributes, ui_settings, pubsub_token, tokens, type`
- Devise 模块:`:database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :password_has_required_content`
- 涉及的业务逻辑:
- **Account::SignUpEmailValidationService**:邮箱有效性 + disposable + blocked domain
- **AccountBuilder**:事务创建 User → Account → AccountUser
- Devise Confirmable:确认邮件 → token 校验 → 设置 confirmed_at
- 涉及的自动化/规则/事件:
- 邮箱确认后才能登录(`DeviseOverrides::SessionsController` 检查 confirmed?)
- 密码必须包含数字+字母+特殊字符(`:password_has_required_content`)
- Chatwoot原实现关键代码文件路径:
- `app/builders/account_builder.rb`
- `app/services/account/sign_up_email_validation_service.rb`
- `app/controllers/devise_overrides/confirmations_controller.rb`
- `app/controllers/auth/resend_confirmations_controller.rb`
- `app/models/user.rb`
- 版本标注:**社区版**
### 用户登录(邮箱+密码 + MFA + SSO)
- 功能描述:支持邮箱密码登录、MFA 二次验证、SSO 一次性令牌登录。基于 DeviseTokenAuth 实现 JWT 式 token 认证(多 token 机制,支持并发多设备)。
- 用户操作流程:
1. 用户输入邮箱 + 密码 → `POST /auth/sign_in`
2. 若启用 MFA,返回 `mfa_required` 错误,前端引导用户输入 OTP/backup code
3. 用户输入 `mfa_token` → 再次 `POST /auth/sign_in` 完成 MFA 校验
4. 若使用 SSO 登录(`sso_auth_token`),直接通过令牌认证
5. 成功后返回 auth headers(`access-token, client, uid, expiry`)
- 涉及的API端点:
- `POST /auth/sign_in` — 登录
- 请求:`{ email, password }` 或 `{ email, password, mfa_token }` 或 `{ email, sso_auth_token }`
- 响应成功:auth headers + 用户 JSON
- 响应 MFA:`{ errors: ["mfa_required"], mfa_required: true }`
- 响应未确认:`{ errors: ["user_not_confirmed"] }`
- 涉及的数据模型:User `email, encrypted_password, otp_required_for_login, otp_secret, confirmed_at, provider`
- 涉及的业务逻辑:
- **DeviseOverrides::SessionsController**:
- `find_user_for_authentication`:邮箱 + 密码校验
- `handle_mfa_verification`:Mfa::AuthenticationService 校验 OTP 或 backup code
- `handle_mfa_required`:返回 MFA 提示
- `handle_sso_authentication`:SsoAuthenticatable#valid_sso_auth_token?
- `process_sso_auth_token`:SSO token 前置处理
- **Mfa::AuthenticationService**:OTP / backup code 校验
- **SsoAuthenticatable**:Redis 管理临时 SSO token(5 分钟有效期)
- 涉及的自动化/规则/事件:
- MFA 启用的用户必须经过二次验证
- SSO auth token 5 分钟过期(Redis::Alfred setex)
- DeviseTokenAuth 多 token 机制:每次登录生成新 token 对(access-token + client)
- Chatwoot原实现关键代码文件路径:
- `app/controllers/devise_overrides/sessions_controller.rb`
- `app/models/concerns/sso_authenticatable.rb`
- `app/services/mfa/management_service.rb`
- `app/services/mfa/authentication_service.rb`
- 版本标注:**社区版**
### 用户密码重置
- 功能描述:通过邮箱发送重置密码链接,用户点击链接后设置新密码。
- 用户操作流程:
1. 用户在登录页点击"忘记密码"
2. 输入邮箱 → `POST /auth/password` → 发送重置邮件
3. 用户点击邮件中的链接
4. 输入新密码 + 确认密码 → `PUT /auth/password` → 返回 auth headers
- 涉及的API端点:
- `POST /auth/password` — 请求重置邮件
- `PUT /auth/password` — 执行重置(`{ reset_password_token, password, password_confirmation }`)
- 涉及的数据模型:User `reset_password_token, reset_password_sent_at, encrypted_password`
- 涉及的业务逻辑:**DeviseOverrides::PasswordsController** — 标准 Devise 流程 + 返回 auth headers
- Chatwoot原实现关键代码文件路径:`app/controllers/devise_overrides/passwords_controller.rb`
- 版本标注:**社区版**
### OAuth 登录(Google OAuth2 / SAML)
- 功能描述:支持 Google OAuth2 和 SAML 作为外部认证提供者。OAuth 回调后查找或创建用户,生成 SSO auth token 重定向到前端登录页完成认证。
- 用户操作流程:
1. 用户点击"Google 登录"按钮
2. 重定向到 Google OAuth 授权页
3. 授权后回调到 `/auth/google_oauth2/callback`
4. 系统查找/创建用户,生成 SSO auth token
5. 重定向到前端 `/app/login?email=xxx&sso_auth_token=xxx`
6. 前端用 SSO auth token 调用 `POST /auth/sign_in` 完成认证
- 涉及的API端点:
- `GET /auth/google_oauth2` — 发起 OAuth
- `GET /auth/google_oauth2/callback` — OAuth 回调
- `POST /auth/saml_login` — SAML 登录入口(企业版)
- 涉及的数据模型:User `provider, uid`(OAuth 用户 provider='google_oauth2', uid=Google sub)
- 涉及的业务逻辑:
- **DeviseOverrides::OmniauthCallbacksController**:
- `sign_in_user`:找到用户 → 生成 SSO auth token → 重定向到登录页
- `sign_up_user`:创建新用户 → 设置随机密码 → 重定向到登录页
- `sign_in_user_on_mobile`:移动端 deeplink 方式
- **SsoAuthenticatable**:`generate_sso_auth_token`(Redis 5分钟有效期)
- 涉及的自动化/规则/事件:
- OAuth 新用户自动确认邮箱(`skip_confirmation!`)
- OAuth 新用户设置随机密码
- 移动端通过 deeplink 跳转
- Chatwoot原实现关键代码文件路径:
- `app/controllers/devise_overrides/omniauth_callbacks_controller.rb`
- `app/models/concerns/sso_authenticatable.rb`
- `enterprise/app/controllers/api/v1/auth_controller.rb`
- 版本标注:**社区版**(Google OAuth2)/ **企业版**(SAML)
### Token 验证
- 功能描述:验证当前 access-token 是否有效,用于前端刷新时校验 session。
- 涉及的API端点:`GET /auth/validate_token`
- 涉及的业务逻辑:**DeviseOverrides::TokenValidationsController** — DeviseTokenAuth 标准 + 自定义渲染
- Chatwoot原实现关键代码文件路径:`app/controllers/devise_overrides/token_validations_controller.rb`
- 版本标注:**社区版**
---
## 3. AccountUser 多账户角色
### AccountUser 关联管理
- 功能描述:一个 User 可属于多个 Account(通过 AccountUser 中间表),每个 AccountUser 独立设定 role(administrator/agent)、availability、auto_offline、custom_role_id、agent_capacity_policy_id。
- 用户操作流程:
1. 管理员在 Settings → Agents 列表中邀请/删除/编辑成员
2. 用户切换账户时前端调用 `update_active_at` 更新活跃账户
3. 用户可在 Profile 中设置各账户的 availability 和 auto_offline
- 涉及的API端点:
- `POST /api/v1/accounts/:account_id/agents` — 邀请成员
- `PUT /api/v1/accounts/:account_id/agents/:id` — 更新成员角色/availability
- `DELETE /api/v1/accounts/:account_id/agents/:id` — 删除成员
- `POST /api/v1/accounts/:account_id/agents/bulk_create` — 批量邀请
- `GET /api/v1/accounts/:account_id/agents` — 列出成员
- `POST /api/v1/profile/availability` — 更新当前用户在某账户的 availability
- `POST /api/v1/profile/auto_offline` — 更新 auto_offline
- `PUT /api/v1/profile/set_active_account` — 切换活跃账户
- 涉及的数据模型:
- **AccountUser**(`account_users` 表):`id, account_id, user_id, role, availability, auto_offline, active_at, inviter_id, custom_role_id, agent_capacity_policy_id`
- `role` enum:agent(0), administrator(1)
- `availability` enum:online(0), offline(1), busy(2)
- 索引:`uniq_user_id_per_account_id`(account_id + user_id 联合唯一)
- 涉及的业务逻辑:
- **AgentBuilder**(`app/builders/agent_builder.rb`):查找或创建 User → 创建 AccountUser → 发送邀请邮件
- **AccountsController#update_active_at**:更新 active_at
- **ProfilesController#availability / #auto_offline / #set_active_account**:各账户独立设置
- 删除 Agent 时:`AccountUser.destroy!` → 如果用户无其他账户则删除 User 记录
- 涉及的自动化/规则/事件:
- `after_create_commit :notify_creation, :create_notification_setting` — 创建 AccountUser 时自动创建通知设置
- `after_destroy :notify_deletion, :remove_user_from_account` — 删除时清理
- `after_save :update_presence_in_redis` — availability 变更时更新 Redis 在线状态
- **AvailabilityStatusable**:用户 availability_status 综合判断(DB availability + Redis online presence + auto_offline)
- Chatwoot原实现关键代码文件路径:
- `app/models/account_user.rb`
- `app/controllers/api/v1/accounts/agents_controller.rb`
- `app/builders/agent_builder.rb`
- `app/controllers/api/v1/profiles_controller.rb`
- `app/models/concerns/availability_statusable.rb`
- `app/policies/user_policy.rb`
- 版本标注:**社区版**(role=agent/administrator)/ **企业版**(custom_role_id, agent_capacity_policy_id)
---
## 4. Profile 管理
### Profile 查看 / 更新
- 功能描述:用户查看和更新自己的个人信息,包括姓名、邮箱、显示名、消息签名、头像、UI 设置等。
- 用户操作流程:
1. 用户点击侧边栏头像 → 进入 Profile 页
2. 编辑 name / display_name / email / message_signature / custom_attributes
3. 更换头像(上传/删除)
4. 修改密码(需输入当前密码验证)
5. 重置 access token(用于 API 访问)
6. 重发邮箱确认
- 涉及的API端点:
- `GET /api/v1/profile` — 查看
- `PUT /api/v1/profile` — 更新(含密码修改需 current_password)
- `DELETE /api/v1/profile/avatar` — 删除头像
- `POST /api/v1/profile/resend_confirmation` — 重发确认邮件
- `POST /api/v1/profile/reset_access_token` — 重置 access token
- `POST /api/v1/profile/availability` — 更新某账户 availability
- `POST /api/v1/profile/auto_offline` — 更新某账户 auto_offline
- `PUT /api/v1/profile/set_active_account` — 设置活跃账户
- 涉及的数据模型:User `name, display_name, email, message_signature, ui_settings, custom_attributes, avatar(ActiveStorage)`
- 涉及的业务逻辑:
- **ProfilesController**:
- `update`:密码修改需验证 current_password;其他字段直接 assign_attributes + merge custom_attributes
- `avatar`:删除 ActiveStorage attachment
- `reset_access_token`:`user.access_token.regenerate_token`
- 邮箱变更触发 Devise Confirmable reconfirmation 流程
- 涉及的自动化/规则/事件:
- 邮箱变更需重新确认(unconfirmed_email 机制)
- 密码修改必须验证当前密码
- Chatwoot原实现关键代码文件路径:
- `app/controllers/api/v1/profiles_controller.rb`
- `app/views/api/v1/profiles/show.json.jbuilder`
- 版本标注:**社区版**
### MFA(多因子认证)管理
- 功能描述:用户启用/禁用/验证 TOTP 二步认证,支持 OTP code 和 backup code。
- 用户操作流程:
1. 用户在 Profile → Security 页点击"启用 MFA"
2. 系统生成 otp_secret → 返回 provisioning URI(QR 码)
3. 用户用 Authenticator App 扫码绑定
4. 输入 OTP code 验证 → `POST /api/v1/profile/mfa/verify`
5. 验证成功后启用 MFA,返回 10 个 backup codes
6. 可随时重新生成 backup codes 或禁用 MFA(需验证 OTP)
- 涉及的API端点:
- `GET /api/v1/profile/mfa` — 查看 MFA 状态
- `POST /api/v1/profile/mfa` — 启用(生成 otp_secret)
- `POST /api/v1/profile/mfa/verify` — 验证并激活
- `POST /api/v1/profile/mfa/backup_codes` — 重新生成 backup codes
- `DELETE /api/v1/profile/mfa` — 禁用 MFA
- 涉及的数据模型:User `otp_secret(encrypted), otp_required_for_login, otp_backup_codes(encrypted)`
- 涉及的业务逻辑:
- **Mfa::ManagementService**:enable/disable/verify/generate_backup_codes
- **Mfa::AuthenticationService**:authenticate(OTP 或 backup code)
- backup code 消耗机制:验证后标记为 'XXXXXXXX'(不可重用)
- OTP secret 和 backup codes 使用 ActiveRecord encryption
- 涉及的自动化/规则/事件:
- 全局 MFA 开关:`Chatwoot.mfa_enabled?`(环境变量控制)
- 禁用 MFA 需验证当前 OTP/backup code
- backup code 常量时间比较(防 timing attack)
- Chatwoot原实现关键代码文件路径:
- `app/controllers/api/v1/profile/mfa_controller.rb`
- `app/services/mfa/management_service.rb`
- `app/services/mfa/authentication_service.rb`
- `app/services/mfa/token_service.rb`
- 版本标注:**社区版**
---
## 5. JWT 认证 + Devise
### DeviseTokenAuth 认证机制
- 功能描述:Chatwoot 使用 DeviseTokenAuth 实现 token-based 认证,而非传统 JWT。每次登录生成一对 token(`access-token` + `client`),通过 HTTP headers 传递。支持多设备并发登录(每个 client 一个 token)。
- 用户操作流程:
1. 登录成功后响应 headers 包含 `access-token, client, uid, expiry, token-type`
2. 前端存储 headers,后续请求携带这些 headers
3. Token 验证:`GET /auth/validate_token`
4. Token 过期后自动刷新(DeviseTokenAuth 内置机制)
- 涉及的API端点:
- `POST /auth/sign_in` — 登录
- `DELETE /auth/sign_out` — 登出
- `GET /auth/validate_token` — 验证 token
- Auth headers:`access-token, client, uid, expiry, token-type`
- 涉及的数据模型:User `tokens`(json 列,存储多 client token 信息)
- 涉及的业务逻辑:
- DeviseTokenAuth 管理多 client token 存储/验证/过期
- `Api::BaseController#authenticate_user!` → DeviseTokenAuth `set_user_by_token`
- `Api::BaseController#set_current_user` → 设置 `Current.user`
- `Api::BaseController#set_current_account` → 根据 `account_id` 参数设置 `Current.account` + `Current.account_user`
- 涉及的自动化/规则/事件:
- Token 过期时间 configurable(默认 2 周)
- 每次请求可更新 token(change_headers_on_each_request)
- Chatwoot原实现关键代码文件路径:
- `app/controllers/api/base_controller.rb`
- `app/controllers/devise_overrides/sessions_controller.rb`
- `app/controllers/devise_overrides/token_validations_controller.rb`
- `config/routes.rb`(mount_devise_token_auth_for 'User', at: 'auth')
- `app/models/user.rb`(DeviseTokenAuth::Concerns::User)
- 版本标注:**社区版**
---
## 6. RBAC 权限 + CustomRole(企业版)
### 内置角色 RBAC
- 功能描述:AccountUser 内置两种角色:administrator(1) 和 agent(0)。各 Policy 类基于 `@account_user.role` 做授权判断。administrator 有全部权限,agent 权限受限。
- 用户操作流程:管理员在邀请成员时选择角色(administrator / agent / custom_role)。
- 涉及的API端点:
- `POST /api/v1/accounts/:account_id/agents`(role 参数)
- `PUT /api/v1/accounts/:account_id/agents/:id`(可更改 role)
- 涉及的数据模型:AccountUser `role` enum(agent:0, administrator:1)
- 涉及的业务逻辑:
- **ApplicationPolicy**:所有 Policy 的基类,接收 `user_context[:account_user]` 进行角色判断
- **AccountPolicy**:show/limits → agent+administrator;update/toggle_deletion/subscription → 仅 administrator
- **UserPolicy**:create/update/destroy/bulk_create → 仅 administrator
- **AgentPolicy**:通过 Pundit + AccountPolicy 授权
- 涉及的自动化/规则/事件:Pundit 中间件在每次 controller action 前调用 `authorize` 方法
- Chatwoot原实现关键代码文件路径:
- `app/policies/application_policy.rb`
- `app/policies/account_policy.rb`
- `app/policies/user_policy.rb`
- `app/controllers/api/base_controller.rb`(`check_authorization` before_action)
- 版本标注:**社区版**
### CustomRole 自定义角色(企业版)
- 功能描述:企业版允许管理员创建自定义角色(CustomRole),定义细粒度权限(conversation_manage, contact_manage 等),并将 CustomRole 关联到 AccountUser,替代内置 agent 角色提供更精细的权限控制。
- 用户操作流程:
1. 管理员进入 Settings → Custom Roles
2. 创建自定义角色:填写名称、描述、勾选权限列表
3. 在邀请/编辑 Agent 时选择自定义角色
- 涉及的API端点:
- `GET /api/v1/accounts/:account_id/custom_roles` — 列出
- `POST /api/v1/accounts/:account_id/custom_roles` — 创建
- `GET /api/v1/accounts/:account_id/custom_roles/:id` — 查看
- `PUT /api/v1/accounts/:account_id/custom_roles/:id` — 更新
- `DELETE /api/v1/accounts/:account_id/custom_roles/:id` — 删除
- 请求:`{ name, description, permissions: ["conversation_manage", "contact_manage", ...] }`
- 涉及的数据模型:
- **CustomRole**(`custom_roles` 表):`id, name, description, permissions(array), account_id`
- 可用权限列表(PERMISSIONS 常量):
- `conversation_manage` — 管理所有会话
- `conversation_unassigned_manage` — 管理未分配会话并自分配
- `conversation_participating_manage` — 管理参与的会话
- `contact_manage` — 管理联系人
- `report_manage` — 管理报告
- `knowledge_base_manage` — 管理知识库
- AccountUser `custom_role_id`(FK → custom_roles)
- 涉及的业务逻辑:
- **CustomRolesController**:CRUD,依赖 EnterpriseAccountsController(企业版校验)
- 删除 CustomRole 时 `account_users.custom_role_id` 被 nullify
- 涉及的自动化/规则/事件:
- Feature flag `custom_roles` 必须启用
- CustomRolePolicy 全部操作仅 administrator
- Chatwoot原实现关键代码文件路径:
- `enterprise/app/models/custom_role.rb`
- `enterprise/app/controllers/api/v1/accounts/custom_roles_controller.rb`
- `enterprise/app/policies/custom_role_policy.rb`
- `enterprise/app/controllers/api/v1/accounts/enterprise_accounts_controller.rb`
- 版本标注:**企业版**
---
## 7. SAML SSO 设置(企业版)
### SAML SSO 配置
- 功能描述:管理员为账户配置 SAML IdP 参数(SSO URL、证书、Entity ID),配置后账户内用户的 `provider` 字段自动更新为 'saml',强制通过 SAML 认证登录。
- 用户操作流程:
1. 管理员进入 Settings → SAML SSO
2. 填写 IdP SSO URL、X.509 Certificate、IdP Entity ID、SP Entity ID
3. 可选配置 role_mappings(SAML 属性 → Chatwoot 角色映射)
4. 保存后,账户用户 provider 字段批量更新为 'saml'
- 涉及的API端点:
- `GET /api/v1/accounts/:account_id/saml_settings` — 查看
- `POST /api/v1/accounts/:account_id/saml_settings` — 创建
- `PUT /api/v1/accounts/:account_id/saml_settings` — 更新
- `DELETE /api/v1/accounts/:account_id/saml_settings` — 删除
- `POST /api/v1/auth/saml_login` — 发起 SAML 登录
- 请求:`{ sso_url, certificate, idp_entity_id, sp_entity_id, role_mappings: {} }`
- 涉及的数据模型:
- **AccountSamlSettings**(`account_saml_settings` 表):`id, account_id, sso_url, certificate, idp_entity_id, sp_entity_id, role_mappings(json)`
- Account `saml_settings`(has_one 关联)
- User `provider`(更新为 'saml')
- 涉及的业务逻辑:
- **SamlSettingsController**:CRUD + SAML feature flag 校验 + SSO 全局开关校验
- **AccountSamlSettings**:
- `after_create_commit :update_account_users_provider` — 批量将账户用户 provider 改为 'saml'
- `after_destroy_commit :reset_account_users_provider` — 批量恢复 provider 为 'email'
- 证书 X.509 校验(`certificate_must_be_valid_x509`)
- SP Entity ID 自动生成(`set_sp_entity_id`)
- `certificate_fingerprint`:计算证书指纹
- **Saml::UpdateAccountUsersProviderJob**:批量更新 provider,1000条/批
- **Api::V1::AuthController#saml_login**:根据邮箱查找 SAML 启用的账户,重定向到 `/auth/saml?account_id=xxx`
- 涉及的自动化/规则/事件:
- Feature flag `saml` 必须启用
- 全局配置 `ENABLE_SAML_SSO_LOGIN` 必须为 true
- SAML 设置创建/删除触发批量 provider 更新 Job
- SAML 回调 → OmniauthCallbacksController → sign_in_user(生成 SSO auth token)
- role_mappings 可将 SAML 属性映射到 Chatwoot 角色
- Chatwoot原实现关键代码文件路径:
- `enterprise/app/models/account_saml_settings.rb`
- `enterprise/app/controllers/api/v1/accounts/saml_settings_controller.rb`
- `enterprise/app/controllers/api/v1/auth_controller.rb`
- `enterprise/app/jobs/saml/update_account_users_provider_job.rb`
- `enterprise/app/policies/account_saml_settings_policy.rb`
- `app/controllers/devise_overrides/omniauth_callbacks_controller.rb`
- 版本标注:**企业版**
---
## 8. Company 组织管理(企业版)
### Company CRUD + 品牌
- 功能描述:企业版提供 Company 模型,用于组织/公司级别管理联系人归属。Company 可设置名称、域名、描述、自定义属性,支持自动从域名拉取 favicon 作为 logo。
- 用户操作流程:
1. 管理员/用户进入 Contacts → Companies 页面
2. 创建公司:填写名称、域名(可选)、描述
3. 编辑/删除公司
4. 将联系人关联到公司
5. 搜索公司(按名称或域名)
- 涉及的API端点:
- `GET /api/v1/accounts/:account_id/companies` — 列出(分页25/页)
- `GET /api/v1/accounts/:account_id/companies/search?q=xxx` — 搜索
- `POST /api/v1/accounts/:account_id/companies` — 创建
- `GET /api/v1/accounts/:account_id/companies/:id` — 查看
- `PUT /api/v1/accounts/:account_id/companies/:id` — 更新
- `DELETE /api/v1/accounts/:account_id/companies/:id` — 删除(仅 administrator)
- `DELETE /api/v1/accounts/:account_id/companies/:id/destroy_custom_attributes` — 删除自定义属性
- 涉及的数据模型:
- **Company**(`companies` 表):`id, account_id, name, domain, description, additional_attributes(jsonb), custom_attributes(jsonb), contacts_count, last_activity_at`
- 索引:`(account_id, domain) UNIQUE WHERE domain IS NOT NULL`
- 关联:`contacts`(has_many, dependent: nullify)
- `Avatarable` — 支持 ActiveStorage avatar + 从域名 favicon 自动拉取
- 涉及的业务逻辑:
- **CompaniesController**:CRUD + 搜索 + 分页 + 排序(Sift gem: name/domain/created_at/last_activity_at/contacts_count)
- `after_create_commit :fetch_favicon` — 从域名自动拉取 favicon 作为 logo
- `record_activity_at!` — 5分钟 rollup 间隔内不重复更新 last_activity_at
- 品名长度限制(COMPANY_NAME_LENGTH_LIMIT)
- 品域名格式校验 + 账户内唯一
- 涉及的自动化/规则/事件:
- Feature flag `companies` 必须启用
- CompanyPolicy:所有用户可 index/show/create/update/search;仅 administrator 可 destroy
- favicon 自动拉取(Avatar::AvatarFromFaviconJob)
- last_activity_at 活动汇总(ACTIVITY_ROLLUP_INTERVAL = 5分钟)
- Chatwoot原实现关键代码文件路径:
- `enterprise/app/models/company.rb`
- `enterprise/app/controllers/api/v1/accounts/companies_controller.rb`
- `enterprise/app/policies/company_policy.rb`
- 版本标注:**企业版**
---
## 9. AgentCapacityPolicy 容量策略(企业版)
### 容量策略 CRUD
- 功能描述:企业版支持定义 Agent 容量策略(AgentCapacityPolicy),限制每个 Agent 在指定 Inbox 中同时处理的会话数量上限。一个策略可关联多个 Inbox 的容量上限(InboxCapacityLimit),并可分配给多个 AccountUser。
- 用户操作流程:
1. 管理员进入 Settings → Agent Capacity Policies
2. 创建策略:填写名称、描述、排除规则(exclusion_rules)
3. 为策略添加 Inbox 容量限制:选择 Inbox + 设置 conversation_limit
4. 将策略分配给特定 Agent
5. 编辑/删除策略
- 涉及的API端点:
- `GET /api/v1/accounts/:account_id/agent_capacity_policies` — 列出
- `POST /api/v1/accounts/:account_id/agent_capacity_policies` — 创建
- `GET /api/v1/accounts/:account_id/agent_capacity_policies/:id` — 查看
- `PUT /api/v1/accounts/:account_id/agent_capacity_policies/:id` — 更新
- `DELETE /api/v1/accounts/:account_id/agent_capacity_policies/:id` — 删除
- 子资源:
- `GET /api/v1/accounts/:account_id/agent_capacity_policies/:policy_id/users` — 查看分配的 Agent
- `POST /api/v1/accounts/:account_id/agent_capacity_policies/:policy_id/users` — 分配 Agent
- `DELETE /api/v1/accounts/:account_id/agent_capacity_policies/:policy_id/users/:id` — 取消分配
- `POST /api/v1/accounts/:account_id/agent_capacity_policies/:policy_id/inbox_limits` — 创建 Inbox 容量限制
- `PUT .../inbox_limits/:id` — 更新容量限制值
- `DELETE .../inbox_limits/:id` — 删除容量限制
- 涉及的数据模型:
- **AgentCapacityPolicy**(`agent_capacity_policies` 表):`id, account_id, name, description, exclusion_rules(jsonb)`
- `exclusion_rules`:`{ exclude_older_than_hours: int, excluded_labels: [string] }`
- 含排除逻辑:超过指定小时数的会话不计入容量;带特定标签的会话不计入容量
- **InboxCapacityLimit**(`inbox_capacity_limits` 表):`id, agent_capacity_policy_id, inbox_id, conversation_limit`
- 索引:`(agent_capacity_policy_id, inbox_id) UNIQUE`
- `conversation_limit` 必须 >= 0
- **AccountUser** `agent_capacity_policy_id`(FK → agent_capacity_policies)
- 涉及的业务逻辑:
- **AgentCapacityPoliciesController**:CRUD + 企业版校验
- **AgentCapacityPolicies::UsersController**:分配/取消 Agent → 更新 AccountUser.agent_capacity_policy_id
- **AgentCapacityPolicies::InboxLimitsController**:管理各 Inbox 的 conversation_limit
- 涉及的自动化/规则/事件:
- 仅 administrator 可操作(AgentCapacityPolicyPolicy 全操作限 administrator)
- 一个 Inbox 在同一策略下只能有一个容量限制(唯一索引)
- AccountUser 删除时 `agent_capacity_policy_id` 被 nullify
- Chatwoot原实现关键代码文件路径:
- `enterprise/app/models/agent_capacity_policy.rb`
- `enterprise/app/models/inbox_capacity_limit.rb`
- `enterprise/app/controllers/api/v1/accounts/agent_capacity_policies_controller.rb`
- `enterprise/app/controllers/api/v1/accounts/agent_capacity_policies/users_controller.rb`
- `enterprise/app/controllers/api/v1/accounts/agent_capacity_policies/inbox_limits_controller.rb`
- `enterprise/app/policies/agent_capacity_policy_policy.rb`
- `db/migrate/20250806140004_add_agent_capacity_policy_to_account_users.rb`
- 版本标注:**企业版**
---
## 10. FeatureFlags 功能开关
### FeatureFlags 管理
- 功能描述:Account 级别功能开关,通过 FlagShihTzu 位运算存储在 `feature_flags` bigint 列中。支持按 Account 启用/禁用特定功能,前端根据 feature flags 动态显示/隐藏功能入口。
- 用户操作流程:
1. 管理员进入 Settings → Account Features
2. 切换功能开关(enable/disable)
3. 前端实时响应功能可见性变化
- 涉及的API端点:
- 通过 Account show/update 间接管理(settings 返回 enabled_features / disabled_features)
- Super Admin 可通过 InstallationConfig 设置 `ACCOUNT_LEVEL_FEATURE_DEFAULTS`
- 涉及的数据模型:
- **Account** `feature_flags`(bigint,位运算存储)
- **Featurable** concern:`enable_features! / disable_features! / feature_enabled? / all_features / enabled_features / disabled_features`
- **config/features.yml**:定义所有功能开关列表(名称 + 显示名 + 默认启用 + premium 标记)
- 涉及的业务逻辑:
- **Featurable**(`app/models/concerns/featurable.rb`):
- `enable_default_features`:创建 Account 时根据 InstallationConfig 设置默认值
- `feature_enabled?(name)` → 位运算检查
- 功能列表(config/features.yml 关键项):
| Feature | Display Name | Default | Premium |
|---|---|---|---|
| inbound_emails | Inbound Emails | true | - |
| channel_email | Email Channel | true | - |
| channel_facebook | Facebook Channel | true | - |
| help_center | Help Center | true | - |
| agent_bots | Agent Bots | true | - |
| macros | Macros | true | - |
| agent_management | Agent Management | true | - |
| team_management | Team Management | true | - |
| inbox_management | Inbox Management | true | - |
| labels | Labels | true | - |
| custom_attributes | Custom Attributes | true | - |
| automations | Automations | true | - |
| campaigns | Campaigns | true | - |
| reports | Reports | true | - |
| crm | CRM | true | - |
| auto_resolve_conversations | Auto Resolve | true | - |
| disable_branding | Disable Branding | false | ✅ premium |
| custom_roles | Custom Roles | false | ✅ premium |
| sla | SLA | false | ✅ premium |
| audit_logs | Audit Logs | false | ✅ premium |
| saml | SAML | false | ✅ premium |
| companies | Companies | false | ✅ premium |
| channel_voice | Voice Channel | false | ✅ premium |
| advanced_search | Advanced Search | false | ✅ premium |
- 涉及的自动化/规则/事件:
- `before_create :enable_default_features` — Account 创建时设置默认 features
- premium 功能需要企业版许可证
- feature flag 变更触发缓存清除(`after_update_commit :clear_unread_conversation_counts_cache` 等条件回调)
- Chatwoot原实现关键代码文件路径:
- `app/models/concerns/featurable.rb`
- `config/features.yml`
- `app/models/account.rb`
- 版本标注:**社区版**(基础功能)/ **企业版**(premium 功能需许可证)
---
## 附录:关键数据模型汇总
### accounts 表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | integer PK | 主键 |
| name | string NOT NULL | 账户名称 |
| domain | string(100) | 入站邮件域名 |
| locale | integer default(en) | 账户语言 |
| status | integer default(active) | active(0)/suspended(1) |
| feature_flags | bigint default(0) | 位运算功能开关 |
| settings | jsonb | 账户设置(自动解决、Captain等) |
| custom_attributes | jsonb | 自定义属性(含 onboarding_step) |
| limits | jsonb | 使用限制 |
| support_email | string(100) | 支持邮箱 |
| auto_resolve_duration | integer | 自动解决时长 |
| internal_attributes | jsonb | 内部属性 |
### users 表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | integer PK | 主键 |
| name | string NOT NULL | 用户名 |
| email | string | 邮箱(唯一) |
| display_name | string | 显示名 |
| encrypted_password | string NOT NULL | 加密密码 |
| provider | string default(email) | 认证提供者(email/google_oauth2/saml) |
| uid | string NOT NULL | 提供者内ID |
| confirmation_token | string | 确认令牌 |
| confirmed_at | datetime | 确认时间 |
| otp_secret | string(encrypted) | MFA TOTP secret |
| otp_required_for_login | boolean default(false) | MFA 启用标志 |
| otp_backup_codes | text(encrypted) | MFA 备用码 |
| availability | integer default(online) | online(0)/offline(1)/busy(2) |
| message_signature | text | 消息签名 |
| custom_attributes | jsonb | 自定义属性 |
| ui_settings | jsonb | UI偏好设置 |
| pubsub_token | string | ActionCable token |
| tokens | json | DeviseTokenAuth 多 token 存储 |
| type | string | 用户类型(SuperAdmin等STI) |
### account_users 表
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint PK | 主键 |
| account_id | bigint FK | 所属账户 |
| user_id | bigint FK | 所属用户 |
| role | integer default(agent) | agent(0)/administrator(1) |
| availability | integer default(online) | online(0)/offline(1)/busy(2) |
| auto_offline | boolean default(true) | 自动离线 |
| active_at | datetime | 活跃时间 |
| inviter_id | bigint FK | 邀请人 |
| custom_role_id | bigint FK | 自定义角色(企业版) |
| agent_capacity_policy_id | bigint FK | 容量策略(企业版) |
### custom_roles 表(企业版)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint PK | 主键 |
| account_id | bigint FK NOT NULL | 所属账户 |
| name | string | 角色名称 |
| description | string | 角色描述 |
| permissions | text array | 权限列表 |
### account_saml_settings 表(企业版)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint PK | 主键 |
| account_id | bigint FK NOT NULL | 所属账户 |
| sso_url | string | IdP SSO URL |
| certificate | text | X.509 Certificate |
| idp_entity_id | string | IdP Entity ID |
| sp_entity_id | string | SP Entity ID |
| role_mappings | json | SAML→角色映射 |
### companies 表(企业版)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint PK | 主键 |
| account_id | bigint FK NOT NULL | 所属账户 |
| name | string NOT NULL | 公司名称 |
| domain | string | 公司域名(账户内唯一) |
| description | text | 描述 |
| additional_attributes | jsonb | 额外属性 |
| custom_attributes | jsonb | 自定义属性 |
| contacts_count | integer | 联系人数 |
| last_activity_at | datetime | 最后活动时间 |
### agent_capacity_policies 表(企业版)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint PK | 主键 |
| account_id | bigint FK NOT NULL | 所属账户 |
| name | string(255) NOT NULL | 策略名称 |
| description | text | 策略描述 |
| exclusion_rules | jsonb NOT NULL | 排除规则 |
### inbox_capacity_limits 表(企业版)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | bigint PK | 主键 |
| agent_capacity_policy_id | bigint FK NOT NULL | 所属策略 |
| inbox_id | bigint FK NOT NULL | 所属 Inbox |
| conversation_limit | integer NOT NULL | 会话容量上限 |
---
## 附录:路由汇总
```
# 认证路由
POST /auth/sign_in # 登录
DELETE /auth/sign_out # 登出
GET /auth/validate_token # Token 验证
POST /auth/password # 密码重置请求
PUT /auth/password # 密码重置执行
GET /auth/confirmation # 邮箱确认
POST /api/v1/resend_confirmation # 重发确认
GET /auth/google_oauth2 # Google OAuth 发起
GET /auth/google_oauth2/callback # Google OAuth 回调
POST /api/v1/auth/saml_login # SAML 登录(企业版)
GET /auth/saml # SAML IdP 重定向
# 账户路由
POST /api/v1/accounts # 创建账户
GET /api/v1/accounts/:id # 查看
PUT /api/v1/accounts/:id # 更新
POST /api/v1/accounts/:id/update_active_at # 更新活跃时间
GET /api/v1/accounts/:id/cache_keys # 缓存键
# 成员管理
GET /api/v1/accounts/:id/agents # 成员列表
POST /api/v1/accounts/:id/agents # 邀请成员
PUT /api/v1/accounts/:id/agents/:id # 更新成员
DELETE /api/v1/accounts/:id/agents/:id # 删除成员
POST /api/v1/accounts/:id/agents/bulk_create # 批量邀请
GET /api/v1/accounts/:id/assignable_agents # 可分配成员
# Profile
GET /api/v1/profile # 查看
PUT /api/v1/profile # 更新
DELETE /api/v1/profile/avatar # 删除头像
POST /api/v1/profile/availability # 更新可用状态
POST /api/v1/profile/auto_offline # 更新自动离线
PUT /api/v1/profile/set_active_account # 切换活跃账户
POST /api/v1/profile/resend_confirmation # 重发确认
POST /api/v1/profile/reset_access_token # 重置 token
# MFA
GET /api/v1/profile/mfa # MFA 状态
POST /api/v1/profile/mfa # 启用
POST /api/v1/profile/mfa/verify # 验证激活
POST /api/v1/profile/mfa/backup_codes # 备用码
DELETE /api/v1/profile/mfa # 禁用
# 企业版路由
GET/POST/PUT/DELETE /api/v1/accounts/:id/saml_settings
GET/POST/PUT/DELETE /api/v1/accounts/:id/custom_roles
GET/POST/PUT/DELETE /api/v1/accounts/:id/agent_capacity_policies
GET/POST/DELETE /api/v1/accounts/:id/agent_capacity_policies/:policy_id/users
POST/PUT/DELETE /api/v1/accounts/:id/agent_capacity_policies/:policy_id/inbox_limits
GET/POST/PUT/DELETE /api/v1/accounts/:id/companies
GET /api/v1/accounts/:id/companies/search
```