docs: doc/ 全量重整——按现状重写并建立文档索引;项目统一更名 auto_control
背景:文档长期落后于代码(Tab 数、任务类型、接口示例等多处与现状不符), 且信息分散重复。这次按当前代码状态逐篇重写,并建立统一的文档体系。 新增 - doc/README.md:文档总索引(文档地图 / 推荐阅读路径 / **文档维护约定**) - doc/DATA_MODEL.md:数据模型(7 张模型表 + 5 张非模型表、迁移机制、app_meta 键、 数据目录、备份覆盖清单与双向自检) - doc/AI_CONSOLE.md:AI 控制台机制(会话与 SSE、经验库/动作库蒸馏与召回、巡检、 Markdown 渲染、推理链、token 统计、故障排查) 重写(按现状,去掉过时与重复) - README.md:7 个 Tab、18 种步骤、设备生命周期、调度/窗口语义、常见问题;修掉 「6 个 Tab / 分组为顶级 Tab」等过时内容与损坏的目录树 - doc/ARCHITECTURE.md:补启动装配顺序(import 期副作用、A~G 七阶段)、线程与锁清单、 设备状态机、调度全链路、前端结构与实时通道、设计决策、**已知缺陷与踩坑清单**、扩展点 - doc/API.md:按蓝图重建「接口总索引」(107 条路由含鉴权)+ 分域详细说明 + 非 JSON 响应汇总 + 错误分支速查 - doc/TASK_DEV.md:18 种步骤全表(参数/默认值/语义)、容器与公共参数、 选择器与 XPath 序号语义、抓取器建议规则、新增任务类型骨架 - doc/DEPLOY.md:容器入口 start.sh 三件事、发布流程与检查清单、备份覆盖红线、 按现象分类的故障排查 - doc/DEVELOPMENT.md:流程/红线/本地开发/**测试与写测试的约定**/配置速查/文档同步 - doc/MCP.md:19 个工具的参数级清单、坐标空间、写门控三连、安全与审计 - doc/MCP_DESIGN.md、doc/AI_TASK_GEN.md:标注设计 vs 实现现状,补交叉链接 - doc/backlog/TODO.md:新增「已知缺陷」小节(含复现与影响)+ 已完成留档 - .env.example:按代码实际读取的键重写(补 USB/DISCOVERY/MCP/AGENT,删死配置) 其它 - 项目名统一 auto_control:README/文档/scripts/pack.py 产物名;代码内的 doc 章节引用(templates/admin/monitor.html)同步更新 - 校验:16 篇文档 156 条相对链接全部可解析;文档中的关键数字与代码核对一致 (19 个 MCP 工具 / 18 种步骤 / 12 张备份表 / 1 种任务类型)
This commit is contained in:
+166
-221
@@ -1,291 +1,236 @@
|
||||
# 开发手册(DEVELOPMENT)
|
||||
|
||||
面向本项目开发者:开发流程、git 工作流、环境说明、技术红线、本地开发、常见开发任务。
|
||||
> 适用读者:所有参与 `auto_control` 开发的人。**动手前先读 §2 技术红线**。
|
||||
> 相关文档:[ARCHITECTURE.md](ARCHITECTURE.md)(架构,先懂再改)、[DATA_MODEL.md](DATA_MODEL.md)(表结构)、[doc/README.md](README.md)(文档索引与维护约定)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 开发流程与 git 工作流
|
||||
## 1. 开发流程
|
||||
|
||||
### 1.1 分支策略
|
||||
|
||||
| 分支 | 用途 |
|
||||
|------|------|
|
||||
| `dev` | **开发分支**,所有新功能/修复都在这里开发 |
|
||||
| `main` | **生产分支**(主分支),只放已确认的稳定版本 |
|
||||
| `dev` | 开发分支,所有新功能/修复从它切出、合并回它 |
|
||||
| `main` | 生产分支,只放已确认的稳定版本 |
|
||||
| `fix/xxx` · `feat/xxx` · `chore/xxx` | 单个改动的临时分支(从 `dev` 切出) |
|
||||
|
||||
生产环境 = 部署机 `192.168.20.220` 的 `/mnt/data/openstf/auto_control`(python-app 容器运行 `web_server.py`)。
|
||||
生产环境 = 部署机 `192.168.20.220` 的 `/mnt/data/openstf/auto_control`(`python-app` 容器)。
|
||||
|
||||
### 1.2 git 操作铁律(重要)
|
||||
### 1.2 git 铁律
|
||||
|
||||
**所有 git 操作都必须先经项目负责人明确确认后才能执行**,包括但不限于:
|
||||
**所有 git 操作都必须先经项目负责人明确确认**,包括但不限于 `commit` / `push`(**即使 push 到 dev 也要确认**)/ `merge` / `rebase` / `reset` / `branch -D`。
|
||||
|
||||
- `commit` / `push`(**即使 push 到 dev 也要确认**)
|
||||
- `merge`(dev → main)
|
||||
- `revert` / `checkout` / `reset` / `branch -D` 等
|
||||
|
||||
**标准流程:**
|
||||
**标准流程**:
|
||||
|
||||
```
|
||||
1. 在 dev 分支开发、本地测试
|
||||
2. 完成改动 → 把改动清单 + 建议 commit 信息 列给负责人
|
||||
3. 负责人确认 → 才能 commit + push dev
|
||||
4. 需要发布 → 负责人确认后再合并到 main
|
||||
5. 部署生产 → 负责人明确指示后才 pull 到 220
|
||||
① 本机新建分支 fix/xxx 或 feat/xxx(从 dev 切出)
|
||||
② 分支上开发 + 自测 跑通本机(服务/接口/页面),能自测就别只靠"看代码没问题"
|
||||
③ 交负责人确认 ★ 未经确认不合 dev
|
||||
④ 合并到 dev 确认通过后(保持线性:rebase 后 ff-merge)
|
||||
⑤ dev 整体就绪 功能齐全、验证完毕
|
||||
⑥ 合并到 main ★ 负责人确认后
|
||||
⑦ 生产 220 部署 git pull → docker restart python-app → 验证(见 DEPLOY.md §3)
|
||||
```
|
||||
|
||||
> 不允许"开发完顺手就 commit/push"。即使是一次性小改动,也要先确认。
|
||||
> 每个改动**单独分支 + 单独 commit**,主题单一,便于评审与回退。不允许"开发完顺手 commit/push"。
|
||||
|
||||
---
|
||||
|
||||
## 2. 环境说明
|
||||
## 2. 技术红线(违反会打断共享 adb transport 或造成生产事故)
|
||||
|
||||
| 环境 | 位置 | 说明 |
|
||||
|------|------|------|
|
||||
| 开发机 | 本机(192.168.20.57) | `.venv` + 本地运行 `web_server.py` |
|
||||
| 生产机 | 部署机 220 的 `auto_control` | python-app 容器,`network_mode: host` |
|
||||
| STF 服务 | ~~`192.168.20.220:7100`~~ | 已停用(代码已摘除依赖)。注意:此处"已停用"与 [STF_REMOVAL.md](STF_REMOVAL.md) 的"待人工确认"项矛盾(220 侧是否已 `docker stop stf` 未核实),需以 220 实际为准 |
|
||||
| adb 容器 | 220 上 `adb`(host 网络 5037) | USB 设备远程 adb server;网络设备补连用 |
|
||||
| 设备 | Tailscale `100.100.10.x:5555` | Xiaomi 舰队,本机 `100.100.10.2` 在 tailnet 内 |
|
||||
| uiautodev | 本机 `20242` | 元素抓取服务(web_server 自动拉起) |
|
||||
| # | 红线 | 为什么 | 代码里的体现 |
|
||||
|---|------|--------|-------------|
|
||||
| 1 | **绝不 `adb kill-server`** | 会断掉所有设备的 adb transport,运行中任务全废 | `core/adb_helper.py` 只 connect 不 kill;Web 层硬拦截 `kill-server`/`disconnect` 字符串 |
|
||||
| 2 | **绝不对 `IP:5555` 设备 `adb disconnect`** | 该地址的 adb transport 是共享的 | `adb_disconnect` **全项目零调用方**;`STFDevice.release()` 空实现 |
|
||||
| 3 | **空闲设备扫描不主动 connect/disconnect** | 避免扰动共享连接 | 前台扫描对空闲设备直接返回"空闲";设备发现用 socket 探测 |
|
||||
| 4 | **adb key 保持历史 key 不变** | 设备信任该 key,换 key 全部 `unauthorized` | 部署沿用 `~/.android/adbkey` |
|
||||
| 5 | **生产(220)默认只读** | 生产事故成本高 | 任何写操作(pull/重启/改文件)都需负责人确认 |
|
||||
| 6 | **新增持久化表必须登记备份覆盖清单** | 漏登记 = 等于没备份 | `core/system_backup.py` 的 `SUMMARY_TABLES` + `TABLE_LABELS`,详见 [DEPLOY.md](DEPLOY.md) §5.2 |
|
||||
| 7 | **功能/配置/接口改动必须同步文档** | 文档落后会误导开发与运维 | 见 §6;索引 [doc/README.md](README.md) |
|
||||
|
||||
### 2.1 adb key(关键)
|
||||
### 其它开发约束
|
||||
|
||||
- 本机 `~/.android/adbkey` 沿用历史 key(原取自 STF adb 容器,全部设备都信任)
|
||||
- **不要随意更换 key**——设备会变 unauthorized 连不上
|
||||
- 旧 key 备份在 `~/.android/adbkey.local.bak`
|
||||
- 生产环境的容器也需要用这把 key(部署时处理)
|
||||
|
||||
### 2.2 设备连接方式
|
||||
|
||||
- 设备 serial 是 `IP:5555`(Tailscale 地址),**直连**优先(只 connect、绝不 disconnect)
|
||||
- USB 设备(serial 无冒号):插本机走本地 adb;插 220 走远程 adb server(`USB_ADB_HOST:5037`)
|
||||
- 本机已在 tailnet 内,直连可靠且快(<1s)
|
||||
- 设备加入/退出平台:工具 → 设备池管理(SQLite 清单,自动连接 + 型号采集)
|
||||
|
||||
### 2.3 配置键速查(`config.py` / `.env`)
|
||||
|
||||
`.env` 加载方式:项目根目录逐行解析、`os.environ.setdefault`(环境变量已设则不覆盖)。以下默认值以 `config.py` 为准:
|
||||
|
||||
| 键 | 默认值 | 说明 |
|
||||
|------|------|------|
|
||||
| `WEB_HOST` / `WEB_PORT` | `0.0.0.0` / `18050` | Web 后台监听(18050 避开 Windows 动态端口范围) |
|
||||
| `DATA_DIR` / `APK_DIR` | `data/` / `data/apks/` | 持久化数据目录 / APK 存储目录 |
|
||||
| `BACKUP_DIR` / `RESTORE_STAGING_DIR` / `RESTORE_PENDING_DIR` | `data/backups` / `data/restore_staging` / `data/restore_pending` | 系统备份:导出 zip、导入暂存、待重启生效的恢复目录 |
|
||||
| `ADB_PATH` | `bin/adb/adb`(Windows 为 `adb.exe`) | 按平台自动识别,代码只拼路径 |
|
||||
| `USB_ADB_HOST` / `USB_ADB_PORT` | `100.100.10.1` / `5037` | 220 的 adb 容器(host 网络),驱动远程 USB 设备 |
|
||||
| `DISCOVERY_PORT` / `DISCOVERY_SUBNETS` / `DISCOVERY_INTERVAL` | `5555` / 局域网+Tailscale 网段 / `60` | 设备自动发现;可在工具页设备池面板改,存 `app_meta` `discovery_*` 覆盖默认 |
|
||||
| `TAILSCALE_API_KEY` / `TAILSCALE_TAILNET` | 空 / 空 | 工具页 Tailscale 管理(官方 API v2) |
|
||||
| `WEB_SECRET_KEY` | 未配置则随机生成 | 会话密钥(web_server 读 `.env`;不配则重启登录态失效) |
|
||||
| `STF_URL` / `STF_TOKEN` / `STF_SSH_*` | 废弃 | STF 摘除后仅历史保留,代码不再使用 |
|
||||
- **`web_server.py` 以 `debug=False` 运行**:改 `core/`、`tasks/`、`templates/` 后**必须重启**;改前端 JS 后**强刷浏览器**
|
||||
- **任务参数放各自 `tasks/<app>/` 顶部**,不放 `config.py`
|
||||
- **运行时数据不提交 git**:`data/`、`logs/` 全是运行时产物
|
||||
- **不要移除分页与错峰**:监控/列表页已分页(100 台设备只渲染 10 行/页);任务批量触发已错峰(`_START_STAGGER_SEC`)
|
||||
- **不要手工改库结构**:走 `SCHEMA_MIGRATIONS`(模型表)或幂等原生建表
|
||||
|
||||
---
|
||||
|
||||
## 3. 技术红线(开发限制)—— 违反会打断共享 adb transport,需人工恢复
|
||||
## 3. 本地开发
|
||||
|
||||
这些是踩过坑后总结的,**任何修改都不能引入**。违反任何一条都会导致设备连接被全部重建(历史原因:STF provider 共享同一 adb transport,摘除 STF 后仍保留此约束):
|
||||
|
||||
1. **绝不 `adb kill-server`**
|
||||
- 会断开所有设备的 adb transport,全部设备连接被重建,运行中任务中断
|
||||
- 见 `core/adb_helper.py`
|
||||
|
||||
2. **绝不对 `IP:5555` 设备 `adb disconnect`**
|
||||
- 该地址的 adb transport 是共享的(历史与 STF provider 共用),disconnect 会断掉全部相关连接
|
||||
- 直连模式下 `release()` 不 disconnect
|
||||
- 见 `core/device_worker.py` `STFDevice.release()`
|
||||
|
||||
3. **空闲设备扫描不主动 connect/disconnect**
|
||||
- IP:5555 的 transport 由多方共享(历史与 STF provider 共用),外部 connect/disconnect 会扰动共享连接
|
||||
- `_ForegroundScanner._scan_free` 对空闲设备直接返回"空闲",不碰 adb
|
||||
- 见 `core/task_manager.py`
|
||||
|
||||
4. **adb key 保持历史 key 不变**(见 2.1,设备信任该 key)
|
||||
|
||||
5. **直连优先,不引入第三方桥接**(见 2.2)
|
||||
|
||||
### 3.1 其他开发限制
|
||||
|
||||
- **`web_server.py` 以 `debug=False` 运行,不热重载**:改 `core/`、`tasks/`、`templates/`、`static/` 后必须重启 web_server(前端 HTML 改完强刷浏览器)
|
||||
- **任务参数放各自 `tasks/<app>/task.py` 顶部,不放 `config.py`**
|
||||
- **生产环境(220)默认只读**:任何写操作(改文件/重启容器/部署)都必须先经负责人确认
|
||||
- **数据库是 SQLite**(`data/users.db`,WAL 模式):运行时数据不提交 git
|
||||
- **前端 JS 已拆分多文件**(均位于 `static/admin/`):`monitor.html` 按 `base.js → markdown.js → list.js → monitor.js → editor.js → tasks.js → tools.js → apps.js → admin.js → agent.js → system.js` 的顺序用 `<script src>` 加载(`markdown.js` 提供 `renderMarkdown()`,AI 控制台回答渲染用;依赖 `base.js` 的 `esc()`,故排在其后、agent.js 之前)
|
||||
- **监控页/大列表已加分页**:100 台设备也只渲染 10 行/页,不要移除分页逻辑
|
||||
- **任务批量触发已错峰**(`_START_STAGGER_SEC`):避免大量设备同时启动造成 adb 连接风暴,不要移除
|
||||
|
||||
---
|
||||
|
||||
## 4. 本地开发手册
|
||||
|
||||
### 4.1 首次安装
|
||||
### 3.1 安装
|
||||
|
||||
```bash
|
||||
# 用 Python 3.12 建 venv(README 推荐版本)
|
||||
/opt/homebrew/bin/python3.12 -m venv .venv
|
||||
.venv/bin/pip install -r requirements.txt
|
||||
|
||||
# macOS:adb 用系统自带的(bin/adb/adb 是被 gitignore 的符号链接)
|
||||
ln -sf /opt/homebrew/bin/adb bin/adb/adb
|
||||
|
||||
# 确认 adb key(必须是 STF 容器的 key,否则设备连不上)
|
||||
ls -la ~/.android/adbkey
|
||||
python -m venv .venv
|
||||
# Windows: .venv\Scripts\activate Linux/macOS: source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 4.2 启动
|
||||
确认 adb key(沿用既有 key,否则设备连不上):`ls -la ~/.android/adbkey`。
|
||||
|
||||
### 3.2 启动
|
||||
|
||||
```bash
|
||||
.venv/bin/python web_server.py
|
||||
# 访问 http://localhost:18050/ 账号 admin/admin123
|
||||
python web_server.py
|
||||
# 访问 http://localhost:18050/ admin / admin123
|
||||
```
|
||||
|
||||
启动日志看到以下即成功:
|
||||
```
|
||||
[INFO] [core.worker] 心跳看门狗已启动
|
||||
[INFO] [web] 管理后台: http://localhost:18050/ (admin/admin123)
|
||||
[INFO] [web] 启动服务: http://localhost:18050/
|
||||
需要 AI 控制台 / MCP 时,**另起一个进程**:
|
||||
|
||||
```bash
|
||||
MCP_ALLOW_WRITE=1 MCP_PLATFORM_USER=admin MCP_PLATFORM_PASS=<密码> \
|
||||
python -m mcp_server.mcp_server # 默认 http://127.0.0.1:8033/mcp
|
||||
```
|
||||
|
||||
### 4.3 测试
|
||||
(容器里由 `scripts/start.sh` 自动拉起,不需要手动。)
|
||||
|
||||
- **后端逻辑**:直接 `.venv/bin/python -c "..."` 调用(如 `tasks/`、`core/` 的函数)
|
||||
- **前端 UI**:Playwright(系统 `python3` 已装),脚本示例见下
|
||||
- **浏览器冒烟**:切 6 个 tab、开任务编辑器,确认无 JS 错误
|
||||
### 3.3 调试
|
||||
|
||||
```python
|
||||
# Playwright 冒烟示例(python3 运行)
|
||||
from playwright.sync_api import sync_playwright
|
||||
with sync_playwright() as p:
|
||||
b = p.chromium.launch(headless=True)
|
||||
pg = b.new_page()
|
||||
pg.goto("http://127.0.0.1:18050/login")
|
||||
pg.fill("input[name=username]", "admin")
|
||||
pg.fill("input[name=password]", "admin123")
|
||||
pg.click("input[type=submit], button[type=submit]")
|
||||
pg.wait_for_load_state("networkidle")
|
||||
# ... 检查各 tab、编辑器
|
||||
b.close()
|
||||
```
|
||||
| 目的 | 做法 |
|
||||
|------|------|
|
||||
| 看日志 | `logs/core.log`(adb/调度)、`task.log`(任务)、`web.log`(Web/AI)、`action.log`;或「日志」Tab |
|
||||
| 看设备/任务状态 | 监控页;或 `GET /api/status`、`GET /api/health` |
|
||||
| 后端逻辑验证 | 直接 `python -c "…"` 调用 `core/`、`tasks/` 的函数(如构造 worker 检查参数合并) |
|
||||
| 前端验证 | 无 npm/构建,改完强刷;浏览器控制台看报错 |
|
||||
| 接口 500 巡检 | `python scripts/regression_test.py`(**⚠️ 当前在 Windows 上会因 `signal.alarm` 报错**,Linux/macOS 可用) |
|
||||
| 停止设备/清异常 | 监控页「停止全部 / 停止选中 / 清除全部异常」 |
|
||||
|
||||
### 4.4 常用调试
|
||||
> **改了数据库/配置想复原**:删 `data/users.db*` 会丢数据,别这么干;用「系统 → 备份/导入」或先手工复制一份 `data/`。
|
||||
|
||||
- **看日志**:`logs/` 下 `core.log` / `task.log` / `web.log` / `action.log`(10MB 滚动,保留 5 份)
|
||||
- **看设备/任务状态**:浏览器监控页,或 `GET /api/status`、`GET /api/health`
|
||||
- **停止设备/清异常**:监控页工具条用"停止全部 / 停止选中 / 清除全部异常"(`AUTO_RELEASE_STALE_OCCUPY` 等 STF occupy 残留清理配置代码已不再读取);崩溃残留的 worker 状态重启即清零
|
||||
- **打包项目**:`python scripts/pack.py`
|
||||
### 3.4 写测试的约定(重要)
|
||||
|
||||
本仓库没有单元测试框架,验证靠"跑起来 + 真实调用"。写验证脚本时**必须**:
|
||||
|
||||
- **不要碰真实数据**:需要会话/任务/分组时**自建**(如 `POST /api/agent/conversations` 建专属会话),绝不要依赖"当前选中项",也不要删自己没建的东西
|
||||
- **改配置前后都要回读校验**:改前 GET 存原值,收尾写回后**再 GET 比对**,不一致要显式报错
|
||||
- 临时数据用完即删,并核对"集合已复原"
|
||||
|
||||
> 教训:曾用浏览器脚本跑 AI 控制台冒烟,脚本清空 `localStorage` 后前端自动选中了**用户最近的会话**,收尾的"删除测试会话"把用户真实会话删了;同一脚本还把 AI 配置改成了假值。恢复手段见 [DATA_MODEL.md](DATA_MODEL.md) §7 与 git 历史。
|
||||
|
||||
---
|
||||
|
||||
## 4. 配置速查
|
||||
|
||||
### 4.1 配置文件与优先级
|
||||
|
||||
- `config.py`:**程序级常量**(端口、路径、USB 远程 adb 等),改它要重启
|
||||
- `.env`(项目根,不入 git):**密钥与可覆盖配置**,逐行解析 + `os.environ.setdefault`(**真实环境变量优先**)
|
||||
- `app_meta`(数据库 KV):**运行时可改的配置**(AI 配置、设备发现参数),在界面上改
|
||||
|
||||
### 4.2 `config.py` 常量
|
||||
|
||||
| 常量 | 默认值 | 来源 | 说明 |
|
||||
|------|--------|------|------|
|
||||
| `ADB_PATH` | `bin/adb/adb(.exe)` | 按平台自动 | **不可用 env 覆盖** |
|
||||
| `WEB_HOST` / `WEB_PORT` | `0.0.0.0` / `18050` | 硬编码 | 18050 避开 Windows 动态端口段 |
|
||||
| `DATA_DIR` / `APK_DIR` | `data/` / `data/apks/` | 代码计算 | |
|
||||
| `BACKUP_DIR` / `RESTORE_STAGING_DIR` / `RESTORE_PENDING_DIR` | `data/backups` / `data/restore_staging` / `data/restore_pending` | 代码计算 | 备份相关 |
|
||||
| `USB_ADB_HOST` / `USB_ADB_PORT` | `100.100.10.1` / `5037` | `.env` 可覆盖 | USB 设备所在部署机的远程 adb server |
|
||||
| `TAILSCALE_API_KEY` / `TAILSCALE_TAILNET` | 空 | `.env` | Tailscale 管理功能 |
|
||||
| `DISCOVERY_PORT` / `DISCOVERY_INTERVAL` | `5555` / `60` | `.env` 可覆盖 | 设备发现(网段在工具页配置,存 `app_meta`) |
|
||||
| `DISCOVERY_SUBNETS` | 局域网 + Tailscale 网段 | **硬编码列表**(当前无 env 支持) | 默认扫描网段 |
|
||||
| `STF_*` | 空 | `.env` | **已废弃**,仅历史保留,代码不再使用 |
|
||||
|
||||
### 4.3 进程读取的环境变量(不在 config.py)
|
||||
|
||||
| 变量 | 默认 | 谁读 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `WEB_SECRET_KEY` | 未配置则随机 | `web_server.py` | 会话密钥,**生产必须固定** |
|
||||
| `DISABLE_SCHEDULER` | 未设 | `core/task_manager.py` | 设任意值则**不启动 cron 调度器**(测试用) |
|
||||
| `MCP_ENABLED` | `1` | `scripts/start.sh` | =0 则不后台拉起 MCP |
|
||||
| `MCP_ALLOW_WRITE` | `0`(脚本内强制 1) | `mcp_server/config.py` | 写操作总开关 |
|
||||
| `MCP_PLATFORM_URL` / `_USER` / `_PASS` | `http://127.0.0.1:18050` / `admin` / 空 | `mcp_server/config.py` | 登录平台的凭据(改过 admin 密码要同步) |
|
||||
| `MCP_ALLOWED_SERIALS` | 空=不限 | 同上 | 逗号分隔白名单(语义缺口见 [backlog](backlog/TODO.md)) |
|
||||
| `MCP_HTTP_HOST` / `_PORT` | `0.0.0.0` / `8033` | 同上 | |
|
||||
| `MCP_SCREENSHOT_WIDTH` / `MCP_JPEG_QUALITY` | `540` / `70` | 同上 | 返回给模型的截图层参数 |
|
||||
| `MCP_AUDIT_FILE` | `/var/log/mcp/audit.log`(脚本兜底 `/tmp/mcp_audit.log`) | 同上 | 审计日志路径 |
|
||||
| `AGENT_API_BASE` / `AGENT_MODEL` / `AGENT_API_KEY` / `DEEPSEEK_API_KEY` | DeepSeek 默认地址 / 默认模型 / 空 | `mcp_agent/config.py` | **仅 CLI 用**;Web 端 AI 配置优先读数据库 `app_meta` |
|
||||
| `AGENT_MCP_URL` / `AGENT_MAX_STEPS` / `AGENT_TIMEOUT` / `AGENT_LANG` | `http://127.0.0.1:8033/mcp` / 40 / 120 / zh | 同上 | |
|
||||
| `ANDROID_ADB_SERVER_ADDRESS` / `_HOST` / `_PORT` | 未设 | **adb 客户端自身**(非本项目代码) | 把 adb 调用指向远程 server;两套变量名都要设 |
|
||||
|
||||
> `mcp_server/config.py` 与 `mcp_agent/config.py` **不读 `.env`**(只读进程环境变量),与根 `config.py` 的行为不同。
|
||||
|
||||
---
|
||||
|
||||
## 5. 常见开发任务
|
||||
|
||||
### 5.1 新增 App 任务类型
|
||||
> 每一项的"改哪里"清单也见 [ARCHITECTURE.md](ARCHITECTURE.md) §10。
|
||||
|
||||
参照 `tasks/generic/` 结构,详见 **[doc/TASK_DEV.md](TASK_DEV.md)**(6 步模板)。
|
||||
注意:当前平台**只保留 `generic_steps` 一种任务类型**;大多数 App 操作直接用步骤编辑器
|
||||
编排即可,不必新增任务类型。
|
||||
### 5.1 新增 HTTP 接口
|
||||
|
||||
```
|
||||
tasks/<app>/
|
||||
__init__.py # from . import task
|
||||
task.py # DEFAULT_PARAMS + Worker + @register_task
|
||||
actions/ # 专属操作(可选)
|
||||
```
|
||||
1. 在对应功能域的 `web/xxx_api.py` 加 `@bp.route(...)` + 鉴权装饰器(`@login_required` / `@perm_required(PERM_X)` / `@admin_required`)
|
||||
2. 新蓝图需在 `web/__init__.py` 的 `register_blueprints` 里注册
|
||||
3. 更新 [API.md](API.md)(路由索引表 + 详细小节)
|
||||
|
||||
### 5.2 新增专属操作
|
||||
### 5.2 新增数据库字段/表
|
||||
|
||||
在 `tasks/<app>/actions/` 建 `.py`,继承 `BaseAction` + `@register_action(ACTIONS)`,在 `__init__.py` import。
|
||||
- 模型改 `core/models.py`;新表 `create_all()` 会建
|
||||
- **老库**要在 `SCHEMA_MIGRATIONS` 里加迁移(版本号递增 + SQL)
|
||||
- **新增表**:登记进 `core/system_backup.py` 的 `SUMMARY_TABLES` + `TABLE_LABELS`(**红线**)
|
||||
- 更新 [DATA_MODEL.md](DATA_MODEL.md) 与 [DEPLOY.md](DEPLOY.md) §5.2
|
||||
|
||||
### 5.3 修改前端
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| `templates/admin/monitor.html` | HTML 结构 + CSS + `<script src>` 引用 |
|
||||
| `static/admin/`(base/markdown/list/monitor/editor/tasks/tools/apps/admin/agent/system.js) | 前端 JS(按 monitor.html 中 `<script src>` 顺序拆分加载,功能归属见各文件;`markdown.js` = 轻量 Markdown 渲染器,AI 控制台回答用) |
|
||||
| 改什么 | 文件 |
|
||||
|--------|------|
|
||||
| 页面结构 / 样式 / 引入脚本 | `templates/admin/monitor.html` |
|
||||
| 公共工具(API/权限/Toast/Tab) | `static/admin/base.js` |
|
||||
| 列表分页排序 | `static/admin/list.js` |
|
||||
| 各功能域逻辑 | `static/admin/{monitor,editor,tasks,tools,apps,admin,agent,system,markdown}.js` |
|
||||
|
||||
改完**强刷浏览器**(Cmd/Ctrl+Shift+R),必要时重启 web_server。
|
||||
新增 JS 模块:建文件 → 在 `monitor.html` 里按依赖顺序加 `<script src>` → 更新 [ARCHITECTURE.md](ARCHITECTURE.md) §6.3 与本文 §5.3。
|
||||
|
||||
### 5.4 新增 API
|
||||
### 5.4 新增步骤类型 / 任务类型
|
||||
|
||||
路由按功能域放在 `web/` 蓝图包(`web/__init__.py` 的 `register_blueprints(app)` 统一注册 10 个蓝图:auth / monitor / tasks / admin / tools / devices / apks / tailscale / agent / system)。
|
||||
见 [TASK_DEV.md](TASK_DEV.md)(步骤类型要同时改后端 `STEP_TYPES` 与前端 `STEP_LIB`)。
|
||||
|
||||
- 新增 API:在对应功能域的 `web/xxx_api.py` 里加 `@bp.route(...)` + 权限装饰器(如 `admin_required`)
|
||||
- 新建蓝图:需在 `web/__init__.py` 里 import 并加进 `register_blueprints` 的注册元组
|
||||
- `web_server.py` 只做 app 装配(初始化、`register_blueprints(app)`、常驻线程启动),一般不改
|
||||
- 最后更新 **[doc/API.md](API.md)**
|
||||
### 5.5 新增 MCP 工具
|
||||
|
||||
### 5.5 新增数据库字段/表
|
||||
在 `mcp_server/mcp_server.py` 加 `@mcp.tool()` 函数;写操作必须挂门控(`_check_write` → `_check_serial` → `_ensure_device_free`);更新 [MCP.md](MCP.md)。
|
||||
|
||||
- 模型改 `core/models.py`,首次建表用 `create_all()`;SQLAlchemy 模型未写 `__tablename__` 时默认表名 = 小写类名
|
||||
- **已有数据的老库**:在 `core/models.py` 的 `SCHEMA_MIGRATIONS` 里加迁移(版本号递增 + SQL)
|
||||
- `app_meta`(KV 配置表)由 `core/models.py` 的 `_migrate_schema()` 建表并维护 `schema_version`
|
||||
- `agent_conversation` / `agent_experience` / `experience_audit` / `agent_action`(动作经验库)由 `web/agent_api.py` 内的原生 `CREATE TABLE IF NOT EXISTS` 幂等创建(模块内首次用时执行),**不经 `SCHEMA_MIGRATIONS`,无版本管理**
|
||||
### 5.6 新增常驻线程
|
||||
|
||||
### 5.6 改动必须同步文档
|
||||
参考 `core/device_discovery.py` 的 `init_app(app)` / `shutdown()` 模式;更新 [ARCHITECTURE.md](ARCHITECTURE.md) §3。
|
||||
|
||||
任何功能/配置/接口/页面改动,须与代码同一 commit 同步更新对应文档:
|
||||
---
|
||||
|
||||
| 改动类型 | 对应文档 |
|
||||
|------|------|
|
||||
## 6. 文档同步(红线)
|
||||
|
||||
**任何功能 / 配置 / 接口 / 表结构的增删改,都要在同一个 commit 里更新对应文档。**
|
||||
|
||||
| 改动类型 | 必须更新 |
|
||||
|---------|---------|
|
||||
| HTTP 接口 | [API.md](API.md) |
|
||||
| 数据表 / schema | [ARCHITECTURE.md](ARCHITECTURE.md) §3.6 |
|
||||
| `config.py` / `.env` 键增删 | 本文档 §2 + [.env.example](../.env.example) |
|
||||
| 页面 Tab / 子分栏 / 前端拆分 | [ARCHITECTURE.md](ARCHITECTURE.md) §5 |
|
||||
| 任务 / 步骤 | [TASK_DEV.md](TASK_DEV.md) |
|
||||
| 常驻线程 / 进程与装配 | [ARCHITECTURE.md](ARCHITECTURE.md) §7 |
|
||||
| MCP 工具 | [MCP.md](MCP.md) 与 [MCP_DESIGN.md](MCP_DESIGN.md) |
|
||||
| 对外接入 / 数字员工知识库 | [staffdeck/KNOWLEDGE_BASE.md](staffdeck/KNOWLEDGE_BASE.md) 与 [staffdeck/JOB_SPEC.md](staffdeck/JOB_SPEC.md) |
|
||||
| 表结构 / 迁移 | [DATA_MODEL.md](DATA_MODEL.md)(+ 备份覆盖清单) |
|
||||
| `config.py` / `.env` 键 | 本文 §4 + [DEPLOY.md](DEPLOY.md) + `.env.example` |
|
||||
| 页面 Tab / 子分栏 / 前端模块 | [ARCHITECTURE.md](ARCHITECTURE.md) §6 + 本文 §5.3 |
|
||||
| 任务类型 / 步骤 schema | [TASK_DEV.md](TASK_DEV.md) |
|
||||
| 常驻线程 / 装配顺序 | [ARCHITECTURE.md](ARCHITECTURE.md) §2-3 |
|
||||
| MCP 工具 | [MCP.md](MCP.md) + [MCP_DESIGN.md](MCP_DESIGN.md) |
|
||||
| 对外接入约定 | [staffdeck/KNOWLEDGE_BASE.md](staffdeck/KNOWLEDGE_BASE.md) |
|
||||
| 暂缓项 / 已知问题 | [backlog/TODO.md](backlog/TODO.md) |
|
||||
|
||||
> **备份覆盖红线(2026-09-10 新增)**:**新增任何持久化表**(业务数据)时,必须同步把它登记进
|
||||
> `core/system_backup.py` 的 `SUMMARY_TABLES`(并在 `TABLE_LABELS` 给中文名)+ 更新
|
||||
> [DEPLOY.md](DEPLOY.md) §3.5 的覆盖清单。理由:清单漏登记 → 导出预览看不到该表 → 会被误判为
|
||||
> "没有备份"(动作库 `agent_action` 就踩过)。导出侧有覆盖自检、导入侧有未登记表反向告警。
|
||||
|
||||
注:STF_REMOVAL.md 是历史迁移记录,不改写。
|
||||
新增文档时:登记进 [doc/README.md](README.md) §1 与根 [README](../README.md) 的文档索引。
|
||||
历史文档([STF_REMOVAL.md](STF_REMOVAL.md))只增不改。
|
||||
|
||||
---
|
||||
|
||||
## 6. 发布流程(团队约定,2026-09-10 更新)
|
||||
## 7. 常见坑速查
|
||||
|
||||
**每个改动都走分支,确认后再并 dev;dev 整体就绪后才并 main 上生产。**
|
||||
| 坑 | 说明 |
|
||||
|----|------|
|
||||
| 跨线程访问 DB | 必须自推 app context(`with app.app_context()`) |
|
||||
| 改了不生效 | `core/`、`tasks/`、`templates/` 改动要重启;JS 要强刷 |
|
||||
| Windows adb 输出 | 不能用 `text=True`(非 GBK 字节会崩),要收 bytes 再解码 |
|
||||
| u2 卡死 | `u2.connect` / `d.info` 可能永久 hang,必须加超时 |
|
||||
| 抢占死锁 | 不能在 `TaskManager._lock` 内调 `stop_device` |
|
||||
| 删除不生效 | 删任务/分组必须显式删行,否则重启会"复活" |
|
||||
| 前端写了 `data-perm` 仍可见 | 它只在 `loadMe()` 时求值一次;改权限后需刷新 |
|
||||
| 新步骤没生效 | 后端 `STEP_TYPES` 与前端 `STEP_LIB` 要同时改 |
|
||||
| 备份导入后没变化 | 必须重启服务 |
|
||||
| `.env` 不生效 | `setdefault` 语义:**已存在的环境变量优先**,检查是否被系统环境覆盖 |
|
||||
|
||||
```
|
||||
① 本机新建分支 fix/xxx 或 feat/xxx(从 dev 切出)
|
||||
② 分支上开发 + 自测 本机跑通(服务/接口/页面)
|
||||
③ 交负责人确认 ★ 未经确认不合 dev
|
||||
④ 合并到 dev 确认通过后(fast-forward 或 merge)
|
||||
⑤ dev 整体就绪 dev 上功能齐全、验证完毕
|
||||
⑥ 合并到 main ★ 负责人确认后
|
||||
⑦ 生产 220 部署 git pull → 重启 python-app 容器 → 验证
|
||||
```
|
||||
|
||||
**生产 220 部署(目录 `/mnt/data/openstf/auto_control`,容器 `python-app` 挂到 `/app`)**:
|
||||
|
||||
```bash
|
||||
cd /mnt/data/openstf/auto_control
|
||||
git fetch origin && git checkout main && git pull --ff-only origin main
|
||||
docker restart python-app # 入口 scripts/start.sh:依赖守卫 → 拉起 MCP → exec web_server
|
||||
# 验证:curl -s http://127.0.0.1:18050/api/health ; ss -ltnp | grep -E ':(18050|8033|20242)'
|
||||
```
|
||||
|
||||
**发布前检查**:生产容器 adb key、依赖(新增依赖看 `requirements.txt`)、数据库迁移(`create_all` 自动补新表)、
|
||||
以及"新增持久化表是否已登记进备份覆盖清单"(见 §5.6 红线)。
|
||||
|
||||
**数据迁移**:用平台自带「系统 → 数据备份导出/导入」;导入后需**重启容器**才生效(见 [DEPLOY.md](DEPLOY.md) §3.5)。
|
||||
|
||||
---
|
||||
|
||||
## 7. 文档索引
|
||||
|
||||
| 文档 | 内容 |
|
||||
|------|------|
|
||||
| [README](../README.md) | 项目总览、快速上手 |
|
||||
| **[DEVELOPMENT.md](DEVELOPMENT.md)** | 本文档:流程/准则/限制/手册 |
|
||||
| [TASK_DEV.md](TASK_DEV.md) | 任务开发指南(新增 App 任务模板) |
|
||||
| [ARCHITECTURE.md](ARCHITECTURE.md) | 架构详解(分层、数据流、设计决策) |
|
||||
| [API.md](API.md) | 全部 HTTP 接口说明 |
|
||||
| [DEPLOY.md](DEPLOY.md) | 部署指南(环境、生产、故障排查) |
|
||||
| [STF_REMOVAL.md](STF_REMOVAL.md) | 摘除 STF 的历史迁移记录(2026-08,不随现状改写) |
|
||||
| [MCP.md](MCP.md) | MCP 手机控制使用手册(工具清单/用法) |
|
||||
| [MCP_DESIGN.md](MCP_DESIGN.md) | MCP 架构与演进设计 |
|
||||
| [AI_TASK_GEN.md](AI_TASK_GEN.md) | AI 建任务设计文档 |
|
||||
| [staffdeck/KNOWLEDGE_BASE.md](staffdeck/KNOWLEDGE_BASE.md) | 给 StaffDeck 数字员工的知识库(MCP 接入/工具/约定/红线) |
|
||||
| [staffdeck/JOB_SPEC.md](staffdeck/JOB_SPEC.md) | 数字员工岗位说明(岗位描述/看板摘要/执行约束) |
|
||||
| [backlog/TODO.md](backlog/TODO.md) | 待完成项(已确认但暂缓的功能/优化,完成时移出并同步文档) |
|
||||
更完整的"代码里写明的坑"见 [ARCHITECTURE.md](ARCHITECTURE.md) §9.2。
|
||||
|
||||
Reference in New Issue
Block a user