# 销冠平台技术实现方案 ## 1. 文档范围 本文档用于指导“场景化销售话术与 SOP 平台”的第一阶段实现。 第一阶段的核心闭环是: ```text 创建场景 -> 配置自定义字段 -> 编排 SOP -> 审核发布 -> 一线人员执行 -> 记录反馈 ``` 场景不写死在代码中。宠物医生问诊问药只是一个配置示例,后续可以创建保险咨询、房地产销售、教育课程顾问等其他场景。 本阶段暂不实现文件存储、AI 自动生成、CRM 集成和微服务拆分。 ## 2. 技术选型 ### 2.1 后端 - Go:业务服务和流程执行引擎 - Gin:HTTP 路由、中间件和请求处理 - Zap:结构化日志 - cleanenv:YAML 配置解析和环境变量覆盖 - GORM:MySQL 数据访问 - golang-migrate:数据库迁移 - `go-playground/validator`:请求参数校验 - JWT + Refresh Token:登录认证 第一阶段采用模块化单体。所有业务模块运行在一个 Go 服务中,通过清晰的内部边界保持可维护性,后续再根据实际负载拆分服务。 配置加载使用 `github.com/ilyakaznacheev/cleanenv`。它的行为简单明确:先读取 YAML 文件,再读取环境变量,环境变量值覆盖文件中的同名配置。 ### 2.2 前端 - Vue 3 - Vite - TypeScript - Ant Design Vue - Vue Router - Pinia - Axios SOP 编辑器第一版使用步骤卡片和条件配置,不立即引入复杂的画布编辑器。需要图形化节点编排时,使用 Vue 生态的流程图组件,不使用 React Flow。 ### 2.3 数据库和运行环境 - MySQL 8.0+ - Docker Compose:本地开发 - Nginx:生产环境反向代理 - Linux 容器部署 本阶段不引入 Redis。登录会话、场景配置和执行状态先使用 MySQL;只有出现异步任务、缓存或高并发需求时再增加 Redis。 ## 3. 配置管理 配置结构统一放在 `internal/config/`,业务代码不能直接读取环境变量。 配置优先级如下: ```text 结构体默认值 < config.yml < 当前环境配置文件 < 环境变量 ``` 配置文件约定如下: ```text configs/config.example.yml # 配置模板,可提交,不包含敏感信息 configs/config.yml # 基础配置 configs/config.test.yml # 测试环境覆盖配置 configs/config.prod.yml # 生产环境覆盖配置 ``` 运行环境通过 `APP_ENV` 或启动参数 `--env` 选择,优先级为启动参数高于环境变量: ```text 未指定环境 -> config.yml APP_ENV=test -> config.yml + config.test.yml APP_ENV=prod -> config.yml + config.prod.yml ``` `config.yml` 作为基础文件必须存在。`test` 和 `prod` 环境对应的覆盖文件也必须存在;缺失时服务直接退出。环境配置文件只填写与基础配置不同的字段,未填写的字段沿用 `config.yml`。 配置文件路径通过 `--config-dir` 指定,默认使用当前工作目录下的 `configs/`。部署时可以挂载外部配置目录,不需要把真实生产配置提交到代码仓库。 环境变量名称通过结构体标签显式声明,例如: ```text APP_SERVER_HOST APP_SERVER_PORT APP_DATABASE_HOST APP_DATABASE_PORT APP_DATABASE_USER APP_DATABASE_PASSWORD APP_DATABASE_NAME ``` 配置字段约定: - `yaml`:YAML 文件中的字段名。 - `env`:环境变量名称,必须显式声明。 - `env-default`:没有文件值和环境变量时使用的默认值。 - `env-required:"true"`:必须由环境变量提供的敏感或关键配置。 - `env-prefix`:为嵌套配置统一增加环境变量前缀。 - `env-layout`:日期、时间等特殊类型的解析格式。 生产环境中,数据库密码、JWT 密钥等敏感字段必须使用 `env-required:"true"`,不写入 YAML 文件。配置加载失败或必填项缺失时,服务直接退出,不使用不完整配置继续启动。 加载过程必须保持以下顺序:先加载基础配置,再加载当前环境配置,最后执行环境变量覆盖。环境变量不能被后续 YAML 文件覆盖。 ## 4. 目录规划 代码统一放在 `codes/` 目录下。按照 `golang-standards/project-layout` 的组织方式,同时遵循“根目录放置 main.go”和“前端放在 web 目录”的项目约束。 ```text codes/ ├── main.go # Go 服务入口,位于代码根目录 ├── go.mod ├── go.sum ├── internal/ │ ├── config/ # 配置加载 │ ├── logger/ # Zap 初始化和日志字段规范 │ ├── middleware/ # 认证、租户、请求日志、异常恢复 │ ├── router/ # 路由注册 │ ├── handler/ # HTTP 接口层 │ ├── service/ # 业务服务层 │ ├── repository/ # 数据访问层 │ ├── model/ # 数据库模型和请求响应模型 │ ├── engine/ # SOP 流程执行引擎 │ └── webassets/ # 前端嵌入和静态资源处理 ├── pkg/ │ └── response/ # 可被外部复用的通用响应结构 ├── configs/ │ ├── config.yml │ ├── config.test.yml │ ├── config.prod.yml │ └── config.example.yml ├── migrations/ # MySQL 数据库迁移文件 ├── scripts/ # 构建、检查和发布脚本 └── web/ ├── package.json ├── vite.config.ts ├── index.html ├── src/ │ ├── api/ │ ├── components/ │ ├── layouts/ │ ├── router/ │ ├── stores/ │ ├── types/ │ └── views/ └── dist/ # 前端构建产物,由 Go 使用 go:embed 嵌入 ``` 说明:`cmd/` 目录不使用,Go 入口固定为 `codes/main.go`。`codes/web/dist/` 是构建产物目录,前端构建完成后由 Go 服务作为静态资源提供。 ```text 浏览器 ├── 管理端:场景、字段、SOP、知识卡、审核 └── 执行端:按 SOP 执行和记录客户回答 | v Go HTTP 服务 ├── 身份认证与租户权限 ├── 场景配置服务 ├── SOP 版本服务 ├── 流程执行引擎 ├── 知识卡服务 └── 执行记录与统计 | v MySQL ``` ## 5. 系统架构 Go 服务同时承担 API 服务和前端静态资源服务。前端构建后通过 `go:embed` 打入 Go 二进制,生产环境只需要部署一个服务包和配置文件。 ## 6. go:embed 方案 前端构建输出到 `codes/web/dist/`,Go 服务通过 `go:embed` 嵌入该目录。 构建流程为: ```text 进入 codes/web -> 安装依赖 -> 执行前端构建 -> 生成 web/dist -> 回到 codes -> 执行 Go 构建 -> 生成包含前端资源的二进制 ``` 服务端静态资源处理规则: - `/api/` 路径只进入 Go API 路由。 - 静态文件路径优先读取 `web/dist` 中对应文件。 - 非 API 且找不到文件的路径回退到 `index.html`,支持 Vue Router 的 history 模式。 - 前端资源由 Nginx 或应用服务设置长期缓存,`index.html` 不使用长期缓存。 前端 `dist` 不存在时,Go 项目不能完成编译,因此代码仓库需要保留一个可构建的前端产物占位文件,或者在 CI 中强制先执行前端构建。 ## 7. 场景模型 场景是平台的一级可配置对象,不能在代码中写死行业字段。 一个场景至少包含: - 场景名称 - 所属行业 - 适用角色 - 使用目标 - 触发条件 - 可见范围 - 自定义字段 - 一个或多个 SOP - 关联知识卡 - 发布状态 例如宠物医生问诊问药场景可以配置: ```text pet_type 宠物种类 pet_age 年龄 pet_weight 体重 symptom 症状 symptom_duration 症状持续时间 has_emergency_sign 是否存在急症 ``` 保险咨询场景则可以配置客户年龄、职业、预算和保险类型。新增场景只需要增加配置数据,不需要修改业务代码。 ## 8. SOP 模型 SOP 由版本、节点和连线组成。 第一阶段支持以下节点类型: - `start`:流程开始 - `message`:展示标准话术 - `question`:提问并写入一个场景字段 - `form`:一次收集多个字段 - `choice`:让执行人员选择客户回答 - `condition`:根据已收集字段进行分支 - `knowledge`:展示已审核知识卡 - `escalate`:转人工、转医生或线下处理 - `finish`:结束流程 条件必须保存为结构化规则,不能让用户输入或执行任意 JavaScript。条件规则支持等于、不等于、包含、大于、小于、全部满足、任一满足等操作。 发布前需要校验: - 只有一个开始节点 - 所有节点都可从开始节点访问 - 所有分支都有出口 - 不存在无法结束的路径 - 必填字段存在对应采集节点 - 关联知识卡已经审核 - 急症或高风险分支有明确的转人工或转诊动作 ## 9. MySQL 数据表 核心表如下: ```text users 用户 tenants 企业或组织 tenant_members 企业成员和角色 roles 角色权限 scenarios 场景 scenario_fields 场景自定义字段 sops SOP 基础信息 sop_versions SOP 版本 sop_nodes SOP 节点 sop_edges SOP 连线和条件 knowledge_cards 话术或知识卡 knowledge_card_versions 知识卡版本 sop_runs SOP 执行实例 sop_run_events SOP 节点执行事件 sop_feedback 执行反馈 audit_logs 操作审计 ``` 关键设计: - 所有租户相关数据必须能追溯到 `tenant_id`。 - 场景字段使用行记录保存,避免把场景字段写死在表结构中。 - 节点配置和条件规则使用 MySQL JSON 字段保存。 - 已发布版本不可直接修改,修改时复制为新的草稿版本。 - 版本状态流转为 `draft -> reviewing -> published -> offline`;管理员也可以从草稿直接发布。 - 执行过程保存事件记录,便于复盘和统计。 - 需要参与筛选和统计的字段不能只存 JSON,应在事件表或统计表中建立结构化字段。 ## 10. 后端接口规划 ### 场景接口 ```text POST /api/v1/scenarios GET /api/v1/scenarios GET /api/v1/scenarios/:id PUT /api/v1/scenarios/:id DELETE /api/v1/scenarios/:id ``` ### 自定义字段接口 ```text POST /api/v1/scenarios/:id/fields PUT /api/v1/scenario-fields/:id DELETE /api/v1/scenario-fields/:id ``` ### SOP 接口 ```text POST /api/v1/scenarios/:id/sops GET /api/v1/scenarios/:id/sops PUT /api/v1/sops/:id/draft POST /api/v1/sops/:id/validate POST /api/v1/sops/:id/submit-review POST /api/v1/sops/:id/publish POST /api/v1/sops/:id/offline ``` ### SOP 执行接口 ```text POST /api/v1/runs GET /api/v1/runs/:id POST /api/v1/runs/:id/answer POST /api/v1/runs/:id/finish POST /api/v1/runs/:id/feedback ``` ## 11. 流程执行引擎 执行流程如下: 1. 创建执行实例,绑定一个已发布的 SOP 版本。 2. 加载开始节点并返回给前端。 3. 前端展示话术、表单或选项。 4. 后端校验客户回答和字段类型。 5. 在事务中保存回答和节点事件。 6. 根据结构化条件计算下一节点。 7. 返回下一节点或结束动作。 流程引擎只处理通用节点和规则,不理解“宠物”“保险”等具体业务。行业知识放在场景字段、话术内容和知识卡中。 ## 12. Zap 日志规范 使用 Zap 输出结构化 JSON 日志到 stdout,由 Docker、Kubernetes 或云平台采集,不由应用自己维护日志文件。 日志至少包含: - `service` - `env` - `request_id` - `tenant_id` - `user_id` - `action` - `resource` - `resource_id` - `duration_ms` - `err` 日志等级约定: - `DEBUG`:本地开发细节 - `INFO`:正常请求、发布、执行等业务事件 - `WARN`:参数异常、权限拒绝、客户端错误 - `ERROR`:服务异常、数据库失败、流程执行失败 禁止记录密码、Token、完整客户聊天内容和未脱敏的个人信息。 Gin 请求日志中需要记录请求方法、路径、状态码、耗时和 Request ID。业务日志使用结构化字段,不使用字符串拼接。 ## 13. 前端页面规划 ### 管理端 - 场景列表 - 创建/编辑场景 - 自定义字段配置 - SOP 列表 - SOP 步骤编辑器 - 节点条件配置 - 知识卡管理 - 审核发布中心 - 执行数据看板 ### 执行端 - 场景选择 - SOP 当前节点 - 客户信息录入 - 标准话术展示 - 分支选择 - 转人工或转诊提醒 - 执行结果和反馈 Ant Design Vue 主要使用 `Form`、`Table`、`Drawer`、`Modal`、`Steps`、`Tree`、`Tabs` 和 `Descriptions`。动态字段表单由场景字段配置生成,字段校验规则也由配置生成。 ## 14. 安全与权限 - 用户登录后从 Token 中获取 `tenant_id`,不能信任前端传入的租户 ID。 - 所有查询必须自动附加租户条件。 - 场景、SOP、知识卡、执行记录都需要做资源级权限判断。 - 发布、下线、审核和修改权限分离。 - 已发布 SOP 版本只读,修改时复制为新的草稿版本。 - 记录关键操作到 `audit_logs`。 - 条件规则禁止执行任意代码。 ## 15. 第一阶段开发顺序 ### 第 1 阶段:基础服务 - Go 服务初始化 - Zap 日志 - 配置加载 - MySQL 连接 - 登录和租户权限 - 前端构建和 go:embed ### 第 2 阶段:场景配置 - 场景 CRUD - 自定义字段 CRUD - 场景权限 - 场景状态管理 ### 第 3 阶段:SOP 编排 - 节点管理 - 连线和条件配置 - 草稿保存 - 流程校验 - 版本复制 ### 第 4 阶段:SOP 执行 - 创建执行实例 - 节点展示 - 回答提交 - 条件跳转 - 执行事件记录 ### 第 5 阶段:审核和反馈 - 提交审核 - 审核发布 - 下线和回滚 - 执行反馈 - 基础数据统计 ## 16. 构建和部署约定 首次初始化本地 MySQL 数据库时执行: ```bash cd codes mysql -uroot -p < scripts/create-databases.sql ``` 服务启动时会自动执行 `migrations/` 中的迁移,创建业务表并记录 `schema_migrations` 版本。 本地开发时前后端可以分别启动: ```text 前端开发服务:codes/web Go API 服务:codes ``` 生产构建时先构建前端,再构建 Go 服务。最终产物只需要: - Go 二进制 - 配置文件 - MySQL 数据库 前端静态资源已经通过 `go:embed` 编译进入 Go 二进制,不需要单独部署前端静态目录。 ## 17. 暂不实现的内容 - 文件上传和对象存储 - AI 自动提炼话术 - AI 客户模拟陪练 - CRM、企业微信和客服系统集成 - 多服务拆分 - Redis 缓存 - 消息队列 - 复杂 BI 分析 这些内容等核心闭环验证成功后再加入,避免第一版架构过度复杂。