跳到正文
☰
UA
评论中间件现状
重构前事实基线
审计日期 2026-08-12
◐
正在渲染文档...
此文档需要启用 JavaScript 才能渲染 Markdown 和 Mermaid 图。
# 系统架构与数据架构现状 > 审计日期:2026-08-12 > 范围:当前仓库中的源码、配置模板、数据库迁移与 `console/runtime/logs/app.log`。本文描述已存在系统,不给出重构目标或实现方案。 > 项目类型:遗留业务集成中间件(评论采集、评论详情补充、评论回复),核心业务位于 Yii 2 Console 应用;frontend 仍保留 Yii Advanced 模板能力,当前副本的 backend 交付不完整。证据:`README.md:9-16`、`console/config/main.php:10-51`、`frontend/config/main.php:9-48`、`backend/web/index.php:11-18`。 ## 1. 证据口径 本文采用以下证据等级: | 等级 | 含义 | 使用边界 | | --- | --- | --- | | **Confirmed** | 可由当前仓库源码、迁移或日志直接证明 | 可以陈述当前代码行为;不等于已在生产正确部署或持续可用 | | **Inferred** | 由多个代码调用关系推断,仓库没有完整运行环境或数据库定义佐证 | 图中使用虚线或显式标注“逻辑关联/推断” | | **Unknown** | 当前仓库无法回答 | 不用经验补齐,列入待确认项 | 证据限制: - 仓库没有八张业务表的完整建表迁移,只有回复表新增字段迁移。因此 ActiveRecord 注释与验证规则只能证明“代码期望字段”,不能证明线上列类型、可空性、默认值、主键、自增、索引、唯一约束或外键。证据:`console/migrations/m251114_094210_add_column_comment_reply_table.php:13-18`。 - `user` 是唯一具有完整建表迁移的表,属于 Yii 模板账户体系,不是评论中间件核心业务数据。证据:`console/migrations/m130524_201442_init.php:15-26`。 - 仓库提供 dev/prod 环境模板,但不能证明生产实际主机、进程编排、Cron、Worker 数量和网络边界。证据:`environments/index.php:7-28`、`environments/prod/console/config/main-local.php:1-4`。 - 日志只用于确认运行现象。本文不复制请求载荷、令牌、个人信息或完整异常上下文。 ## 2. 系统性质与边界 ### 2.1 核心职责(Confirmed) 当前业务系统承担四类职责: 1. 从 `app_info` 读取京东、天猫、淘宝、抖音店铺及渠道授权信息。渠道枚举为 Tmall=1、JD=2、TaoBao=3、DouYin=4。证据:`console/models/AppInfo.php:19-22`、`console/models/AppInfo.php:91-97`。 2. 创建 `comments_limitation` 时间窗口或回复游标记录,然后向 Redis Queue 投递任务。证据:`console/modules/jd/controllers/CommentsController.php:47-82`、`console/modules/tmall/controllers/CommentsController.php:61-96`、`console/modules/douyin/controllers/CommentsController.php:61-80`。 3. 调用渠道接口抓取评论,将渠道返回对象序列化为 JSON,保存至渠道独立评论表;天猫额外抓取评价详情,抖音先抓商品再按商品抓评论。证据:`console/modules/jd/CommentJob.php:34-79`、`console/modules/tmall/CommentJob.php:37-91`、`console/modules/tmall/CommenDetailtJob.php:31-59`、`console/modules/douyin/CommentJob.php:31-69`、`console/modules/douyin/ProductCommentJob.php:19-77`。 4. 扫描京东、天猫/淘宝回复表中的 `new` 记录,改为 `processing` 后投递回复任务;任务调用渠道接口并写回结果、重试次数和最终状态。证据:`console/modules/jd/controllers/ReplyController.php:21-59`、`console/modules/jd/CommentReplyJob.php:23-65`、`console/modules/tmall/controllers/ReplyController.php:21-61`、`console/modules/tmall/CommentReplyJob.php:26-66`。 ### 2.2 不在核心链路中的模板能力(Confirmed) - `frontend` 仍配置 Yii 用户、Session、登录等模板 Web 能力。证据:`frontend/config/main.php:9-35`。 - `frontend` 与 README 延续 Yii Advanced 模板结构;当前评论同步入口均为 `yii\console\Controller`。证据:`README.md:24-47`、`frontend/config/main.php:9-48`、`console/modules/jd/controllers/CommentsController.php:7-10`、`console/modules/tmall/controllers/CommentsController.php:7-10`、`console/modules/douyin/controllers/CommentsController.php:8-11`。 - 当前副本的 `backend` 只有 `web/` 和 `tests/` 等残余文件,入口仍要求加载不存在的 `backend/config/main.php` 等配置;因此不能确认 backend 可启动,也不能确认其评论后台能力。证据:`backend/web/index.php:11-18`。 - 当前仓库未发现 Web Controller 直接调用评论采集/回复模块的证据。 ### 2.3 当前系统上下文图 ```mermaid flowchart LR Trigger["外部触发者<br/>人工命令或调度器:具体方式 Unknown"] subgraph Middleware["UA Comments 中间件(Yii 2 Console)"] Cmd["渠道 Console Controllers<br/>创建窗口 / 扫描回复"] Queue["Redis Queue<br/>任务载荷、延迟执行、TTR"] Worker["Queue Worker<br/>执行 Comment / Detail / Reply Job"] AR["Yii ActiveRecord<br/>读取配置、写入业务状态与原始 JSON"] SDK["渠道 Client / 内嵌 SDK"] Log["Yii FileTarget / Queue LogBehavior"] end DB[("MySQL<br/>店铺配置、窗口/游标、评论、回复")] JD["京东虎符 API 网关 / 京东中间件"] TM["淘宝开放平台 / 天猫评价接口"] DY["抖店开放平台"] Files[("console/runtime/logs/app.log")] Trigger --> Cmd Cmd --> AR Cmd --> Queue Queue --> Worker Worker --> AR AR --> DB Worker --> SDK SDK --> JD SDK --> TM SDK --> DY Worker --> Log Queue --> Log Log --> Files ``` 图中“外部触发者”是 **Unknown**:仓库确认了命令入口和队列消费模型,但未发现 Cron、Supervisor、systemd、Kubernetes 或其他生产调度/守护配置。 ## 3. 运行时组件与职责 | 组件 | 状态 | 当前角色 | 关键证据 | | --- | --- | --- | --- | | Yii 2 Console | Confirmed | 注册 `jd`、`tmall`、`douyin` 模块,提供评论抓取、按 ID 重启和回复扫描命令 | `console/config/main.php:10-14`、`console/config/main.php:47-51` | | Redis Queue | Confirmed | 异步保存序列化 Job;支持延迟投递;任务 TTR 配置为 4 小时;加载 Queue 日志行为 | `console/config/main.php:13-37`、`console/config/main-local.php:6-16`、`console/modules/jd/controllers/CommentsController.php:35-38` | | Queue Worker | Confirmed(代码/日志),部署 Unknown | 执行实现 `JobInterface` 的评论和回复任务;日志证明曾以 CLI Queue 进程运行 | `console/modules/jd/CommentJob.php:8-11`、`console/runtime/logs/app.log:1-8` | | MySQL / Yii DB | Confirmed(技术选型),实例 Unknown | ActiveRecord 持久化业务表;环境模板使用 `yii\db\Connection` 与 MySQL DSN | `environments/dev/common/config/main-local.php:5-10`、`environments/prod/common/config/main-local.php:5-10` | | `app_info` | Confirmed | 店铺、渠道和渠道授权资料来源;Job 通过 `limit_type` 反查店铺 | `console/models/AppInfo.php:27-40`、`console/models/AppInfo.php:71-83` | | `comments_limitation` | Confirmed | 复用为评论抓取时间窗口及回复扫描游标;状态为 `new/success/error` | `console/models/Limitation.php:19-28`、`console/modules/jd/controllers/ReplyController.php:99-121` | | 京东 `HuFuClient` | Confirmed | 以 JDCloud Signature V4 对虎符 API 网关请求签名;将本地 `shop_code` 映射为中间件 `appId`;调用 `/comments` 与 `/comments/reply` | `console/modules/jd/HuFuClient.php:25-35`、`console/modules/jd/HuFuClient.php:51-58`、`console/modules/jd/HuFuClient.php:61-109`、`console/modules/jd/HuFuClient.php:112-123` | | 天猫/淘宝 TOP SDK | Confirmed | 用 `app_key`、`secret_key`、`access_token` 调淘宝评论列表、天猫评价详情和解释/回复接口 | `console/modules/tmall/Client.php:22-41`、`console/modules/tmall/Client.php:64-100` | | 抖店 SDK | Confirmed | 用店铺授权信息获取商品列表和商品评论 | `console/modules/douyin/Client.php:18-55`、`console/modules/douyin/Client.php:96-129`、`console/modules/douyin/Client.php:137-144` | | FileTarget | Confirmed | 记录 error/warning;Queue LogBehavior 同时记录 Job 执行错误 | `console/config/main.php:34-44` | | frontend | Confirmed(模板存在),业务职责 Unknown | Yii Advanced 模板 Web 入口;未发现与评论模块的调用关系 | `README.md:9-16`、`frontend/config/main.php:9-48` | | backend | Confirmed(当前副本不完整),评论后台能力 Unknown | 仅残留 Web 入口和测试;入口依赖当前不存在的 backend 配置,无法据此确认可运行后台 | `backend/web/index.php:11-18` | ### 3.1 Redis Queue 的数据边界 Redis 保存的是序列化 Job,而非评论主数据: - 评论任务主要携带 `limitId`;抖音子任务另携带 `productIds`,天猫详情任务另携带 `oids`。证据:`console/modules/jd/CommentJob.php:16`、`console/modules/douyin/ProductCommentJob.php:8-10`、`console/modules/tmall/CommenDetailtJob.php:13-20`。 - 回复任务携带回复表 `id`、重试上限 `limit` 和延迟 `delay`。证据:`console/modules/jd/CommentReplyJob.php:14-16`、`console/modules/tmall/CommentReplyJob.php:17-19`。 - Job 执行时再从 MySQL 读取 `comments_limitation`、`app_info` 或回复记录。因此 Redis 中的旧消息依赖对应数据库行与当前类结构仍然存在。证据:`console/modules/tmall/CommentJob.php:33-35`、`console/modules/tmall/CommentReplyJob.php:28-32`。 - 日志中存在 Job 引用的窗口或回复记录已经不存在,随后访问空对象失败的现象;这证明运行时确有“Redis 消息 ID -> MySQL 行”依赖。脱敏证据:`console/runtime/logs/app.log:18077`、`console/runtime/logs/app.log:18190-18191`。 Redis 服务器地址在当前本地配置中是 `127.0.0.1`、数据库编号 1;主配置里的 Redis 子配置被注释。生产 Redis 地址及是否与应用同机为 **Unknown**。证据:`console/config/main-local.php:6-13`、`console/config/main.php:26-33`。 ### 3.2 MySQL 的数据边界 MySQL 是系统记录层: - 授权配置:`app_info`。 - 同步范围、执行状态与回复扫描位置:`comments_limitation`。 - 渠道评论副本:`jd_comments`、`tmall_comments`、`douyin_comments`。 - 抖音商品索引:`douyin_products`。 - 待提交回复及渠道响应:`jd_comments_reply`、`tmall_comments_reply`。 - Yii 模板账号:`user`。 当前源码没有 ActiveRecord relation、数据库事务或外键迁移证据;跨表连接均通过业务字段查询实现。证据:`console/models/AppInfo.php:80-83`、`console/modules/jd/CommentJob.php:49`、`console/modules/douyin/ProductCommentJob.php:38-42`。 ### 3.3 第三方 SDK 与虎符中间件 - 天猫/淘宝和抖音 SDK 源码直接位于各渠道模块的 `sdk/` 目录;京东包含 JDCloud API Gateway signer。Composer 只为京东 signer 显式添加 PSR-4 与 functions 自动加载。证据:`composer.json:40-46`、`console/modules/tmall/Client.php:5`、`console/modules/douyin/Client.php:6`。 - 京东不是由本系统直接调用公开 JD 评论 SDK,而是经配置的 JDCloud 虎符网关访问一个京东评论中间件,并用 `id_map` 把本地店铺映射为对方 `appId`。证据:`console/config/params.php:5-13`、`console/modules/jd/HuFuClient.php:51-58`、`console/modules/jd/HuFuClient.php:74-88`。 - 日志确认这些外部依赖会产生 DNS、远端响应结构及历史 Job 兼容类错误,但本文不据此推断外部系统内部架构。脱敏证据:`console/runtime/logs/app.log:5413`、`console/runtime/logs/app.log:10743`、`console/runtime/logs/app.log:17327`。 ## 4. 部署与运行现状 ### 4.1 可由仓库确认的运行图 ```mermaid flowchart TB subgraph Host["运行主机边界:实际数量与拆分 Unknown"] CLI["PHP CLI<br/>yii jd/*, tmall/*, douyin/*"] QW["PHP Queue Worker<br/>yii queue/listen 或 queue/run:具体命令 Unknown"] Redis[("Redis<br/>本地配置 127.0.0.1 / DB 1")] MySQL[("MySQL<br/>环境模板为 localhost")] Log[("本地文件日志<br/>console/runtime/logs/app.log")] Web["Apache/Nginx + PHP 7.4 Web 模板<br/>是否用于业务 Unknown"] end CLI -->|"写窗口 / 扫描回复"| MySQL CLI -->|"push / delay"| Redis Redis -->|"取出序列化 Job"| QW QW -->|"ActiveRecord 读写"| MySQL QW -->|"HTTPS"| External["京东虎符、淘宝/天猫、抖店"] QW --> Log Web --> MySQL ``` 证据说明: - Console Queue 使用 Redis 且本地配置指向 loopback。证据:`console/config/main-local.php:6-13`。 - dev/prod 数据库模板都使用 localhost MySQL,但模板值不能代表实际生产配置。证据:`environments/dev/common/config/main-local.php:5-10`、`environments/prod/common/config/main-local.php:5-10`。 - 唯一 Dockerfile 是 frontend 的 PHP 7.4 Apache 镜像;Vagrant Nginx 配置包含 frontend/backend 两个虚拟主机。它们不包含 Queue Worker、Redis、MySQL 或 Cron 编排。证据:`frontend/Dockerfile:1-3`、`vagrant/nginx/app.conf:1-70`。 - 生产 Console 环境模板为空,没有仓库内可核实的 Worker 守护参数。证据:`environments/prod/console/config/main-local.php:1-4`。 ### 4.2 已确认与未知的运行事实 | 主题 | 状态 | 当前结论 | | --- | --- | --- | | Queue 类型 | Confirmed | `yii\queue\redis\Queue`,TTR 4 小时,支持 delay | | Worker 曾运行 | Confirmed | 日志包含 `yii\queue\Queue`、Job ID、attempt 和 PID | | 实际 Worker 命令/数量 | Unknown | 仓库无进程管理配置 | | 调度来源与频率 | Unknown | 仓库无 Cron/systemd/K8s 调度定义 | | Redis 生产拓扑 | Unknown | 仅本地配置可见 | | MySQL 生产拓扑与版本 | Unknown | 仅环境模板可见 | | Web 是否承载评论业务 | Unknown | 未发现业务路由调用,但不能证明线上没有外部代码/入口 | | 外部系统 SLA/限流 | Unknown | Client 只显示 30 秒超时,未见协议文档 | ## 5. 数据架构总览 ### 5.1 表清单 | 表 | 类型 | 代码所有者 | 主要用途 | 建表迁移状态 | | --- | --- | --- | --- | --- | | `app_info` | 业务共享 | `console/models/AppInfo.php` | 店铺、渠道、渠道密钥/令牌 | 缺失 | | `comments_limitation` | 业务共享 | `console/models/Limitation.php` | 评论同步时间片;回复扫描游标 | 缺失 | | `jd_comments` | 京东业务 | `console/modules/jd/models/Comments.php` | 京东评论原始 JSON 副本 | 缺失 | | `jd_comments_reply` | 京东业务 | `console/modules/jd/models/CommentsReply.php` | 京东待回复内容、结果与状态 | 建表缺失;仅两列增量迁移存在 | | `tmall_comments` | 天猫/淘宝业务 | `console/modules/tmall/models/Comments.php` | 评论列表原始 JSON及天猫详情 JSON | 缺失 | | `tmall_comments_reply` | 天猫/淘宝业务 | `console/modules/tmall/models/CommentsReply.php` | 待回复内容、结果与状态 | 建表缺失;仅两列增量迁移存在 | | `douyin_products` | 抖音业务 | `console/modules/douyin/models/Products.php` | 店铺商品 ID 与 offset 字段 | 缺失 | | `douyin_comments` | 抖音业务 | `console/modules/douyin/models/Comments.php` | 按商品获取的评论原始 JSON | 缺失 | | `user` | Yii 模板 | `common/models/User.php` | Web 模板账号与认证 | 完整建表迁移存在 | 八张评论中间件业务表均没有完整 DDL。`m251114...` 在既有回复表上新增 `submit_status` 和 `retry_count`,反而证明建表历史不在当前迁移集中。证据:`console/migrations/m251114_094210_add_column_comment_reply_table.php:13-18`。 ### 5.2 当前逻辑 ER 图 > 所有虚线关系均为源码查询产生的**逻辑关联,不是已确认的数据库 FK**。`comments_limitation.limit_type` 不是单列外键:评论场景使用 `ChannelName>channel_type>shop_code`,回复场景再加 `replay_` 前缀。证据:`console/models/AppInfo.php:71-83`、`console/modules/jd/controllers/ReplyController.php:99-118`。 ```mermaid erDiagram APP_INFO { string shop_code "logical shop key" number channel_type "1 Tmall, 2 JD, 3 Taobao, 4 Douyin" string shop_name string app_key "credential" string secret_key "credential" string access_token "credential" } COMMENTS_LIMITATION { int id "expected identifier" string limit_type "encoded channel/shop or replay prefix" number start_time "Unix time or reply lower bound" number end_time "Unix time or last reply id" string status "new/success/error" number created_at } JD_COMMENTS { int id "expected identifier" string shop_code string comment_id "channel comment identifier" text comment "raw JSON" int created_at int updated_at } JD_COMMENTS_REPLY { int id "expected identifier" string shop_code string comment_id string reply_id text reply text result "raw response/error JSON" string submit_status int retry_count int created_at } TMALL_COMMENTS { int id "expected identifier" string shop_code int product_id "documented but not assigned in sync job" int oid "order line identifier" text comment "list response JSON" text detail "detail response JSON" int created_at int updated_at } TMALL_COMMENTS_REPLY { int id "expected identifier" string shop_code int oid text reply text result "raw response/error JSON" string submit_status int retry_count int created_at } DOUYIN_PRODUCTS { int id "expected identifier" string shop_code int product_id int offset int updated_at } DOUYIN_COMMENTS { int id "expected identifier" string shop_code int product_id int comment_id text comment "raw JSON" int created_at int updated_at } APP_INFO ||..o{ COMMENTS_LIMITATION : "LOGICAL encoded limit_type" APP_INFO ||..o{ JD_COMMENTS : "LOGICAL shop_code" APP_INFO ||..o{ JD_COMMENTS_REPLY : "LOGICAL shop_code" APP_INFO ||..o{ TMALL_COMMENTS : "LOGICAL shop_code" APP_INFO ||..o{ TMALL_COMMENTS_REPLY : "LOGICAL shop_code" APP_INFO ||..o{ DOUYIN_PRODUCTS : "LOGICAL shop_code" APP_INFO ||..o{ DOUYIN_COMMENTS : "LOGICAL shop_code" JD_COMMENTS ||..o{ JD_COMMENTS_REPLY : "LOGICAL shop_code + comment_id" TMALL_COMMENTS ||..o{ TMALL_COMMENTS_REPLY : "LOGICAL shop_code + oid" DOUYIN_PRODUCTS ||..o{ DOUYIN_COMMENTS : "LOGICAL shop_code + product_id" ``` 基数同样是业务意图层面的推断。例如代码按 `(shop_code, comment_id)` 查找京东评论,但缺少唯一索引 DDL,数据库不一定阻止重复行。证据:`console/modules/jd/CommentJob.php:45-51`。 ## 6. 业务表结构字典 以下“代码期望类型”来自 PHPDoc、ActiveRecord rules 或字段写入方式,不等同于 MySQL 实际列定义。“约束状态”只有迁移可证明时才写为 Confirmed。 ### 6.1 `app_info` 来源:`console/models/AppInfo.php:7-16`、`console/models/AppInfo.php:27-40`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `shop_code` | string,最大 64 | 店铺逻辑标识;查询、跨表关联、编码到 `limit_type` | PK/唯一/可空/索引 Unknown | | `channel_type` | number | 渠道枚举 | 可空/索引/枚举约束 Unknown | | `shop_name` | string,最大 255 | 店铺名称 | Unknown | | `app_key` | string,最大 255 | 渠道应用凭据 | Unknown | | `secret_key` | string,最大 255 | 渠道应用密钥 | Unknown | | `access_token` | string,最大 255 | 渠道访问令牌 | Unknown | 逻辑业务键被代码当作 `(channel_type, shop_code)` 使用,但是否存在唯一索引为 **Unknown**。证据:`console/models/AppInfo.php:80-97`。 ### 6.2 `comments_limitation` 来源:`console/models/Limitation.php:8-16`、`console/models/Limitation.php:19-39`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `id` | int | Redis Job 引用的窗口/游标 ID | PK/自增由使用方式推断,DDL Unknown | | `limit_type` | string,最大 255 | 评论窗口:渠道/渠道值/店铺编码;回复游标:`replay_` + 同一编码 | 可空/索引/唯一 Unknown | | `start_time` | number | 评论窗口起点 Unix 时间;回复游标初始化为 0 | 实际列类型/可空 Unknown | | `end_time` | number | 评论窗口终点 Unix 时间;回复流程复用为最后扫描的回复表 ID | 实际列类型/可空 Unknown | | `status` | string,最大 255 | `new`、`success`、`error` | DB 默认值/枚举约束 Unknown | | `created_at` | number | 创建时间及回复游标最新记录排序 | 实际列类型/可空/索引 Unknown | `Limitation::end($status, $message)` 接收 `message` 但只保存 `status`,模型中没有错误消息字段。证据:`console/models/Limitation.php:74-78`。 ### 6.3 `jd_comments` 来源:`console/modules/jd/models/Comments.php:7-16`、`console/modules/jd/models/Comments.php:22-37`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `id` | int | 行标识 | PK/自增 Unknown | | `shop_code` | string,最大 32 | 所属店铺 | FK/索引 Unknown | | `comment_id` | string,最大 64 | 京东评论 ID | 与 `shop_code` 的组合唯一约束 Unknown | | `comment` | text/string | 渠道评论对象 JSON | JSON/TEXT 实际类型 Unknown | | `created_at` | integer | 本系统首次写入时间 | 默认值/可空 Unknown | | `updated_at` | integer | JSON 变化后的更新时间 | 默认值/可空 Unknown | Job 先按 `(shop_code, comment_id)` 查找,再插入或比较 JSON 更新。证据:`console/modules/jd/CommentJob.php:45-75`。 ### 6.4 `jd_comments_reply` 来源:`console/modules/jd/models/CommentsReply.php:7-19`、`console/modules/jd/models/CommentsReply.php:22-45`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `id` | int | 回复扫描顺序、Job 引用 | PK/自增 Unknown | | `shop_code` | string,最大 32 | 所属店铺 | FK/索引 Unknown | | `comment_id` | string,最大 64 | 被回复的京东评论 ID | FK/索引 Unknown | | `reply_id` | string,最大 64 | 可选回复 ID,提交给京东接口 | 可空 Unknown | | `reply` | text/string | 待提交回复正文 | 可空/长度 Unknown | | `result` | text/string | 渠道响应或异常 JSON | 实际列类型 Unknown | | `submit_status` | char(32) | `new/processing/success/error` | **Confirmed**:默认 `new`;其余约束 Unknown | | `retry_count` | smallint | 已执行次数 | **Confirmed**:默认 0;其余约束 Unknown | | `created_at` | integer | 创建时间 | 默认值/可空 Unknown | `submit_status` 与 `retry_count` 的实际增量 DDL 由迁移确认。证据:`console/migrations/m251114_094210_add_column_comment_reply_table.php:15-16`。其余列的建表 DDL 缺失。 ### 6.5 `tmall_comments` 来源:`console/modules/tmall/models/Comments.php:7-17`、`console/modules/tmall/models/Comments.php:24-37`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `id` | int | 行标识 | PK/自增 Unknown | | `shop_code` | string | 所属天猫/淘宝店铺 | FK/长度/索引 Unknown | | `product_id` | PHPDoc 为 int | 模型记录该字段,但当前同步 Job 未赋值 | 实际存在性/类型/可空 Unknown | | `oid` | integer rule;PHPDoc string | 订单明细 ID,列表/详情/回复逻辑关联键 | 模型内部类型证据冲突;实际类型 Unknown | | `comment` | text/string | 评论列表项 JSON | JSON/TEXT 实际类型 Unknown | | `detail` | text/string | 天猫详情接口 `tmall_rate_info` JSON;初始为 `[]` | JSON/TEXT 实际类型 Unknown | | `created_at` | integer | 本系统首次写入时间 | 默认值/可空 Unknown | | `updated_at` | integer | 列表或详情变化后的更新时间 | 默认值/可空 Unknown | 列表 Job 按 `(shop_code, oid)` 查找并写 `comment`,之后按每页 OID 投递详情 Job更新 `detail`。证据:`console/modules/tmall/CommentJob.php:46-84`、`console/modules/tmall/CommenDetailtJob.php:36-53`。 ### 6.6 `tmall_comments_reply` 来源:`console/modules/tmall/models/CommentsReply.php:7-17`、`console/modules/tmall/models/CommentsReply.php:21-42`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `id` | int | 回复扫描顺序、Job 引用 | PK/自增 Unknown | | `shop_code` | string | 所属天猫/淘宝店铺 | FK/长度/索引 Unknown | | `oid` | integer | 被回复的订单明细 ID | FK/索引 Unknown | | `reply` | text/string | 待提交解释/回复正文 | 可空/长度 Unknown | | `result` | text/string | 渠道响应或异常 JSON | 实际列类型 Unknown | | `submit_status` | char(32) | `new/processing/success/error` | **Confirmed**:默认 `new`;其余约束 Unknown | | `retry_count` | smallint | 已执行次数 | **Confirmed**:默认 0;其余约束 Unknown | | `created_at` | integer | 创建时间 | 默认值/可空 Unknown | 增量 DDL 证据:`console/migrations/m251114_094210_add_column_comment_reply_table.php:17-18`。 ### 6.7 `douyin_products` 来源:`console/modules/douyin/models/Products.php:7-15`、`console/modules/douyin/models/Products.php:21-34`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `id` | int | 行标识 | PK/自增 Unknown | | `shop_code` | string | 所属抖音店铺 | FK/长度/索引 Unknown | | `product_id` | integer | 抖音商品 ID | 与 `shop_code` 的组合唯一约束 Unknown | | `offset` | integer | 新商品初始化为 0;当前源码未发现后续读取/更新 | 默认值/可空 Unknown | | `updated_at` | integer | 新商品发现时间 | 默认值/可空 Unknown | 商品 Job 先查询已有商品 ID,再为差集插入记录并初始化 `offset=0`。证据:`console/modules/douyin/CommentJob.php:41-60`。 ### 6.8 `douyin_comments` 来源:`console/modules/douyin/models/Comments.php:7-16`、`console/modules/douyin/models/Comments.php:22-36`。 | 字段 | 代码期望类型/长度 | 当前用途 | 约束证据 | | --- | --- | --- | --- | | `id` | int | 行标识 | rule 声明 `id` 唯一,但 PK/自增 DDL Unknown | | `shop_code` | string | 所属抖音店铺 | FK/长度/索引 Unknown | | `product_id` | integer | 抖音商品 ID | FK/索引 Unknown | | `comment_id` | integer | 抖音评论 ID | 组合唯一约束 Unknown | | `comment` | text/string | 排序顶层键后的评论对象 JSON | JSON/TEXT 实际类型 Unknown | | `created_at` | integer | 本系统首次写入时间 | 默认值/可空 Unknown | | `updated_at` | integer | JSON 变化后的更新时间 | 默认值/可空 Unknown | Job 按 `(shop_code, product_id, comment_id)` 查找并插入/更新。证据:`console/modules/douyin/ProductCommentJob.php:34-69`。 ### 6.9 `user`(非核心业务表) `user` 的字段、类型与约束可由迁移直接确认:`id` 主键,`username` 非空唯一,`auth_key` 非空,`password_hash` 非空,`password_reset_token` 唯一,`email` 非空唯一,`status` 非空默认 10,`created_at/updated_at` 非空;后续增加可空 `verification_token`。证据:`console/migrations/m130524_201442_init.php:15-26`、`console/migrations/m190124_110200_add_verification_token_column_to_user_table.php:7-10`。 该表服务于 Yii Web 模板认证;当前评论 Console 模块没有引用它。 ## 7. 当前数据流 ### 7.1 评论采集数据流 ```mermaid sequenceDiagram participant T as "外部触发者(Unknown)" participant C as "渠道 CommentsController" participant DB as "MySQL" participant Q as "Redis Queue" participant W as "Comment Job" participant X as "渠道 Client / 外部 API" T->>C: 执行 fetch/tmall/tao-bao 命令 C->>DB: 查询 app_info C->>DB: 检查 new 窗口并创建 comments_limitation C->>Q: 投递 limitId Q->>W: Worker 反序列化并执行 Job W->>DB: 按 limitId 读取窗口并反解店铺 loop 渠道分页 W->>X: 查询评论/商品 X-->>W: 渠道响应 W->>DB: 按逻辑键查询后插入或更新原始 JSON opt 天猫详情或抖音商品评论 W->>Q: 投递子任务 end end W->>DB: 将父窗口标记 success/error ``` 三个渠道共用 `app_info + comments_limitation + Redis Queue`,但评论实体分表存储。天猫和抖音是父 Job 再派生子 Job;父 Job 标记 `success` 时没有查询子 Job 完成状态。此处是当前状态语义,不代表端到端采集已完成。证据:`console/modules/tmall/CommentJob.php:81-91`、`console/modules/douyin/CommentJob.php:63-69`。 ### 7.2 回复数据流 ```mermaid sequenceDiagram participant T as "外部触发者(Unknown)" participant C as "ReplyController" participant DB as "MySQL" participant Q as "Redis Queue" participant W as "CommentReplyJob" participant X as "京东虎符或淘宝开放平台" T->>C: 执行 reply/index C->>DB: 读取/创建 replay_ 前缀游标 loop 按 id 升序扫描 new 回复 C->>DB: submit_status = processing C->>Q: 投递 id, limit=5, delay=120 C->>DB: end_time = 回复 id end Q->>W: 执行回复任务 W->>DB: 按 id 读取回复与店铺 W->>X: 提交回复 X-->>W: 响应或异常 W->>DB: 保存 result、retry_count、submit_status opt 未成功且未达上限 W->>Q: 延迟 120 秒再次投递 end ``` 证据:`console/modules/jd/controllers/ReplyController.php:21-59`、`console/modules/jd/CommentReplyJob.php:23-65`、`console/modules/tmall/controllers/ReplyController.php:21-61`、`console/modules/tmall/CommentReplyJob.php:26-66`。 抖音模块当前没有回复表、ReplyController 或 ReplyJob,因此源码可确认的抖音能力只有商品/评论读取,没有评论回复。 ## 8. 数据所有权与内容形态 | 数据 | 当前写入者 | 当前读取者 | 所有权现状 | | --- | --- | --- | --- | | 店铺与渠道授权 | 仓库内未发现管理入口 | 三个渠道 Controller/Job/Client | 来源系统和维护流程 Unknown;本中间件直接消费 | | 同步窗口 | 渠道 CommentsController | 对应 Comment/Detail Job | 本中间件拥有并更新 | | 回复游标 | JD/Tmall ReplyController | 同一 Controller 下次扫描 | 本中间件拥有;复用 `comments_limitation` | | 渠道评论 JSON | 各渠道 Comment Job | 仓库内未发现业务读取者 | 本中间件保存外部数据副本;下游消费者 Unknown | | 天猫评论详情 JSON | `CommenDetailtJob` | 仓库内未发现业务读取者 | 本中间件保存外部数据副本 | | 抖音商品索引 | `DouYin CommentJob` | 同一 Job 用于去重;评论子 Job 直接用任务内 product IDs | 本中间件维护的渠道商品索引 | | 待回复内容 | 仓库内未发现创建者 | ReplyController/ReplyJob | 上游生产者 Unknown;本中间件负责提交与回写状态 | | 回复结果 JSON | ReplyJob | 仓库内未发现业务读取者 | 本中间件保存外部响应/异常副本 | ### 8.1 原始 JSON(Confirmed) - 京东评论对象在顶层 `ksort` 后 `json_encode` 保存到 `jd_comments.comment`。证据:`console/modules/jd/CommentJob.php:45-58`。 - 天猫列表项直接 `json_encode` 保存到 `tmall_comments.comment`;详情接口中的 `tmall_rate_info` 保存到 `detail`。证据:`console/modules/tmall/CommentJob.php:46-60`、`console/modules/tmall/CommenDetailtJob.php:39-47`。 - 抖音评论对象在顶层 `ksort` 后保存到 `douyin_comments.comment`。证据:`console/modules/douyin/ProductCommentJob.php:34-53`。 - 回复 Job 将完整渠道响应或包含异常文本/调用栈的数组 JSON 保存到 `result`。证据:`console/modules/jd/CommentReplyJob.php:31-48`、`console/modules/tmall/CommentReplyJob.php:33-50`。 当前仓库没有 JSON Schema、版本字段、规范化评论实体或内容保留周期定义。字段内容是否含个人信息必须以真实脱敏样本和渠道协议进一步确认。 ### 8.2 密钥与授权信息(Confirmed) - 店铺级 `app_key`、`secret_key`、`access_token` 被设计为 `app_info` 普通字段,并由渠道 Client 直接读取。证据:`console/models/AppInfo.php:10-16`、`console/modules/tmall/Client.php:22-27`、`console/modules/douyin/Client.php:18-23`。 - 京东虎符网关 key/secret 从 Yii params 读取,配置结构位于 `console/config/params.php`,本地覆盖文件位于 `console/config/params-local.php`。证据:`console/config/params.php:5-13`、`console/modules/jd/HuFuClient.php:25-34`、`console/config/main.php:3-8`。 - 当前仓库没有加密字段、密钥管理服务或密钥轮换流程的代码证据。 本文不展示任何真实密钥值。配置文件是否被版本控制、线上是否使用不同注入机制,需要结合实际 Git 仓库与部署系统确认。 ## 9. 状态与一致性语义(现状记录) ### 9.1 评论窗口 - 状态集合只有 `new/success/error`。证据:`console/models/Limitation.php:19-21`。 - 创建入口只阻止同一 `limit_type` 存在 `new` 记录;未见数据库唯一约束。证据:`console/modules/jd/controllers/CommentsController.php:47-53`、`console/modules/tmall/controllers/CommentsController.php:61-67`、`console/modules/douyin/controllers/CommentsController.php:61-67`。 - 京东与天猫都将最近 180 天拆成时间片。京东 Controller fallback 为 30 天;天猫 Controller fallback 为 3 天,但当前副本的 `params-local.php` 经配置合并后覆盖为 30 天。实际部署使用何值仍为 Unknown。抖音使用单个 180 天窗口。证据:`console/modules/jd/controllers/CommentsController.php:56-76`、`console/modules/tmall/controllers/CommentsController.php:70-90`、`console/config/params-local.php:14`、`console/config/main.php:3-8`、`console/modules/douyin/controllers/CommentsController.php:70-77`。 - 父任务捕获异常后直接写窗口 error,没有把原异常重新抛给 Queue;天猫/抖音子任务也在内部捕获错误。证据:`console/modules/jd/CommentJob.php:79-86`、`console/modules/tmall/CommenDetailtJob.php:55-65`、`console/modules/douyin/ProductCommentJob.php:78-88`。 ### 9.2 回复状态 - 状态集合为 `new/processing/success/error`;每次 Job 执行将 `retry_count + 1`,未成功且小于 5 次则延迟 120 秒重投。证据:`console/modules/jd/models/CommentsReply.php:22-25`、`console/modules/jd/CommentReplyJob.php:47-65`。 - Controller 更新 `processing`、投递队列、推进游标是三个独立操作;源码中未见事务。证据:`console/modules/jd/controllers/ReplyController.php:45-58`、`console/modules/tmall/controllers/ReplyController.php:47-60`。 - 回复扫描使用 `id > end_time`,即 `comments_limitation.end_time` 在这里不是时间,而是回复表游标。证据:`console/modules/jd/controllers/ReplyController.php:27-38`、`console/modules/jd/controllers/ReplyController.php:53-58`。 ## 10. 迁移与模式可恢复性 当前迁移历史只能从空库建立 `user` 表,不能建立评论业务所需的八张表: | 迁移 | Confirmed 内容 | 对业务库恢复的意义 | | --- | --- | --- | | `m130524_201442_init` | 创建 `user` | 仅恢复模板账户表 | | `m190124_110200_add_verification_token_column_to_user_table` | 给 `user` 增加验证令牌 | 仅模板账户表 | | `m251114_094210_add_column_comment_reply_table` | 给 JD/Tmall 回复表各加状态、重试列 | 依赖回复表预先存在,不能从空库执行完整业务建库 | 证据:`console/migrations/m130524_201442_init.php:15-31`、`console/migrations/m190124_110200_add_verification_token_column_to_user_table.php:7-15`、`console/migrations/m251114_094210_add_column_comment_reply_table.php:13-31`。 因此以下数据库事实全部为 **Unknown**: - 八张业务表的真实 `SHOW CREATE TABLE`。 - 主键、自增、字符集、collation、存储引擎。 - NOT NULL、默认值、唯一索引、普通索引、外键。 - 线上是否还有当前源码未引用的字段、表、触发器、视图或存储过程。 - 数据量、增长率、重复率、孤儿记录及状态分布。 ## 11. 日志对架构依赖的旁证 以下仅记录脱敏后的现象,不复制完整上下文: | 现象 | 架构含义 | 日志证据 | | --- | --- | --- | | 历史 Tmall Job 的 `limit_type` 格式不能被当前解析逻辑完整拆分 | Redis 中的序列化任务及其数据库窗口与代码版本存在兼容依赖 | `console/runtime/logs/app.log:1`、`console/models/AppInfo.php:80-83` | | 抖店、京东网关出现 DNS 解析失败 | Worker 运行时直接依赖外部网络与渠道域名 | `console/runtime/logs/app.log:5413`、`console/runtime/logs/app.log:10743` | | 回复 Job 按 ID 读取到空记录 | Redis 消息生命周期可能长于对应 MySQL 行 | `console/runtime/logs/app.log:18077` | | 多个 Tmall Job 找不到窗口,异常处理又调用空对象 | Job 与 `comments_limitation` 存在无 FK、无消息快照的强运行时依赖 | `console/runtime/logs/app.log:18190-18191`、`console/runtime/logs/app.log:19772-19773` | | 历史回复 Job 类名/对象序列化相关错误 | Redis Queue 载荷依赖 PHP 类名及可序列化属性 | `console/runtime/logs/app.log:13194` | 这些日志证明依赖关系和历史现象,不足以统计当前故障率,也不能证明问题仍在最新部署中存在。 ## 12. 关键待确认项 在进入重构数据设计或迁移方案前,仍需从运行环境获取以下事实: 1. **数据库真实 DDL**:八张业务表的 `SHOW CREATE TABLE`、索引、外键、字符集,以及是否存在仓库外业务表。 2. **数据剖面**:各表行数、日期范围、状态分布、逻辑键重复数、孤儿记录、JSON 字段大小与样本结构;样本必须脱敏。 3. **数据生产者/消费者**:谁写入 `app_info` 和两张回复表,谁读取三张评论表及回复结果,是否存在另一个 PIM 服务直连这些表。 4. **生产运行拓扑**:Cron/人工触发方式、Queue Worker 命令与数量、Redis/MySQL 实例位置、网络出口、日志采集方式。 5. **渠道账户语义**:`shop_code` 是否跨渠道唯一,天猫与淘宝是否共享店铺记录/回复表,`id_map` 的维护来源。 6. **标识与类型**:Tmall `oid`、抖音 `product_id/comment_id` 的线上真实 MySQL 类型,是否可能超出 PHP/MySQL 有符号整数范围。 7. **原始 JSON 合约**:实际字段、版本变化、敏感数据、下游依赖字段及保留期限。 8. **状态含义**:业务方是否把父任务 `success` 解释为已完成所有详情/商品评论子任务;error 任务实际如何补偿。 9. **密钥治理**:当前 Git 历史、部署注入方式、数据库字段加密情况、密钥轮换记录与日志脱敏策略。 10. **外部协议**:京东虎符中间件接口文档、淘宝/天猫与抖店 API 版本、限流、分页边界、幂等及错误码约定。 ## 13. 现状结论 当前系统的数据与执行核心可以归纳为:**共享店铺配置 + 共享窗口/游标表 + Redis 序列化 Job + 渠道独立原始数据表 + 渠道客户端**。渠道间复用了调度和状态概念,但没有统一评论实体;数据库关系通过字符串编码和业务字段维持,仓库没有 FK 或完整建表迁移证据。Redis 负责异步执行而非主数据保存,MySQL 行 ID 是多数 Job 的运行时前置条件。京东通过虎符中间件接入,天猫/淘宝和抖音直接经内嵌 SDK 接入。 这份现状文档能够确认代码希望如何读写数据以及组件如何调用;不能替代线上 DDL、数据剖面、部署配置和外部接口协议。所有后续数据模型决策都应先补齐第 12 节所列证据。