---
name: sop-generate
description: 对已部署、可访问的 Web 应用生成带截图的中文业务 SOP(操作手册)。触发词:生成业务SOP、操作手册、sop-generate、给这个系统写个操作流程文档。注意与开发流程 SOP 区分——本 skill 产出的是"业务人员怎么用这个系统办公"的手册,不是代码/部署流程文档。
---

# sop-generate — 业务 SOP 生成

## Overview

给一个**已部署、可访问**的 Web 应用生成中文业务操作手册:谁在什么环节、在哪个页面、做什么操作、系统自动做什么、异常怎么办,并配真实截图与至少一个可复现的使用样例。

核心分工(参照 Flaex/web-app-tutorial-generator):**脚本只管截图和抓 DOM/accessibility 摘要,模型只管读摘要写文案**。绝不把整页截图喂给模型做文案——省 token,也省时间。

硬规则(贯穿全流程,违反即返工):

1. **凭据绝不写入产出文档,也绝不经命令行参数传递**。测试账号的用户名/密码/token 只能出现在你与用户的对话、本地 `.env` 读取、或传给 crawl.mjs 的**环境变量**(`SOP_USER`/`SOP_PASS`)里;`docs/SOP-*.md`、`docs/sop-images/` 及其任何提交物中**一律不出现真实凭据**。手册里提到登录时写"使用测试账号登录"而非具体值。调用 `<本 skill base directory>/scripts/crawl.mjs` 时凭据只经环境变量传入(`SOP_USER=... SOP_PASS=... node ...`),不出现在 `--user`/`--pass` 命令行参数里——argv 会落进 shell history、`ps aux` 可见的进程列表、以及会话记录,即使脚本本身不回写文件,凭据也已经泄漏到这几处。
2. **业务黑话首次出现必须解释**(如"红点/非红点"这类项目内部术语)。
3. **页面矩阵必须全覆盖**——遍历到的每个页面、每个功能点都要在矩阵里出现,不允许"看起来不重要就跳过"。
4. **样例必须真实走一遍**,不能编造操作结果;截图即证据。

## 技术路线

- **主路径**:用本 skill 自带的原生 Playwright Node 脚本 `<本 skill base directory>/scripts/crawl.mjs`(登录→遍历→截图三段式;用绝对路径调用,因为执行时 cwd 是被测项目根目录,相对路径 `scripts/crawl.mjs` 解析不到)。首次用需要 `npm install playwright` 或已有全局安装;脚本会自检并报缺失依赖的安装命令,不擅自静默安装。凭据经环境变量传入(见硬规则 1),例如:
  ```
  SOP_USER='<测试账号>' SOP_PASS='<密码>' node <本 skill base directory>/scripts/crawl.mjs --url <部署URL> --out docs/sop-images
  ```
  **能力落差**:该脚本只负责静态页面的首轮采集,每页产出一张全页截图 + accessibility 摘要,不做步骤 3 要求的"关键操作前/后两张"截图——那需要脚本感知具体的点击/表单提交动作。脚本支持可选的 `--actions <json文件>` 参数,传入一份动作清单(`[{name, url, click}]`,可选 before/after 字段仅作截图文件名后缀;权威格式见 scripts/crawl.mjs 文件头注释)即可对指定操作做前/后两张截图;不传时关键操作的 before/after 需临时写一段一次性 Playwright 片段补,不能只靠 `full.png` 交差。
- **可选替代**:若用户在当前环境已配置浏览器类 MCP(如 playwright 系),可自行改用其工具做导航/快照/截图代替 crawl.mjs——不展开,按其自身用法即可,产出物(截图 + accessibility 摘要 + 不整页喂模型)的约束不变。
- **登录选择器探测**(可选):不确定登录表单的 CSS 选择器时,先跑 `node <本 skill base directory>/scripts/probe-login.mjs <登录页URL>`,打印出该页所有 input/button 的 tag/type/name/id/placeholder,据此填 crawl.mjs 的 `--login-selector-user`/`--login-selector-pass`/`--login-selector-submit` 参数,免得盲猜选择器反复试错。
- **反检测浏览器**(browser-use/camoufox 等)已排除评估:对确定性遍历的内网/已授权系统是负收益,不引入。
- **省 token 设计**(借鉴 westpoint-io/mimik):每页产出两样东西——
  - accessibility snapshot 或精简 DOM 摘要(可交互元素 role/name/位置)→ 喂给模型写操作说明;
  - 截图文件 → 只存盘、只在最终 SOP 里以 `![]()` 引用路径,**不**整图上传给模型做文案。

## 五步流程

### 1. 输入采集

- 项目根目录:读 `HANDOVER.md`(若已由交接文档包生成)、`BUSINESS.md`、`REQUIREMENTS.md`,提炼业务流程与角色列表(谁、在什么环节)。没有这些文档就问用户要业务背景。
- 部署 URL:优先从 `HANDOVER.md`/`DEPLOYMENT.md` 或 `.env` 里的 `APP_URL`/`BASE_URL` 类变量取;取不到就问用户。
- 测试账号:优先从项目 `.env`(本地读取,不外传)取;没有就问用户要一个专用测试账号,并向用户确认"这不是真实业务账号"。**读到即用,绝不回显在任何写盘文档里**;调用脚本时通过 `SOP_USER`/`SOP_PASS` 环境变量传入,不写进命令行参数(见硬规则 1)。

### 2. 页面清单

- 用测试账号登录后,从导航结构(顶栏/侧栏菜单、路由表若可读)枚举全部页面。
- 与步骤 1 提炼的功能清单对照,产出一张"页面 × 功能"矩阵(先在草稿里列出,验收时核对全覆盖)。

### 3. 遍历截图

- 逐页面逐功能截图,存 `docs/sop-images/<页面slug>/`(页面 slug 用页面英文路由名或拼音,不用中文文件名避免部分工具乱码)。
- **关键操作**(提交表单、导出报表、触发批处理等有副作用或状态变化的操作)截**操作前/操作后**两张,文件名加 `-before` / `-after` 后缀。
- 每张截图旁边记一句该页/该状态的 accessibility 摘要要点(供步骤 4 写文案用,不必逐字保留全量摘要)。

### 4. 成文

产出 `docs/SOP-<业务名>.md`,**按业务流程顺序组织,不是按页面顺序**——同一个业务环节可能横跨多个页面,合在一节里讲。每个业务环节包含:

- **谁**(角色)
- **在哪个页面**(链接/路由 + 截图)
- **做什么操作**(配截图,步骤化)
- **系统自动做什么**(免得读者以为要手工做本该自动的事)
- **异常怎么办**(常见报错、边界情况、找谁兜底)
- 每份 SOP **至少一个真实使用样例**——用测试数据完整走一遍业务流程的记录,附截图,证明手册可复现

若旧版 SOP 已存在,对照校准:旧版通常缺**页面截图**和**使用样例**这两块,这是新版必须补齐的差距,其余内容(口径、术语解释)可参考旧版但要按新结构重组,不是简单拼接。

### 5. 验收自检

产出后逐条自查,任一项不过就回到对应步骤补:

- [ ] 页面矩阵全覆盖(步骤 2 的矩阵里每一项在正文里都能找到对应段落)
- [ ] 每个功能点至少一张截图,关键操作有前/后两张
- [ ] 至少一个使用样例,且步骤可按文档复现(自己按文档说的点一遍,能得到一致结果)
- [ ] 全文搜索一遍确认无真实凭据(用户名/密码/token/API key)残留
- [ ] 业务黑话首次出现有解释
- [ ] UTF-8 无乱码

## 网络不可达时的降级交付

若目标部署 URL 在当前环境不可达(如需要 VPN/内网,当前会话连不上):

1. 不产出 SOP 正文,改为产出**可执行 runbook**:`docs/SOP-<业务名>-runbook.md`,**按 `<本 skill base directory>/references/runbook-template.md` 填写**——内容是"网络恢复后按此脚本/步骤跑一遍即可自动生成 SOP 草稿",包含已采集好的业务流程骨架(角色/环节/页面清单,能提前从文档拿到的部分)+ 待执行的遍历截图命令。不要脱离模板重新手搓结构,避免与模板漂移。
2. 明确告知用户这是待办,列出触发条件(如"接入内网后重跑 `<本 skill base directory>/scripts/crawl.mjs`")。
3. 不得为了交付而编造截图或臆造页面结构。

## 试点策略

首次使用时,优先在有旧版 SOP 可对照的项目上打样,用旧版校准新版的详略程度和术语解释粒度,再推广到没有旧版参照的项目。校准过程中若发现新旧口径冲突(如旧版某个数字/规则已过时),以项目当前文档(`HANDOVER.md`/`DECISIONS.md`/代码现状)为准,SOP 里不沿用旧版的过时说法。

## Common mistakes

| 错误 | 纠正 |
|---|---|
| 把整页截图传给模型写文案 | 只传 accessibility/DOM 摘要;截图只存盘引用 |
| SOP 按页面顺序罗列("首页有什么、报表页有什么") | 必须按业务流程顺序——同一环节跨页面时合并讲 |
| 测试账号密码写进 SOP 方便"以后照着填" | 绝不写入任何产出文档,只在对话/本地 .env 里出现 |
| 网络不通就跳过、什么都不产出 | 降级产出 runbook,骨架用已有文档提前搭好 |
| 术语("红点"这类)不解释直接用 | 首次出现必须一句话解释业务含义 |
| 只截"正常路径"没有异常截图 | 关键操作要前/后对照;异常怎么办至少文字说明,有截图更好 |
| 有旧版 SOP 就直接复制改个格式 | 旧版只用于校准详略/术语粒度,截图和样例必须重新做 |
| 调用 crawl.mjs 时用 `--user`/`--pass` 传密码图省事 | 用 `SOP_USER`/`SOP_PASS` 环境变量;argv 会落进 shell history 与 `ps aux`,即使脚本不落盘也已经泄漏 |
| 遍历导航链接时把"退出登录"也点了 | 脚本已按关键词/同源/协议过滤,若自己临时写遍历代码也要照做,否则 session 作废后续全是登录页截图 |
| hash 路由 SPA 只信 `domcontentloaded`/`networkidle` 就截图 | 客户端内路由跳转不触发浏览器原生导航事件,这两个事件几乎立即通过,而页面数据是路由切换后才由前端异步发起的;实测除首次真实整页加载外,后续每个 hash 内跳转截图都会拍到"加载中…"半成品。crawl.mjs 已在每次 goto 后追加 `waitForAppReady`(轮询等待"加载中"类文案消失)兜底,自己写遍历代码时也要照做,不能只等 networkidle |
| 忽略登录页(`/login` 等独立路由)不在矩阵里 | 遍历脚本按设计不会顺着已登录会话把登录页也走一遍(会拿到"已登录自动跳转"的假页面),登录页需要额外用无 cookie 的新 context 单独截图,且要覆盖登录失败/异常态,不能只写一句"用账号登录" |
