docs: establish ShopHelm harness coding baseline

This commit is contained in:
QiuSW
2026-07-11 17:02:30 +08:00
parent 51fc27f5c3
commit e62b691b59
25 changed files with 2916 additions and 2 deletions
+12
View File
@@ -0,0 +1,12 @@
# Keep repository text files on LF so Windows tools do not create full-file
# line-ending diffs. PowerShell accepts LF, and shell scripts require it.
* text=auto eol=lf
# Binary assets must never receive text conversion.
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
*.zip binary
+110
View File
@@ -0,0 +1,110 @@
# AGENTS.md
> ShopHelm 的仓库级 AI coding agent 入口。进入仓库后先读本文,再读 [`docs/00-ai-start-here.md`](docs/00-ai-start-here.md)。
## 项目定位
ShopHelm(店小航)是面向小团队跨境卖家的 Windows 本地运营工作台。当前只交付三条业务主线:
1. 多店铺运营台。
2. 商品运营助手,其中包含单张商品图叠加预览和导出。
3. 客服话术与跟进助手。
项目采用 Go + Gio、SQLite 和外部 Chrome。它不是完整 ERP,不是浏览器“防关联”产品,也不以全自动 RPA 为核心。
## 事实优先级
发生冲突时按以下顺序处理:
1. 用户在当前会话中的最新明确指令。
2. 本文件的仓库级执行与安全规则。
3. [`docs/02-requirements.md`](docs/02-requirements.md) 的产品范围和验收标准。
4. [`docs/03-tech-stack.md`](docs/03-tech-stack.md)、[`docs/04-architecture.md`](docs/04-architecture.md)、[`docs/api.md`](docs/api.md) 和 [`docs/routes.md`](docs/routes.md) 的技术事实。
5. [`docs/06-tasks.md`](docs/06-tasks.md) 的任务拆分。
6. [`docs/current-state.md`](docs/current-state.md) 和代码、测试所反映的当前现实。
若计划文档与可运行代码冲突,先在 `current-state.md` 记录差异,再确认应修文档还是修实现;不得静默选择一边。
## 必读顺序
每次开始编码前按顺序读取:
1. `AGENTS.md`
2. `docs/00-ai-start-here.md`
3. `docs/01-vision.md`
4. `docs/02-requirements.md`
5. `docs/03-tech-stack.md`
6. `docs/04-architecture.md`
7. `docs/05-coding-rules.md`
8. `docs/api.md` 和 `docs/routes.md` 中与任务相关的部分
9. `docs/06-tasks.md`
10. `progress.md`
11. `docs/current-state.md`
## 固定开工流程
1. 用 `pwd` 确认仓库根目录。
2. 读取 `progress.md` 和 `docs/current-state.md`,恢复当前事实。
3. 若存在 `.git`,运行 `git status --short --branch` 和 `git log --oneline -5`;若尚未初始化 Git,以 `current-state.md` 为准。
4. 若存在 `go.mod`,运行 `./init.ps1`;若不存在,只允许领取负责初始化项目的 T-001。
5. 基线失败时先修基线,不叠加新功能。
6. 从 `docs/06-tasks.md` 领取第一个依赖均为 `DONE` 的 `TODO` 任务。
## 任务纪律
- 单 agent 模式下一轮只做一个任务。
- 开始前把任务改为 `DOING`;同一时间最多一个 `DOING`。
- 只修改完成该任务所需的代码和文档,不顺手实现 Backlog。
- 验收和验证全部通过后才能改为 `DONE`。
- 把真实命令、结果、阻塞和关键决策追加到 `progress.md`,并覆盖更新 `docs/current-state.md`。
- 会话结束前执行 [`docs/clean-state-checklist.md`](docs/clean-state-checklist.md)。
- 多 agent 并发时切换到 [`docs/tasks/README.md`](docs/tasks/README.md) 的一任务一文件模式。
## 业务与安全硬边界
- 密码、Cookie、token、代理密码不得明文进入 SQLite、日志、测试夹具或文档。
- MVP 不保存平台密码;依靠独立 Chrome profile 保留用户登录会话。
- `user-data-dir` 只表示会话和缓存隔离,不得宣传或实现“防关联”“反指纹”能力。
- Chrome 必须通过 `exec.Command` 参数启动,不拼接 shell 命令。
- 删除或归档店铺时不得自动删除对应 profile 目录。
- 图片导出默认写入独立目录,不覆盖原图;覆盖必须由用户明确选择并二次确认。
- 不绕过验证码、平台风控、权限校验、限流或反爬机制。
- 不实现刷单、刷评、批量未确认发消息、批量爬取或自动修改平台数据。
- 新增任何会改变第三方平台数据的自动化前,必须先补需求、合规边界、dry-run、人工确认、审计和失败恢复设计。
## 工程规则
- 标识符、包名和文件名使用英文;产品界面和项目文档默认使用简体中文。
- 遵守 `internal/domain -> internal/application -> internal/infrastructure/platform -> internal/ui` 的依赖方向。
- Gio 的 frame/layout 回调中不得做数据库、网络、文件或进程阻塞操作。
- UI 控件状态必须持久化在页面状态结构中,不得在每帧临时创建导致状态丢失。
- 数据库 schema 只能通过追加 migration 演进,不得修改已经发布的 migration。
- 文件和数据库写入需处理部分失败;备份、恢复和图片导出使用临时文件加原子替换。
- 新增依赖前先更新 `docs/03-tech-stack.md`,说明用途、许可证、替代方案和锁定版本。
- 默认优先标准库和现有项目组件,不为未来可能需求提前抽象。
## 文档同步规则
| 变化 | 必须同步 |
| --- | --- |
| 产品范围或验收变化 | `02-requirements.md`、`06-tasks.md` |
| 依赖、Go/Gio 版本或命令变化 | `03-tech-stack.md`、`00-ai-start-here.md`、`current-state.md`、`init.*` |
| 模块边界或数据模型变化 | `04-architecture.md`、`api.md`、相关 migration 和任务 |
| 页面或导航变化 | `routes.md`、相关需求和任务 |
| 代码现实或下一任务变化 | `current-state.md`、`06-tasks.md`、`progress.md` |
## 对话约定
- 用户输入 `grill me:` 或 `grill:` 时,执行反方评审:先查事实,指出需求、技术、商业和合规上的薄弱点,只讨论,不修改代码或文件,除非用户同时明确要求落地修改。
## 最低验证
代码初始化后,任务结束前至少运行:
```powershell
go test ./...
go vet ./...
go build -o build/shophelm.exe ./cmd/shophelm
```
涉及 Chrome、图片导出、备份恢复或 Gio 交互时,还必须执行任务中写明的手工 smoke,并在 `progress.md` 记录输入、观察结果和环境。
+5
View File
@@ -0,0 +1,5 @@
# CLAUDE.md
> Claude Code 的仓库级薄入口。进入本仓库后先读 [`AGENTS.md`](AGENTS.md)。
ShopHelm 的权威 agent 规则、产品边界、阅读顺序和验证要求统一维护在 `AGENTS.md`。本文不重复任务流程,避免规则漂移。
+65 -2
View File
@@ -1,3 +1,66 @@
# shop_helm # 店小航 ShopHelm
外贸电商助手 ShopHelm 是面向小团队跨境卖家的 Windows 本地运营工作台。首发版本按以下顺序交付:
1. 多店铺运营台:管理店铺、独立 Chrome profile、快捷入口和普通代理。
2. 商品运营助手:管理商品草稿、文案模板、价格、图片素材,并完成单张图片叠加预览与导出。
3. 客服助手:管理多语言话术、买家问题和跟进提醒。
产品不以“防关联”或全自动 RPA 为卖点。不同 `user-data-dir` 只用于隔离本地登录会话;平台操作优先采用官方 API、CSV/XLSX 和人工确认流程。
## 当前状态
- Harness Coding 文档已初始化。
- Git 仓库已初始化并配置 `origin`;生产代码和 `go.mod` 尚未初始化。
- 本机已安装 `go1.23.0 windows/amd64`;第一项开发任务会验证 Gio 兼容性并锁定依赖版本。
- 下一个任务是 [`T-001`](docs/06-tasks.md):初始化 Go module 和 Go + Gio 最小可运行骨架。
当前代码现实以 [`docs/current-state.md`](docs/current-state.md) 为准。
## Agent 入口
AI coding agent 进入仓库后按此顺序读取:
1. [`AGENTS.md`](AGENTS.md)
2. [`docs/00-ai-start-here.md`](docs/00-ai-start-here.md)
3. [`docs/05-coding-rules.md`](docs/05-coding-rules.md)
4. [`docs/06-tasks.md`](docs/06-tasks.md)
5. [`progress.md`](progress.md)
6. [`docs/current-state.md`](docs/current-state.md)
完整文档索引见 [`docs/README.md`](docs/README.md)。
## 标准命令
T-001 完成后,Windows PowerShell 使用:
```powershell
./init.ps1
```
脚本执行 `go mod download` 和 `go test ./...`,然后打印开发启动命令。当前没有 `go.mod`,脚本会主动失败并指向 T-001,这是预期状态。
常用命令:
```powershell
go run ./cmd/shophelm
go test ./...
go vet ./...
go build -o build/shophelm.exe ./cmd/shophelm
```
## 文档分工
| 文件 | 唯一职责 |
| --- | --- |
| [`docs/01-vision.md`](docs/01-vision.md) | 产品为什么做、服务谁、什么不做 |
| [`docs/02-requirements.md`](docs/02-requirements.md) | 用户需求、优先级和可观察验收标准 |
| [`docs/03-tech-stack.md`](docs/03-tech-stack.md) | 技术选型、版本策略和运行命令 |
| [`docs/04-architecture.md`](docs/04-architecture.md) | 模块边界、数据模型和关键数据流 |
| [`docs/api.md`](docs/api.md) | 本地 Go 服务、事件和错误合约 |
| [`docs/routes.md`](docs/routes.md) | Gio 页面、导航状态和组件归属 |
| [`docs/06-tasks.md`](docs/06-tasks.md) | 单 agent 任务看板 |
| [`progress.md`](progress.md) | 只追加的执行与验证证据 |
| [`docs/current-state.md`](docs/current-state.md) | 可覆盖的仓库当前快照 |
核心原则:需求和架构先成为仓库内事实,代码再按任务逐步实现;没有验证证据的任务不能标记完成。
+131
View File
@@ -0,0 +1,131 @@
# AI 开发入口
> ShopHelm coding agent 的固定入口。硬性实现规则见 [`05-coding-rules.md`](05-coding-rules.md)。
## 一句话定位
ShopHelm 是面向小团队跨境卖家的 Windows 本地运营工作台。
首发闭环是:管理店铺和独立 Chrome profile,维护商品草稿与简单图片合成,复用多语言客服话术并记录跟进。
## 必读顺序
每次写代码前完整读取:
1. [`../AGENTS.md`](../AGENTS.md)
2. [`01-vision.md`](01-vision.md)
3. [`02-requirements.md`](02-requirements.md)
4. [`03-tech-stack.md`](03-tech-stack.md)
5. [`04-architecture.md`](04-architecture.md)
6. [`05-coding-rules.md`](05-coding-rules.md)
7. 与任务相关的 [`api.md`](api.md) 和 [`routes.md`](routes.md)
8. [`06-tasks.md`](06-tasks.md)
9. [`../progress.md`](../progress.md)
10. [`current-state.md`](current-state.md)
## 固定开工流程
1. `pwd`,确认根目录是 `D:\OPC\shop_helm`。
2. 读取 `progress.md` 和 `current-state.md`。
3. 若有 `.git`,运行 `git status --short --branch` 和 `git log --oneline -5`。
4. 若有 `go.mod`,运行 `./init.ps1`;若没有,只领取 T-001。
5. 若基线测试或构建失败,先记录并修复基线。
6. 在 `06-tasks.md` 中领取第一个 `TODO` 且依赖均为 `DONE` 的任务。
7. 把任务改为 `DOING` 后再编辑代码。
## 当前阶段
当前处于“文档基线完成、生产代码尚未初始化”阶段。
实施顺序:
1. Phase 0:Go、Gio、SQLite 工程地基。
2. Phase 1:先验证 Gio 表格/表单、Chrome profile 启动、图片预览与导出三个高风险点。
3. Phase 2:业务阶段一,多店铺运营台。
4. Phase 3:业务阶段四,商品运营助手。
5. Phase 4:业务阶段五,客服助手。
6. Phase 5:稳定性、完整验收和 Windows 打包。
## 领取和完成规则
- 一轮只领取一个任务。
- 依赖未完成不跳步。
- `DOING` 同一时间最多一个。
- 验收必须使用任务中列出的命令和可观察步骤。
- 只有代码、测试、文档和手工 smoke 全部符合时才能标 `DONE`。
- 完成后追加 `progress.md`,覆盖更新 `current-state.md`,再执行 `clean-state-checklist.md`。
- 多 agent 并发时改用 [`tasks/README.md`](tasks/README.md),执行记录写入各自任务文件。
## 首发范围
首发必须交付:
- 今日工作台。
- 店铺 CRUD、筛选、快捷入口、独立 Chrome profile、普通无认证代理、运行状态、备份恢复。
- 商品草稿、文案模板、价格计算、检查清单、CSV/XLSX、图片素材。
- 一张底图加一张叠加图的预览、位置/缩放/透明度调整及 PNG/JPG 导出。
- 多语言客服话术、一键复制、买家问题与跟进提醒。
首发明确不做:
- 平台账号密码保存。
- 代理账号密码自动注入。
- 自动登录、验证码处理、批量发消息、批量改商品。
- 反指纹、防关联、绕过风控或批量爬取。
- 完整订单、库存、财务、广告和团队权限系统。
- Photoshop 式多图层、滤镜、抠图和复杂排版。
## 事实来源
业务和技术事实只信:
- 本仓库 `docs/` 中的权威文档。
- 已应用的 SQLite migration。
- `go.mod` / `go.sum` 中已锁定的依赖。
- 当前代码、测试和真实运行结果。
- 第三方平台的官方文档;使用前需在任务中记录具体来源和访问日期。
不把聊天记忆、旧导出文件、浏览器页面猜测、临时实验或未引用草稿当作当前事实。
## 常见任务入口
做 Gio 页面:
1. 查 `02-requirements.md` 的需求 ID。
2. 查 `routes.md` 的页面职责。
3. 查 `api.md` 的服务调用。
4. 遵守 `04-architecture.md` 的 UI 异步边界。
做 SQLite:
1. 查 `04-architecture.md` 的数据模型。
2. 新增不可变 migration。
3. 同步 repository、`api.md` 和相关测试。
做 Chrome 启动:
1. 查 `api.md` 的 `BrowserLauncher` 合约。
2. 只使用外部 Chrome 和独立 profile。
3. 检查 profile 占用、启动参数、进程状态和错误映射。
做图片:
1. Gio 只负责交互和预览。
2. 正式导出走独立 CPU 合成管线。
3. 校验预览与导出几何参数一致,且不覆盖原图。
## 标准命令
T-001 完成前,`./init.ps1` 会因缺少 `go.mod` 主动失败。
T-001 完成后:
```powershell
./init.ps1
go run ./cmd/shophelm
go test ./...
go vet ./...
go build -o build/shophelm.exe ./cmd/shophelm
```
改动 Gio 交互、Chrome 进程、备份恢复或图片导出时,还需执行对应任务的 Windows 手工 smoke。
+59
View File
@@ -0,0 +1,59 @@
# 项目愿景
## 一、核心目标
店小航 ShopHelm 要解决跨境卖家在多个店铺之间反复找账号、找浏览器环境、找商品资料和找客服话术的问题。
> 让小团队运营人员从一个本地工作台进入正确店铺环境,完成商品资料整理和客服跟进,减少混店、漏事和重复劳动。
它不是完整 ERP,也不是规避平台风控的浏览器工具,而是围绕日常运营动作组织信息和入口的桌面工作台。
## 二、目标用户
- **店铺运营人员**:同时维护多个平台或站点,需要快速进入正确店铺、整理商品并处理买家问题。
- **小团队负责人**:需要知道店铺负责人、最近维护状态、待处理事项,并沉淀可交接的模板。
- **个人跨境卖家**:希望用一个本地、低部署成本的工具替代零散表格、书签和临时文件夹。
首发不面向大型企业复杂组织,也不提供多人实时协作。
## 三、产品原则
- **每日工作优先**:第一屏直接呈现近期店铺、今日待办、待优化商品和客服跟进。
- **人工可控优先**:影响平台数据或用户文件的动作必须可见、可确认、可追踪。
- **本地优先**:首发无需云账号,业务数据保存在用户电脑。
- **平台合规优先**:官方 API 高于文件导入导出,文件流程高于辅助 RPA。
- **资料沉淀优先**:店铺、商品、图片和话术使用结构化关联,支持交接和复用。
- **小步交付**:按店铺、商品、客服顺序完成闭环,不同时铺开订单、库存、财务和广告。
- **原始数据安全**:不明文保存密码,不自动删除 profile,不覆盖原始图片。
## 四、核心价值
| 价值 | 用户得到的结果 |
| --- | --- |
| 找对店 | 从店铺记录直接打开对应的独立 Chrome profile 和后台入口 |
| 少重复 | 商品文案、图片素材、价格计算和客服话术可以复用 |
| 不漏事 | 今日工作台聚合店铺待办、商品待优化和客服跟进 |
| 可交接 | 店铺负责人、模板、备注和处理状态集中保存 |
| 可控 | 自动化保持辅助性质,关键操作由用户确认 |
## 五、成功标准
首发成功不以功能数量衡量,而以用户是否愿意每天打开衡量:
- 至少 20 个店铺可以稳定管理和分别打开。
- 用户无需在文件夹和书签中寻找 profile 与后台链接。
- 商品草稿、模板和图片素材能够按店铺归档。
- 常见 Logo、角标或水印叠加无需打开复杂设计软件。
- 客服人员能快速找到并复制合适话术,按时处理跟进。
- 重启应用后业务数据、状态和关联不丢失。
## 六、非目标
- 不做浏览器指纹伪装、环境伪装或“防关联”承诺。
- 不做自动绕验证码、自动批量登录、刷单、刷评或未经确认的批量发送。
- 不做大规模抓取 Shopee、Lazada、Amazon 等平台页面。
- 不做完整订单中心、WMS、财务结算、广告投放和利润分析。
- 不做 Photoshop 级图片编辑器。
- 不在首发提供云同步、多人权限和移动端。
具体范围与验收标准见 [`02-requirements.md`](02-requirements.md)。
+215
View File
@@ -0,0 +1,215 @@
# 需求
> 本文只定义产品需要什么以及如何验收。技术实现和字段存储方式见 [`04-architecture.md`](04-architecture.md)。
## 一、业务现状
| 项 | 当前事实 |
| --- | --- |
| 用户 | 个人卖家或小团队运营人员,同时维护多个跨境店铺 |
| 常见痛点 | 店铺入口、Chrome 会话、商品资料、图片、话术和待办分散 |
| 当前项目 | 空项目,尚无生产代码和历史数据 |
| 首发平台 | Windows 10/11 x64 桌面 |
| 首发平台业务 | 字段支持多平台,功能和示例优先覆盖 Shopee |
| 数据来源 | 用户手工录入、本地文件、CSV/XLSX;平台官方 API 后置 |
| 网络边界 | 核心数据管理离线可用;打开 Chrome 或显式代理检测时才联网 |
## 二、用户角色
- **店铺运营**:维护店铺、商品、图片、客服记录和个人待办。
- **团队负责人**:在同一台电脑查看负责人、状态、模板和处理记录。
- **未登录用户**:首发没有 ShopHelm 云账号,启动本机应用即可使用。
首发没有应用内角色权限。平台后台权限仍由 Chrome 中的平台账号决定。
## 三、发布顺序
1. 业务阶段一:多店铺运营台。
2. 业务阶段四:商品运营助手。
3. 业务阶段五:客服助手。
工程上先完成地基和高风险原型,再依上述业务顺序交付。
## 四、首发功能需求
### 4.1 今日工作台
| ID | 需求 | 优先级 |
| --- | --- | --- |
| DASH-001 | 展示最近打开的店铺,并可直接再次打开 | P0 |
| DASH-002 | 展示今天到期和已逾期的店铺待办、客服跟进 | P0 |
| DASH-003 | 展示待上架、需优化的商品和最近图片导出 | P0 |
| DASH-004 | 提供新增店铺、商品、客服跟进和图片预览入口 | P0 |
### 4.2 多店铺运营台
| ID | 需求 | 优先级 |
| --- | --- | --- |
| STORE-001 | 新增、查看、编辑、归档店铺 | P0 |
| STORE-002 | 维护平台、国家/站点、店铺名、账号标识、负责人、标签、状态和备注 | P0 |
| STORE-003 | 按关键词、平台、国家、负责人、标签和状态筛选 | P0 |
| STORE-004 | 每个店铺绑定唯一 Chrome profile 目录和起始地址 | P0 |
| STORE-005 | 一键用绑定 profile 打开外部 Chrome,并更新最后打开时间 | P0 |
| STORE-006 | 显示未运行、启动中、运行中、已退出和启动失败状态 | P0 |
| STORE-007 | profile 已被占用时阻止重复启动,并给出可操作提示 | P0 |
| STORE-008 | 维护订单、商品、营销、客服、数据等快捷链接,并用当前店铺 profile 打开 | P0 |
| STORE-009 | 可选配置 HTTP/HTTPS/SOCKS 普通无认证代理 | P0 |
| STORE-010 | 维护店铺待办及到期时间 | P0 |
| STORE-011 | 备份并恢复本地业务数据和配置引用 | P0 |
| STORE-012 | 批量打开、分组视图和快捷键 | P2 |
归档店铺不得自动删除 Chrome profile。首发不支持需要用户名/密码认证的代理自动注入。
### 4.3 商品运营助手
| ID | 需求 | 优先级 |
| --- | --- | --- |
| PROD-001 | 新增、查看、编辑、归档商品草稿 | P0 |
| PROD-002 | 维护店铺、商品名、SKU、成本、售价、币种、库存、链接、状态和备注 | P0 |
| PROD-003 | 管理标题模板和描述模板 | P0 |
| PROD-004 | 维护上架检查项,并显示未完成项 | P0 |
| PROD-005 | 根据明确输入计算收入、成本和基础利润参考,不把结果称为财务利润 | P0 |
| PROD-006 | CSV 和 XLSX 导入/导出商品草稿,导入前显示校验结果 | P0 |
| PROD-007 | 关联主图、详情图、Logo、角标和水印等本地图片素材 | P0 |
| IMG-001 | 选择一张底图和一张叠加图进行预览 | P0 |
| IMG-002 | 调整叠加图位置、缩放和透明度,并可恢复默认值 | P0 |
| IMG-003 | 选择输出尺寸与 PNG/JPG 格式后导出合成图 | P0 |
| IMG-004 | 导出记录关联回商品,且默认不覆盖任何输入文件 | P0 |
| PROD-008 | 多语言草稿、关键词库和标题候选 | P1 |
| IMG-005 | 保存图片模板、批量套用和批量导出 | P2 |
首发图片工具只支持“单底图 + 单叠加图”。旋转、混合模式、滤镜、抠图、文字排版和任意多图层不在范围内。
### 4.4 客服助手
| ID | 需求 | 优先级 |
| --- | --- | --- |
| CS-001 | 新增、查看、编辑、归档客服话术 | P0 |
| CS-002 | 按售前、物流、退款、退货、催发货、评价、缺货、尺码、售后等分类 | P0 |
| CS-003 | 维护语言、标题、正文和使用次数 | P0 |
| CS-004 | 一键复制话术正文,并给出成功或失败反馈 | P0 |
| CS-005 | 记录买家问题、店铺、订单标识、问题类型、状态、下次跟进时间和备注 | P0 |
| CS-006 | 按店铺、状态和到期时间筛选跟进记录 | P0 |
| CS-007 | 支持变量预览、多语言回复草稿和超时提醒 | P1 |
| CS-008 | 对接官方聊天 API 或辅助打开聊天页 | P2 |
首发不读取真实聊天消息,也不自动发送回复。
### 4.5 设置和数据安全
| ID | 需求 | 优先级 |
| --- | --- | --- |
| SET-001 | 配置 Chrome 可执行文件、profile 根目录和默认图片导出目录 | P0 |
| SET-002 | 配置默认货币、显示语言和日志目录 | P0 |
| SEC-001 | SQLite、日志、导出文件和测试数据中不出现平台明文密码 | P0 |
| SEC-002 | 所有外部文件路径在使用前校验存在性、类型和可读写权限 | P0 |
| SEC-003 | 删除、恢复、覆盖和批量动作必须有明确影响说明和确认 | P0 |
| AUDIT-001 | 记录店铺打开、备份恢复、导入和图片导出结果,不记录秘密 | P1 |
## 五、核心用户流程
### 5.1 打开正确店铺
1. 用户在店铺列表搜索或筛选目标店铺。
2. 用户点击打开或某个快捷入口。
3. 系统检查 Chrome 路径、profile 和代理配置。
4. 若 profile 已占用,系统阻止重复启动并说明原因。
5. 若可启动,外部 Chrome 使用该店铺 profile 打开目标地址。
6. 系统显示运行状态并记录最后打开时间。
### 5.2 整理商品并导出主图
1. 用户创建或导入商品草稿。
2. 用户补充价格、SKU、模板和检查项。
3. 用户关联底图与 Logo/角标/水印。
4. 用户在预览中调整位置、缩放和透明度。
5. 用户选择输出尺寸和格式。
6. 系统导出新文件并将记录关联到商品,原图保持不变。
### 5.3 复用话术并跟进
1. 用户按分类和语言找到话术。
2. 用户一键复制并在平台页面手工发送。
3. 用户记录买家问题和下次跟进时间。
4. 到期记录出现在今日工作台。
5. 用户更新处理状态直至解决。
## 六、首发验收标准
### 6.1 店铺
- 可创建至少 20 条店铺记录,重启应用后仍存在。
- 两个店铺使用不同 profile 目录启动 Chrome,登录会话和缓存目录不相同。
- 同一 profile 运行中再次打开时,不启动第二个实例,并显示占用提示。
- 快捷入口使用绑定 profile 打开配置的 URL。
- 配置无认证代理后,Chrome 启动参数包含对应代理;无代理时不附加代理参数。
- 归档店铺后默认列表不显示,但 profile 目录仍存在且可恢复记录。
### 6.2 商品和图片
- 可手工创建商品,也可从有效 CSV/XLSX 导入;无效行会列出行号和原因,不部分静默导入。
- 价格计算结果能追溯到全部输入,不使用隐含汇率或费率。
- 图片预览和导出使用同一组几何参数;基准测试图中叠加层位置误差不超过 1 个输出像素。
- PNG 保留预期透明度;JPG 使用明确背景色。
- 导出到独立文件,输入图片校验和与内容不变。
- 退出并重进应用后,图片素材和导出记录仍关联到原商品。
### 6.3 客服
- 可按分类和语言维护话术,重启后不丢失。
- 点击复制后,系统剪贴板内容与话术正文一致。
- 可创建关联店铺的跟进记录,并在到期日出现在工作台。
- 任何流程都不会自动向平台发送消息。
### 6.4 数据和恢复
- 在包含店铺、商品、图片引用、话术和跟进的数据库上完成备份。
- 在测试目录中恢复备份后,记录数量、关联和设置与备份时一致。
- 备份或恢复失败时保留原数据库,不留下被应用当成有效数据的半成品。
- 对 SQLite 文件和日志进行文本检查,不含测试输入的明文密码标记。
## 七、非功能要求
| 维度 | 要求 |
| --- | --- |
| 平台 | 首发支持 Windows 10/11 x64 |
| 可用性 | 无云账号、无平台 API 时,除外部 Chrome 操作外核心 CRUD 可离线使用 |
| 数据一致性 | 外键启用;多表写入使用事务;所有时间按 UTC 存储、按本地时区显示 |
| 性能 | 500 条店铺或 5000 条商品数据下,筛选和翻页不冻结 UI;阻塞操作不得在 Gio frame 中执行 |
| 可恢复性 | 应用异常退出后数据库可再次打开;运行状态可从真实进程重新核对 |
| 可访问性 | 关键动作有文字或标准图标与 tooltip;状态不只依赖颜色表达 |
| 可诊断性 | 用户可看到可行动的错误;日志包含错误码和上下文,但不含秘密 |
| 语言 | 首发界面为简体中文;业务内容允许多语言 |
## 八、范围决策
| 问题 | 当前决策 |
| --- | --- |
| 产品名 | 店小航 ShopHelm |
| 应用形态 | Windows 本地桌面应用 |
| UI | Go + Gio |
| 数据 | 本地 SQLite 和本地文件引用 |
| 应用账号 | 首发不需要 |
| 平台密码 | 首发不保存 |
| 代理 | 首发只支持无认证代理 |
| 平台能力 | 字段支持多平台,优先按 Shopee 场景设计 |
| RPA | 不进入首发主链路 |
| 图片 | 首发单底图、单叠加图、单张导出 |
## 九、后续范围
- 官方 Shopee Open Platform API。
- 订单、库存、利润和广告 ROI。
- 图片模板与批量导出。
- AI 标题、描述、图片和客服建议。
- 团队账号、权限、同步与审计。
- 在平台允许范围内、人工确认的辅助 RPA。
## 十、待确认但不阻塞地基
- 公开发布前采用哪个仍受支持的 Go 版本。
- 默认支持哪些 Shopee 站点和后台快捷链接种子。
- 价格计算器首发需要哪些用户显式输入的费率。
- 首发安装包采用 ZIP 便携版还是安装器。
这些问题必须在对应实现任务前定稿,不允许 agent 在业务代码中静默猜测。
+101
View File
@@ -0,0 +1,101 @@
# 技术栈(Tech Stack)
> 本文是“用什么”的权威来源。系统如何分层见 [`04-architecture.md`](04-architecture.md)。
## 一、技术栈一览
| 维度 | 选型 | 状态 | 理由 |
| --- | --- | --- | --- |
| 操作系统 | Windows 10/11 x64 | 已定 | 首发围绕本地 Chrome、profile 和 Windows 文件系统 |
| 语言 | Go;本机基线 `go1.23.0` | 临时已定 | 用户选定 Go;T-001 验证 Gio 兼容性,公开发布前升级到受支持版本 |
| 桌面 UI | Gio `gioui.org` | 已定,版本待 T-001 锁定 | 单语言、本地可控;接受自行封装管理台组件 |
| UI 组件 | Gio Material + 项目内组件 | 已定 | 只建设 ShopHelm 需要的表格、表单、弹窗和预览画布 |
| 扩展组件 | `gioui.org/x/component` | 待原型确认 | API 稳定性较弱;只有 T-101 证明有价值后才引入并锁 commit |
| 状态管理 | 页面状态结构体 + application event channel | 已定 | 匹配 Gio immediate-mode,避免额外状态框架 |
| 持久化 | SQLite + `database/sql` | 已定 | 本地单用户、备份简单 |
| SQLite 驱动 | `modernc.org/sqlite` | 已定 | 避免 Windows CGO 工具链依赖 |
| Migration | `embed` 嵌入顺序 SQL + `schema_migrations` | 已定 | 依赖少、版本可审计、离线可用 |
| 图片预览 | Gio 画布,必要时 CPU 生成预览帧 | 已定 | 负责交互反馈,不作为正式导出结果 |
| 图片导出 | `image`、`image/draw`、`image/png`、`image/jpeg`,缩放用 `golang.org/x/image/draw` | 已定 | 预览和导出解耦,输出分辨率可控 |
| 表格文件 | `encoding/csv` + `github.com/xuri/excelize/v2` | 已定 | 满足 CSV/XLSX 人工交换 |
| Chrome | `os/exec` 启动系统 Chrome | 已定 | 平台页面不嵌入 Gio,不依赖 WebView |
| 密码 | 首发不保存 | 已定 | Chrome profile 保留会话,避免凭证落库 |
| 日志 | `log/slog` + 本地文件 sink | 已定 | 结构化、标准库优先;不得记录秘密 |
| 配置 | SQLite `settings` + 固定的本地数据目录 | 已定 | 统一备份和恢复 |
| 测试 | `go test`、临时 SQLite、fake process/file adapters、Windows 手工 smoke | 已定 | 隔离系统副作用并验证真实集成 |
| 发布 | 单机 Windows 构建;安装包形式待 T-503 | 部分待定 | 先保证二进制可运行,再选 ZIP 或安装器 |
## 二、版本策略
- 当前机器只有 Go 1.23.0,因此文档基线如实记录该版本,不声称它是最新或仍受支持。
- T-001 必须实际运行最小 Gio 窗口并锁定兼容的 Go/Gio 版本,随后同步本文、`go.mod` 和 `current-state.md`。
- 依赖首次加入后必须由 `go.mod` / `go.sum` 固定;后续任务不得直接使用浮动 `@latest`。
- Go、Gio 或 SQLite 驱动升级必须单独成任务,先跑完整测试和三个高风险 smoke。
- 若目标 Gio 版本不支持 Go 1.23.0,优先升级 Go 工具链,不为保留旧版本降级架构或复制旧依赖。
## 三、关键技术决策
- **选择 Gio**:保持 Go 单语言和本地部署,但接受 CRUD UI 需要项目内组件建设。
- **不选择 Wails**:当前产品方向已选 Gio;只有 T-101 证明核心管理台交互无法达到可用标准时才重新评估。
- **外部 Chrome**:真实店铺后台始终由独立 Chrome 进程打开,Gio 只做控制台。
- **无远程后端**:首发没有 REST 服务、云账号和同步服务。
- **不存平台密码**:账号字段只是用户识别信息;登录由 Chrome profile 会话和用户手工操作承担。
- **预览/导出分离**:Gio 显示交互预览,CPU 合成器生成正式 PNG/JPG。
- **RPA 后置**:官方 API、CSV/XLSX 和人工操作无法满足且平台允许时,才建立辅助自动化任务。
## 四、计划依赖
| 依赖 | 用途 | 引入任务 |
| --- | --- | --- |
| `gioui.org` | 窗口、布局、输入、Material 组件 | T-001 |
| `modernc.org/sqlite` | CGO-free SQLite 驱动 | T-003 |
| `golang.org/x/image` | 高质量图片缩放 | T-103 |
| `github.com/xuri/excelize/v2` | XLSX 导入导出 | T-304 |
`gioui.org/x/component`、Windows 专用系统库和日志轮转库均不是预先批准依赖;使用前必须由对应任务验证并更新本文。
## 五、构建与运行
当前在 T-001 前没有 `go.mod`,以下命令是初始化后的标准接口:
| 用途 | 命令 |
| --- | --- |
| 同步依赖 | `go mod download` |
| 本地开发 | `go run ./cmd/shophelm` |
| 单元/集成测试 | `go test ./...` |
| 竞态检查 | `go test -race ./...` |
| 静态检查 | `go vet ./...` |
| 格式检查 | `gofmt -l .`,输出必须为空 |
| Windows 构建 | `go build -o build/shophelm.exe ./cmd/shophelm` |
| 标准入口 | `./init.ps1` |
是否使用 `-race` 和 Windows GUI linker flags,以 T-001 在目标工具链上的实际结果为准。
## 六、本地目录约定
默认运行数据位于:
```text
%LOCALAPPDATA%\ShopHelm\
├── data\shophelm.db
├── profiles\<store-id>\
├── assets\
├── backups\
└── logs\
```
默认图片导出目录:
```text
%USERPROFILE%\Pictures\ShopHelm\Exports\
```
用户可以在设置中改 profile 根目录、备份目录和导出目录,但迁移或切换目录必须显式确认。
## 七、依赖纪律
- 标准库可解决时不加依赖。
- 新依赖必须记录用途、许可证、维护状态、替代方案和测试范围。
- 同一职责不得并存两套数据库驱动、图片库、日志框架或状态管理方式。
- 不因示例代码方便而加入 Web 框架、嵌入浏览器、ORM 或依赖注入框架。
- 依赖变更后运行 `go mod tidy`,审查 `go.mod` / `go.sum` 差异并记录验证结果。
+622
View File
@@ -0,0 +1,622 @@
# 架构设计
> 本文定义 ShopHelm 的系统结构、模块职责、数据模型和关键数据流。依赖选择见 [`03-tech-stack.md`](03-tech-stack.md),公开调用形状见 [`api.md`](api.md)。
## 一、架构约束
- Windows 本地单用户桌面应用,无远程后端。
- Gio 负责控制台 UI;店铺后台在外部 Chrome 中运行。
- SQLite 是结构化业务数据的唯一持久化事实来源。
- 图片原文件按路径引用;应用管理缩略图、合成参数和导出记录。
- 平台密码不保存,运行时也不要求输入。
- 首发无 CDP、无平台 API、无自动页面操作。
- 所有可能阻塞的数据库、文件、图片和进程操作都在 Gio frame 之外执行。
## 二、系统结构
```text
用户
|
v
Gio Desktop UI
|- 今日工作台
|- 店铺管理
|- 商品与图片
|- 客服助手
`- 设置
|
| UI Intent / Application Event
v
Application Services
|- StoreService / DashboardService
|- BrowserProfileService / BrowserLaunchService
|- ProductService / ImportExportService
|- ImageAssetService / ImageComposerService
|- ReplyTemplateService / FollowupService
`- BackupService / SettingsService
|
+---------------------------+
| |
v v
Domain + Repository Ports Platform Ports
| |- Chrome process adapter
v |- Filesystem / clipboard
SQLite Repositories `- Clock / path resolver
|
v
%LOCALAPPDATA%\ShopHelm + 用户选择的素材/导出目录
```
依赖方向固定为:
```text
internal/ui
-> internal/application
-> internal/domain
-> repository/platform interfaces
internal/infrastructure/sqlite
-> internal/domain
-> repository interfaces
internal/platform
-> platform interfaces
```
`domain` 不得导入 Gio、SQLite driver 或 Windows API。`application` 不得依赖具体 repository 实现。
## 三、模块职责
### 3.1 `internal/domain`
包含:
- 实体和值对象:Store、BrowserProfile、ProxyConfig、Product、ImageAsset、ImageComposition、ReplyTemplate、CustomerFollowup、Todo。
- 枚举和状态转换。
- 无 I/O 的校验、价格计算和图片几何计算。
- 领域错误,不包含 UI 文案。
不包含:
- SQL。
- Gio widget。
- `exec.Command`。
- 文件读写或剪贴板调用。
### 3.2 `internal/application`
负责用例编排:
- 校验输入并调用 repository。
- 用事务协调多表写入。
- 将平台错误映射为稳定的应用错误码。
- 发布 UI 可消费的完成事件。
- 维护异步任务的 context、取消和并发边界。
application service 不直接绘制 UI,不拼 SQL,不依赖全局单例。
### 3.3 `internal/infrastructure/sqlite`
负责:
- 打开数据库并设置 PRAGMA。
- 应用嵌入 migration。
- 实现 repository interface。
- 事务、查询、扫描和约束错误映射。
- 备份验证所需的只读打开和完整性检查。
每次连接至少设置:
```sql
PRAGMA foreign_keys = ON;
PRAGMA busy_timeout = 5000;
```
WAL 是否启用由 T-003 用 Windows 实测决定;确定后写入 migration/连接配置和本文,不在不同启动路径中采用不同值。
### 3.4 `internal/platform/chrome`
负责:
- 查找或使用配置的 Chrome 可执行文件。
- 规范化 profile 路径。
- 检查 ShopHelm 已知进程和 Chrome profile 占用。
- 以参数数组启动 Chrome,不经过 shell。
- 监听进程退出并发布状态。
- 对普通无认证代理生成启动参数。
该模块不判断店铺业务状态,也不写 SQLite。
### 3.5 `internal/platform/files`
负责:
- 应用数据目录和用户目录解析。
- 原子文件写入。
- 图片文件探测、校验和与编码。
- CSV/XLSX 文件打开和输出。
- 备份、恢复临时文件管理。
### 3.6 `internal/ui`
负责:
- Gio 窗口、导航和主题。
- 页面状态、输入校验显示、加载/空/错误状态。
- 将用户动作转成 application intent。
- 消费 application event 并使窗口失效重绘。
- 表格、表单、弹窗、toast、状态标识和图片画布等项目内组件。
frame/layout 函数只能布局、处理已到达的 UI 事件和提交 intent;不能等待数据库、文件、网络或进程。
## 四、关键数据流
### 4.1 店铺保存
```text
用户提交表单
-> UI 做必填和格式预检查
-> StoreService.Validate/Create/Update
-> domain 校验枚举、URL、路径和代理
-> repository transaction 写 stores/profile/proxy/tags
-> 返回 StoreView
-> UI 更新列表并显示结果
```
UI 校验用于快速反馈,domain/application 校验才是写入前的权威校验。
### 4.2 打开店铺 Chrome
```text
用户点击店铺或快捷入口
-> BrowserLaunchService 读取 StoreLaunchConfig
-> 校验 Chrome、URL、profile、proxy
-> ProfileInspector 检查占用
-> 状态改为 starting(内存)
-> ChromeLauncher.Start(args)
-> 记录 PID、last_opened_at 和 launch log
-> 状态改为 running
-> Wait goroutine 监听退出
-> 状态改为 exited/failed
```
规则:
- `running` 是运行时事实,不以数据库布尔值作为权威来源。
- 可以持久化最后 PID、退出码和时间用于诊断,但应用启动时必须重新核对真实进程。
- 同一 profile 不允许由 ShopHelm 重复启动。
- 归档店铺不杀进程、不删除 profile。
- 远程调试端口和 CDP 默认完全关闭。
标准参数形状:
```text
chrome.exe
--user-data-dir=<absolute-profile-dir>
--no-first-run
--disable-default-apps
[--proxy-server=<scheme://host:port>]
<target-url>
```
代理认证不通过命令行注入。URL、路径和 host/port 分别校验后再作为独立参数传递。
### 4.3 图片预览与导出
```text
底图 + 叠加图 + CompositionSpec
-> ImageProbe 读取尺寸和格式
-> CompositionPlanner 生成目标像素矩形
|- UI 预览按 viewport 比例绘制
`- Exporter 按输出分辨率 CPU 合成
-> 编码临时 PNG/JPG
-> fsync / close / 原子改名
-> 写 image_exports
```
`CompositionSpec` 使用与画布无关的归一化参数:
- `center_x`、`center_y`:叠加层中心相对画布宽高的位置,建议范围 `0..1`,允许用户拖出边缘但必须有上限。
- `width_ratio`:叠加层宽度 / 画布宽度,保持原始宽高比。
- `opacity`:`0..1`。
- `canvas_width`、`canvas_height`:正式输出像素尺寸。
- `base_fit`:首发固定支持 `contain` 和 `cover`。
- `background`:PNG 可透明;JPG 必须是明确 RGBA 颜色,默认白色。
预览和导出必须调用同一个 `CompositionPlanner`,不得分别实现位置公式。Gio 截图不得作为导出文件。
### 4.4 CSV/XLSX 导入
```text
用户选择文件
-> parser 读取为 ImportRow
-> 全量字段校验并生成 Preview
-> UI 展示有效数、错误行和原因
-> 用户确认
-> 单事务写入有效数据
-> 返回创建/更新/跳过统计
```
首发不做“遇错继续并静默丢行”。导入策略必须由用户选择:全部有效才导入,或只导入有效行并明确列出跳过项。
### 4.5 备份与恢复
备份:
1. 获取应用级写锁。
2. 生成一致性 SQLite 副本到临时路径。
3. 对副本运行 `PRAGMA integrity_check`。
4. 写入备份元信息后原子改名。
5. 释放写锁。
恢复:
1. 用户选择备份并明确确认。
2. 在测试连接中检查文件头、完整性和 schema 版本。
3. 暂停写入并关闭活动数据库连接。
4. 先把当前数据库移动为可回滚副本。
5. 复制备份到临时路径并原子替换。
6. 重新打开、迁移和 smoke;失败则恢复旧数据库。
备份默认只包含数据库和应用管理的配置,不复制外部 Chrome profile 或外部原图。备份清单必须说明引用文件可能仍在原路径。
## 五、运行时并发模型
- Gio window event loop 由 UI 层独占。
- application 使用有界 worker 或按操作启动的 goroutine,不创建无限队列。
- 每个异步 intent 携带 `context.Context` 和稳定 request ID。
- 相同资源的保存操作串行化;按钮在请求进行中显示 busy 并防重复提交。
- repository 可供多个 goroutine 使用,但事务对象不跨 goroutine。
- Chrome `Wait` 每个已启动进程一个 goroutine,退出后立即释放 registry。
- 大图解码、缩放和导出可取消;新预览请求替换旧请求时取消旧任务。
- UI 销毁时取消根 context,等待必要的数据库和日志 flush,不强制杀死用户 Chrome。
## 六、持久化位置
```text
%LOCALAPPDATA%\ShopHelm\
├── data\
│ `- shophelm.db
├── profiles\
│ `- <store-id>\
├── assets\
│ |- imported\
│ `- thumbnails\
├── backups\
└── logs\
```
- 应用管理的 profile 只能建立在配置的 profile 根目录下。
- 用户可绑定已有外部 profile,但系统将其标为 `external`,绝不移动或删除。
- 原图默认只记录规范化绝对路径;用户选择“复制到素材库”时才复制到 `assets/imported`。
- 导出默认写到 `%USERPROFILE%\Pictures\ShopHelm\Exports`。
## 七、数据模型
### 7.1 通用规则
- 主键使用 SQLite `INTEGER PRIMARY KEY`。
- 时间以 UTC RFC3339 字符串存储,UI 按本地时区显示。
- `created_at`、`updated_at` 由 application 通过注入的 Clock 生成。
- 外键始终开启。
- 店铺和核心资料使用归档时间 `archived_at`,默认查询排除已归档记录。
- 用户可见顺序需要稳定的二级排序:主要排序字段相同后按 `id`。
- 不存在 `password`、`cookie`、`token` 或代理秘密列。
### 7.2 Schema 版本
```sql
CREATE TABLE schema_migrations (
version INTEGER PRIMARY KEY,
applied_at TEXT NOT NULL
);
```
migration 文件命名为 `000001_initial.sql`、`000002_*.sql`,只追加不修改。
### 7.3 店铺域
```sql
CREATE TABLE stores (
id INTEGER PRIMARY KEY,
platform TEXT NOT NULL,
country_code TEXT NOT NULL DEFAULT '',
name TEXT NOT NULL,
account_label TEXT NOT NULL DEFAULT '',
owner TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL,
note TEXT NOT NULL DEFAULT '',
last_opened_at TEXT,
archived_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE UNIQUE INDEX ux_stores_identity_active
ON stores(platform, country_code, name)
WHERE archived_at IS NULL;
CREATE TABLE browser_profiles (
id INTEGER PRIMARY KEY,
store_id INTEGER NOT NULL UNIQUE REFERENCES stores(id),
profile_dir TEXT NOT NULL UNIQUE,
path_kind TEXT NOT NULL,
chrome_path TEXT NOT NULL DEFAULT '',
start_url TEXT NOT NULL,
last_pid INTEGER,
last_exit_code INTEGER,
last_exited_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE proxy_configs (
id INTEGER PRIMARY KEY,
store_id INTEGER NOT NULL UNIQUE REFERENCES stores(id),
enabled INTEGER NOT NULL DEFAULT 0,
scheme TEXT NOT NULL DEFAULT 'http',
host TEXT NOT NULL DEFAULT '',
port INTEGER,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE store_shortcuts (
id INTEGER PRIMARY KEY,
store_id INTEGER NOT NULL REFERENCES stores(id),
kind TEXT NOT NULL,
label TEXT NOT NULL,
url TEXT NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE(store_id, kind, label)
);
CREATE TABLE tags (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE
);
CREATE TABLE store_tags (
store_id INTEGER NOT NULL REFERENCES stores(id),
tag_id INTEGER NOT NULL REFERENCES tags(id),
PRIMARY KEY(store_id, tag_id)
);
```
`path_kind` 只允许 `managed` 或 `external`。`proxy_configs` 不增加用户名和密码列。
### 7.4 待办和商品域
```sql
CREATE TABLE todos (
id INTEGER PRIMARY KEY,
store_id INTEGER REFERENCES stores(id),
title TEXT NOT NULL,
status TEXT NOT NULL,
due_at TEXT,
note TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE products (
id INTEGER PRIMARY KEY,
store_id INTEGER NOT NULL REFERENCES stores(id),
name TEXT NOT NULL,
sku TEXT NOT NULL DEFAULT '',
cost_minor INTEGER,
sale_price_minor INTEGER,
currency TEXT NOT NULL DEFAULT '',
stock INTEGER,
product_url TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL,
note TEXT NOT NULL DEFAULT '',
archived_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX ix_products_store_status
ON products(store_id, status, updated_at);
CREATE TABLE content_templates (
id INTEGER PRIMARY KEY,
store_id INTEGER REFERENCES stores(id),
kind TEXT NOT NULL,
language TEXT NOT NULL DEFAULT '',
title TEXT NOT NULL,
content TEXT NOT NULL,
archived_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE product_check_items (
id INTEGER PRIMARY KEY,
product_id INTEGER NOT NULL REFERENCES products(id),
item_key TEXT NOT NULL,
label TEXT NOT NULL,
checked INTEGER NOT NULL DEFAULT 0,
sort_order INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL,
UNIQUE(product_id, item_key)
);
```
金额以最小货币单位整数保存,避免 `REAL` 舍入误差。汇率和平台费率必须是当次计算的显式输入;首发不把计算结果持久化为财务事实。
### 7.5 图片域
```sql
CREATE TABLE image_assets (
id INTEGER PRIMARY KEY,
store_id INTEGER REFERENCES stores(id),
product_id INTEGER REFERENCES products(id),
asset_type TEXT NOT NULL,
file_path TEXT NOT NULL,
storage_kind TEXT NOT NULL,
width INTEGER,
height INTEGER,
checksum_sha256 TEXT,
note TEXT NOT NULL DEFAULT '',
missing INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE image_exports (
id INTEGER PRIMARY KEY,
store_id INTEGER REFERENCES stores(id),
product_id INTEGER REFERENCES products(id),
base_asset_id INTEGER NOT NULL REFERENCES image_assets(id),
overlay_asset_id INTEGER NOT NULL REFERENCES image_assets(id),
output_path TEXT NOT NULL,
output_format TEXT NOT NULL,
output_width INTEGER NOT NULL,
output_height INTEGER NOT NULL,
composition_json TEXT NOT NULL,
checksum_sha256 TEXT NOT NULL,
created_at TEXT NOT NULL
);
```
首发不需要保存 `image_templates`。模板和批量导出进入 Backlog 后新增 migration,不能提前把未使用的通用图层系统塞进 MVP。
### 7.6 客服域
```sql
CREATE TABLE reply_templates (
id INTEGER PRIMARY KEY,
category TEXT NOT NULL,
language TEXT NOT NULL,
title TEXT NOT NULL,
content TEXT NOT NULL,
usage_count INTEGER NOT NULL DEFAULT 0,
archived_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE customer_followups (
id INTEGER PRIMARY KEY,
store_id INTEGER NOT NULL REFERENCES stores(id),
buyer_label TEXT NOT NULL DEFAULT '',
order_ref TEXT NOT NULL DEFAULT '',
issue_type TEXT NOT NULL,
status TEXT NOT NULL,
next_followup_at TEXT,
note TEXT NOT NULL DEFAULT '',
archived_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE INDEX ix_followups_due
ON customer_followups(status, next_followup_at);
```
`buyer_label` 只保存完成跟进所需的最小标识,不要求保存买家完整个人资料。
### 7.7 设置与操作记录
```sql
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value_json TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE operation_logs (
id INTEGER PRIMARY KEY,
action TEXT NOT NULL,
entity_type TEXT NOT NULL,
entity_id INTEGER,
result TEXT NOT NULL,
error_code TEXT,
detail_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
```
operation log 只记录业务动作摘要、路径的脱敏形式和稳定错误码,不记录话术正文、买家详细信息、账号、Cookie 或命令行秘密。
## 八、状态枚举
| 领域 | 合法值 |
| --- | --- |
| 店铺业务状态 | `active`、`login_required`、`attention`、`paused` |
| Chrome 运行状态 | `stopped`、`occupied`、`starting`、`running`、`exited`、`failed` |
| 待办 | `pending`、`done`、`cancelled` |
| 商品 | `draft`、`pending_listing`、`listed`、`optimize`、`paused` |
| 图片素材 | `main`、`detail`、`logo`、`badge`、`watermark` |
| 内容模板 | `title`、`description` |
| 客服跟进 | `pending`、`in_progress`、`waiting_buyer`、`resolved`、`escalated` |
数据库约束或 domain 校验必须拒绝其他值。UI 文案与内部枚举通过集中映射,不把中文展示值写入状态列。
## 九、项目结构
```text
shop_helm/
├── cmd/
│ `-- shophelm/
│ `-- main.go
├── internal/
│ ├── application/
│ ├── domain/
│ ├── infrastructure/
│ │ `-- sqlite/
│ ├── platform/
│ │ ├── chrome/
│ │ ├── clipboard/
│ │ `-- files/
│ `-- ui/
│ ├── components/
│ ├── pages/
│ `-- theme/
├── migrations/
├── assets/
├── testdata/
├── docs/
├── init.ps1
├── init.sh
├── go.mod
└── go.sum
```
Go 测试优先与被测包同目录。跨模块验收夹具放 `testdata/`,不得包含真实账号或隐私数据。
## 十、错误处理
- domain 返回可判定的 sentinel/typed errors。
- application 映射为 [`api.md`](api.md) 定义的稳定错误码。
- infrastructure 附加底层原因供日志诊断,但 UI 不直接展示 SQL、绝对秘密路径或系统堆栈。
- UI 显示“发生了什么 + 用户能做什么”,例如“该店铺浏览器环境正在使用,请先关闭对应 Chrome 后重试”。
- 可重试操作明确提供重试;不可恢复操作不做无限重试。
## 十一、测试策略
| 层 | 测试 |
| --- | --- |
| domain | 状态校验、价格计算、图片几何的表驱动单元测试 |
| application | fake repository/platform adapter,验证编排、事务和错误映射 |
| SQLite | 临时目录真实数据库、migration、约束、CRUD、备份恢复 |
| Chrome adapter | 参数生成单元测试 + fake executable;真实 Chrome 手工 smoke |
| Image composer | 固定小图 golden/pixel 测试、PNG alpha、JPG 背景、原图不变 |
| CSV/XLSX | round-trip、错误行、编码和事务行为 |
| Gio UI | 页面状态和 intent 单测 + Windows 手工 smoke;不依赖像素脆弱截图作为唯一证据 |
## 十二、关键风险和闸门
| 风险 | 必须先通过的闸门 |
| --- | --- |
| Go 1.23.0 与目标 Gio 不兼容 | T-001 最小窗口在目标 Windows 上运行并锁版本 |
| Gio 管理台组件成本过高 | T-101 用真实店铺字段完成表格、筛选和表单原型 |
| profile 占用判断不可靠 | T-102 覆盖本应用启动、外部占用、进程退出和脏状态 |
| 预览和导出不一致 | T-103 使用同一 CompositionPlanner 通过像素测试 |
| SQLite 恢复损坏现有数据 | T-208 在测试目录执行成功和故障注入恢复 |
| RPA 导致平台风险 | 首发无 RPA;任何引入必须新建需求与合规任务 |
高风险闸门未通过时,不继续依赖它的业务任务,也不以 mock 成功替代真实结论。
+176
View File
@@ -0,0 +1,176 @@
# 编码规则(Coding Rules)
> 每次改代码前完整读取。本文件是实现硬约束;产品范围以 [`02-requirements.md`](02-requirements.md) 为准,模块事实以 [`04-architecture.md`](04-architecture.md) 和 [`api.md`](api.md) 为准。
## 0. 黄金法则
1. **不臆造**:字段、平台规则、路径、依赖和接口必须查仓库事实。
2. **一次一事**:只实现当前 `DOING` 任务,不夹带 Backlog 和无关重构。
3. **依赖向内**:UI 和基础设施依赖 application/domain,domain 不依赖框架。
4. **先验证风险**:Gio 组件、Chrome profile 和图片合成闸门未通过前,不大规模铺业务页面。
5. **副作用可控**:进程、文件、数据库、剪贴板和恢复操作必须可观察、可失败、可追踪。
6. **完成有证据**:没有测试、构建和任务要求的 smoke,不得标记 `DONE`。
## 1. 动手前
- 按 `vision -> requirements -> tech-stack -> architecture -> api/routes -> tasks -> current-state` 建立上下文。
- 找到任务对应的需求 ID、服务合约和页面。
- 检查是否已有可复用 package、component、repository 和测试夹具。
- 运行标准基线并记录当前失败;基线坏时先处理基线。
- 查看工作区已有改动,保留不属于本任务的用户修改。
- 若任务会改变第三方平台数据、删除用户文件、保存秘密或扩大自动化范围,先停止并要求产品决策。
## 2. Go 规则
- package 名短小、全小写、单数优先,不使用 `utils`、`common`、`helpers` 作为无边界杂物包。
- 公开标识符只在跨包合约需要时导出;先使用小接口,接口由消费者定义。
- 所有 I/O 方法接收 `context.Context`,不把 context 存在 struct 中。
- 错误必须包装上下文并保留 `errors.Is/As` 可判定性,不比较底层错误字符串。
- 不使用 `panic` 处理可预期业务错误;启动期不可恢复错误可以返回到 `main` 后记录并退出。
- 不忽略返回值,不用空 `recover`,不在 library code 中 `os.Exit`。
- 时间通过注入的 Clock 获取,测试不依赖真实等待。
- 金额不用 `float64` 持久化;用最小货币单位整数,比例/汇率用可精确解析表示。
- 路径用 `filepath`,URL 用 `net/url`,CSV/XLSX 用结构化解析器,不手工拆字符串。
- 代码必须通过 `gofmt`;注释解释边界和原因,不复述代码。
## 3. 分层规则
- `internal/domain`:纯规则、实体和值对象,不导入 Gio、driver、Windows API。
- `internal/application`:用例编排和稳定错误码,不写 SQL、不布局 UI。
- `internal/infrastructure/sqlite`:repository 和 migration,不出现 UI 文案。
- `internal/platform`:进程、路径、剪贴板和文件副作用,不决定业务优先级。
- `internal/ui`:页面状态和展示,不直接打开数据库或启动进程。
- 不通过全局变量跨层共享数据库、页面状态或 process registry。
- 新增跨层调用前先更新 `api.md`;不得为绕过接口而从 UI 直接引用 concrete repository。
## 4. Gio 规则
- widget、clickable、editor、list、drag 和页面状态必须跨 frame 持久存在。
- layout 函数不得执行 SQL、文件读写、大图解码、网络请求、`Process.Wait` 或阻塞 channel receive。
- 用户动作只提交 intent;异步结果通过 event channel 返回并调用 window invalidate。
- 每个异步操作有 busy、success、error 和必要的 cancel 状态。
- 同一按钮请求进行中防重复提交。
- 页面切换保留列表筛选和滚动状态;销毁页面时取消所属 context。
- 固定画布、表格、工具栏和图标按钮设置稳定约束,动态文字不得挤压相邻控件。
- 关键状态不能只用颜色;图标按钮必须有 tooltip/可访问名称。
- 项目内组件只在存在真实复用时抽取,不创建通用 UI DSL。
- UI 自动测试不稳定时可以保留手工 smoke,但 domain/application 行为必须有自动测试。
## 5. SQLite 规则
- schema 只通过按序 migration 变化,已经提交或发布的 migration 不修改。
- 每个连接启用外键和 busy timeout。
- 多表写入、导入提交和计数更新使用事务。
- repository 查询显式列名,不使用 `SELECT *`。
- nullable 数据使用明确类型,不用魔法空字符串混淆“未填写”和有效值,除非 schema 已定义为空字符串语义。
- 列表查询有稳定排序、分页边界和必要索引。
- 唯一约束、外键约束和 busy 错误映射到稳定应用错误码。
- 测试使用临时目录的真实 SQLite,不共享开发数据库。
- 不把密码、Cookie、token、代理秘密或图片二进制写进数据库。
- 备份恢复前后执行完整性检查;失败必须保留可回滚旧库。
## 6. Chrome 与进程规则
- 只能用 `exec.CommandContext` 或经审查的等价 API 和独立参数启动,不使用 `cmd /c`、PowerShell 字符串或 shell 拼接。
- Chrome executable、profile 目录和目标 URL 分别校验。
- profile 必须是绝对规范路径;managed path 必须位于配置根目录内。
- 不使用默认用户 Chrome profile 作为 ShopHelm managed profile。
- 同一 profile 占用时返回 `profile_in_use`,不尝试强制解锁或删除 lock 文件。
- 不在命令行传密码、Cookie 或代理认证信息。
- 不默认加 `--remote-debugging-port`、规避检测或安全降级参数。
- 进程退出必须释放 registry;应用重启后不得相信陈旧 PID。
- 应用退出默认不杀用户打开的 Chrome;需要关闭能力时必须单独立项和确认。
- 测试参数生成时用 fake runner,真实 Chrome smoke 只能使用测试 profile 和非生产账号。
## 7. 文件、导入和图片规则
- 任何用户路径先做存在性、文件类型、权限和规范化检查。
- 读取外部文件不修改源文件。
- 写入先落同目录临时文件,成功 close/sync 后原子改名。
- 默认 `overwrite=false`;即使允许覆盖,也绝不能覆盖底图或叠加图。
- 图片解码设置尺寸和内存上限,防止异常大文件耗尽内存。
- 预览和导出共用 `CompositionPlanner`,不得复制位置/缩放公式。
- Gio framebuffer 截图不能作为正式图片输出。
- PNG alpha 和 JPG 背景有固定测试。
- CSV/XLSX 先 preview 后 commit;文件 fingerprint 改变时拒绝提交。
- 导入错误包含行号、字段和原因;不静默修复未知值。
- 删除数据库素材关联默认不删除物理文件。
## 8. 安全、隐私与合规
- 真实账号、密码、token、Cookie、买家隐私、私有 URL 不进入代码、文档、日志、截图或测试数据。
- 账号标识只用于人类识别;日志中仍应最小化或脱敏。
- 不实现绕验证码、绕风控、反指纹、刷单、刷评、批量抓取和未经确认的批量消息。
- 不把 `user-data-dir` 描述成防关联功能。
- 平台规则变化必须以官方来源为准,记录链接、访问日期和影响。
- 未来自动化默认具备 dry-run、明确预览、人工确认、速率边界、审计和取消。
- 操作日志记录 action、entity、result、error code,不记录完整话术、买家详情或命令秘密。
## 9. 依赖规则
- 新依赖前检查标准库和已引入依赖能否满足。
- 在 `03-tech-stack.md` 记录用途、版本策略和引入任务。
- 运行 `go mod tidy` 后审查直接和间接依赖变化。
- 不引入 ORM、Web 框架、嵌入浏览器、依赖注入框架或第二套图片库,除非新任务明确批准。
- `gioui.org/x/component` 只有 T-101 通过后才允许保留。
- 依赖升级单独提交,不与业务功能混在同一任务。
## 10. 测试规则
最低自动验证:
```powershell
go test ./...
go vet ./...
go build -o build/shophelm.exe ./cmd/shophelm
```
按改动增加:
- 并发和共享状态:`go test -race ./...`,若目标工具链不支持则记录真实原因。
- migration/repository:临时数据库从空库迁移,运行 CRUD、约束和重开测试。
- Chrome:参数单测、fake process 生命周期、Windows 真实 Chrome smoke。
- 图片:固定夹具 pixel/golden 测试、原图校验和、格式和失败清理。
- 导入:CSV/XLSX round-trip、错误行、fingerprint 和事务测试。
- 备份:完整性、恢复成功、损坏备份、替换失败回滚测试。
- Gio:对应页面手工 smoke,记录窗口尺寸、动作和观察结果。
测试禁止:
- 为绿灯删除断言、降低验收或跳过失败用例。
- 使用真实用户数据库、真实 Chrome profile 或真实店铺凭证。
- 依赖测试执行顺序或固定本机绝对路径。
## 11. 文档与提交
- 需求变化先改 `02-requirements.md`,再改代码。
- schema 或 service 合约变化同步 `04-architecture.md` 和 `api.md`。
- 页面变化同步 `routes.md`。
- 版本、依赖和命令变化同步 `03-tech-stack.md`、`00-ai-start-here.md`、`current-state.md` 和 `init.*`。
- 每轮实际命令和结果只追加到 `progress.md`。
- 提交只包含当前任务相关文件;不重写或撤销用户无关改动。
- 提交信息建议:`T-XXX: imperative summary`。
## 12. 完成定义
任务标记 `DONE` 前逐项确认:
- [ ] 需求 ID 和任务验收全部满足。
- [ ] 代码遵守模块和副作用边界。
- [ ] 自动测试、vet、build 通过。
- [ ] 任务要求的手工 smoke 已执行并记录环境。
- [ ] 没有真实秘密、隐私或生产路径进入变更。
- [ ] 没有无关重构或 Backlog 功能。
- [ ] 相关文档、任务状态和 current state 已同步。
- [ ] `progress.md` 有真实验证证据。
- [ ] `clean-state-checklist.md` 已通过。
## 13. 绝不
- 绝不明文保存密码。
- 绝不删除或强制解锁 Chrome profile。
- 绝不覆盖原始图片作为默认行为。
- 绝不在 Gio frame 中等待 I/O。
- 绝不把数据库 `running` 字段当真实进程状态。
- 绝不静默吞掉导入、恢复或导出中的部分失败。
- 绝不因为任务困难就跳过高风险闸门。
+100
View File
@@ -0,0 +1,100 @@
# 任务看板(Tasks)
> ShopHelm 单 agent 开发看板。每轮只领取一个 `TODO` 且依赖均为 `DONE` 的任务。
## 使用规则
1. 开始前读 `00-ai-start-here.md`、`05-coding-rules.md`、`current-state.md` 和任务相关合约。
2. 取编号最小、依赖均 `DONE` 的 `TODO`,先改为 `DOING`。
3. 同一时间最多一个 `DOING`,不得跳过技术闸门。
4. 验收步骤必须真实执行;只有代码而无命令/观察证据不能 `DONE`。
5. 完成后更新本看板、追加 `../progress.md`、覆盖 `current-state.md` 并走 `clean-state-checklist.md`。
6. 多 agent 并发时冻结本文,切换到 [`tasks/README.md`](tasks/README.md)。
状态:`TODO` 待开始 · `DOING` 进行中 · `DONE` 已验证 · `BLOCKED` 有明确阻塞
## Phase 0 · 工程地基
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-001 | 初始化 Go module 和最小 Gio 窗口 | - | 保留现有 Git 配置;建立 module `shophelm`;锁定兼容 Go/Gio 版本并同步技术文档;`./init.ps1`、`go run ./cmd/shophelm`、`go test ./...`、`go build -o build/shophelm.exe ./cmd/shophelm` 成功;窗口可正常打开和关闭 | TODO |
| T-002 | 建立目录、运行路径、配置和日志骨架 | T-001 | SEC-002;目录符合 `04-architecture.md`;默认本地目录可解析/创建;路径解析和设置校验有测试;日志不含环境秘密;应用启动能显示配置错误 | TODO |
| T-003 | 接入 SQLite、migration 和 repository 测试基座 | T-002 | 使用 `modernc.org/sqlite`;空库迁移到当前版本;外键/busy timeout 生效;临时库重开测试通过;migration 失败不被标记已应用 | TODO |
| T-004 | 建立 application event loop 和生命周期 | T-003 | UI intent 在 frame 外执行;request ID、busy、success/error 事件可用;关闭窗口取消 root context 并关闭数据库;竞态测试或替代验证有记录 | TODO |
| T-005 | 实现 AppShell、主题和基础反馈组件 | T-004 | 五项主导航可切换;loading/empty/error/toast/modal/status badge 有稳定演示;小窗口无关键重叠;Windows 手工 smoke 有记录 | TODO |
## Phase 1 · 高风险技术闸门
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-101 | Gio 管理台表格与表单原型 | T-005 | 用真实店铺字段展示 500 行、固定表头/列、滚动、选中、排序和筛选;新增/编辑表单校验可用;窗口缩放不重叠;决定是否保留 `x/component` 并同步技术文档 | TODO |
| T-102 | Chrome profile、进程和代理启动原型 | T-004 | fake runner 验证参数无 shell 注入;两个 managed profile 可分别启动;同 profile 重复打开被阻止;退出后状态释放;无认证代理参数正确;不启用 CDP;真实 Chrome smoke 有记录 | TODO |
| T-103 | 图片 CompositionPlanner 与导出原型 | T-004 | 固定底图/叠加图通过位置、缩放、透明度 pixel 测试;预览与导出共享 planner;PNG alpha、JPG 背景、目标存在、输入不变和取消均有测试 | TODO |
| T-104 | 技术闸门结论与正式组件归档 | T-101,T-102,T-103 | 原型代码进入正式模块或被删除;Go/Gio/组件/Chrome 占用/图片限制写回架构;三项 smoke 全部可复现;任何未达标项标 `BLOCKED` 并由用户决策是否调整技术路线 | TODO |
## Phase 2 · 业务阶段一:多店铺运营台
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-201 | 实现店铺域 migration 和 repositories | T-104 | SEC-001;`stores`、profile、proxy、shortcut、tags 表和索引符合架构;CRUD/归档/恢复/唯一约束/事务测试通过;schema 无秘密列 | TODO |
| T-202 | 实现店铺列表和 CRUD 页面 | T-201 | STORE-001、STORE-002;新增、查看、编辑、归档和恢复可用;错误保留输入;重启后 20 条测试记录存在;列表默认不显示归档 | TODO |
| T-203 | 实现 profile 配置和店铺快捷入口 | T-202 | STORE-004、STORE-008;managed/external 路径规则生效;managed 目录唯一;快捷 URL 校验协议;归档不删除 profile;详情页可打开文件位置 | TODO |
| T-204 | 接入 Chrome 启动和运行状态 | T-203,T-102 | STORE-005、STORE-006、STORE-007;启动、占用、退出、失败状态进入 UI;last_opened_at 只在成功启动后更新;应用重启核对陈旧 PID;不强杀 Chrome | TODO |
| T-205 | 实现普通代理、筛选和排序 | T-204 | STORE-003、STORE-009;平台/国家/负责人/标签/状态筛选和最近打开排序稳定;代理开启/关闭参数正确;认证字段不存在;500 行操作不冻结 UI | TODO |
| T-206 | 实现店铺待办和首版今日工作台 | T-205 | STORE-010、DASH-001、DASH-002;待办 CRUD、到期/逾期计算和最近店铺展示;分区错误不伪装为空;重启后状态保留 | TODO |
| T-207 | 实现设置持久化和设置页面 | T-206 | SET-001、SET-002;Chrome、profile、导出目录、默认货币和界面语言可保存并校验;路径切换说明影响;重启后设置保留;密码或代理认证字段不存在 | TODO |
| T-208 | 实现数据库备份与恢复 | T-207 | STORE-011、SEC-003;有效备份可恢复全部关联;损坏/高版本备份被拒;替换失败恢复旧库;明确不包含 profile/外部素材;手工故障 smoke 有证据 | TODO |
| T-209 | 验收多店铺运营台 | T-208 | 执行 `02-requirements.md` 6.1 和店铺相关 6.4;运行测试/vet/build;用至少两个测试 profile 完成 Windows smoke;发现缺口新建任务,不用降低验收 | TODO |
## Phase 3 · 业务阶段四:商品运营助手
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-301 | 实现商品、模板和检查项 migration/repositories | T-209 | 表结构、金额整数、状态、索引和外键符合架构;CRUD/归档/检查项事务测试通过;SKU 重复策略定稿并同步需求/schema | TODO |
| T-302 | 实现商品草稿列表和 CRUD | T-301 | PROD-001、PROD-002;按店铺/状态/关键词筛选;金额解析错误可见;详情关联店铺;重启后数据保留 | TODO |
| T-303 | 实现文案模板、上架检查和价格计算 | T-302 | PROD-003、PROD-004、PROD-005;模板和检查项可复用;计算回显全部输入;空费率无隐含默认;边界/舍入测试通过 | TODO |
| T-304 | 实现 CSV/XLSX 商品导入导出 | T-303 | PROD-006;preview 显示行号错误;fingerprint 变化拒绝 commit;两种策略行为明确;CSV/XLSX round-trip 和事务测试通过 | TODO |
| T-305 | 实现图片素材库 | T-302 | PROD-007;路径引用/复制到素材库、缩略图和缺失状态可用;删除关联默认不删文件;异常大图被安全拒绝;重启后关联保留 | TODO |
| T-306 | 实现图片叠加预览页面 | T-305,T-103 | IMG-001、IMG-002;选择底图/叠加图,拖动、位置、缩放、透明度、重置可用;画布缩放不改变 spec;旧预览请求不会覆盖新结果 | TODO |
| T-307 | 实现 PNG/JPG 导出和导出记录 | T-306 | IMG-003、IMG-004;尺寸/格式/背景可选;输出原子写入且默认不覆盖;原图校验和不变;成功记录关联商品;失败不留有效半成品 | TODO |
| T-308 | 完成商品工作台集成和阶段验收 | T-304,T-307 | DASH-003 和商品/图片相关 DASH-004、`02-requirements.md` 6.2 全部通过;最近导出/待优化商品可进入详情;测试/vet/build 和图片 Windows smoke 有证据 | TODO |
## Phase 4 · 业务阶段五:客服助手
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-401 | 实现话术和跟进 migration/repositories | T-308 | 表、状态、到期索引和归档符合架构;CRUD/筛选/重开测试通过;买家字段保持最小化 | TODO |
| T-402 | 实现多语言话术库和一键复制 | T-401 | CS-001、CS-002、CS-003、CS-004;分类/语言/关键词筛选;剪贴板成功才增加次数;失败反馈明确;不出现发送按钮 | TODO |
| T-403 | 实现买家问题和跟进页面 | T-401 | CS-005、CS-006;关联店铺/订单标识;状态和时间校验;逾期/今日优先;归档和重启行为正确 | TODO |
| T-404 | 把客服跟进接入今日工作台 | T-402,T-403 | 客服相关 DASH-004;到期/逾期跟进展示并可进入记录;局部加载失败可重试;系统不读取或发送平台消息 | TODO |
| T-405 | 验收客服助手 | T-404 | 执行 `02-requirements.md` 6.3;多语言文本、剪贴板、时区和重启 smoke 通过;测试/vet/build 有证据 | TODO |
## Phase 5 · 稳定性与发布
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-501 | 统一错误体验、日志脱敏和运行状态恢复 | T-405 | AUDIT-001;所有稳定错误码有 UI 映射;日志无密码/隐私测试标记;启动时校验素材缺失和 Chrome 陈旧状态;关键操作有可诊断结果 | TODO |
| T-502 | 完整首发验收与性能/恢复测试 | T-501 | SEC-001、SEC-002、SEC-003;`02-requirements.md` 6.1-6.4 和非功能要求有逐项证据;500 店铺/5000 商品数据不冻结 frame;备份恢复、异常退出和原图保护通过 | TODO |
| T-503 | Windows 可交付构建与运行文档 | T-502 | 决定 ZIP/安装器并记录;干净 Windows 环境可启动;数据目录/升级/卸载不误删 profile 和素材;版本信息可见;完整测试/vet/build 通过 | TODO |
## 里程碑
- M0:工程地基可运行。
- M1:三个高风险闸门通过,确认继续 Gio。
- M2:多店铺运营台可每日使用。
- M3:商品资料和单张图片合成闭环完成。
- M4:客服话术与跟进闭环完成。
- M5:Windows 首发包可交付。
## Backlog
- authenticated proxy 的合规实现。
- 代理可用性检测和检测历史。
- 图片模板、平台尺寸预设、批量套用和批量导出。
- 多语言标题/描述和 AI 辅助。
- Shopee Open Platform 官方 API。
- 在平台许可范围内、人工确认的辅助 RPA。
- 订单、库存、利润和广告 ROI。
- 云同步、团队成员和权限。
- 操作日志浏览与导出。
- macOS/Linux 评估。
+47
View File
@@ -0,0 +1,47 @@
# ShopHelm 项目文档导航
> 本目录是 ShopHelm 的产品与工程事实来源。AI coding agent 每次从 [`00-ai-start-here.md`](00-ai-start-here.md) 进入。
## 一句话定位
店小航 ShopHelm 是面向小团队跨境卖家的 Windows 本地运营工作台,首发跑通“找到正确店铺并打开独立 Chrome 环境 -> 整理商品与图片 -> 复用客服话术并跟进”的日常闭环。
## 核心文档
| 文档 | 职责 |
| --- | --- |
| [`../AGENTS.md`](../AGENTS.md) | 仓库级 agent 规则和安全边界 |
| [`00-ai-start-here.md`](00-ai-start-here.md) | 每轮开工、领任务和收尾流程 |
| [`01-vision.md`](01-vision.md) | 产品目标、用户、原则和非目标 |
| [`02-requirements.md`](02-requirements.md) | 功能范围、优先级、用户故事和验收 |
| [`03-tech-stack.md`](03-tech-stack.md) | 技术选型、依赖纪律和命令 |
| [`04-architecture.md`](04-architecture.md) | 分层、模块、数据模型和关键数据流 |
| [`05-coding-rules.md`](05-coding-rules.md) | Go、Gio、SQLite、文件和进程硬规则 |
| [`06-tasks.md`](06-tasks.md) | 单 agent 任务看板和依赖 |
| [`api.md`](api.md) | 本地应用服务、事件和错误合约 |
| [`routes.md`](routes.md) | 桌面页面、导航状态和组件归属 |
| [`current-state.md`](current-state.md) | 当前代码现实和下一个可领取任务 |
## 执行与质量文档
| 文档 | 职责 |
| --- | --- |
| [`../progress.md`](../progress.md) | 只追加的任务执行和验证证据 |
| [`clean-state-checklist.md`](clean-state-checklist.md) | 每轮结束前的干净收尾检查 |
| [`adoption-checklist.md`](adoption-checklist.md) | 当前空项目从文档进入代码的基线清单 |
| [`method-map.md`](method-map.md) | 常见失败模式到修复工件的导航 |
| [`evaluator-rubric.md`](evaluator-rubric.md) | 单次交付质量评分 |
| [`quality-document.md`](quality-document.md) | 产品域和架构层长期健康度 |
| [`tasks/README.md`](tasks/README.md) | 多 agent 时的一任务一文件规则 |
## 职责边界
- “做什么、怎么算完成”只在 `02-requirements.md` 定义。
- “用什么”只在 `03-tech-stack.md` 定义。
- “模块和数据如何组织”只在 `04-architecture.md` 定义。
- “公开服务如何调用”只在 `api.md` 定义。
- “页面放在哪里”只在 `routes.md` 定义。
- “现在代码实际是什么状态”只在 `current-state.md` 维护。
- 历史命令和结果只追加到 `../progress.md`。
同一事实不要在多个文件各写一个版本。需要摘要时链接到权威文档。
+41
View File
@@ -0,0 +1,41 @@
# 空项目初始化与 Harness 接入清单
> ShopHelm 当前从空目录起步。本文只记录从“文档基线”进入“可运行代码基线”的一次性准备状态。
## 文档基线
- [x] 建立 `AGENTS.md` 和 AI 开工入口。
- [x] 固定产品愿景、需求范围和首发验收。
- [x] 固定 Go + Gio、SQLite、外部 Chrome 技术路线。
- [x] 定义模块边界、数据模型、页面和本地服务合约。
- [x] 建立单 agent 任务看板、执行流水和当前状态。
- [x] 建立验证、收尾、评审和质量跟踪文档。
## 代码基线
- [x] 初始化 Git 仓库并配置远程。
- [ ] 初始化 Go module `shophelm`。
- [ ] 在目标 Windows 上运行最小 Gio 窗口。
- [ ] 锁定 Go/Gio 版本并更新技术文档。
- [ ] 建立 `cmd/`、`internal/`、`migrations/` 和测试结构。
- [ ] 让 `./init.ps1` 完成依赖同步、测试并打印启动命令。
- [ ] 运行 `go test ./...`、`go vet ./...` 和 Windows build。
- [ ] 把真实结果追加到 `progress.md` 并更新 `current-state.md`。
代码基线由 [`T-001`](06-tasks.md) 到 T-005 逐项完成,不在文档初始化任务中顺带生成未经验证的业务代码。
## 首轮决策闸门
完成工程基线后,必须在扩展业务页面前验证:
| 闸门 | 任务 | 通过标准 |
| --- | --- | --- |
| Gio 管理台可用性 | T-101 | 真实字段表格、筛选和表单在 Windows 上可用 |
| Chrome/profile 安全启动 | T-102 | 参数、占用、退出和代理行为可复现 |
| 图片预览/导出一致性 | T-103 | 共享几何算法和像素测试通过 |
任一闸门失败时,先在 T-104 记录证据和替代方案,由用户决定是否调整技术路线,不继续堆业务代码。
## 完成判据
当 T-005 完成后,本接入清单视为完成。后续状态只在 `current-state.md`、`06-tasks.md` 和 `progress.md` 维护,不继续修改本文的历史勾选。
+550
View File
@@ -0,0 +1,550 @@
# 本地模块合约
> ShopHelm 首发没有 HTTP 后端。本文定义 Gio UI 可调用的 application service、平台 port、事件和错误合约。实现可以拆分文件,但不得另起一套语义不兼容的接口。
## 一、通用约定
- 所有可能 I/O 的方法第一个参数是 `context.Context`。
- application service 输入输出使用 domain/application DTO,不把 Gio widget 或 SQL row 暴露出去。
- ID 使用 `int64`,`0` 表示尚未持久化,外部输入不接受负数。
- 时间在 service 边界使用 `time.Time`,持久化时转 UTC RFC3339。
- 金额输入先按货币精度解析成整数最小单位;比例和汇率使用十进制字符串或 `big.Rat`,不直接用二进制浮点作为业务事实。
- 列表默认 `limit=50`,最大 `200`;必须有稳定的 ID 二级排序。
- 写操作成功后返回持久化后的完整 view。
- 错误使用稳定 code;底层 cause 只供日志,不直接显示给用户。
## 二、通用类型
目标形状:
```go
type SortDirection string
const (
SortAsc SortDirection = "asc"
SortDesc SortDirection = "desc"
)
type PageRequest struct {
Offset int
Limit int
SortBy string
Direction SortDirection
}
type Page[T any] struct {
Items []T
Total int
Offset int
Limit int
}
type ErrorCode string
type AppError struct {
Code ErrorCode
Message string
FieldErrors map[string]string
Retryable bool
Cause error
}
```
`Message` 是安全的默认用户提示;UI 可以按 `Code` 替换为更具体中文,但不得展示 `Cause`。
## 三、店铺服务
### 3.1 输入与视图
```go
type StoreInput struct {
Platform string
CountryCode string
Name string
AccountLabel string
Owner string
Tags []string
Status string
Note string
Profile BrowserProfileInput
Proxy ProxyInput
}
type BrowserProfileInput struct {
PathKind string // managed | external
ProfileDir string
ChromePath string
StartURL string
}
type ProxyInput struct {
Enabled bool
Scheme string // http | https | socks4 | socks5
Host string
Port int
}
type StoreFilter struct {
Query string
Platforms []string
Countries []string
Owners []string
Tags []string
Statuses []string
IncludeArchived bool
Page PageRequest
}
type StoreView struct {
Store domain.Store
Profile domain.BrowserProfile
Proxy domain.ProxyConfig
Tags []string
Runtime BrowserRuntimeView
ShortcutCount int
PendingTodoCount int
}
```
`StoreInput` 没有密码、Cookie、token 或代理认证字段。MVP 期间不得添加这些字段的“临时字符串”替代品。
### 3.2 服务接口
```go
type StoreService interface {
List(ctx context.Context, filter StoreFilter) (Page[StoreView], error)
Get(ctx context.Context, id int64) (StoreView, error)
Create(ctx context.Context, input StoreInput) (StoreView, error)
Update(ctx context.Context, id int64, input StoreInput) (StoreView, error)
Archive(ctx context.Context, id int64) error
Restore(ctx context.Context, id int64) (StoreView, error)
}
```
规则:
- `Create` 对 managed profile 生成 `<profile-root>\<store-id>`,因此可以先事务创建店铺再补 profile;任一步失败整体回滚。
- external profile 必须已存在且是目录;managed profile 可由服务创建。
- `Archive` 只写 `archived_at`,不关闭 Chrome,不删目录。
- `(platform, country, name)` 在未归档记录中重复时返回 `conflict`。
## 四、快捷入口和待办
```go
type StoreShortcutService interface {
List(ctx context.Context, storeID int64) ([]domain.StoreShortcut, error)
Create(ctx context.Context, storeID int64, input ShortcutInput) (domain.StoreShortcut, error)
Update(ctx context.Context, id int64, input ShortcutInput) (domain.StoreShortcut, error)
Delete(ctx context.Context, id int64) error
}
type TodoService interface {
List(ctx context.Context, filter TodoFilter) (Page[domain.Todo], error)
Create(ctx context.Context, input TodoInput) (domain.Todo, error)
Update(ctx context.Context, id int64, input TodoInput) (domain.Todo, error)
SetStatus(ctx context.Context, id int64, status string) (domain.Todo, error)
Delete(ctx context.Context, id int64) error
}
```
快捷链接只接受绝对 `http` 或 `https` URL。`javascript:`、`file:` 和命令协议必须拒绝。
## 五、Chrome 与 profile 合约
### 5.1 Application service
```go
type OpenStoreRequest struct {
StoreID int64
ShortcutID *int64
}
type LaunchResult struct {
StoreID int64
PID int
TargetURL string
StartedAt time.Time
}
type BrowserRuntimeView struct {
StoreID int64
Status string
PID int
ExitCode *int
LastError *AppError
ChangedAt time.Time
}
type BrowserLaunchService interface {
Open(ctx context.Context, request OpenStoreRequest) (LaunchResult, error)
Runtime(ctx context.Context, storeID int64) (BrowserRuntimeView, error)
ListRuntime(ctx context.Context) ([]BrowserRuntimeView, error)
}
```
`Open` 的副作用:
- 可能创建 managed profile 目录。
- 启动外部 Chrome。
- 成功后更新 `last_opened_at` 和最后 PID。
- 发布 `browser.status.changed`。
`Open` 不等待 Chrome 退出。应用退出时默认不结束已打开的 Chrome。
### 5.2 Platform ports
```go
type LaunchSpec struct {
Executable string
ProfileDir string
TargetURL string
ProxyURL string
}
type ProcessHandle interface {
PID() int
Wait(ctx context.Context) (exitCode int, err error)
}
type ChromeLauncher interface {
Start(ctx context.Context, spec LaunchSpec) (ProcessHandle, error)
}
type ProfileInspector interface {
Inspect(ctx context.Context, profileDir string) (ProfileUse, error)
}
type ProfileUse struct {
Occupied bool
PID int
Source string // shophelm_registry | chrome_lock | unknown
}
```
`ChromeLauncher` 的单元测试必须能注入 fake executable/command runner。只有 platform adapter 可构造 Chrome 参数。
## 六、商品服务
```go
type ProductInput struct {
StoreID int64
Name string
SKU string
Cost string
SalePrice string
Currency string
Stock *int
ProductURL string
Status string
Note string
}
type ProductFilter struct {
Query string
StoreIDs []int64
Statuses []string
IncludeArchived bool
Page PageRequest
}
type ProductService interface {
List(ctx context.Context, filter ProductFilter) (Page[domain.Product], error)
Get(ctx context.Context, id int64) (domain.Product, error)
Create(ctx context.Context, input ProductInput) (domain.Product, error)
Update(ctx context.Context, id int64, input ProductInput) (domain.Product, error)
Archive(ctx context.Context, id int64) error
Restore(ctx context.Context, id int64) (domain.Product, error)
}
type ContentTemplateService interface {
List(ctx context.Context, filter TemplateFilter) (Page[domain.ContentTemplate], error)
Create(ctx context.Context, input ContentTemplateInput) (domain.ContentTemplate, error)
Update(ctx context.Context, id int64, input ContentTemplateInput) (domain.ContentTemplate, error)
Archive(ctx context.Context, id int64) error
}
type ProductChecklistService interface {
List(ctx context.Context, productID int64) ([]domain.ProductCheckItem, error)
SeedDefaults(ctx context.Context, productID int64) ([]domain.ProductCheckItem, error)
SetChecked(ctx context.Context, itemID int64, checked bool) (domain.ProductCheckItem, error)
}
```
商品 URL 可以为空;非空时只接受绝对 HTTP(S) URL。SKU 可为空,但同一店铺非空 SKU 重复时 UI 必须警告;是否阻止保存由 T-301 根据用户确认定稿并同步 schema。
## 七、价格计算
```go
type PriceCalculationInput struct {
SalePrice string
ProductCost string
ShippingCost string
OtherCost string
PlatformFeeRate string
ExchangeRate string
Currency string
CostCurrency string
}
type PriceCalculationResult struct {
Inputs PriceCalculationInput
PlatformFee string
TotalCost string
ReferenceMargin string
ReferenceMarginRate string
Warnings []string
}
type PriceCalculator interface {
Calculate(input PriceCalculationInput) (PriceCalculationResult, error)
}
```
规则:
- 空费率、汇率或费用不能偷偷套默认值;返回校验错误或明确的零值警告。
- 除数为零时返回 `validation_failed`。
- 输出必须回显输入,界面称其为“基础利润参考”,不称财务报表。
## 八、商品文件导入导出
```go
type ImportFormat string // csv | xlsx
type ImportStrategy string // all_or_nothing | valid_rows_only
type ProductImportPreview struct {
SourcePath string
Fingerprint string
Format ImportFormat
Sheet string
ValidRows []ProductImportRow
Errors []ImportRowError
TotalRows int
}
type ProductImportCommit struct {
SourcePath string
Fingerprint string
Strategy ImportStrategy
DefaultStoreID int64
}
type ImportResult struct {
Created int
Updated int
Skipped int
}
type ProductImportExportService interface {
PreviewImport(ctx context.Context, path string, format ImportFormat) (ProductImportPreview, error)
CommitImport(ctx context.Context, request ProductImportCommit) (ImportResult, error)
Export(ctx context.Context, filter ProductFilter, destination string, format ImportFormat) (FileResult, error)
}
```
提交时重新计算文件 SHA-256;与 preview fingerprint 不同则返回 `source_changed`,要求重新预览。
## 九、图片素材与合成
### 9.1 素材服务
```go
type ImageAssetInput struct {
StoreID *int64
ProductID *int64
AssetType string
SourcePath string
CopyToLibrary bool
Note string
}
type ImageAssetService interface {
List(ctx context.Context, filter ImageAssetFilter) (Page[domain.ImageAsset], error)
Add(ctx context.Context, input ImageAssetInput) (domain.ImageAsset, error)
Update(ctx context.Context, id int64, input ImageAssetInput) (domain.ImageAsset, error)
Remove(ctx context.Context, id int64) error
RefreshMetadata(ctx context.Context, id int64) (domain.ImageAsset, error)
}
```
`Remove` 删除数据库关联;仅当文件是 app-managed 且用户明确勾选删除文件时,才能进入独立确认流程。默认不删文件。
### 9.2 合成规格
```go
type CompositionSpec struct {
BaseAssetID int64
OverlayAssetID int64
CanvasWidth int
CanvasHeight int
BaseFit string // contain | cover
CenterX float64 // normalized canvas coordinate
CenterY float64
WidthRatio float64
Opacity float64
BackgroundRGBA uint32
}
type CompositionPlan struct {
Canvas image.Rectangle
BaseSource image.Rectangle
BaseTarget image.Rectangle
OverlaySource image.Rectangle
OverlayTarget image.Rectangle
Opacity uint8
}
type ExportImageRequest struct {
StoreID *int64
ProductID *int64
Spec CompositionSpec
Format string // png | jpg
Destination string
Overwrite bool
}
type ImageComposerService interface {
Plan(ctx context.Context, spec CompositionSpec) (CompositionPlan, error)
RenderPreview(ctx context.Context, spec CompositionSpec, maxWidth, maxHeight int) (image.Image, error)
Export(ctx context.Context, request ExportImageRequest) (domain.ImageExport, error)
}
```
约束:
- `CanvasWidth`、`CanvasHeight` 必须为正,并受实现中明确的像素/内存上限约束。
- `WidthRatio` 大于 0;`Opacity` 在 `0..1`。
- `Plan` 是预览和导出的唯一几何算法。
- `Overwrite=false` 且目标存在时返回 `destination_exists`。
- `Overwrite=true` 仍不得覆盖任一输入素材文件。
- 导出成功前不写 `image_exports`;数据库记录失败时删除本次新建输出或报告可恢复的部分失败。
## 十、客服服务
```go
type ReplyTemplateInput struct {
Category string
Language string
Title string
Content string
}
type ReplyTemplateService interface {
List(ctx context.Context, filter ReplyTemplateFilter) (Page[domain.ReplyTemplate], error)
Create(ctx context.Context, input ReplyTemplateInput) (domain.ReplyTemplate, error)
Update(ctx context.Context, id int64, input ReplyTemplateInput) (domain.ReplyTemplate, error)
Archive(ctx context.Context, id int64) error
Copy(ctx context.Context, id int64) (CopyResult, error)
}
type CustomerFollowupInput struct {
StoreID int64
BuyerLabel string
OrderRef string
IssueType string
Status string
NextFollowupAt *time.Time
Note string
}
type CustomerFollowupService interface {
List(ctx context.Context, filter FollowupFilter) (Page[domain.CustomerFollowup], error)
Create(ctx context.Context, input CustomerFollowupInput) (domain.CustomerFollowup, error)
Update(ctx context.Context, id int64, input CustomerFollowupInput) (domain.CustomerFollowup, error)
Archive(ctx context.Context, id int64) error
}
```
`Copy` 成功写入系统剪贴板后才增加 `usage_count`。剪贴板失败时不增加计数。
## 十一、工作台
```go
type DashboardQuery struct {
Now time.Time
RecentStoreLimit int
RecentExportLimit int
}
type DashboardView struct {
RecentStores []StoreView
DueTodos []domain.Todo
DueFollowups []domain.CustomerFollowup
PendingProducts []domain.Product
RecentExports []domain.ImageExport
}
type DashboardService interface {
Load(ctx context.Context, query DashboardQuery) (DashboardView, error)
}
```
Dashboard 允许各分区分别失败并显示局部错误,但不得把失败分区伪装为空数据。
## 十二、设置、备份与恢复
```go
type SettingsService interface {
Get(ctx context.Context) (domain.Settings, error)
Update(ctx context.Context, input SettingsInput) (domain.Settings, error)
}
type BackupService interface {
Create(ctx context.Context, destination string) (BackupResult, error)
Inspect(ctx context.Context, source string) (BackupManifest, error)
Restore(ctx context.Context, source string, confirmation RestoreConfirmation) (RestoreResult, error)
}
```
`RestoreConfirmation` 必须包含 UI 展示过的备份 fingerprint 和用户确认标志。恢复期间 application 进入 maintenance 状态,其他写操作返回 `maintenance_mode`。
## 十三、应用事件
| 事件 | 触发时机 | 负载 | UI 结果 |
| --- | --- | --- | --- |
| `operation.started` | 异步 intent 接受 | request ID、operation、entity | 显示 busy,禁用重复提交 |
| `operation.completed` | 操作成功 | request ID、result summary | 更新页面并反馈成功 |
| `operation.failed` | 操作失败 | request ID、AppError | 保留输入,显示可行动错误 |
| `browser.status.changed` | Chrome 启动、运行或退出 | BrowserRuntimeView | 更新店铺行状态 |
| `data.restored` | 恢复并重新打开数据库成功 | backup ID、schema version | 清空页面缓存并重载 |
| `preview.ready` | 最新图片预览完成 | request ID、preview image | 仅接收当前 request ID 的结果 |
旧请求的预览事件到达时,UI 根据 request ID 丢弃,避免快速拖动后显示过期画面。
## 十四、错误码
| Code | 含义 | 是否可重试 |
| --- | --- | --- |
| `validation_failed` | 字段或组合不合法 | 修正输入后 |
| `not_found` | 资源不存在或已归档 | 否 |
| `conflict` | 唯一约束或状态冲突 | 修改输入后 |
| `profile_in_use` | Chrome profile 已占用 | 关闭对应进程后 |
| `chrome_not_found` | Chrome 路径无效 | 配置后 |
| `chrome_start_failed` | 进程启动失败 | 视 cause |
| `proxy_invalid` | 代理格式无效 | 修正配置后 |
| `source_missing` | 素材或导入文件不存在 | 重新选择 |
| `source_changed` | 导入 preview 后文件已变化 | 重新预览 |
| `unsupported_format` | 文件或图片格式不支持 | 选择支持格式 |
| `destination_exists` | 输出已存在且未允许覆盖 | 改名或确认覆盖 |
| `file_access_denied` | 文件权限不足 | 修改目录权限后 |
| `database_busy` | SQLite 超时仍被占用 | 是 |
| `database_corrupt` | 完整性检查失败 | 使用有效备份 |
| `backup_incompatible` | schema 版本不支持 | 升级应用或选其他备份 |
| `maintenance_mode` | 恢复期间拒绝写入 | 恢复完成后 |
| `cancelled` | 用户取消或 context 结束 | 可重新发起 |
| `internal` | 未分类内部错误 | 视日志 |
新增错误码必须同步 UI 映射和测试,不得把底层错误字符串当稳定合约。
## 十五、副作用边界
| 操作 | 允许的副作用 | 禁止的副作用 |
| --- | --- | --- |
| 保存店铺 | SQLite 写入;创建 managed profile 目录 | 登录平台、删除已有 profile |
| 打开店铺 | 启动 Chrome;记录状态 | 注入凭证、开启 CDP、操作网页 |
| 导入商品 | 读取用户文件;确认后事务写 SQLite | 修改源文件、静默跳过错误 |
| 添加素材 | 读取图片;可选复制到素材库 | 修改原图 |
| 导出图片 | 创建新输出;写导出记录 | 用 UI 截图导出、默认覆盖 |
| 复制话术 | 写系统剪贴板;增加使用次数 | 自动发送到平台 |
| 备份 | 创建一致性数据库副本 | 复制全部 Chrome profile |
| 恢复 | 验证后替换数据库并保留回滚副本 | 未确认覆盖、删除外部素材 |
+18
View File
@@ -0,0 +1,18 @@
# 干净收尾检查清单
> 每轮会话结束前逐项检查,确保下一轮只依靠仓库即可继续。
- [ ] 当前只存在一个 `DOING` 任务,或没有进行中任务。
- [ ] 当前任务状态与实际完成边界一致,没有无证据的 `DONE`。
- [ ] `go test ./...`、`go vet ./...` 和 build 已运行;无法运行时已在 `progress.md` 如实记录。
- [ ] 任务要求的 Gio、Chrome、图片、导入或恢复 smoke 已运行并记录环境。
- [ ] `progress.md` 已追加真实命令、结果、阻塞和决策。
- [ ] `current-state.md` 已覆盖为当前目录、命令、版本、blocker 和下一任务。
- [ ] 需求、依赖、schema、合约或页面发生变化时,对应权威文档已同步。
- [ ] 没有真实密码、Cookie、token、买家隐私、生产 profile 或私有 URL 进入变更。
- [ ] 没有未说明的半成品、临时输出或测试进程残留。
- [ ] 测试没有改写用户数据库、外部 profile 或原始图片。
- [ ] 工作区中的用户无关改动未被覆盖或回退。
- [ ] 如使用 Git,`git status --short` 中每项变化都能解释;必要提交仅包含当前任务。
任一项不满足时先补齐;确实无法补齐则把任务保留为 `DOING` 或标 `BLOCKED`,记录原因和恢复步骤。
+97
View File
@@ -0,0 +1,97 @@
# 当前实现状态
> 可覆盖的仓库现实快照。历史执行和验证结果只追加到 [`../progress.md`](../progress.md)。
## 当前快照
- 日期:2026-07-11
- 阶段:Harness 文档基线完成,生产代码待初始化
- 项目目录:`D:\OPC\shop_helm`
- 产品:店小航 ShopHelm,Windows 本地跨境电商运营工作台
- 技术路线:Go + Gio + SQLite + 外部 Chrome
- 本机 Go:`go1.23.0 windows/amd64`
- 本机 Git:`git version 2.49.0.windows.1`
- Git 仓库:已初始化,当前为 `main`,已有初始提交并配置 `origin`
- Go module:尚未初始化
- 生产代码:无
- 自动测试:无
- Harness 校验:本地链接、占位符、空白、code fence、任务图、P0 追踪、脚本语法和 `git diff --check` 均已通过
- 当前 blocker:无;T-001 尚未执行是计划状态,不是阻塞
## 已存在内容
| 路径 | 状态 | 说明 |
| --- | --- | --- |
| `AGENTS.md` | 已有 | 仓库级 agent 规则和安全边界 |
| `README.md` | 已有 | 人类入口和项目状态 |
| `.git` / `.gitignore` | 已有 | 现有 Git 仓库和 Go ignore 规则,保持用户配置 |
| `.gitattributes` | 已有 | 文本统一 LF,二进制素材不做行尾转换 |
| `docs/` | 已有 | 产品、技术、架构、任务和质量文档 |
| `progress.md` | 已有 | 只追加执行流水 |
| `init.ps1` / `init.sh` | 已有 | 计划中的标准 Go 启动入口 |
| `cmd/` | 待建 | T-001 创建 Gio 应用入口 |
| `internal/` | 待建 | T-002 起创建模块 |
| `migrations/` | 待建 | T-003 创建 |
| `go.mod` / `go.sum` | 待建 | T-001 创建并锁定版本 |
## 任务状态
任务权威来源是 [`06-tasks.md`](06-tasks.md)。
- 已完成:无生产开发任务。
- 正在进行:无。
- 下一个可领取任务:T-001 初始化 Go module 和最小 Gio 窗口。
## 当前可运行内容
当前只有文档,没有可启动应用。
```powershell
./init.ps1
```
该命令当前会因缺少 `go.mod` 主动退出并提示执行 T-001,这是设计行为。
T-001 完成后的预期标准命令:
```powershell
./init.ps1
go run ./cmd/shophelm
go test ./...
go vet ./...
go build -o build/shophelm.exe ./cmd/shophelm
```
在实际成功运行前,不得把这些预期命令描述为已验证。
## 已确认决策
- 首发只支持 Windows 本地桌面。
- 使用 Go + Gio,不使用 Wails。
- 首发按店铺 -> 商品/图片 -> 客服顺序交付。
- SQLite 保存结构化数据,原图按路径引用。
- MVP 不保存平台密码,不支持代理认证。
- 每个店铺使用独立 Chrome `user-data-dir`,但不提供防关联能力。
- 图片预览使用 Gio,正式导出使用独立 CPU 合成管线。
- 首发不接平台 API、不做 RPA 和自动页面操作。
## 下一轮开工
1. 读取 `AGENTS.md` 和 `docs/00-ai-start-here.md`。
2. 在 `docs/06-tasks.md` 把 T-001 改为 `DOING`。
3. 保留现有 Git 配置,初始化 module `shophelm`。
4. 用本机 Go 运行最小 Gio 窗口;若不兼容,升级到受支持 Go 工具链并记录结论。
5. 锁定依赖版本,同步本文和 `docs/03-tech-stack.md`。
6. 完成全部验收后才能将 T-001 改为 `DONE`。
## 维护规则
以下变化发生时覆盖更新本文件:
- Git 状态、Go module 或生产目录发生变化。
- 实际 Go/Gio 版本确定。
- 标准命令首次运行或发生变化。
- 任务状态变化。
- 新增 blocker 或文档与代码出现差异。
同时把任务状态同步到 `06-tasks.md`,把真实执行证据追加到 `../progress.md`。
+49
View File
@@ -0,0 +1,49 @@
# 单次交付评审评分表
> 任务实现完成、正式接受前使用。它评估一轮交付;长期代码库质量见 [`quality-document.md`](quality-document.md)。
## 评分
每项 0-2 分:`0` 不满足,`1` 部分满足,`2` 完全满足。
| 维度 | 2 分标准 | 分数 | 证据 |
| --- | --- | --- | --- |
| 需求正确性 | 当前任务对应需求 ID 和全部验收均满足 | | |
| 验证真实性 | 自动命令和手工 smoke 均实际运行,结果写入 progress | | |
| 范围纪律 | 只修改当前任务需要内容,无 Backlog 和无关重构 | | |
| 架构边界 | UI/application/domain/infrastructure/platform 依赖符合文档 | | |
| 数据与副作用安全 | 数据库、文件、profile、进程和恢复失败路径均受控 | | |
| 安全与合规 | 无秘密泄露、无绕过平台边界、无未经确认自动化 | | |
| 交接准备度 | 文档、任务、current state 和下一步足够新会话继续 | | |
总分:`/14`
## 强制门槛
结论为 **Accept** 必须同时满足:
- 总分至少 12。
- “需求正确性”和“验证真实性”均为 2。
- 不存在任何 0 分。
- 安全硬边界没有违反。
- 任务状态、progress 和 current state 已同步。
任一安全硬边界违反,直接 **Block**,不能用总分抵消。
## 结论
- **Accept**:达到门槛,可以将任务保持为 `DONE`。
- **Revise**:实现方向可用,但有明确缺口;任务回到 `DOING`,列出修复。
- **Block**:存在根本风险、技术闸门失败或需要用户决策;任务标 `BLOCKED`。
## 评审记录
- 任务 ID:
- 评审日期:
- 结论:
- 缺失证据:
- 必须修复:
- 残余风险:
- 下次复审条件:
评审不能靠 agent 自己概括“看起来没问题”。每个 2 分都要引用测试命令、手工步骤、代码位置或文档条目。
+27
View File
@@ -0,0 +1,27 @@
# 方法对照表
> 遇到失败模式时先修最相关的工件或边界,不把新规则全部塞进入口文件。
| 失败模式 | 表现 | 首要修复 | 权威工件 |
| --- | --- | --- | --- |
| 新会话重新摸索 | 不知道现在能否运行、下一个任务是什么 | 恢复现实快照 | [`current-state.md`](current-state.md) + [`../progress.md`](../progress.md) |
| 范围扩散 | 店铺没闭环就开始订单、AI、RPA | 回到需求和任务依赖 | [`02-requirements.md`](02-requirements.md) + [`06-tasks.md`](06-tasks.md) |
| Gio 页面卡顿 | 滚动或拖动时 UI 冻结 | 把 I/O 移出 frame,检查事件模型 | [`04-architecture.md`](04-architecture.md) + [`05-coding-rules.md`](05-coding-rules.md) |
| UI 状态丢失 | 输入框、按钮或滚动每帧重置 | 持久化页面/widget 状态 | [`routes.md`](routes.md) + [`05-coding-rules.md`](05-coding-rules.md) |
| Chrome 混店或重复启动 | profile 参数错误、占用仍启动 | 收紧 launch/profile port 和测试 | [`api.md`](api.md) + T-102 |
| 把 profile 当防关联 | 文案承诺规避平台关联 | 回到产品和合规边界 | [`01-vision.md`](01-vision.md) + [`AGENTS.md`](../AGENTS.md) |
| 图片预览与导出不一致 | 位置、缩放或透明度改变 | 只保留共享 planner | [`04-architecture.md`](04-architecture.md) + T-103 |
| 原图被改写 | 输出路径等于输入或直接原地保存 | 原子新文件和覆盖保护 | [`05-coding-rules.md`](05-coding-rules.md) + [`api.md`](api.md) |
| 导入静默丢数据 | 无效行跳过但用户不知道 | preview、fingerprint、事务提交 | [`api.md`](api.md) + T-304 |
| 数据恢复后损坏 | 未校验就替换 SQLite | 完整性检查和回滚副本 | [`04-architecture.md`](04-architecture.md) + T-208 |
| 代码改了就宣布完成 | 没有测试、build 或 smoke | 绑定完成到证据 | [`06-tasks.md`](06-tasks.md) + [`clean-state-checklist.md`](clean-state-checklist.md) |
| 多 agent 抢改看板 | 状态覆盖、ID 冲突 | 切换一任务一文件 | [`tasks/README.md`](tasks/README.md) |
| 文档与实现漂移 | schema/API/页面各自演化 | 按变更类型同步权威文档 | [`AGENTS.md`](../AGENTS.md) 的文档同步规则 |
| 日志泄露敏感数据 | 错误日志包含账号或路径秘密 | 结构化错误码和脱敏测试 | [`05-coding-rules.md`](05-coding-rules.md) + T-501 |
## 使用原则
- 先确认失败模式,再修最小的一项事实、边界或测试。
- 修复完成的同一任务同步相关工件。
- 同一个事实只有一个权威位置,其他文档只做摘要和链接。
- 高风险功能用可复现原型和测试给结论,不靠“理论上可行”。
+50
View File
@@ -0,0 +1,50 @@
# 代码库质量文档
> 跟踪 ShopHelm 产品领域和架构层的长期健康度。单次任务输出使用 [`evaluator-rubric.md`](evaluator-rubric.md)。
## 评级
- **A**:完整验证通过,边界清楚,测试稳定,新 agent 可直接接手。
- **B**:主要验证通过,有少量明确缺口但不影响核心使用。
- **C**:部分可用,存在可靠性、测试或可读性缺口。
- **D**:不可用,或存在数据/安全/结构性问题。
- **N/A**:尚未实现,不参与质量趋势判断。
## 产品领域
| 领域 | 评级 | 验证状态 | Agent 可读性 | 测试稳定性 | 关键缺口 | 上次更新 |
| --- | --- | --- | --- | --- | --- | --- |
| 多店铺运营台 | N/A | 未实现 | 文档已定义 | 无测试 | T-201 至 T-209 | 2026-07-11 |
| 商品运营助手 | N/A | 未实现 | 文档已定义 | 无测试 | T-301 至 T-308 | 2026-07-11 |
| 图片预览与导出 | N/A | 未实现 | 合约已定义 | 无测试 | T-103、T-305 至 T-307 | 2026-07-11 |
| 客服助手 | N/A | 未实现 | 文档已定义 | 无测试 | T-401 至 T-405 | 2026-07-11 |
| 数据备份恢复 | N/A | 未实现 | 流程已定义 | 无测试 | T-208 | 2026-07-11 |
## 架构层
| 层级 | 评级 | 边界执行 | Agent 可读性 | 关键缺口 | 上次更新 |
| --- | --- | --- | --- | --- | --- |
| Harness / 项目文档 | A | 入口和权威来源已建立 | 高 | 随实现持续校准 | 2026-07-11 |
| Gio UI | N/A | 未实现 | 目标边界已定义 | T-001、T-101 | 2026-07-11 |
| Application / Domain | N/A | 未实现 | 合约已定义 | T-004 起实现 | 2026-07-11 |
| SQLite persistence | N/A | 未实现 | schema 草案已定义 | T-003、T-201 起实现 | 2026-07-11 |
| Chrome platform adapter | N/A | 未实现 | 副作用边界已定义 | T-102 | 2026-07-11 |
| Image pipeline | N/A | 未实现 | 几何与导出边界已定义 | T-103 | 2026-07-11 |
## 更新规则
- 每个阶段验收任务完成后更新对应产品领域。
- 架构或高风险模块发生实质变化后更新对应架构层。
- 评级下降必须写明触发变更和恢复任务。
- 没跑验证不能给 A;仅“代码已完成”最高不得超过 C。
- 尚未实现用 N/A,不用 D 惩罚计划中的空白。
## 变更历史
### 2026-07-11
- 变更:按 Harness Coding 模板建立 ShopHelm 产品、技术、架构、任务和质量文档。
- 提升:聊天中的产品结论转为仓库内可执行事实。
- 下降:无。
- 新缺口:生产代码、自动测试和真实 Windows smoke 尚未开始。
- 下一检查点:T-104 三个高风险技术闸门完成后。
+252
View File
@@ -0,0 +1,252 @@
# Gio 页面与导航结构
> ShopHelm 是桌面应用,没有浏览器 URL。本文用稳定的 route ID 定义页面、参数、职责和组件归属。
## 一、应用框架
首发窗口由 `AppShell` 组成:
```text
+----------------+---------------------------------------------+
| 主导航 | 页面工具栏 |
| +---------------------------------------------+
| 今日工作台 | |
| 店铺管理 | 当前页面内容 |
| 商品助手 | |
| 客服助手 | |
| 设置 | |
+----------------+---------------------------------------------+
| 全局状态栏:数据库 / 后台操作 / 错误入口 |
+--------------------------------------------------------------+
```
主页面不做营销首页。窗口最小尺寸由 T-101 实测确定;低于舒适宽度时侧栏可折叠,但表格和表单不得重叠或截断关键动作。
## 二、Route 定义
| Route ID | 参数 | 页面 | 首发 |
| --- | --- | --- | --- |
| `dashboard` | 无 | 今日工作台 | 是 |
| `stores.list` | 可选 filter snapshot | 店铺列表 | 是 |
| `stores.new` | 无 | 新增店铺 | 是 |
| `stores.detail` | `store_id` | 店铺详情 | 是 |
| `stores.edit` | `store_id` | 编辑店铺 | 是 |
| `products.list` | 可选 `store_id` | 商品草稿列表 | 是 |
| `products.new` | 可选 `store_id` | 新增商品 | 是 |
| `products.detail` | `product_id` | 商品详情/编辑 | 是 |
| `products.templates` | `kind` | 标题/描述模板 | 是 |
| `products.import` | 无 | 商品导入预览 | 是 |
| `images.assets` | 可选 `store_id`,`product_id` | 图片素材库 | 是 |
| `images.compose` | 可选 `product_id`,`base_asset_id` | 图片叠加预览 | 是 |
| `customer.replies` | 可选 category/language | 客服话术库 | 是 |
| `customer.followups` | 可选 `store_id`,`status` | 跟进记录 | 是 |
| `settings.general` | 无 | 常规和路径设置 | 是 |
| `settings.backup` | 无 | 备份与恢复 | 是 |
| `settings.logs` | 无 | 日志位置和诊断信息 | P1 |
无效或已归档 ID 导航到当前页面的 `not_found` 状态,提供返回列表入口,不打开空白窗口。
## 三、主导航
主导航固定五项:
1. 今日工作台。
2. 店铺管理。
3. 商品助手。
4. 客服助手。
5. 设置。
图片素材和图片叠加属于商品助手,不作为一级导航。备份恢复属于设置。
## 四、页面职责
### 4.1 今日工作台
- 最近打开店铺,可直接打开默认入口。
- 今日/逾期待办与客服跟进。
- 待上架、需优化商品。
- 最近图片导出。
- 四个新增快捷动作。
- 每个分区独立显示 loading、empty 或 error,局部失败不清空其他分区。
### 4.2 店铺列表
- 表格列:店铺名、平台、国家/站点、账号标识、负责人、标签、业务状态、Chrome 状态、最后打开、更新时间、操作。
- 工具栏:搜索、平台/国家/负责人/标签/状态筛选、排序、新增。
- 行操作使用图标按钮并带 tooltip:打开、快捷入口菜单、编辑、归档。
- 双击或点击店铺名进入详情;“打开 Chrome”必须是独立明确动作。
- 默认排除归档记录。
### 4.3 店铺新增/编辑
分区:
- 基本信息。
- Chrome/profile。
- 代理。
- 快捷入口。
- 备注。
保存前显示字段错误。切换页面时有未保存内容则确认离开。密码字段不得出现。
### 4.4 店铺详情
- 顶部显示店铺身份和业务/Chrome 状态。
- 主要命令:打开默认入口、打开快捷入口、编辑。
- 显示 profile 路径、代理摘要、最后打开、负责人、标签和待办。
- profile 路径可复制或在文件管理器中定位;不得提供“一键删除 profile”。
### 4.5 商品列表和详情
列表:
- 按店铺、状态和关键词筛选。
- 显示商品名、SKU、店铺、价格、库存、状态、检查进度、更新时间。
- 提供新增、导入、导出入口。
详情:
- 基础资料和价格。
- 标题/描述模板选择。
- 上架检查清单。
- 图片素材。
- 打开图片叠加预览。
价格计算结果与输入放在同一无嵌套面板中,明确标记为参考值。
### 4.6 商品导入
- 第一步选择 CSV/XLSX。
- 第二步显示文件摘要、列映射、有效行和错误行。
- 第三步选择 `all_or_nothing` 或 `valid_rows_only` 并确认。
- 提交后显示创建、更新、跳过统计。
未经 preview 不允许直接导入。
### 4.7 图片素材库
- 显示真实缩略图、类型、所属店铺/商品、尺寸和缺失状态。
- 支持按路径引用或复制到 ShopHelm 素材库。
- 原图缺失时显示路径和重新定位入口。
- 删除关联和删除受管文件是两个不同动作。
### 4.8 图片叠加预览
稳定布局:
```text
+----------------------------+----------------------+
| | 底图 / 叠加图选择 |
| | 位置 X / Y |
| 实时预览画布 | 缩放 |
| | 透明度 |
| | 输出尺寸 / 格式 |
| | 导出 |
+----------------------------+----------------------+
```
- 画布保持目标宽高比,窗口变化不改变 composition spec。
- 拖动叠加图时更新归一化中心点。
- 数字输入、滑杆和重置按钮保持同步。
- 预览生成中显示稳定 loading,不改变画布尺寸。
- 导出成功后显示输出路径和“在文件夹中显示”动作。
- 不放多图层列表、滤镜、文字工具或旋转工具。
窄窗口下控制区移到画布下方,不覆盖画布。
### 4.9 客服话术
- 分类、语言、关键词筛选。
- 列表显示标题和安全长度的内容预览。
- 一键复制是主要动作,并显示反馈。
- 新增/编辑使用同页表单或 modal,由 T-101 的组件原型决定,整个应用保持一致。
### 4.10 客服跟进
- 表格显示店铺、买家标识、订单标识、问题类型、状态、下次跟进和更新时间。
- 默认优先显示逾期、今日到期和未解决记录。
- 可快速更新状态。
- 不显示“发送消息”按钮。
### 4.11 设置
常规设置:
- Chrome 可执行文件。
- managed profile 根目录。
- 默认图片导出目录。
- 默认货币和界面语言。
备份设置:
- 创建备份。
- 备份清单和位置。
- 检查后恢复。
- 清晰说明备份不包含 Chrome profile 和外部素材。
## 五、项目内组件
| 组件 | 归属 | 稳定职责 |
| --- | --- | --- |
| `AppShell` | `ui/components` | 侧栏、工具栏、内容区、全局状态 |
| `DataTable` | `ui/components` | 固定列、表头、滚动、选中、排序、行操作 |
| `FilterBar` | `ui/components` | 搜索、筛选、重置 |
| `FormField` | `ui/components` | 标签、输入、帮助和字段错误 |
| `Select` | `ui/components` | 有限枚举选择 |
| `Modal` | `ui/components` | 确认和小型编辑流程 |
| `Toast` | `ui/components` | 短时成功/失败反馈 |
| `StatusBadge` | `ui/components` | 状态文字、图标和颜色 |
| `EmptyState` | `ui/components` | 空数据和一个主要动作 |
| `ErrorPanel` | `ui/components` | 可行动错误与重试 |
| `PathPicker` | `ui/components` | 路径显示、选择和校验 |
| `ImagePreviewCanvas` | `ui/components` | 画布、拖动和 viewport 映射 |
| `ImageLayerControls` | `ui/components` | 位置、缩放、透明度和重置 |
组件只抽象已经在至少两个页面出现的稳定交互;首个页面不提前建设通用表单 DSL。
## 六、导航状态
```go
type Route struct {
Name RouteName
Params map[string]string
}
type Navigator interface {
Push(Route)
Replace(Route)
Back()
}
```
- 应用启动进入 `dashboard`。
- 列表进入详情后返回时保留搜索、筛选、排序和滚动位置。
- 保存成功后回到来源页或留在详情,由页面任务验收明确;不可每页自行决定不同模式。
- 恢复数据库成功后清空历史栈并进入 `dashboard`。
- 未保存表单离开时弹确认;没有改动时直接离开。
## 七、统一页面状态
每个页面显式维护:
```text
idle -> loading -> ready
`-> empty
`-> error
ready -> submitting -> ready/error
```
- loading、empty、error 使用稳定尺寸,避免整个布局跳动。
- 请求进行中禁用重复动作,但保留取消或返回能力。
- error 保留用户已输入的表单内容。
- 删除/归档、覆盖、恢复等不可逆或高影响动作使用确认 modal。
## 八、UI 文字与图标
- 命令按钮优先使用 Gio/项目已有标准图标;不手画重复图标。
- 图标按钮必须有 tooltip 和可访问名称。
- 状态必须同时有文字或图标,不只靠颜色。
- 表格内部使用紧凑字号,不使用 hero 级标题。
- 固定格式画布、表格列和工具栏必须有稳定尺寸约束。
- 页面不放“本功能可以做什么”的宣传说明;只在错误、空状态和确认流程中显示必要操作信息。
+50
View File
@@ -0,0 +1,50 @@
# 多 agent 一任务一文件
> 当前默认使用 [`../06-tasks.md`](../06-tasks.md) 单文件看板。只有多个 agent 或人/agent 并发开发时才切换本模式。
## 切换规则
1. 把 `docs/06-tasks.md` 冻结为已存在任务的索引,不再并发修改任务行。
2. 新任务在本目录使用 `T-<编号>.md`。
3. 每个 agent 只编辑自己领取的任务文件和该任务必要的代码。
4. 执行记录写入任务文件,不逐任务抢改共享 `progress.md` 和 `current-state.md`。
5. 阶段性汇总由单一协调者更新共享文件。
## 文件名和编号
- 文件名:`T-101.md`,细分任务可用 `T-101a.md`。
- 新编号取 `06-tasks.md` 与本目录现有任务最大编号加一。
- 目标文件存在时换下一个编号,不覆盖。
- `_template.md` 不参与编号。
## Frontmatter
```yaml
---
id: T-XXX
title: 一句话任务名
phase: 1
deps: []
status: TODO
created: YYYY-MM-DD
owner:
---
```
状态只允许 `TODO`、`DOING`、`DONE`、`BLOCKED`。
## 领取
- 选择编号最小且依赖全 `DONE` 的 `TODO`。
- 设置 `owner` 和 `DOING` 后再开始。
- 同一 agent 一次只领取一个。
- 发现已有 owner 或状态刚变化时不得覆盖,重新选择任务。
## 完成
- 在任务文件记录变更、真实命令、结果、手工 smoke、决策和残余风险。
- 全部验收通过后改为 `DONE`。
- 验证失败时保持 `DOING`;确有外部决策阻塞时标 `BLOCKED` 并写清恢复条件。
- 不以“代码已写”代替证据。
流程和安全规则的唯一权威源仍是 [`../../AGENTS.md`](../../AGENTS.md)。用户使用 `grill me:` 时只做反方评审,不自动建立或实现任务。
+36
View File
@@ -0,0 +1,36 @@
---
id: T-XXX
title: 一句话任务名
phase: 1
deps: []
status: TODO
created: YYYY-MM-DD
owner:
---
## 需求与背景
对应需求 ID、现象和为什么要做。
## 方案
明确修改的模块、数据/服务/页面变化和副作用边界。
## 验收要点
- 可执行的自动验证命令。
- 可观察的手工 smoke。
- 失败路径和安全边界。
## 边界
明确本任务不修改和不实现的内容。
## 执行记录
- 状态:
- 变更:
- 验证:
- 阻塞:
- 决策:
- 残余风险:
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env pwsh
# ShopHelm 标准启动与验证入口(Windows PowerShell)。
# 默认执行依赖同步和基础测试,只打印启动命令。
# 设置 RUN_START_COMMAND=1 后才会实际启动 Gio 应用。
$ErrorActionPreference = "Stop"
Set-Location -Path $PSScriptRoot
if (-not (Test-Path -LiteralPath "go.mod")) {
Write-Error "尚未找到 go.mod。当前应先完成 docs/06-tasks.md 的 T-001,再运行本脚本。"
exit 2
}
$InstallCmd = "go mod download"
$VerifyCmd = "go test ./..."
$StartCmd = "go run ./cmd/shophelm"
Write-Host "==> 当前目录: $($PWD.Path)"
Write-Host "==> 同步 Go 依赖"
Invoke-Expression $InstallCmd
Write-Host "==> 运行基础测试"
Invoke-Expression $VerifyCmd
Write-Host "==> 开发启动命令"
Write-Host " $StartCmd"
if ($env:RUN_START_COMMAND -eq "1") {
Write-Host "==> 启动 ShopHelm"
Invoke-Expression $StartCmd
} else {
Write-Host "设置 RUN_START_COMMAND=1 可让 init.ps1 在验证通过后启动应用。"
}
Executable
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# ShopHelm 标准启动与验证入口(WSL / Git Bash / macOS / Linux)。
# Windows 原生开发以 ./init.ps1 为权威入口;本文件保持等价命令。
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT_DIR"
if [[ ! -f go.mod ]]; then
echo "ERROR: 尚未找到 go.mod。当前应先完成 docs/06-tasks.md 的 T-001。"
exit 2
fi
INSTALL_CMD=(go mod download)
VERIFY_CMD=(go test ./...)
START_CMD=(go run ./cmd/shophelm)
echo "==> 当前目录: $PWD"
echo "==> 同步 Go 依赖"
"${INSTALL_CMD[@]}"
echo "==> 运行基础测试"
"${VERIFY_CMD[@]}"
echo "==> 开发启动命令"
printf ' %q' "${START_CMD[@]}"
printf '\n'
if [[ "${RUN_START_COMMAND:-0}" == "1" ]]; then
echo "==> 启动 ShopHelm"
exec "${START_CMD[@]}"
fi
echo "设置 RUN_START_COMMAND=1 可让 init.sh 在验证通过后启动应用。"
+33
View File
@@ -0,0 +1,33 @@
# 执行进度记录
> 本文件只追加历史记录。任务状态以 [`docs/06-tasks.md`](docs/06-tasks.md) 为准;当前可运行状态以 [`docs/current-state.md`](docs/current-state.md) 为准。
## 记录规则
每轮任务完成、部分完成或阻塞时,在文件末尾追加:
```markdown
## YYYY-MM-DD T-XXX 任务名
- 状态:DONE / PARTIAL / BLOCKED
- 变更:修改的文件和行为
- 验证:真实执行的命令、结果和必要的手工 smoke
- 阻塞:没有则写“无”
- 决策:本轮新增或确认的关键取舍
- 下一步:下一个可领取任务或需要用户确认的问题
```
没有命令或可观察证据,不得把任务记为 `DONE`。
## 执行记录
<!-- 从此处向下只追加,不重写历史。 -->
## 2026-07-11 DOC-000 建立 ShopHelm Harness Coding 文档
- 状态:DONE
- 变更:参考 `D:\github\harness_coding_docs`,建立仓库入口、产品愿景、37 项 P0 需求追踪、Go + Gio 技术栈、分层架构、本地模块合约、Gio 页面结构、编码规则、34 项依赖任务、当前状态和质量文档;补充标准启动脚本与 LF 行尾规则。
- 验证:本地 Markdown 链接全部可解析;无意外模板占位符和行尾空格;Markdown code fence 成对;34 个任务依赖无缺失/无环且 0 个 `DOING`;37 个 P0 需求 ID 全部映射到任务;`git diff --check` 通过;`bash -n ./init.sh` 通过;`init.ps1` 在缺少 `go.mod` 时按预期非零退出并提示 T-001。
- 阻塞:生产代码和 `go.mod` 尚不存在,因此没有运行 Go test/build;这是 T-001 的计划范围。
- 决策:首发固定为 Windows 本地 Go + Gio 应用,按多店铺运营台 -> 商品/单图合成 -> 客服助手推进;不保存平台密码,不做防关联、RPA 主链路和未经确认的平台自动化。
- 下一步:领取 T-001,初始化 module `shophelm` 和最小 Gio 窗口,实测并锁定 Go/Gio 版本。