Files
goauto/docs/02-architecture-and-code-map.md
T
QiuSWandClaude Opus 5 c86e98d0cb feat(#48): make one config work for both development and deployment
The repo already layered file defaults under environment overrides, on
both the backend (settings.yml < GOAUTO_*) and the frontend
(.env.production < process.env). What was missing was a translator for
production: config.yaml only ever existed for the PowerShell launchers,
so a packaged binary read none of it and had no database credentials
either — SYB was inheriting an existing gap, not creating one.

The server now reads config.yaml itself, between settings.yml and the
environment. Lookup is GOAUTO_CONFIG, then ./config.yaml, then beside the
executable, so a packaged binary works wherever it is started. An absent
file is not an error: containers supply everything through the
environment. Scalars are read by YAML type and coerced, so an unquoted
all-digit password cannot take startup down over a quoting detail.

This removed the need for a Read-SybConfig in PowerShell: the launcher
just hands over the path it already knows, rather than reimplementing a
YAML parser.

The server also serves the built frontend when dist is present, which is
what .env.production's empty VUE_APP_BASE_API already assumes. The
history fallback is restricted to non-API GETs, and is not installed at
all without dist, so development 404s stay 404s.

Precedence is mutation-tested: applying the local file after the
environment instead of before makes the layering test fail.

Not verified: the PowerShell change and any Windows deployment — both
need a run on the Windows side.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 09:28:45 +08:00

121 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- gitea-wiki-mirror:start -->
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
wiki_page: Architecture-and-Code-Map
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Architecture-and-Code-Map.-
wiki_revision: a81b23771f859e89d16a8626735f1f3425d063e2
synchronized_at: 2026-08-20T01:27:29Z
<!-- gitea-wiki-mirror:end -->
# 架构与代码地图
## MVP 架构
```text
go-admin-ui
│ REST:PDD商品、规则、任务、任务详情
▼
go-admin Server ───────── 数据库
│ ├─ pdd_product
│ REST:注册/心跳/任务 ├─ collection_rule
│ ├─ collection_task(任务+结果)
▼ └─ dimension/value/color_price/sku 子表
Android Portal/Agent
├─ 注册、心跳与设备串行锁
├─ 领取指定任务或空闲领取未指定任务
├─ 执行任务内的 URL 与规则快照
└─ 提交结构化结果或明确错误
```
## 最小闭环
1. 管理员添加 PDD URL,服务端规范化 URL 并提取唯一 `goods_id`。
2. 管理员创建规则;规则创建后立即可用于创建任务。
3. 管理员从一个 PDD 商品创建任务,可指定设备,也可留空等待空闲设备领取。
4. 任务固化 URL、goods_id 和完整规则快照。
5. Android 串行执行并把结果写回同一条任务;规格与 SKU 写入任务结果子表。
6. 同一事务把 `completed` 结果全量覆盖到 PDD 商品最新档案,把 `completed_partial` 明确采集到的字段和规格安全合并;`failed` 不修改商品。
7. 管理员在任务详情查看原始结构化结果,也可在 PDD 商品页面查看和人工覆盖最新商品资料。
## 关键设计
- `pdd_product.goods_id` 唯一;重复时提示商品已存在,不重复新增。
- 规则没有草稿、发布和版本流程;软删除只阻止创建新任务。
- 已有任务不依赖规则当前状态,始终执行自身 `rule_snapshot`。
- `collection_task` 同时保存任务生命周期和结果摘要,不建立 `collection_result` 主表。
- 同一 PDD 商品最多存在一个 `pending` 或 `running` 任务。
- 指定设备只能由该设备领取;未指定任务由在线空闲设备原子领取。
- 重置在事务中清空原结果,保留 URL、goods_id、规则和设备快照,状态恢复为 `pending`。
- Android 本地互斥与服务端原子领取共同保证单设备串行。
- 原始控件树和截图不持久化;Android Agent 端第一期不使用 OCR/VLM。服务端 SYB 登录验证码识别是唯一例外,见 [#48](https://git.ilapage.cn/OPC/goauto/issues/48)。
## 最小业务数据
| 表 | 必要内容 |
|---|---|
| `agent_device` | 唯一 `install_id`、设备信息、状态、Token 摘要、版本化能力、最后心跳 |
| `pdd_product` | 唯一 `goods_id`、当前 URL、标题、店铺、数字销量/评价、三态状态和通用多维 `specs_json` 最新值 |
| `collection_rule` | `id`、`name`、`content_json`、创建/更新时间、`deleted_at` |
| `collection_task` | 商品/设备外键、五态状态、URL/goods_id/规则快照、租约、结果摘要、错误和时间 |
| `collection_dimension` | 任务、维度键、名称、排序 |
| `collection_dimension_value` | 维度、值、排序 |
| `collection_color_price` | 任务、颜色、该颜色统一使用的整数分价格 |
| `collection_sku` | 任务、整数分价格、可用性、完整性 |
| `collection_sku_value` | SKU 与规格值的多对多关联 |
`collection_task` 的状态仅为 `pending`、`running`、`completed`、`completed_partial`、`failed`。设备身份和心跳表属于 Agent 领取任务的必要基础,不承载 PDD 业务数据。
设备以 JSON 数组保存最后一次注册或心跳上报的版本化能力。v1 任务兼容未上报能力的旧 Agent;v2 任务在创建指定设备任务、获取下一任务、领取和开始四个边界重复校验能力,避免旧 APK 执行未知规则。
数据库使用两个可空 guard 列表达跨数据库唯一约束:活动任务的 `active_slot=1`,运行中设备的 `device_run_slot=1`;终态记录对应列为 `NULL`。复合唯一索引据此保证同商品最多一个活动任务、同设备最多一个运行中任务,同时允许保留任意数量的终态历史任务。状态与 guard 列还有数据库检查约束,必须在同一条状态变更语句中更新。
## 配置分层
配置分三层,下层覆盖上层:
| 层 | 文件 | 是否进 Git | 放什么 |
|---|---|---|---|
| 1 默认值 | `server/config/settings.yml` | **是** | 应用配置和非机密运维参数(`extend.syb` 的 `baseurl` / `pagesize` / `maxmatches` / `ocrurl`) |
| 2 部署本地值 | `config.yaml`(仓库根) | **否**(`.gitignore`) | 数据库、端口、顺云宝凭据 |
| 3 覆盖值 | `GOAUTO_*` 环境变量 | — | 服务、容器和 CI 用;优先级最高 |
`[必须]` **凭据只允许出现在第 2、3 层。** `settings.yml` 被 Git 跟踪,任何时候都不能往里写账号密码。
服务端自己读第 2 层(`config/local.go` 的 `ApplyLocalConfig`),查找顺序为 `GOAUTO_CONFIG` 指定的路径 → 当前目录 `./config.yaml` → 可执行文件同级目录。**找不到不是错误**:容器场景只用环境变量,本来就没有这个文件。回调注册在 `ApplyEnvironment` 之前,环境变量因此始终有最后决定权。
`[必须]` 第 2 层的标量按 YAML 原始类型读取后统一转字符串。纯数字密码不加引号会被 YAML 读成整数,这里不能因此启动失败——但仍应加引号,否则前导零会丢。
开发启动脚本把 `config.yaml` 的路径通过 `GOAUTO_CONFIG` 传给服务端,不在 PowerShell 里重复解析 YAML。
## 前端伺服
`web/.env.production` 的 `VUE_APP_BASE_API` 为空,即生产构建发的是相对请求,**前端与接口必须同源**。服务端在 `dist/index.html` 存在时伺服构建产物并为 history 路由回退到 `index.html`(`app/admin/router/spa.go`)。
`[必须]` 回退只对非接口路径的 GET 生效。给写错的接口路径回 200 + HTML,客户端看到的会是 JSON 解析错误而不是 404。
`[必须]` `dist` 不存在时不注册 `NoRoute`。开发环境前端跑在 vite 独立端口上,装了回退会把每个真 404 变成一张 HTML 页。
## 已建立的工程入口
| 功能 | 当前目录 |
|---|---|
| 服务端基线 | `server/`(go-admin v2.3.0) |
| 最小闭环数据模型 | `server/app/goauto/models/` |
| 数据迁移与约束测试 | `server/app/goauto/migrations/` |
| go-admin 迁移注册 | `server/cmd/migrate/migration/version-local/1786700000000_goauto_schema.go` |
| 设备注册、认证、停用与吊销 | `server/app/goauto/device/` |
| PDD 商品与规则 | `server/app/goauto/product/`、`server/app/goauto/rule/` |
| PDD 商品档案增量迁移 | `server/cmd/migrate/migration/version-local/1786700500000_pdd_product_archive.go` |
| 虾皮商品档案与规格映射 | `server/app/goauto/shopeeproduct/`(服务端 API 已实现;Admin 页面待实现) |
| 虾皮商品档案增量迁移 | `server/cmd/migrate/migration/version-local/1786700600000_shopee_product_archive.go` |
| SYB 商品明细导入、解析与虾皮档案合并 | `server/app/goauto/sybimport/`(解析、幂等落库、同步编排、导入端点、管理端 API 和 Admin 页面均已实现) |
| 顺云宝(SYB)ERP HTTP 客户端与登录会话 | `server/app/goauto/sybclient/`(登录、OCR 验证码、会话缓存、列表与明细读取;见 [SYB-ERP-Interface-Contract](SYB-ERP-Interface-Contract)) |
| SYB 商品明细增量迁移 | `server/cmd/migrate/migration/version-local/1786700700000_syb_product_import.go` |
| 任务领取、结果、重置与删除 | `server/app/goauto/task/` |
| 管理端基线 | `web/`(go-admin-ui v3.0.0) |
| 管理端闭环页面 | `web/src/views/goauto/` |
| Android Agent 基线 | `android/app/src/main/java/cn/ilapage/goauto/agent/` |
| Android 无障碍规则执行 | `android/app/src/main/java/cn/ilapage/goauto/agent/automation/` |
| 三端统一验证 | `scripts/verify.ps1` |
以上入口均已落地;新增 API、表或执行动作时必须同步更新本代码地图与共享契约。