- DatabaseConfig: Host/Port/User/Password/Name/DBName/SSLMode → 单个 DSN 字段 - RedisConfig: Host/Port/Password/DB/URL → 单个 DSN 字段 - 环境变量: GOCHAT_DATABASE_* (7个) → GOCHAT_DATABASE_DSN, GOCHAT_REDIS_* (5个) → GOCHAT_REDIS_DSN - validator.go: DSN URL 解析校验 (scheme + host) - redis.go: redis.ParseURL(cfg.DSN) 直连 - 所有 docker-compose / CI / shell 脚本 / .env 同步更新 - 删除 deploy/helm/ 整个目录 (20个文件) - CI 删除 helm-validate / deploy-staging / deploy-production 三个 job - 文档同步更新 (README, 架构设计, PRD, 滚动升级)
934 lines
43 KiB
Markdown
934 lines
43 KiB
Markdown
# P2A GoChat 项目结构与模块划分
|
||
|
||
> 版本:v1.1
|
||
> 产出日期:2026-05-22(设计阶段)/ 2026-07-09 更新
|
||
> 项目定位:Go语言 1:1 重写 Chatwoot(开源多渠道客服平台)
|
||
> 状态:设计文档,项目结构已实际落地。当前实际结构参见 02-architecture.md 或 AGENTS.md。
|
||
> 架构模式:单体架构(保证渠道扩展方便性)
|
||
> 第一阶段优先渠道:Web Widget + Telegram
|
||
> 第一阶段企业功能:Captain AI助手 + Copilot
|
||
|
||
---
|
||
|
||
## 1. 设计原则
|
||
|
||
### 1.1 Go语言特有的架构决策
|
||
|
||
| 决策维度 | Chatwoot Rails 实现 | GoChat 实现 | 原因 |
|
||
|---------|--------------------|-----------|------|
|
||
| 代码组织 | Rails MVC(按技术层分层) | 按业务域分包(domain-driven) | Go惯例是按业务功能组织包,而非按MVC角色 |
|
||
| 依赖注入 | 无(Rails自动加载) | 手动DI + 构造函数注入 | Go无自动DI容器,显式依赖更清晰 |
|
||
| 实时推送 | ActionCable(WebSocket) | Redis Pub/Sub + WebSocket handler | Go更适合用Redis Pub/Sub做跨进程事件分发 |
|
||
| 异步任务 | Sidekiq(Ruby进程) | Goroutine + Worker池 | Go原生并发,无需外部Job队列 |
|
||
| 数据库迁移 | ActiveRecord Migration | GORM AutoMigrate + 手动Migration | 首版用AutoMigrate快速迭代,后续迁移用golang-migrate |
|
||
| 配置管理 | InstallationConfig表 + ENV | Viper配置层 + DB配置表 | Go项目用Viper统一管理env/file/DB配置 |
|
||
| 中间件 | Rails before_action | Gin/Chi中间件链 | Go HTTP中间件是显式链式调用 |
|
||
| 权限校验 | Pundit Policy类 | 中间件 + 内联权限函数 | Go没有class继承,用组合模式实现权限检查 |
|
||
| 多态关联 | polymorphic(owner_type+owner_id) | 独立关联表 + JSON字段 | Go ORM对多态支持弱,用独立表更清晰 |
|
||
| 文件存储 | ActiveStorage | 本地存储抽象 + S3可选 | Go无ActiveStorage,自建存储抽象层 |
|
||
| 事件分发 | Dispatcher + Listener | EventBus接口 + Redis Pub/Sub | Go用channel/Redis实现事件分发,更高效 |
|
||
|
||
### 1.2 单体架构下的模块化策略
|
||
|
||
GoChat采用**单仓库、多模块**策略:
|
||
- 所有代码在一个Git仓库中
|
||
- 每个业务域是独立的Go包(package)
|
||
- 包之间通过接口(interface)解耦,不直接引用内部实现
|
||
- 渠道(Channel)通过插件接口注册,保证扩展方便性
|
||
- 企业版功能通过`enterprise`子包提供,社区版编译时可选排除
|
||
|
||
---
|
||
|
||
## 2. 顶层目录结构
|
||
|
||
```
|
||
gochat/
|
||
├── cmd/ # 应用入口
|
||
│ ├── server/ # 主HTTP服务器
|
||
│ │ └── main.go # 启动入口
|
||
│ ├── worker/ # 后台Worker进程(可选独立部署)
|
||
│ │ └── main.go
|
||
│ ├── migrate/ # 数据库迁移工具
|
||
│ │ └── main.go
|
||
│ └── seed/ # 数据填充工具
|
||
│ │ └── main.go
|
||
│
|
||
├── internal/ # 核心业务代码(不可外部引用)
|
||
│ ├── domain/ # 业务域定义
|
||
│ │ ├── account/ # 账户管理(M1)
|
||
│ │ ├── user/ # 用户管理(M1)
|
||
│ │ ├── inbox/ # 收件箱管理(M2)
|
||
│ │ ├── channel/ # 渠道抽象层(M2)
|
||
│ │ │ ├── webwidget/ # Web Widget渠道
|
||
│ │ │ ├── telegram/ # Telegram渠道
|
||
│ │ │ ├── facebook/ # Facebook渠道(第二阶段)
|
||
│ │ │ ├── whatsapp/ # WhatsApp渠道(第二阶段)
|
||
│ │ │ ├── email/ # Email渠道(第二阶段)
|
||
│ │ │ ├── twilio/ # Twilio SMS渠道(第二阶段)
|
||
│ │ │ ├── api/ # API渠道(第二阶段)
|
||
│ │ │ └── registry.go # 渠道注册器
|
||
│ │ ├── conversation/ # 对话管理(M3)
|
||
│ │ ├── message/ # 消息管理(M3)
|
||
│ │ ├── contact/ # 联系人管理(M4)
|
||
│ │ ├── team/ # 团队管理(M5)
|
||
│ │ ├── assignment/ # 分配策略(M5)
|
||
│ │ ├── automation/ # 自动化规则(M6)
|
||
│ │ ├── macro/ # 宏操作(M6)
|
||
│ │ ├── canned/ # 模板消息(M6)
|
||
│ │ ├── reporting/ # 报告与CSAT(M7)
|
||
│ │ ├── notification/ # 通知系统(M8)
|
||
│ │ ├── webhook/ # Webhook系统(M8)
|
||
│ │ ├── knowledgebase/ # 知识库(M9)
|
||
│ │ ├── captain/ # Captain AI助手(M10企业版)
|
||
│ │ ├── copilot/ # Copilot副驾驶(M10企业版)
|
||
│ │ ├── sla/ # SLA策略(M11企业版)
|
||
│ │ ├── auditlog/ # 审计日志(M11企业版)
|
||
│ │ ├── customrole/ # 自定义角色(M11企业版)
|
||
│ │ ├── company/ # 公司管理(M11企业版)
|
||
│ │ ├── agentcapacity/ # 坐席容量(M11企业版)
|
||
│ │ ├── call/ # 语音通话(M11企业版)
|
||
│ │ ├── saml/ # SAML SSO(M11企业版)
|
||
│ │ ├── platform/ # 平台API(M12)
|
||
│ │ ├── agentbot/ # AgentBot(M12)
|
||
│ │ ├── dashboardapp/ # Dashboard App(M12)
|
||
│ │ ├── dataimport/ # 数据导入(M12)
|
||
│ │ ├── label/ # 标签系统
|
||
│ │ ├── note/ # 笔记
|
||
│ │ └── customattr/ # 自定义属性
|
||
│ │
|
||
│ ├── model/ # GORM数据模型定义(所有表)
|
||
│ │ ├── account.go
|
||
│ │ ├── user.go
|
||
│ │ ├── account_user.go
|
||
│ │ ├── inbox.go
|
||
│ │ ├── channel_web_widget.go
|
||
│ │ ├── channel_telegram.go
|
||
│ │ ├── conversation.go
|
||
│ │ ├── message.go
|
||
│ │ ├── contact.go
|
||
│ │ ├── contact_inbox.go
|
||
│ │ ├── team.go
|
||
│ │ ├── team_member.go
|
||
│ │ ├── assignment_policy.go
|
||
│ │ ├── automation_rule.go
|
||
│ │ ├── macro.go
|
||
│ │ ├── canned_response.go
|
||
│ │ ├── csat_survey_response.go
|
||
│ │ ├── reporting_event.go
|
||
│ │ ├── notification.go
|
||
│ │ ├── notification_setting.go
|
||
│ │ ├── notification_subscription.go
|
||
│ │ ├── webhook.go
|
||
│ │ ├── integrations_hook.go
|
||
│ │ ├── portal.go
|
||
│ │ ├── category.go
|
||
│ │ ├── folder.go
|
||
│ │ ├── article.go
|
||
│ │ ├── captain_assistant.go
|
||
│ │ ├── captain_assistant_response.go
|
||
│ │ ├── captain_custom_tool.go
|
||
│ │ ├── captain_document.go
|
||
│ │ ├── captain_inbox.go
|
||
│ │ ├── captain_scenario.go
|
||
│ │ ├── copilot_thread.go
|
||
│ │ ├── copilot_message.go
|
||
│ │ ├── sla_policy.go
|
||
│ │ ├── applied_sla.go
|
||
│ │ ├── sla_event.go
|
||
│ │ ├── audit.go
|
||
│ │ ├── custom_role.go
|
||
│ │ ├── company.go
|
||
│ │ ├── agent_capacity_policy.go
|
||
│ │ ├── inbox_capacity_limit.go
|
||
│ │ ├── call.go
|
||
│ │ ├── account_saml_settings.go
|
||
│ │ ├── platform_app.go
|
||
│ │ ├── platform_app_permissible.go
|
||
│ │ ├── agent_bot.go
|
||
│ │ ├── agent_bot_inbox.go
|
||
│ │ ├── dashboard_app.go
|
||
│ │ ├── data_import.go
|
||
│ │ ├── label.go
|
||
│ │ ├── tagging.go
|
||
│ │ ├── note.go
|
||
│ │ ├── custom_attribute_definition.go
|
||
│ │ ├── custom_filter.go
|
||
│ │ ├── campaign.go
|
||
│ │ ├── inbox_member.go
|
||
│ │ ├── conversation_participant.go
|
||
│ │ ├── mention.go
|
||
│ │ ├── attachment.go
|
||
│ │ ├── working_hour.go
|
||
│ │ ├── installation_config.go
|
||
│ │ ├── access_token.go
|
||
│ │ ├── email_template.go
|
||
│ │ ├── dashboard_app.go
|
||
│ │ ├── leave.go
|
||
│ │ ├── platform_banner.go
|
||
│ │ ├── article_embedding.go # 企业版
|
||
│ │ ├── related_category.go
|
||
│ │ ├── inbox_assignment_policy.go
|
||
│ │ └── user_serializer.go # JSON序列化辅助
|
||
│ │
|
||
│ ├── handler/ # HTTP请求处理器(相当于Controller)
|
||
│ │ ├── api/ # API v1 处理器
|
||
│ │ │ ├── v1/
|
||
│ │ │ │ ├── account_handler.go
|
||
│ │ │ │ ├── agent_handler.go
|
||
│ │ │ │ ├── inbox_handler.go
|
||
│ │ │ │ ├── conversation_handler.go
|
||
│ │ │ │ ├── message_handler.go
|
||
│ │ │ │ ├── contact_handler.go
|
||
│ │ │ │ ├── team_handler.go
|
||
│ │ │ │ ├── assignment_handler.go
|
||
│ │ │ │ ├── automation_handler.go
|
||
│ │ │ │ ├── macro_handler.go
|
||
│ │ │ │ ├── canned_handler.go
|
||
│ │ │ │ ├── csat_handler.go
|
||
│ │ │ │ ├── reporting_handler.go
|
||
│ │ │ │ ├── notification_handler.go
|
||
│ │ │ │ ├── webhook_handler.go
|
||
│ │ │ │ ├── integration_handler.go
|
||
│ │ │ │ ├── portal_handler.go
|
||
│ │ │ │ ├── category_handler.go
|
||
│ │ │ │ ├── article_handler.go
|
||
│ │ │ │ ├── captain_handler.go
|
||
│ │ │ │ ├── copilot_handler.go
|
||
│ │ │ │ ├── sla_handler.go
|
||
│ │ │ │ ├── audit_handler.go
|
||
│ │ │ │ ├── customrole_handler.go
|
||
│ │ │ │ ├── company_handler.go
|
||
│ │ │ │ ├── agentcapacity_handler.go
|
||
│ │ │ │ ├── call_handler.go
|
||
│ │ │ │ ├── saml_handler.go
|
||
│ │ │ │ ├── platform_handler.go
|
||
│ │ │ │ ├── agentbot_handler.go
|
||
│ │ │ │ ├── label_handler.go
|
||
│ │ │ │ ├── note_handler.go
|
||
│ │ │ │ ├── customattr_handler.go
|
||
│ │ │ │ ├── customfilter_handler.go
|
||
│ │ │ │ ├── campaign_handler.go
|
||
│ │ │ │ ├── dashboardapp_handler.go
|
||
│ │ │ │ ├── dataimport_handler.go
|
||
│ │ │ │ ├── search_handler.go
|
||
│ │ │ │ └── upload_handler.go
|
||
│ │ │ ├── v2/ # API v2 处理器(报告等)
|
||
│ │ │ │ ├── report_handler.go
|
||
│ │ │ │ ├── summary_report_handler.go
|
||
│ │ │ │ └── live_report_handler.go
|
||
│ │ │ └── platform/ # Platform API 处理器
|
||
│ │ │ ├── platform_handler.go
|
||
│ │ │ ├── user_handler.go
|
||
│ │ │ ├── agentbot_handler.go
|
||
│ │ │ └── account_handler.go
|
||
│ │ ├── auth/ # 认证处理器
|
||
│ │ │ ├── auth_handler.go
|
||
│ │ │ ├── oauth_handler.go
|
||
│ │ │ └── saml_handler.go
|
||
│ │ ├── public/ # 公开API(面向客户)
|
||
│ │ │ ├── inbox_handler.go
|
||
│ │ │ ├── contact_handler.go
|
||
│ │ │ ├── conversation_handler.go
|
||
│ │ │ ├── message_handler.go
|
||
│ │ │ ├── csat_handler.go
|
||
│ │ │ └── portal_handler.go
|
||
│ │ ├── widget/ # Widget API
|
||
│ │ │ ├── config_handler.go
|
||
│ │ │ ├── message_handler.go
|
||
│ │ │ ├── conversation_handler.go
|
||
│ │ │ ├── contact_handler.go
|
||
│ │ │ ├── event_handler.go
|
||
│ │ │ └── label_handler.go
|
||
│ │ ├── superadmin/ # 超级管理员
|
||
│ │ │ ├── dashboard_handler.go
|
||
│ │ │ ├── account_handler.go
|
||
│ │ │ ├── user_handler.go
|
||
│ │ │ ├── installation_handler.go
|
||
│ │ │ └── agentbot_handler.go
|
||
│ │ ├── webhook/ # 渠道Webhook处理器
|
||
│ │ │ ├── telegram_handler.go
|
||
│ │ │ ├── facebook_handler.go
|
||
│ │ │ ├── whatsapp_handler.go
|
||
│ │ │ ├── twilio_handler.go
|
||
│ │ │ ├── line_handler.go
|
||
│ │ │ └── instagram_handler.go
|
||
│ │ └── enterprise/ # 企业版Webhook
|
||
│ │ ├── stripe_handler.go
|
||
│ │ └── firecrawl_handler.go
|
||
│ │
|
||
│ ├── service/ # 业务逻辑层(相当于Rails的Service/Builder)
|
||
│ │ ├── account_service.go
|
||
│ │ ├── user_service.go
|
||
│ │ ├── inbox_service.go
|
||
│ │ ├── conversation_service.go
|
||
│ │ ├── message_service.go
|
||
│ │ ├── contact_service.go
|
||
│ │ ├── team_service.go
|
||
│ │ ├── assignment_service.go
|
||
│ │ ├── auto_assignment_service.go
|
||
│ │ ├── automation_service.go
|
||
│ │ ├── automation_executor.go
|
||
│ │ ├── macro_service.go
|
||
│ │ ├── canned_service.go
|
||
│ │ ├── csat_service.go
|
||
│ │ ├── reporting_service.go
|
||
│ │ ├── reporting_rollup_service.go
|
||
│ │ ├── notification_service.go
|
||
│ │ ├── webhook_service.go
|
||
│ │ ├── webhook_trigger_service.go
|
||
│ │ ├── integration_hook_service.go
|
||
│ │ ├── portal_service.go
|
||
│ │ ├── article_service.go
|
||
│ │ ├── captain_service.go
|
||
│ │ ├── captain_assistant_chat_service.go
|
||
│ │ ├── captain_agent_runner_service.go
|
||
│ │ ├── copilot_service.go
|
||
│ │ ├── sla_service.go
|
||
│ │ ├── sla_evaluator_service.go
|
||
│ │ ├── audit_service.go
|
||
│ │ ├── customrole_service.go
|
||
│ │ ├── company_service.go
|
||
│ │ ├── agentcapacity_service.go
|
||
│ │ ├── call_service.go
|
||
│ │ ├── saml_service.go
|
||
│ │ ├── platform_service.go
|
||
│ │ ├── agentbot_service.go
|
||
│ │ ├── dataimport_service.go
|
||
│ │ ├── contact_merge_service.go
|
||
│ │ ├── contact_import_service.go
|
||
│ │ ├── search_service.go
|
||
│ │ ├── campaign_service.go
|
||
│ │ ├── label_service.go
|
||
│ │ ├── note_service.go
|
||
│ │ ├── customattr_service.go
|
||
│ │ ├── upload_service.go
|
||
│ │ ├── branding_service.go
|
||
│ │ └── email_validation_service.go
|
||
│ │
|
||
│ ├── repository/ # 数据访问层(GORM查询封装)
|
||
│ │ ├── account_repo.go
|
||
│ │ ├── user_repo.go
|
||
│ │ ├── inbox_repo.go
|
||
│ │ ├── conversation_repo.go
|
||
│ │ ├── message_repo.go
|
||
│ │ ├── contact_repo.go
|
||
│ │ ├── team_repo.go
|
||
│ │ ├── assignment_policy_repo.go
|
||
│ │ ├── automation_rule_repo.go
|
||
│ │ ├── macro_repo.go
|
||
│ │ ├── canned_response_repo.go
|
||
│ │ ├── csat_repo.go
|
||
│ │ ├── reporting_repo.go
|
||
│ │ ├── notification_repo.go
|
||
│ │ ├── webhook_repo.go
|
||
│ │ ├── integration_hook_repo.go
|
||
│ │ ├── portal_repo.go
|
||
│ │ ├── article_repo.go
|
||
│ │ ├── captain_repo.go
|
||
│ │ ├── copilot_repo.go
|
||
│ │ ├── sla_repo.go
|
||
│ │ ├── audit_repo.go
|
||
│ │ ├── customrole_repo.go
|
||
│ │ ├── company_repo.go
|
||
│ │ ├── agentcapacity_repo.go
|
||
│ │ ├── call_repo.go
|
||
│ │ ├── platform_repo.go
|
||
│ │ ├── agentbot_repo.go
|
||
│ │ ├── label_repo.go
|
||
│ │ ├── note_repo.go
|
||
│ │ ├── customattr_repo.go
|
||
│ │ ├── customfilter_repo.go
|
||
│ │ ├── campaign_repo.go
|
||
│ │ ├── dashboardapp_repo.go
|
||
│ │ ├── dataimport_repo.go
|
||
│ │ ├── search_repo.go # 全文搜索(PostgreSQL pg_trgm)
|
||
│ │ └── base_repo.go # 基础CRUD泛型封装
|
||
│ │
|
||
│ ├── middleware/ # HTTP中间件
|
||
│ │ ├── auth.go # JWT/Token认证中间件
|
||
│ │ ├── account_scope.go # 账户范围中间件(注入account_id)
|
||
│ │ ├── permission.go # 权限校验中间件
|
||
│ │ ├── rate_limit.go # 速率限制
|
||
│ │ ├── cors.go # CORS
|
||
│ │ ├── logger.go # 请求日志
|
||
│ │ ├── recovery.go # 异常恢复
|
||
│ │ ├── platform_auth.go # Platform API认证
|
||
│ │ ├── super_admin_auth.go # 超级管理员认证
|
||
│ │ ├── public_auth.go # 公开API认证(contact token)
|
||
│ │ ├── widget_auth.go # Widget API认证(widget token)
|
||
│ │ └── enterprise_check.go # 企业版功能检查中间件
|
||
│ │
|
||
│ ├── eventbus/ # 事件分发系统
|
||
│ │ ├── bus.go # EventBus核心
|
||
│ │ ├── redis_pubsub.go # Redis Pub/Sub实现
|
||
│ │ ├── local.go # 本地事件分发(goroutine)
|
||
│ │ ├── events.go # 事件类型定义
|
||
│ │ └── listeners.go # Listener注册
|
||
│ │
|
||
│ ├── realtime/ # 实时通信层
|
||
│ │ ├── hub.go # WebSocket连接管理器
|
||
│ │ ├── client.go # WebSocket客户端
|
||
│ │ ├── handler.go # WebSocket处理器
|
||
│ │ ├── channel.go # 订阅频道
|
||
│ │ └── redis_subscriber.go # Redis消息订阅转发WebSocket
|
||
│ │
|
||
│ ├── worker/ # 后台异步任务
|
||
│ │ ├── pool.go # Worker池管理
|
||
│ │ ├── scheduler.go # 定时任务调度
|
||
│ │ ├── jobs.go # Job定义
|
||
│ │ ├── branding_job.go # 品牌信息异步获取
|
||
│ │ ├── notification_job.go # 通知投递Job
|
||
│ │ ├── webhook_job.go # Webhook投递Job
|
||
│ │ ├── csat_job.go # CSAT发送Job
|
||
│ │ ├── reporting_job.go # 报告聚合Job
|
||
│ │ ├── sla_job.go # SLA评估Job
|
||
│ │ ├── auto_resolve_job.go # 自动解决Job
|
||
│ │ ├── campaign_job.go # Campaign执行Job
|
||
│ │ ├── dataimport_job.go # 数据导入Job
|
||
│ │ └── contact_merge_job.go # 联系人合并Job
|
||
│ │
|
||
│ ├── mailer/ # 邮件发送
|
||
│ │ ├── mailer.go # 邮件发送器
|
||
│ │ ├── templates/ # 邮件模板
|
||
│ │ │ ├── confirmation.html
|
||
│ │ │ ├── reset_password.html
|
||
│ │ │ ├── invitation.html
|
||
│ │ │ ├── csat_survey.html
|
||
│ │ │ └── dns_instructions.html
|
||
│ │ └── smtp.go # SMTP配置
|
||
│ │
|
||
│ ├── push/ # Push通知
|
||
│ │ ├── fcm.go # Firebase Cloud Messaging
|
||
│ │ └ push_subscription.go # Push订阅管理
|
||
│ │
|
||
│ ├── validator/ # 数据校验
|
||
│ │ ├── email.go # 邮箱校验(disposable domain检测)
|
||
│ │ ├── json_schema.go # JSON Schema校验
|
||
│ │ ├── captcha.go # CAPTCHA校验
|
||
│ │ └── custom_attr.go # 自定义属性校验
|
||
│ │
|
||
│ ├── storage/ # 文件存储抽象
|
||
│ │ ├── storage.go # Storage接口定义
|
||
│ │ ├── local.go # 本地文件存储
|
||
│ │ ├── s3.go # S3存储
|
||
│ │ └── upload.go # 上传处理
|
||
│ │
|
||
│ ├── serializer/ # JSON序列化层
|
||
│ │ ├── account_serializer.go
|
||
│ │ ├── user_serializer.go
|
||
│ │ ├── inbox_serializer.go
|
||
│ │ ├── conversation_serializer.go
|
||
│ │ ├── message_serializer.go
|
||
│ │ ├── contact_serializer.go
|
||
│ │ ├── team_serializer.go
|
||
│ │ ├── notification_serializer.go
|
||
│ │ └── common.go # 通用序列化辅助
|
||
│ │
|
||
│ ├── featureflag/ # Feature Flag系统
|
||
│ │ ├── flags.go # Feature Flag定义
|
||
│ │ ├── manager.go # Flag管理器
|
||
│ │ └── checker.go # Flag检查器
|
||
│ │
|
||
│ └── config/ # 配置管理
|
||
│ ├── config.go # Viper配置加载
|
||
│ ├── database.go # 数据库配置
|
||
│ ├── redis.go # Redis配置
|
||
│ ├── smtp.go # SMTP配置
|
||
│ └── storage.go # 存储配置
|
||
│
|
||
├── pkg/ # 可外部引用的公共包
|
||
│ ├── errors/ # 错误定义
|
||
│ │ ├── errors.go
|
||
│ │ └── codes.go
|
||
│ ├── response/ # HTTP响应封装
|
||
│ │ ├── response.go
|
||
│ │ └── pagination.go
|
||
│ ├── crypto/ # 加密工具
|
||
│ │ ├── hash.go
|
||
│ │ ├── jwt.go
|
||
│ │ └ token.go
|
||
│ ├── utils/ # 通用工具
|
||
│ │ ├── time.go
|
||
│ │ ├── slug.go
|
||
│ │ ├── uuid.go
|
||
│ │ └── string.go
|
||
│ └── validator/ # 公共校验
|
||
│ └ validator.go
|
||
│
|
||
├── migrations/ # 数据库迁移文件
|
||
│ ├── 000001_init_schema.up.sql
|
||
│ ├── 000001_init_schema.down.sql
|
||
│ └── ...
|
||
│
|
||
├── docs/ # 文档
|
||
│ ├── requirements/ # 需求文档(M1-M12)
|
||
│ ├── architecture/ # 架构文档(本目录)
|
||
│ └── api/ # API文档(Swagger/OpenAPI)
|
||
│
|
||
├── scripts/ # 辅助脚本
|
||
│ ├── setup.sh # 开发环境设置
|
||
│ └── seed.sh # 数据填充
|
||
│
|
||
├── deploy/ # 部署配置
|
||
│ ├── docker/
|
||
│ │ ├── Dockerfile
|
||
│ │ └── docker-compose.yaml
|
||
│ └── quickstart/ # 一键启动 Compose 栈
|
||
│
|
||
├── go.mod # Go模块定义
|
||
├── go.sum # Go依赖锁定
|
||
├── Makefile # 构建脚本
|
||
├── .env.example # 环境变量示例
|
||
├── README.md # 项目说明
|
||
└── LICENSE # MIT许可证
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 包依赖关系图
|
||
|
||
### 3.1 核心分层架构
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────┐
|
||
│ cmd/ │ ← 应用入口
|
||
│ (server, worker, migrate, seed) │
|
||
└──────────────────────┬───────────────────────────┘
|
||
│
|
||
↓
|
||
┌──────────────────────────────────────────────────┐
|
||
│ handler/ │ ← HTTP处理层
|
||
│ (api/v1, api/v2, auth, widget, public, │
|
||
│ superadmin, webhook, platform, enterprise) │
|
||
└──────────────────────┬───────────────────────────┘
|
||
│
|
||
↓
|
||
┌──────────────────────────────────────────────────┐
|
||
│ middleware/ │ ← 中间件层
|
||
│ (auth, account_scope, permission, rate_limit, │
|
||
│ cors, logger, enterprise_check) │
|
||
└──────────────────────┬───────────────────────────┘
|
||
│
|
||
↓
|
||
┌──────────────────────────────────────────────────┐
|
||
│ service/ │ ← 业务逻辑层
|
||
│ (account_service, conversation_service, │
|
||
│ message_service, captain_service, ...) │
|
||
└──────────┬───────────┬──────────────────────────┘
|
||
│ │
|
||
↓ ↓
|
||
┌──────────────┐ ┌──────────────────────────────────┐
|
||
│ model/ │ │ repository/ │ ← 数据层
|
||
│ (GORM模型) │ │ (account_repo, conversation_repo │
|
||
│ │ │ message_repo, ...) │
|
||
└──────────────┘ └──────────────────────────────────┘
|
||
│
|
||
↓
|
||
┌──────────────────────────────────────────────────┐
|
||
│ 基础设施层 │
|
||
│ ┌────────────┐ ┌──────────┐ ┌────────────┐ │
|
||
│ │ eventbus/ │ │ realtime/│ │ worker/ │ │
|
||
│ │(Redis Pub/ │ │(WebSocket│ │ (goroutine │ │
|
||
│ │ Sub) │ │ hub) │ │ pool) │ │
|
||
│ └────────────┘ └──────────┘ └────────────┘ │
|
||
│ ┌────────────┐ ┌──────────┐ ┌────────────┐ │
|
||
│ │ mailer/ │ │ push/ │ │ storage/ │ │
|
||
│ │ (SMTP) │ │ (FCM) │ │ (Local/S3) │ │
|
||
│ └────────────┘ └──────────┘ └────────────┘ │
|
||
│ ┌────────────┐ ┌──────────┐ ┌────────────┐ │
|
||
│ │ config/ │ │validator/│ │featureflag/ │ │
|
||
│ │ (Viper) │ │(校验) │ │(FlagShihTzu)│ │
|
||
│ └────────────┘ └──────────┘ └────────────┘ │
|
||
└──────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3.2 模块间依赖规则
|
||
|
||
| 规则 | 说明 |
|
||
|------|------|
|
||
| handler → service | handler调用service,不直接访问repository |
|
||
| service → repository | service调用repository,不直接写GORM查询 |
|
||
| service → model | service引用model做类型转换,不直接做CRUD |
|
||
| service → eventbus | service发布事件,通过eventbus通知其他模块 |
|
||
| service → worker | service可触发异步Job |
|
||
| service → realtime | service通过realtime推送WebSocket消息 |
|
||
| repository → model | repository操作model,执行GORM查询 |
|
||
| domain包互不引用 | 各domain包通过eventbus解耦,不直接调用其他domain的service |
|
||
| handler互不引用 | 各handler独立,通过路由组织 |
|
||
|
||
### 3.3 渠道(Channel)扩展架构
|
||
|
||
```
|
||
┌─────────────────┐
|
||
│ ChannelRegistry │ ← 渠道注册器
|
||
│ (registry.go) │
|
||
└─────────┬────────┘
|
||
│
|
||
┌───────────────┼───────────────┐
|
||
│ │ │
|
||
↓ ↓ ↓
|
||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||
│ WebWidget │ │ Telegram │ │ (更多渠道) │
|
||
│ Channel │ │ Channel │ │ Facebook │
|
||
│ │ │ │ │ WhatsApp │
|
||
│ - HandleIn() │ │ - HandleIn() │ │ Email │
|
||
│ - HandleOut()│ │ - HandleOut()│ │ Twilio │
|
||
│ - Validate() │ │ - Validate() │ │ ... │
|
||
│ - Config() │ │ - Config() │ │ │
|
||
└──────────────┘ └──────────────┘ └──────────────┘
|
||
|
||
所有渠道实现 ChannelInterface:
|
||
HandleInbound(ctx, message) → 创建Contact/Conversation/Message
|
||
HandleOutbound(ctx, message) → 向渠道发送消息
|
||
ValidateConfig(config) → 校验渠道配置
|
||
GetConfig() → 返回渠道配置模板
|
||
RegisterWebhook(router) → 注册渠道Webhook路由
|
||
```
|
||
|
||
**关键设计决策**:
|
||
- Chatwoot用Rails的多态关联(channel_type + channel_id)实现渠道扩展
|
||
- GoChat改为**接口+注册器**模式,每个渠道是一个独立package实现ChannelInterface
|
||
- 新增渠道只需:①实现ChannelInterface ②在registry.go注册 ③在路由中添加Webhook端点
|
||
- 无需修改任何已有代码,完全符合开闭原则
|
||
|
||
---
|
||
|
||
## 4. 与Chatwoot原实现的对比说明
|
||
|
||
### 4.1 保留的设计
|
||
|
||
| 功能 | Chatwoot实现 | GoChat保留原因 |
|
||
|------|-------------|--------------|
|
||
| 多账户隔离 | Account + AccountUser 多租户 | 核心需求,多账户隔离是客服平台基础 |
|
||
| 多态渠道 | Channelable concern | 改为接口模式,但多渠道概念保留 |
|
||
| 对话生命周期 | open/resolved/pending/snoozed | 核心业务状态机,必须保留 |
|
||
| 自动分配 | RoundRobin + AssignmentPolicy | 保留算法逻辑,Go实现更高效 |
|
||
| Feature Flag | FlagShihTzu位运算 | 保留位运算方式,Go用int64位掩码 |
|
||
| 事件驱动 | Dispatcher + Listener | 保留事件驱动架构,改为Redis Pub/Sub |
|
||
| CSAT调查 | CsatSurveyService | 保留CSAT完整流程 |
|
||
| 知识库 | Portal + Category + Article | 保留知识库结构 |
|
||
| Webhook投递 | Webhooks::TriggerJob | 保留Webhook投递机制 |
|
||
|
||
### 4.2 简化的设计
|
||
|
||
| 功能 | Chatwoot实现 | GoChat简化 | 原因 |
|
||
|------|-------------|-----------|------|
|
||
| ActiveStorage | 3表(blobs+attachments+variants) | 1个Attachment模型+Storage接口 | Go无ActiveStorage,自建更简洁 |
|
||
| ActionMailbox | 独立表+IMAP处理 | 集成到email渠道内 | 第一阶段不优先,简化合并 |
|
||
| Pundit Policy | 独立Policy类 | middleware+内联权限函数 | Go无class继承,中间件更自然 |
|
||
| Devise认证 | 5个Controller+Omniauth | JWT Token+OAuth2中间件 | Go无Devise,JWT更主流 |
|
||
| Sidekiq Cron | 外部依赖 | 内置scheduler包 | Go原生并发,无需Sidekiq |
|
||
| Rails Concern | 25+个Concern模块 | 接口组合+embed struct | Go用struct embedding替代Concern |
|
||
| polymorphic关联 | owner_type+owner_id | 独立关联表或JSON字段 | GORM多态支持弱,独立表更清晰 |
|
||
| 93表全部实现 | 全部93表 | 分阶段实现,第一阶段约45表 | 渠道分阶段,不优先的渠道表延后 |
|
||
| 327路由全部实现 | 全部327路由 | 简化到约150路由 | 合理去重、合并RESTful风格 |
|
||
|
||
### 4.3 新增的设计
|
||
|
||
| 功能 | 说明 | 原因 |
|
||
|------|------|------|
|
||
| ChannelInterface接口 | 渠道统一接口定义 | Go接口比Rails多态更规范 |
|
||
| ChannelRegistry注册器 | 渠道动态注册 | 便于渠道扩展,开闭原则 |
|
||
| repository层 | 数据访问抽象 | Go惯例分层,隔离GORM细节 |
|
||
| serializer层 | JSON序列化独立 | Go JSON序列化与模型分离 |
|
||
| EventBus + Redis Pub/Sub | 跨进程事件分发 | Go单体多实例部署需要跨进程通信 |
|
||
| Worker池 + goroutine | Go原生并发替代Sidekiq | 更高效,无外部依赖 |
|
||
| Viper配置层 | 统一配置管理 | Go项目标准做法 |
|
||
| Storage接口 | 文件存储抽象 | 支持Local/S3切换 |
|
||
| enterprise_check中间件 | 企业版功能守卫 | 编译时/运行时企业版功能控制 |
|
||
|
||
---
|
||
|
||
## 5. 关键接口定义
|
||
|
||
### 5.1 ChannelInterface(渠道接口)
|
||
|
||
```go
|
||
// internal/domain/channel/registry.go
|
||
package channel
|
||
|
||
// ChannelType 渠道类型枚举
|
||
type ChannelType string
|
||
const (
|
||
ChannelWebWidget ChannelType = "web_widget"
|
||
ChannelTelegram ChannelType = "telegram"
|
||
ChannelFacebook ChannelType = "facebook"
|
||
ChannelWhatsApp ChannelType = "whatsapp"
|
||
ChannelEmail ChannelType = "email"
|
||
ChannelTwilio ChannelType = "twilio_sms"
|
||
ChannelAPI ChannelType = "api"
|
||
)
|
||
|
||
// ChannelInterface 渠道必须实现的接口
|
||
type ChannelInterface interface {
|
||
// HandleInbound 处理渠道入站消息
|
||
HandleInbound(ctx context.Context, inboxID uint, params InboundParams) (*ConversationResult, error)
|
||
// HandleOutbound 通过渠道发送出站消息
|
||
HandleOutbound(ctx context.Context, conversation *Conversation, message *Message) error
|
||
// ValidateConfig 校验渠道配置参数
|
||
ValidateConfig(config map[string]interface{}) error
|
||
// GetConfigTemplate 返回渠道配置模板
|
||
GetConfigTemplate() *ChannelConfigTemplate
|
||
// RegisterWebhook 注册渠道Webhook路由到HTTP router
|
||
RegisterWebhook(router gin.IRouter)
|
||
// RefreshOAuth 刷新OAuth令牌(可选,如Facebook/Instagram)
|
||
RefreshOAuth(ctx context.Context, channelModel *ChannelModel) error
|
||
}
|
||
|
||
// ChannelRegistry 渠道注册器
|
||
type ChannelRegistry struct {
|
||
channels map[ChannelType]ChannelInterface
|
||
}
|
||
|
||
func (r *ChannelRegistry) Register(ct ChannelType, ch ChannelInterface) { ... }
|
||
func (r *ChannelRegistry) Get(ct ChannelType) (ChannelInterface, bool) { ... }
|
||
func (r *ChannelRegistry) AllTypes() []ChannelType { ... }
|
||
```
|
||
|
||
### 5.2 EventBus接口(事件分发)
|
||
|
||
```go
|
||
// internal/eventbus/bus.go
|
||
package eventbus
|
||
|
||
type EventName string
|
||
const (
|
||
ConversationCreated EventName = "conversation_created"
|
||
ConversationUpdated EventName = "conversation_updated"
|
||
ConversationOpened EventName = "conversation_opened"
|
||
ConversationResolved EventName = "conversation_resolved"
|
||
MessageCreated EventName = "message_created"
|
||
MessageUpdated EventName = "message_updated"
|
||
ContactCreated EventName = "contact_created"
|
||
ContactUpdated EventName = "contact_updated"
|
||
AssignmentChanged EventName = "assignment_changed"
|
||
)
|
||
|
||
type Event struct {
|
||
Name EventName
|
||
AccountID uint
|
||
Data map[string]interface{}
|
||
Timestamp time.Time
|
||
}
|
||
|
||
type EventBus interface {
|
||
Publish(ctx context.Context, event Event) error
|
||
Subscribe(name EventName, handler EventHandler) error
|
||
}
|
||
|
||
type EventHandler func(ctx context.Context, event Event) error
|
||
```
|
||
|
||
### 5.3 Repository接口(数据访问)
|
||
|
||
```go
|
||
// internal/repository/base_repo.go
|
||
package repository
|
||
|
||
// BaseRepository 泛型基础CRUD接口
|
||
type BaseRepository[T any] interface {
|
||
Create(ctx context.Context, entity *T) error
|
||
GetByID(ctx context.Context, id uint) (*T, error)
|
||
Update(ctx context.Context, entity *T) error
|
||
Delete(ctx context.Context, id uint) error
|
||
List(ctx context.Context, filter Filter, page Pagination) ([]T, int64, error)
|
||
}
|
||
|
||
type Filter struct {
|
||
AccountID uint
|
||
Conditions []Condition
|
||
OrderBy string
|
||
}
|
||
|
||
type Pagination struct {
|
||
Page int
|
||
PerPage int
|
||
}
|
||
|
||
type Condition struct {
|
||
Field string
|
||
Operator string // eq, ne, gt, lt, in, like, between
|
||
Value interface{}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 第一阶段与第二阶段模块划分
|
||
|
||
### 6.1 第一阶段(Web Widget + Telegram + Captain/Copilot)
|
||
|
||
| 优先级 | 包 | 核心功能 |
|
||
|--------|---|---------|
|
||
| P0 | account | 账户CRUD + 设置 |
|
||
| P0 | user | 用户CRUD + 认证 + AccountUser |
|
||
| P0 | inbox | 收件箱CRUD + InboxMember |
|
||
| P0 | channel/webwidget | Web Widget渠道入站/出站 |
|
||
| P0 | channel/telegram | Telegram渠道入站/出站 |
|
||
| P0 | conversation | 对话CRUD + 状态流转 |
|
||
| P0 | message | 消息CRUD + 附件 |
|
||
| P0 | contact | 联系人CRUD + ContactInbox |
|
||
| P0 | realtime | WebSocket实时推送 |
|
||
| P0 | eventbus | Redis Pub/Sub事件分发 |
|
||
| P1 | team | 团队管理 + TeamMember |
|
||
| P1 | assignment | 自动分配 + RoundRobin |
|
||
| P1 | notification | 通知 + NotificationSetting |
|
||
| P1 | webhook | Webhook投递 |
|
||
| P1 | label | 标签系统 |
|
||
| P1 | note | 笔记 |
|
||
| P1 | canned | 模板消息 |
|
||
| P1 | automation | 自动化规则(基础版) |
|
||
| P1 | reporting | 报告 + CSAT |
|
||
| P1 | campaign | Campaign(基础版) |
|
||
| P1 | customattr | 自定义属性 |
|
||
| P1 | search | 全文搜索(pg_trgm) |
|
||
| P2-企业版 | captain | Captain AI助手 + Playground |
|
||
| P2-企业版 | copilot | Copilot副驾驶 + Thread |
|
||
| P2-企业版 | sla | SLA策略 |
|
||
| P2-企业版 | customrole | 自定义角色权限 |
|
||
| P2-企业版 | auditlog | 审计日志 |
|
||
| P2-企业版 | agentcapacity | 坐席容量策略 |
|
||
|
||
### 6.2 第二阶段(更多渠道 + 更多企业功能)
|
||
|
||
| 包 | 新增渠道/功能 |
|
||
|----|-------------|
|
||
| channel/facebook | Facebook Messenger渠道 |
|
||
| channel/whatsapp | WhatsApp渠道 |
|
||
| channel/email | Email渠道 |
|
||
| channel/twilio | Twilio SMS渠道 |
|
||
| channel/api | API渠道 |
|
||
| company | 公司管理(企业版) |
|
||
| call | 语音通话(企业版) |
|
||
| saml | SAML SSO(企业版) |
|
||
| macro | 宏操作 |
|
||
| knowledgebase | 知识库 + Help Center |
|
||
| platform | Platform API |
|
||
| agentbot | AgentBot |
|
||
| dashboardapp | Dashboard App |
|
||
| dataimport | 数据导入 |
|
||
| assignment_v2 | AssignmentPolicy V2 |
|
||
|
||
---
|
||
|
||
## 7. Go模块依赖(go.mod)
|
||
|
||
```
|
||
module github.com/gochat/gochat
|
||
|
||
go 1.23
|
||
|
||
require (
|
||
// HTTP框架
|
||
github.com/gin-gonic/gin v1.10+
|
||
// ORM
|
||
gorm.io/gorm v1.25+
|
||
gorm.io/driver/postgres v1.5+
|
||
// Redis
|
||
github.com/redis/go-redis/v9 v9.7+
|
||
// 配置
|
||
github.com/spf13/viper v1.19+
|
||
// JWT
|
||
github.com/golang-jwt/jwt/v5 v5.2+
|
||
// WebSocket
|
||
github.com/gorilla/websocket v1.5+
|
||
// 数据库迁移
|
||
github.com/golang-migrate/migrate/v4 v4.18+
|
||
// 日志
|
||
go.uber.org/zap v1.27+
|
||
// 校验
|
||
github.com/go-playground/validator/v10 v10.22+
|
||
// 邮件
|
||
github.com/wneessen/go-mail v0.5+
|
||
// 加密
|
||
golang.org/x/crypto v0.31+
|
||
// UUID
|
||
github.com/google/uuid v1.6+
|
||
// S3存储(可选)
|
||
github.com/aws/aws-sdk-go-v2 v1.32+
|
||
// LLM SDK(企业版Captain)
|
||
github.com/sashabaranov/go-openai v1.32+
|
||
// Telegram Bot SDK
|
||
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5+
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 编译与部署架构
|
||
|
||
### 8.1 编译目标
|
||
|
||
```bash
|
||
# 社区版编译(不含企业版功能)
|
||
go build -tags community -o gochat-server cmd/server/main.go
|
||
|
||
# 企业版编译(含全部功能)
|
||
go build -tags enterprise -o gochat-server cmd/server/main.go
|
||
|
||
# Worker独立部署(可选)
|
||
go build -o gochat-worker cmd/worker/main.go
|
||
```
|
||
|
||
### 8.2 企业版功能隔离策略
|
||
|
||
GoChat使用Go的build tags实现企业版功能隔离:
|
||
|
||
```go
|
||
// internal/domain/captain/captain_service.go
|
||
// +build enterprise
|
||
|
||
package captain
|
||
|
||
func NewCaptainService(...) *CaptainService { ... }
|
||
```
|
||
|
||
```go
|
||
// internal/domain/captain/captain_stub.go
|
||
// +build !enterprise
|
||
|
||
package captain
|
||
|
||
func NewCaptainService(...) *CaptainService {
|
||
// 返回stub实现,提示需要企业版许可
|
||
return nil
|
||
}
|
||
```
|
||
|
||
`enterprise_check`中间件在运行时也做二次校验:
|
||
- 编译时:build tags控制代码是否编译
|
||
- 运行时:中间件检查Account的feature flags或License
|
||
|
||
---
|
||
|
||
## 9. 与Chatwoot目录结构的完整对比
|
||
|
||
| Chatwoot目录 | GoChat对应 | 说明 |
|
||
|-------------|-----------|------|
|
||
| `app/controllers/` | `internal/handler/` | Go用handler命名 |
|
||
| `app/models/` | `internal/model/` | GORM模型集中定义 |
|
||
| `app/models/channel/` | `internal/domain/channel/各渠道子包/` | 按渠道分包 |
|
||
| `app/models/concerns/` | `接口+struct embedding` | Go无Concern,用组合 |
|
||
| `app/services/` | `internal/service/` | 业务逻辑层 |
|
||
| `app/builders/` | `internal/service/`(合并) | Builder在Go中合并到service |
|
||
| `app/finders/` | `internal/repository/` | Finder合并到repository |
|
||
| `app/policies/` | `internal/middleware/permission.go` | 权限检查用中间件 |
|
||
| `app/presenters/` | `internal/serializer/` | 序列化层 |
|
||
| `app/listeners/` | `internal/eventbus/listeners.go` | Listener注册到EventBus |
|
||
| `app/dispatchers/` | `internal/eventbus/bus.go` | 事件分发 |
|
||
| `app/jobs/` | `internal/worker/` | Go goroutine替代Sidekiq |
|
||
| `app/mailers/` | `internal/mailer/` | 邮件发送 |
|
||
| `app/dashboards/` | 删除 | Go无Administrate |
|
||
| `app/channels/` (ActionCable) | `internal/realtime/` | WebSocket |
|
||
| `app/views/` (Jbuilder) | `internal/serializer/` | JSON序列化 |
|
||
| `enterprise/` | `internal/domain/各企业版子包/` | 企业版包(build tags) |
|
||
| `config/routes.rb` | `internal/handler/路由注册函数/` | Go显式路由注册 |
|
||
| `config/` | `internal/config/` + `.env` | Viper + ENV |
|
||
| `db/schema.rb` | `internal/model/` + `migrations/` | GORM + golang-migrate |
|
||
| `db/migrate/` | `migrations/` | SQL迁移文件 |
|
||
| `spec/` | `tests/`(待创建) | Go测试 |
|
||
| `swagger/` | `docs/api/` | OpenAPI文档 |
|
||
|
||
---
|
||
|
||
*文档结束。下一步:产出 04-design-database.md 和 05-design-routing-and-api.md* |