# 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 │ └── k8s/ # Kubernetes配置(可选) │ ├── 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*