清理: - 删除 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 相关修改
41 KiB
GoChat 企业功能分析文档
版本:v1.1 更新日期:2026-07-09 目标:Chatwoot 企业版功能深度分析 + GoChat 商业收费功能构思 + CaptainAI/SSO/语音通话等功能设计方案 注:本文档最初生成于 2026-05-25,当时多数企业功能标记为 "Stub/未实现"。 截至更新日期,SLA/AuditLog/CustomRole/Company/AgentCapacity/AssignmentPolicy/Captain/Copilot 等已实现并通过 Chatwoot parity 对齐,详见 tracking/01-chatwoot-parity-tracker.md。
目录
一、Chatwoot 企业版功能全景分析
1.1 Chatwoot 版本分层
Chatwoot 采取 社区版(开源) + 企业版(付费) 双轨模式:
| 版本 | 定价 | 定位 | 核心差异 |
|---|---|---|---|
| Community (开源) | 免费 / 自部署 | 小团队、初创企业 | 基础客服功能,无 SLA/SSO/AI/语音 |
| Cloud Pro | $29/坐席/月 | 中型企业 | 云托管,含基础自动化 |
| Cloud Enterprise | $69/坐席/月 | 大型企业 | 全功能 + SSO + SLA + CaptainAI + 语音 |
| Self-hosted Enterprise | 按需报价 | 大型企业自部署 | 同 Cloud Enterprise,但自行部署 |
1.2 企业版独占功能清单
以下功能 仅在 Enterprise 版本开放,社区版无法使用:
| # | 功能 | 模块 | Chatwoot 实现 | GoChat 状态 |
|---|---|---|---|---|
| 1 | SLA 策略 | SlaPolicy + AppliedSla + SlaEvent | 完整实现 | Stub/未实现 |
| 2 | 审计日志 | AuditLog | 完整实现 | Stub/未实现 |
| 3 | 自定义角色权限 | CustomRole | 完整实现 | Stub/未实现 |
| 4 | 公司/组织管理 | Company | 完整实现 | Stub/未实现 |
| 5 | 坐席容量策略 | AgentCapacityPolicy + InboxCapacityLimit | 完整实现 | Stub/未实现 |
| 6 | 语音通话 | Call + Voice 系列 Service | Twilio 集成 | Stub/未实现 |
| 7 | SAML SSO | AccountSamlSettings | 完整实现 | 部分(仅 Enable) |
| 8 | Captain AI | Captain::Assistant + Document + Scenario | 完整实现 | 已实现 |
| 9 | Copilot | SuggestReplies/Summarize/Translate | 完整实现 | 已实现 |
| 10 | 定时任务调度 | SidekiqCron | 完整实现 | 未实现 |
| 11 | 自动分配策略 | AssignmentPolicy | 完整实现 | Stub/未实现 |
| 12 | Platform App / Partner API | PlatformApp + Permissible | 完整实现 | Stub/未实现 |
| 13 | AgentBot 智能机器人 | AgentBot + AgentBotInbox | 完整实现 | Stub/未实现 |
| 14 | 数据导入 | DataImport + DataImportJob | 完整实现 | 未实现 |
| 15 | 多品牌 Help Center | Portal + Category + Article | 完整实现 | Stub/未实现 |
1.3 Chatwoot 功能授权机制
Chatwoot 通过以下三层机制控制企业版功能:
-
Feature Flag(
features.yml):全局功能开关enterpriseflag → 企业版总开关samlflag → SAML SSO 子开关voiceflag → 语音通话子开关
-
Billing Subscription(云版):
InstallationConfig+Subscription模型- 超级管理员配置订阅状态
- API 中间件检查订阅 → 未订阅则 403
-
Policy 授权:Pundit Policy 类
CustomRole→ 精细化角色权限AccountPolicy→ 账户级操作权限
1.4 GoChat 当前差距总结
基于 Gochat-vs-Chatwoot-Full-Comparison.md 分析:
| 维度 | Chatwoot | GoChat | 差距 |
|---|---|---|---|
| API 路由数 | 327+ | 106 | 缺 221+(仅 32% 覆盖) |
| Handler 方法数 | 150+ | 99 | 缺 51+ |
| 真实实现率 | 100% | 57% | 差 43% |
| Stub/Placeholder | 0 | 37 | 全部需补实现 |
| 501 Not Implemented | 0 | 6 | 全部需补实现 |
| 消息队列调度 | Sidekiq 完整 | WorkerPool 全 stub | 不可用 |
| 渠道扩展机制 | 11 渠道 | 仅 2 渠道 | 缺 9 渠道 |
| 事件分发 | 9 Listener | 无真实 Listener | 事件驱动完全不可用 |
二、GoChat 商业收费模式构思
2.1 定价策略定位
GoChat 作为 Chatwoot 的 Go 语言高性能重写,应借鉴但超越 Chatwoot 的定价模式:
核心差异化卖点:
- Go 语言带来的 10x 性能优势(并发处理、内存占用、延迟)
- 更轻量的部署架构(单二进制 vs Ruby+Sidekiq+Redis 多进程)
- 开源友好 + 自部署优先
- AI 能力原生集成(而非插件式)
2.2 版本分层设计
| 版本 | 定价 | 目标用户 | 功能范围 |
|---|---|---|---|
| Community(开源) | 免费 | 小团队/个人/初创 | 核心客服功能:对话、联系人、收件箱、基础渠道、基础报表 |
| Professional | ¥99/坐席/月($15) | 中型企业 | +自动化规则 +高级报表 +批量操作 +Email渠道 +品牌定制 |
| Enterprise | ¥299/坐席/月($45) | 大型企业 | +SLA +SSO +语音通话 +CaptainAI +审计日志 +自定义角色 +坐席容量 |
| Ultimate | ¥599/坐席/月($90) | 超大型/政府 | +全功能 +私有部署支持 +定制开发 +专属SLA保障 |
2.3 功能-版本矩阵
| 功能 | Community | Professional | Enterprise | Ultimate |
|---|---|---|---|---|
| 对话管理 | ✅ | ✅ | ✅ | ✅ |
| 联系人 CRM | ✅ | ✅ | ✅ | ✅ |
| 收件箱(5个) | ✅ | ✅ 20个 | ✅ 无限 | ✅ 无限 |
| 坐席数 | 5 | 20 | 无限 | 无限 |
| Telegram 渠道 | ✅ | ✅ | ✅ | ✅ |
| WebWidget 渠道 | ✅ | ✅ | ✅ | ✅ |
| API 渠道 | ✅ | ✅ | ✅ | ✅ |
| Email 渠道 | - | ✅ | ✅ | ✅ |
| WhatsApp 渠道 | - | ✅ | ✅ | ✅ |
| Facebook 渠道 | - | ✅ | ✅ | ✅ |
| Instagram 渠道 | - | ✅ | ✅ | ✅ |
| Slack 渠道 | - | - | ✅ | ✅ |
| Line 渠道 | - | - | ✅ | ✅ |
| 语音通话 | - | - | ✅ | ✅ |
| SLA 策略 | - | - | ✅ | ✅ |
| SAML SSO | - | - | ✅ | ✅ |
| Captain AI | - | - | ✅ | ✅ |
| Copilot 副驾驶 | - | - | ✅ | ✅ |
| 自定义角色权限 | - | - | ✅ | ✅ |
| 审计日志 | - | - | ✅ | ✅ |
| 坐席容量管理 | - | - | ✅ | ✅ |
| 公司/组织管理 | - | ✅ 基础 | ✅ 高级 | ✅ 高级 |
| Help Center | - | - | ✅ | ✅ |
| 自动分配策略 | - | ✅ 基础 | ✅ 高级 | ✅ 高级 |
| 自动化规则 | - | ✅ | ✅ | ✅ |
| 批量操作 | - | ✅ | ✅ | ✅ |
| 高级报表/洞察 | - | ✅ | ✅ | ✅ |
| 实时报表 | - | ✅ | ✅ | ✅ |
| Platform API/Partner | - | - | - | ✅ |
| 私有部署支持 | - | - | ✅ 基础 | ✅ 专属 |
| 定制开发 | - | - | - | ✅ |
2.4 计费模型设计
计费维度
-
坐席数(Agent):主计费单位,按月/年订阅
- 月付:标准价格
- 年付:8折优惠
-
用量加价(Overage):
- 对话量超限:每 1K 对话 ¥10
- AI 调用量超限:每 1K 次 ¥5
- 存储超限:每 GB ¥2/月
-
附加功能包(Add-on):
- CaptainAI 增强包:¥50/坐席/月(更高 AI 调用额度)
- 语音通话包:¥30/坐席/月 + Twilio 话费
- SSO 增强包:¥20/坐席/月(支持 OIDC + LDAP + SAML)
数据模型设计
// Subscription 订阅模型
type Subscription struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
Plan string `gorm:"not null;type:varchar(20)"` // community/professional/enterprise/ultimate
BillingCycle string `gorm:"not null;type:varchar(10)"` // monthly/yearly
AgentCount int `gorm:"not null;default:5"`
StartedAt time.Time `gorm:"not null"`
ExpiresAt time.Time `gorm:"not null"`
Status string `gorm:"not null;type:varchar(20)"` // active/expired/cancelled/suspended
AutoRenew bool `gorm:"default:true"`
Addons json.RawMessage `gorm:"type:jsonb"` // [{name, quantity, unit_price}]
OverageAlert bool `gorm:"default:true"` // 用量超限是否告警
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// BillingUsage 计费用量
type BillingUsage struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
Period string `gorm:"not null;type:varchar(7)"` // 2026-05
Conversations int `gorm:"default:0"`
AICalls int `gorm:"default:0"`
StorageGB float64 `gorm:"default:0"`
VoiceMinutes float64 `gorm:"default:0"`
CreatedAt time.Time
UpdatedAt time.Time
}
// FeatureEntitlement 功能授权
type FeatureEntitlement struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;uniqueIndex"`
Plan string `gorm:"not null"`
Features json.RawMessage `gorm:"type:jsonb"` // {"sla": true, "sso": true, "voice": true, ...}
MaxInboxes int `gorm:"default:5"`
MaxAgents int `gorm:"default:5"`
AICallLimit int `gorm:"default:0"` // 月度 AI 调用上限
StorageLimitGB float64 `gorm:"default:5"`
CreatedAt time.Time
UpdatedAt time.Time
}
2.5 功能开关中间件
// FeatureGate 中间件:根据订阅计划控制功能访问
func FeatureGate(requiredFeature string) gin.HandlerFunc {
return func(c *gin.Context) {
accountID := getAccountID(c)
entitlement := getFeatureEntitlement(accountID)
features := parseFeatures(entitlement.Features)
if !features[requiredFeature] {
c.JSON(403, gin.H{
"error": "Feature not available in your plan",
"feature": requiredFeature,
"plan": entitlement.Plan,
"upgrade_url": "/billing/upgrade",
})
c.Abort()
return
}
c.Next()
}
}
// 路由注册示例
router.POST("/api/v1/accounts/:id/sla_policies",
FeatureGate("sla"), // Enterprise 专属
authMiddleware(),
slaHandler.Create(),
)
router.POST("/api/v1/accounts/:id/captain/assistants",
FeatureGate("captain_ai"), // Enterprise 专属
authMiddleware(),
captainHandler.Create(),
)
2.6 GoChat vs Chatwoot 商业模式差异
| 维度 | Chatwoot | GoChat 设计 |
|---|---|---|
| 定价模型 | 按坐席/月(美元) | 按坐席/月(人民币优先,支持多币种) |
| 自部署 | 免费社区版 + 企业版需购买 license | Community 免费 + Enterprise 自部署可购买 license 密钥 |
| 功能授权 | features.yml + InstallationConfig | config.yaml + FeatureEntitlement DB + FeatureGate 中间件 |
| AI 计费 | 无独立计费(含在 Enterprise) | CaptainAI 独立 Add-on 包 + 用量计费 |
| 语音计费 | 含在 Enterprise | 独立 Add-on + Twilio 话费透明 |
| 开放策略 | 企业版源码闭源 | 全源码开放 + license 密钥解锁企业功能 |
三、CaptainAI 功能设计
3.1 Captain AI 架构概览
Captain AI 是 GoChat 企业版的 AI 助手系统,提供两大核心能力:
- Captain(船长):AI 自动回复引擎,可绑定 Inbox 后自动处理客户咨询
- Copilot(副驾驶):AI 辅助工具,帮助坐席更快回复(建议回复、摘要、翻译)
3.2 功能模块拆解
| # | 子模块 | Chatwoot 对应 | 功能描述 | GoChat 实现状态 |
|---|---|---|---|---|
| 1 | CaptainAssistant | Captain::Assistant | AI 助手 CRUD + Playground | ✅ 已实现 |
| 2 | CaptainDocument | Captain::Document | 知识库文档管理 | ✅ 已实现 |
| 3 | CaptainScenario | Captain::Scenario | 场景化对话流程 | ✅ 已实现 |
| 4 | CaptainCustomTool | Captain::CustomTool | 自定义 AI 工具 | ✅ 已实现 |
| 5 | CopilotSuggest | Copilot::SuggestReplies | 建议回复 | ✅ 已实现 |
| 6 | CopilotSummarize | Copilot::Summarize | 对话摘要 | ✅ 已实现 |
| 7 | CopilotTranslate | Copilot::Translate | 多语言翻译 | ✅ 已实现 |
| 8 | CaptainInbox | CaptainInbox | 助手-Inbox 绑定 | ✅ 已实现 |
| 9 | Playground | AssistantChatService/AgentRunnerService | 在线调试 | ✅ 已实现 |
| 10 | DocumentSearch | pgvector 向量检索 | 知识库搜索 | ✅ 已实现 |
3.3 CaptainAI 增强设计(超越 Chatwoot)
3.3.1 多 LLM Provider 支持
Chatwoot 仅支持 OpenAI。GoChat 设计为多 Provider 架构:
// LLMProvider 接口
type LLMProvider interface {
ChatCompletion(ctx context.Context, req ChatRequest) (ChatResponse, error)
Embedding(ctx context.Context, text string) ([]float32, error)
StreamChat(ctx context.Context, req ChatRequest) (<-chan ChatChunk, error)
}
// 支持的 Provider
var Providers = map[string]LLMProvider{
"openai": &OpenAIProvider{},
"azure": &AzureOpenAIProvider{},
"anthropic": &AnthropicProvider{}, // Claude
"deepseek": &DeepSeekProvider{}, // DeepSeek
"qwen": &QwenProvider{}, // 通义千问
"glm": &GLMProvider{}, // 智谱 GLM
"local": &LocalProvider{}, // llama.cpp 本地
"ollama": &OllamaProvider{}, // Ollama 本地
}
3.3.2 RAG 知识库增强
| 特性 | Chatwoot | GoChat 增强 |
|---|---|---|
| 向量存储 | pgvector 单一 | pgvector + Elasticsearch + Milvus 可选 |
| 文档类型 | 知识库文档 | + 网页抓取 + PDF + FAQ 自动提取 |
| 检索策略 | 简单向量相似度 | 混合检索(向量 + 关键词 + 重排序) |
| 上下文窗口 | 固定 | 动态窗口 + MMR 去重 |
| 多语言支持 | 英文为主 | 中英双语 + 自动检测 |
3.3.3 Agent Tool 框架
GoChat Agent Tool 设计超越 Chatwoot 的简单工具列表:
// AgentTool 接口
type AgentTool interface {
Name() string
Description() string
Parameters() ToolParameters // JSON Schema
Execute(ctx context.Context, args map[string]interface{}) (ToolResult, error)
}
// 内置工具
type FAQTool struct{} // FAQ 检索
type MemoryTool struct{} // 对话记忆
type ContactAttributesTool struct{} // 客户属性查询
type OrderStatusTool struct{} // 订单状态查询(需企业定制)
type KnowledgeBaseTool struct{} // 知识库检索
// 自定义工具注册表
type ToolRegistry struct {
builtin map[string]AgentTool
custom map[string]AgentTool // 用户通过 API 注册
}
// Agent Runner(v2 引擎)
type AgentRunnerService struct {
provider LLMProvider
registry *ToolRegistry
assistant *CaptainAssistant
documents []CaptainDocument
}
func (s *AgentRunnerService) Run(ctx context.Context, message string) (*AgentResponse, error) {
// 1. 构建系统 prompt(assistant config + response_guidelines + guardrails)
// 2. 检索相关文档(RAG)
// 3. 调用 LLM(带 tool_choice)
// 4. LLM 返回 tool_call → 执行工具 → 回注结果
// 5. 循环直到 LLM 返回最终回复
// 6. 返回回复 + 引用来源 + 工具调用日志
}
3.3.4 Copilot 增强功能
| 增强功能 | 描述 | 优先级 |
|---|---|---|
| 情绪分析 | 分析客户情绪(正面/负面/中性),帮助坐席判断应对策略 | P1 |
| 意图识别 | 自动识别客户意图(投诉/咨询/退换/续费等) | P1 |
| 智能摘要 | 不仅摘要对话,还提取关键决策点和承诺 | P0 |
| 知识推荐 | 根据对话上下文推荐相关知识库文档 | P1 |
| 多轮建议 | 不仅建议单条回复,还提供后续跟进建议 | P2 |
| 质检辅助 | 对话结束后自动标注质检项(合规/违规) | P2 |
3.4 CaptainAI API 设计
# Captain Assistant CRUD
GET /api/v1/accounts/{id}/captain/assistants # 列表
POST /api/v1/accounts/{id}/captain/assistants # 创建
GET /api/v1/accounts/{id}/captain/assistants/{aid} # 详情
PATCH /api/v1/accounts/{id}/captain/assistants/{aid} # 更新
DELETE /api/v1/accounts/{id}/captain/assistants/{aid} # 删除
# Playground
POST /api/v1/accounts/{id}/captain/assistants/{aid}/playground # 调试
# Tools
GET /api/v1/accounts/{id}/captain/assistants/tools # 可用工具列表
# Inbox Binding
POST /api/v1/accounts/{id}/captain/assistants/{aid}/inboxes # 绑定
DELETE /api/v1/accounts/{id}/captain/assistants/{aid}/inboxes/{inbox_id} # 解绑
# Captain Document CRUD
GET /api/v1/accounts/{id}/captain/assistants/{aid}/documents
POST /api/v1/accounts/{id}/captain/assistants/{aid}/documents
DELETE /api/v1/accounts/{id}/captain/assistants/{aid}/documents/{did}
# Captain Scenario CRUD
GET /api/v1/accounts/{id}/captain/assistants/{aid}/scenarios
POST /api/v1/accounts/{id}/captain/assistants/{aid}/scenarios
PATCH /api/v1/accounts/{id}/captain/assistants/{aid}/scenarios/{sid}
DELETE /api/v1/accounts/{id}/captain/assistants/{aid}/scenarios/{sid}
# Copilot
POST /api/v1/accounts/{id}/copilot/suggest_replies # 建议回复
POST /api/v1/accounts/{id}/copilot/summarize # 对话摘要
POST /api/v1/accounts/{id}/copilot/translate # 翻译
POST /api/v1/accounts/{id}/copilot/analyze_sentiment # 情绪分析(新增)
POST /api/v1/accounts/{id}/copilot/detect_intent # 意图识别(新增)
3.5 数据模型
// CaptainAssistant — AI 助手
type CaptainAssistant struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
Name string `gorm:"not null;type:varchar(255)"`
Description string `gorm:"type:text"`
Status AssistantStatus `gorm:"type:varchar(20);default:'draft'"` // active/draft/archived
Config json.RawMessage `gorm:"type:jsonb"` // {temperature, feature_faq, feature_memory, ...}
Guardrails json.RawMessage `gorm:"type:jsonb"` // 限制性规则
ResponseGuidelines json.RawMessage `gorm:"type:jsonb"` // 回复指导方针
LLMProvider string `gorm:"type:varchar(50);default:'openai'"` // 新增:LLM Provider
LLMModel string `gorm:"type:varchar(100);default:'gpt-4'"` // 新增:具体模型
MaxTokens int `gorm:"default:2048"` // 新增:最大 token
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// CaptainDocument — 知识库文档
type CaptainDocument struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
AssistantID uint `gorm:"not null;index"`
ExternalURL string `gorm:"type:varchar(500)"` // 外部链接
Content string `gorm:"type:text"` // 文档内容
Embedding []float32 `gorm:"type:vector(1536)"` // pgvector
SourceType string `gorm:"type:varchar(20)"` // url/file/faq/api
Status string `gorm:"type:varchar(20);default:'active'"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// CaptainScenario — 对话场景
type CaptainScenario struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
AssistantID uint `gorm:"not null;index"`
Name string `gorm:"not null;type:varchar(255)"`
Description string `gorm:"type:text"`
TriggerRules json.RawMessage `gorm:"type:jsonb"` // 触发条件
FlowConfig json.RawMessage `gorm:"type:jsonb"` // 场景流程配置
Priority int `gorm:"default:0"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// CaptainCustomTool — 自定义工具
type CaptainCustomTool struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
AssistantID uint `gorm:"not null;index"`
Name string `gorm:"not null;type:varchar(100)"`
Description string `gorm:"type:text"`
Parameters json.RawMessage `gorm:"type:jsonb"` // JSON Schema
Endpoint string `gorm:"type:varchar(500)"` // API endpoint
Method string `gorm:"type:varchar(10);default:'POST'"`
Headers json.RawMessage `gorm:"type:jsonb"`
AuthType string `gorm:"type:varchar(20)"` // none/bearer/basic/oauth2
AuthConfig json.RawMessage `gorm:"type:jsonb"`
Status string `gorm:"type:varchar(20);default:'active'"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// CaptainInbox — 助手-Inbox 绑定
type CaptainInbox struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
AssistantID uint `gorm:"not null;index"`
InboxID uint `gorm:"not null;index"`
CreatedAt time.Time
}
四、SSO 单点登录设计
4.1 SSO 架构概览
GoChat 企业版 SSO 支持 三种协议,超越 Chatwoot 仅支持 SAML:
| 协议 | Chatwoot | GoChat | 适用场景 |
|---|---|---|---|
| SAML 2.0 | ✅ 仅此一种 | ✅ | Okta、Azure AD、OneLogin |
| OIDC (OAuth 2.0) | ❌ | ✅ 新增 | Google Workspace、Auth0、Keycloak |
| LDAP | ❌ | ✅ 新增 | 传统企业 AD/LDAP |
4.2 SAML 2.0 设计
数据模型
// AccountSamlSettings — SAML 配置
type AccountSamlSettings struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;uniqueIndex"`
SsoURL string `gorm:"not null;type:varchar(500)"` // IdP SSO URL
Certificate string `gorm:"not null;type:text"` // X509 证书
IdpEntityID string `gorm:"not null;type:varchar(500)"` // IdP Entity ID
SpEntityID string `gorm:"type:varchar(500)"` // 自动生成 SP Entity ID
RoleMappings json.RawMessage `gorm:"type:jsonb"` // SAML 属性 → GoChat 角色
SamlVersion string `gorm:"type:varchar(10);default:'2.0'"`
NameIDFormat string `gorm:"type:varchar(50);default:'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'"`
SignAssertions bool `gorm:"default:true"`
SignRequests bool `gorm:"default:false"`
EncryptAssertions bool `gorm:"default:false"`
ForceAuthn bool `gorm:"default:false"` // 强制重新认证
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
SAML 认证流程
1. 用户点击 "SSO Login" → GoChat 生成 SAML AuthnRequest
2. 重定向到 IdP SsoURL(Okta/Azure AD 等)
3. 用户在 IdP 完成认证
4. IdP 返回 SAML Response → GoChat ACS URL (/api/v1/saml/callback)
5. GoChat 验证 SAML Response:
a. 验证签名(使用 Certificate)
b. 验证时间戳(NotOnOrAfter)
c. 验证 Audience(SpEntityID)
d. 提取 NameID(email)
6. SamlUserBuilder 处理:
a. 按 email 查找已有用户 → 如属于账户直接登录
b. 新用户 → 创建 + 设置 provider='saml' + 自动确认邮箱
c. 角色映射 → 根据 RoleMappings 配置分配 AccountUser 角色
7. 返回 JWT token → 完成登录
API 端点
# SAML 配置管理
GET /api/v1/accounts/{id}/saml_settings # 获取配置
POST /api/v1/accounts/{id}/saml_settings # 创建配置
PUT /api/v1/accounts/{id}/saml_settings # 更新配置
DELETE /api/v1/accounts/{id}/saml_settings # 删除配置
# SAML 认证流程
GET /api/v1/accounts/{id}/saml/authn_request # 生成 AuthnRequest + 重定向
POST /api/v1/saml/callback # ACS 回调处理
GET /api/v1/accounts/{id}/saml/metadata # SP Metadata(供 IdP 配置)
GET /api/v1/accounts/{id}/saml/certificate_fingerprint # 证书指纹
4.3 OIDC (OpenID Connect) 设计
// AccountOIDCSettings — OIDC 配置(新增)
type AccountOIDCSettings struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;uniqueIndex"`
IssuerURL string `gorm:"not null;type:varchar(500)"` // OIDC Issuer URL
ClientID string `gorm:"not null;type:varchar(200)"`
ClientSecret string `gorm:"not null;type:varchar(200)"`
Scopes string `gorm:"type:varchar(200);default:'openid,email,profile'"`
AuthorizationURL string `gorm:"type:varchar(500)"` // 自动从 Issuer 发现
TokenURL string `gorm:"type:varchar(500)"` // 自动从 Issuer 发现
JWKSURL string `gorm:"type:varchar(500)"` // 自动从 Issuer 发现
UserInfoURL string `gorm:"type:varchar(500)"`
RoleClaim string `gorm:"type:varchar(100);default:'roles'"` // 角色声明字段
GroupClaim string `gorm:"type:varchar(100);default:'groups'"` // 组声明字段
AutoProvision bool `gorm:"default:true"` // 自动创建新用户
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
OIDC 认证流程
1. 用户点击 "OIDC Login" → 重定向到 AuthorizationURL
2. IdP 认证 → 返回 authorization_code
3. GoChat 交换 code → TokenURL 获取 access_token + id_token
4. 验证 id_token(JWKS) → 提取 claims(email, name, roles)
5. OIDCUserBuilder 处理(类似 SamlUserBuilder)
6. 返回 JWT token → 完成登录
API 端点
GET /api/v1/accounts/{id}/oidc_settings # 获取配置
POST /api/v1/accounts/{id}/oidc_settings # 创建配置
PUT /api/v1/accounts/{id}/oidc_settings # 更新配置
DELETE /api/v1/accounts/{id}/oidc_settings # 删除配置
GET /api/v1/accounts/{id}/oidc/authorize # 发起 OIDC 认证
POST /api/v1/oidc/callback # OIDC 回调
4.4 LDAP 设计
// AccountLDAPSettings — LDAP 配置(新增)
type AccountLDAPSettings struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;uniqueIndex"`
Host string `gorm:"not null;type:varchar(200)"` // LDAP 服务器
Port int `gorm:"not null;default:389"`
UseTLS bool `gorm:"default:false"`
BaseDN string `gorm:"not null;type:varchar(200)"` // 搜索基准 DN
BindDN string `gorm:"type:varchar(200)"` // 绑定 DN
BindPassword string `gorm:"type:varchar(200)"` // 绑定密码
UserFilter string `gorm:"type:varchar(200);default:'(objectClass=person)'"`
EmailAttribute string `gorm:"type:varchar(50);default:'mail'"`
NameAttribute string `gorm:"type:varchar(50);default:'cn'"`
GroupAttribute string `gorm:"type:varchar(50);default:'memberOf'"`
RoleMappings json.RawMessage `gorm:"type:jsonb"` // LDAP group → GoChat 角色
AutoProvision bool `gorm:"default:true"`
SyncInterval int `gorm:"default:3600"` // 同步间隔(秒)
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
LDAP 认证流程
1. 用户输入企业账号密码 → GoChat 发起 LDAP Bind
2. BindDN + BindPassword 连接 LDAP 服务器
3. 搜索 BaseDN + UserFilter → 获取用户 DN
4. 用户 DN + 密码验证(Bind 验证)
5. 提取 email/name/groups 属性
6. LDAPUserBuilder 处理(类似 SamlUserBuilder)
7. 返回 JWT token → 完成登录
8. 后台定时同步 LDAP 组 → GoChat 角色
4.5 SSO 中间件设计
// SSOMiddleware — SSO 通用中间件
func SSOMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
accountID := getAccountID(c)
// 检查账户是否配置了 SSO
samlSettings := getSamlSettings(accountID)
oidcSettings := getOIDCSettings(accountID)
ldapSettings := getLDAPSettings(accountID)
if samlSettings != nil || oidcSettings != nil || ldapSettings != nil {
// 强制 SSO 登录(禁用普通邮箱登录)
// 仅管理员可绕过 SSO(super_admin bypass)
if !isSuperAdmin(c) {
enforceSSO(c)
}
}
c.Next()
}
}
// SSOProviderRouter — 根据配置路由到不同 SSO Provider
func SSOProviderRouter(accountID uint) string {
if getSamlSettings(accountID) != nil { return "saml" }
if getOIDCSettings(accountID) != nil { return "oidc" }
if getLDAPSettings(accountID) != nil { return "ldap" }
return "email" // 默认邮箱登录
}
五、语音通话功能设计
5.1 语音通话架构概览
GoChat 语音通话采用 Conference 模式(坐席 + 客户通过会议桥连接),与 Chatwoot 保持一致,但增加更多 Provider 支持:
| Provider | Chatwoot | GoChat | 说明 |
|---|---|---|---|
| Twilio | ✅ | ✅ | 主要语音 Provider |
| WhatsApp 通话 | ✅ | ✅ | WhatsApp Voice Call |
| Agora(声网) | ❌ | ✅ 新增 | 国内音视频首选 |
| Tencent RTC | ❌ | ✅ 新增 | 腾讯实时音视频 |
5.2 数据模型
// Call — 通话记录
type Call struct {
ID uint `gorm:"primaryKey"`
AccountID uint `gorm:"not null;index"`
InboxID uint `gorm:"not null;index"`
ConversationID uint `gorm:"not null;index"`
ContactID uint `gorm:"not null"`
AgentID uint `gorm:"index"` // 接听坐席
CallSource string `gorm:"not null;type:varchar(20)"` // inbox/initiated
CallDirection string `gorm:"not null;type:varchar(20)"` // inbound/outbound
Status string `gorm:"not null;type:varchar(20)"` // ringing/in_progress/completed/no_answer/failed/busy
Provider string `gorm:"type:varchar(20);default:'twilio'"` // twilio/agora/tencent/whatsapp
CallSID string `gorm:"type:varchar(100)"` // Provider 侧通话 ID
ConferenceSID string `gorm:"type:varchar(100)"` // Conference SID(Twilio)
DurationSeconds int `gorm:"default:0"` // 通话时长
RecordingURL string `gorm:"type:varchar(500)"` // 录音 URL
RecordingSID string `gorm:"type:varchar(100)"` // 录音 SID
Transcript string `gorm:"type:text"` // 通话转录
VoipToken string `gorm:"type:varchar(500)"` // Twilio Access Token
ClientIdentity string `gorm:"type:varchar(100)"` // Client 标识
AdditionalAttrs json.RawMessage `gorm:"type:jsonb"` // 附加属性
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// CallStatus 状态机
// ringing → in_progress → completed
// ringing → no_answer
// ringing → failed
// ringing → busy
// in_progress → completed(正常结束)
5.3 通话流程设计
5.3.1 呼出通话(Outbound)
1. 坐席在对话页面点击 "Call" 按钮
2. GoChat 创建 Call 记录(status=ringing, direction=outbound)
3. 生成 VoipToken(Twilio Access Token + VoiceGrant)
4. 前端使用 Twilio Client SDK 发起通话
5. 同时通过 Twilio API 呼叫客户号码
6. Twilio Conference 模式:坐席 + 客户加入会议桥
7. 客户接听 → status=in_progress + 自动分配坐席到对话
8. 通话结束 → status=completed + 更新 duration_seconds
9. 对话中插入 voice_call 消息气泡(含通话详情)
5.3.2 呼入通话(Inbound)
1. 客户拨打企业号码 → Twilio 转发到 GoChat Webhook
2. GoChat Voice::IncomingCallService 处理:
a. 查找关联 Inbox + Contact
b. 创建/查找 Conversation
c. 创建 Call(status=ringing, direction=inbound)
d. 通知坐席(WebSocket 推送 + 呼叫响铃)
3. 坐席接听 → claim_call + auto_assign
4. 通话进行 → status=in_progress
5. 通话结束 → status=completed + 录音处理
5.3.3 WhatsApp 通话
1. WhatsApp 客户发起通话请求 → GoChat Webhook 接收 SDP offer
2. CallPermissionReplyService 处理权限判断
3. 呼入通话创建 → 通知坐席
4. 坐席 accept/reject → WhatsApp SDP answer/reject
5. 通话进行 → 状态更新
5.4 通话 Provider 抽象层
// VoiceProvider 接口
type VoiceProvider interface {
// 基础通话
MakeCall(ctx context.Context, params MakeCallParams) (*CallResult, error)
HangupCall(ctx context.Context, callSID string) error
// Conference
CreateConference(ctx context.Context, params ConferenceParams) (*ConferenceResult, error)
EndConference(ctx context.Context, conferenceSID string) error
// Token
GenerateToken(ctx context.Context, identity string) (string, error)
// 录音
StartRecording(ctx context.Context, callSID string) error
StopRecording(ctx context.Context, callSID string) error
GetRecordingURL(ctx context.Context, recordingSID string) (string, error)
// Webhook 处理
HandleIncomingCall(ctx context.Context, payload map[string]interface{}) (*IncomingCallResult, error)
HandleConferenceEvent(ctx context.Context, event ConferenceEvent) error
HandleRecordingStatus(ctx context.Context, payload map[string]interface{}) error
}
// Twilio Provider 实现
type TwilioProvider struct {
AccountSID string
AuthToken string
AppSID string
PhoneNumber string
APIBase string // https://api.twilio.com
}
// Agora Provider 实现(新增)
type AgoraProvider struct {
AppID string
AppCertificate string
APIBase string
}
// TencentRTC Provider 实现(新增)
type TencentRTCProvider struct {
SDKAppID int
SecretKey string
APIBase string
}
5.5 通话 API 设计
# 通话管理
POST /api/v1/accounts/{id}/calls # 创建通话(呼出)
GET /api/v1/accounts/{id}/calls/{call_id} # 通话详情
PUT /api/v1/accounts/{id}/calls/{call_id} # 更新通话状态
DELETE /api/v1/accounts/{id}/calls/{call_id} # 结束通话
# 通话动作
POST /api/v1/accounts/{id}/calls/{call_id}/answer # 接听
POST /api/v1/accounts/{id}/calls/{call_id}/hangup # 挂断
POST /api/v1/accounts/{id}/calls/{call_id}/reject # 拒接
POST /api/v1/accounts/{id}/calls/{call_id}/mute # 静音
POST /api/v1/accounts/{id}/calls/{call_id}/unmute # 取消静音
# Twilio Token
GET /api/v1/accounts/{id}/voice/token # 获取 VoIP Token
# 录音
POST /api/v1/accounts/{id}/calls/{call_id}/record # 开始录音
GET /api/v1/accounts/{id}/calls/{call_id}/recording # 获取录音
# Webhook(Twilio 回调)
POST /voice/twilio/incoming # Twilio 呼入回调
POST /voice/twilio/conference # Twilio 会议事件
POST /voice/twilio/recording_status # Twilio 录音状态
# WhatsApp 通话
POST /api/v1/accounts/{id}/whatsapp/call/accept # 接听 WhatsApp 通话
POST /api/v1/accounts/{id}/whatsapp/call/reject # 拒绝 WhatsApp 通话
5.6 录音与转录设计
// VoiceRecordingService — 录音处理
type VoiceRecordingService struct {
provider VoiceProvider
storage StorageProvider // 本地/S3/OSS
}
func (s *VoiceRecordingService) ProcessRecording(ctx context.Context, callID uint) error {
// 1. 从 Provider 获取录音文件 URL
// 2. 下载录音文件
// 3. 存储到对象存储(S3/OSS)
// 4. 创建 Attachment 关联到对话消息
// 5. 可选:调用转录服务(Whisper/阿里语音识别)
// 6. 更新 Call.RecordingURL + Call.Transcript
}
// VoiceTranscriptionService — 通话转录
type VoiceTranscriptionService interface {
Transcribe(ctx context.Context, audioURL string) (TranscriptionResult, error)
}
// 支持的转录 Provider
var TranscriptionProviders = map[string]VoiceTranscriptionService{
"whisper": &WhisperProvider{}, // OpenAI Whisper
"aliyun": &AliyunASRProvider{}, // 阿里云语音识别
"tencent": &TencentASRProvider{}, // 腾讯云语音识别
"azure": &AzureSpeechProvider{}, // Azure Speech
}
六、企业版功能实施路线图
6.1 Phase 分期
| Phase | 功能 | 优先级 | 预估工时 | 前置条件 |
|---|---|---|---|---|
| E1 | Feature Gate + Subscription 模型 | P0 | 3天 | 无 |
| E2 | SAML SSO 完整实现 | P0 | 5天 | E1 |
| E3 | OIDC SSO 实现 | P1 | 4天 | E2 |
| E4 | LDAP SSO 实现 | P2 | 4天 | E2 |
| E5 | SLA 策略完整实现 | P0 | 4天 | E1 |
| E6 | 审计日志实现 | P0 | 3天 | E1 |
| E7 | 自定义角色权限 | P0 | 5天 | E1 |
| E8 | 语音通话(Twilio) | P1 | 7天 | E1 |
| E9 | 语音通话(Agora/Tencent) | P2 | 4天 | E8 |
| E10 | CaptainAI 增强(多 LLM) | P1 | 5天 | E1 |
| E11 | Copilot 增强 | P2 | 3天 | E10 |
| E12 | 坐席容量策略 | P1 | 3天 | E7 |
| E13 | 公司/组织管理完善 | P1 | 3天 | E7 |
| E14 | 定时任务调度 | P2 | 2天 | Worker Pool 可用 |
| E15 | AgentBot 完善 | P1 | 4天 | E1 |
6.2 E1 Feature Gate 实现细节
E1 是所有企业功能的基石,需要优先实现:
1. 数据模型:Subscription + BillingUsage + FeatureEntitlement
2. 中间件:FeatureGate(requiredFeature) → 403 if not entitled
3. 路由注册:所有企业版路由加 FeatureGate 中间件
4. 配置管理:config.yaml 增加 billing section
5. License 密钥验证(自部署场景)
6. API:
- GET /api/v1/accounts/{id}/subscription # 查看订阅
- POST /api/v1/accounts/{id}/subscription # 创建/更新订阅
- GET /api/v1/accounts/{id}/entitlement # 查看功能授权
- GET /api/v1/accounts/{id}/billing_usage # 查看用量
6.3 关键技术决策
| 决策点 | 选项 | 推荐 | 原因 |
|---|---|---|---|
| 向量存储 | pgvector vs Milvus vs ES | pgvector(默认) + Milvus(可选) | pgvector 与 PG 一体化,运维简单 |
| LLM 调用 | 直接 HTTP vs SDK | 直接 HTTP(resty/v2) | 减少依赖,多 Provider 更灵活 |
| SSO 协议 | 仅 SAML vs 三协议 | 三协议(SAML+OIDC+LDAP) | 国内企业 OIDC/LDAP 更常见 |
| 语音 Provider | 仅 Twilio vs 多 Provider | Twilio(海外) + Agora(国内) | 国内 Agaora 生态更成熟 |
| 计费存储 | Stripe vs 本地 | Stripe(海外) + 支付宝/微信(国内) | 双币种双渠道 |
| 功能授权 | config.yaml vs DB | DB(FeatureEntitlement) | 云版动态调整,自部署用 config.yaml + license |
| 录音转录 | Whisper vs 云 ASR | Whisper(本地) + 阿里 ASR(云) | 灵活选择 |
| Conference 模式 | 保留 vs 简化 | 保留 Conference 模式 | 与 Chatwoot 一致,坐席可转接 |
附录A:Chatwoot 企业版 Feature Flag 对照表
| Flag | 功能 | GoChat 对应开关 |
|---|---|---|
enterprise |
企业版总开关 | FeatureEntitlement.plan >= enterprise |
saml |
SAML SSO | FeatureEntitlement.features.sso_saml |
voice |
语音通话 | FeatureEntitlement.features.voice |
captain_ai |
Captain AI | FeatureEntitlement.features.captain_ai |
audit_log |
审计日志 | FeatureEntitlement.features.audit_log |
custom_roles |
自定义角色 | FeatureEntitlement.features.custom_roles |
sla |
SLA 策略 | FeatureEntitlement.features.sla |
agent_capacity |
坐席容量 | FeatureEntitlement.features.agent_capacity |
附录B:GoChat 新增企业版功能 Flag(超越 Chatwoot)
| Flag | 功能 | 描述 |
|---|---|---|
oidc_sso |
OIDC SSO | OpenID Connect 单点登录(新增) |
ldap_sso |
LDAP SSO | LDAP 认证(新增) |
multi_llm |
多 LLM Provider | 支持 Claude/DeepSeek/Qwen/GLM 等(新增) |
voice_agora |
Agora 语音 | 声网语音通话(新增) |
voice_tencent |
Tencent RTC | 腾讯实时音视频(新增) |
sentiment_analysis |
情绪分析 | Copilot 情绪分析(新增) |
intent_detection |
意图识别 | Copilot 意图识别(新增) |
voice_transcription |
通话转录 | 通话自动转录(新增) |
hybrid_rag |
混合 RAG | 向量+关键词混合检索(新增) |
文档维护说明:本文档随 GoChat 企业版功能迭代持续更新。每次 Phase 完成后更新实施状态和差距分析。