# CLAUDE.md

> 本文件为 Claude Code 在此项目中工作时的指导文档。Claude Code 在每次会话开始时会自动读取本文件。
> 维护者：czj · 最后更新：2026-07-21

---

## ⚠️ 多窗口并行开发注意

如需开多个 Claude Code 窗口同时开发不同子菜单功能，**必须先阅读** `Docs/多窗口并行开发指南.md`，了解：
- 端口隔离（8001/8002）
- 数据库操作错开
- Playwright 执行互斥（不可同时执行用例）
- Git 提交协作

---

## 项目概述

**平台自动化测试可视化系统 (platform-auto-test)** — 一个 Web 可视化自动化测试平台，核心创新是用例录制器：用户在目标网站上操作，系统自动捕获行为并转换为测试步骤，无需手动编写测试代码。

- **被测系统**：统一管理平台 (https://192.168.5.44)
- **登录凭据**：admin@xty / Ubains@13579 · 验证码固定 `csba`
- **远程仓库**：http://git.ubainsyun.com/bing/ubains-module-test.git
- **当前分支**：`platform-auto-test`（主分支：`main`）

---

## 常用命令

### 启动服务

```bash
# 后端（端口 8001，工作目录 backend/）
cd backend
pip install -r requirements.txt
playwright install chromium
uvicorn app.main:app --reload --port 8001

# 前端（端口 3000，代理指向 8001，工作目录 frontend/）
cd frontend
npm install
npm run dev
```

### 构建 & 测试

```bash
# 前端构建（类型检查 + Vite 打包）
cd frontend && npm run build

# 前端 Lint
cd frontend && npm run lint

# 后端测试
cd backend && pytest tests/ -v --cov=app --cov-report=html

# WebSocket 流程集成测试
cd backend && python scripts/test_websocket_flow.py
```

### 访问地址

- 前端：http://localhost:3000
- API 文档：http://localhost:8001/docs
- 健康检查：http://localhost:8001/health

---

## 代码架构

### 后端分层（`backend/app/`）

- **`main.py`** — FastAPI 入口，注册 10 个路由模块（modules / cases / executions / recorder / stats / reports / cleanup / batch / dependencies）。**已配置 Windows ProactorEventLoop，勿删**。
- **`config.py`** — `Settings` 类，支持环境变量覆盖（DATABASE_URL / PLAYWRIGHT_HEADLESS / SCREENSHOT_DIR 等）。
- **`database.py`** — SQLite 异步引擎 + 表初始化。已配置 `check_same_thread=False` + `pool_pre_ping=True`。
- **`models/`** — SQLAlchemy ORM：module / test_case / execution / case_result / case_dependency。
- **`schemas/`** — Pydantic 校验层。
- **`routers/`** — API 路由（薄层，仅参数校验 + 调用 service）。
- **`services/`** — 业务逻辑层（核心业务在此）。
- **`executors/playwright_executor.py`** — 执行引擎核心，**同步 API**，13 种动作 + 8 种断言。
- **`websocket/manager.py`** — WebSocket 连接管理（分组广播 + 断线重连）。
- **`utils/selector_mapper.py`** — 选择器映射，多选器回退策略。
- **`scripts/`** — 15 个辅助脚本（create_cases / test_websocket_flow / 数据清理等）。

### 前端分层（`frontend/src/`）

- **`App.vue`** — 根布局（侧边栏 220px + 顶部栏 + 内容区）。
- **`router/index.ts`** — 7 个路由，懒加载。
- **`api/`** — 各模块的 axios 封装调用。
- **`utils/request.ts`** — Axios 全局封装，**baseURL 为空字符串**，超时 5 分钟。
- **`utils/websocket.ts`** — WS 客户端，事件驱动 + 自动重连 3 次。
- **`views/`** — 7 个页面：Dashboard / Modules / Cases / Recorder / Execution / Reports / Settings。
- **`types/`** — TypeScript 类型定义。

### API 前缀约定

所有 API 前缀为 `/api/{模块}`（如 `/api/cases`、`/api/executions`）。前端 axios `baseURL` **必须为空字符串**，路由路径写完整 `/api/...`，否则会出现 `/api/api/cases` 双重前缀 404。

---

## 关键约束（务必遵守）

### 1. Playwright 必须用同步 API

Windows 上 Playwright 异步 API 在 FastAPI asyncio 循环中无法启动。**不要**尝试改回 `async_playwright`，也不要用 `asyncio.create_task` / `threading` / `multiprocessing` 在 Windows 上实现异步执行——都已验证失败。

正确模式（已固化）：
1. `main.py` 设置 `asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())`
2. `playwright_executor.py` 使用 `sync_playwright` 同步 API
3. `execution_service.py` 通过 `loop.run_in_executor()` 在线程池中执行
4. **每个测试用例创建独立的 `PlaywrightExecutor` 实例**（共享实例在 `stop()` 后 `_is_running=False`，下次 `start()` 会失败）
5. **`playwright_executor.py` 的 `start()` 方法中必须 `asyncio.set_event_loop(None)`**——Playwright 内部用 `asyncio.get_running_loop()` 检测 asyncio 循环，在工作线程中必须将事件循环设为 None 才能绕过检测

### 2. 前端 useRoute() 必须在 setup 顶层

`useRoute()` 不能在 `computed()` 回调内调用，否则报 `inject() can only be used inside setup()`，导致页面主内容区域为空。统一在 `<script setup>` 顶层调用。

### 3. 前端 axios 超时设 5 分钟

默认 30s 太短，Playwright 执行可能需要几分钟。`request.ts` 已配置 `timeout: 300000`。

### 4. SQLite 并发写锁

已配置 `check_same_thread=False` + `pool_pre_ping=True`。同步执行期间的并发写入仍需注意；如遇 `database is locked`，检查是否有未关闭的会话。`error_message` 字段必须 `nullable=True`（成功执行后为 None）。

### 5. 数据目录（gitignored）

- `data/test_platform.db` — SQLite 数据库
- `data/screenshots/` — 执行截图
- `data/reports/` — 生成的报告

这些目录在应用启动时由 `lifespan` 自动创建，无需手动 mkdir。

---

## 踩坑记录（绝对不要重复踩）

| # | 现象 | 根因 | 正确做法 |
|---|------|------|---------|
| 1 | `NotImplementedError` / Sync API inside asyncio | Windows 默认 SelectorEventLoop 不支持子进程 | 同步 API + ProactorEventLoop + 线程池 |
| 2 | 第二次执行 `start()` 失败 | 共享执行器 `_is_running` 状态 | 每用例新建 PlaywrightExecutor 实例 |
| 3 | 请求 `/api/api/cases` 404 | `baseURL:'/api'` 与路径叠加 | baseURL 留空，路径写完整 `/api/...` |
| 4 | `SQLite database is locked` | 同步执行并发写入 | check_same_thread=False + pool_pre_ping |
| 5 | bash 中 `start` 启动 CMD 失败 | MSYS 封装损坏 `&&` 引号 | `MSYS_NO_PATHCONV=1 cmd.exe /c start ...` |
| 6 | `claude` 命令不在 PATH | Windows 未配全局 PATH | `which claude` 找路径，补 `.cmd` 后缀 |
| 7 | 前端页面空白 | `useRoute()` 在 computed 内调用 | 移到 setup 顶层 |
| 8 | `NOT NULL constraint failed: error_message` | 字段 nullable=False 但成功时为 None | 改为 nullable=True |
| 9 | Playwright Sync API inside asyncio loop | `run_in_executor` 线程中 Playwright 检测到 asyncio 循环 | `asyncio.set_event_loop(None)` 在工作线程中 |
| 10 | **MySQL 连接 `Can't connect on '2026@mysql'`** | DATABASE_URL 密码含 `@`，被 URL 解析为主机分隔符 | MySQL 密码不要含 `@` 等 URL 特殊字符（已用 `PlatApp2026`） |
| 11 | **MySQL `Data too long for column 'id'`** | 模型 `String(32)` 容不下带前缀 ID（如 `module_xxx` 39 字符），SQLite 不校验长度但 MySQL 校验 | ID 类字段统一用 `String(64)` |
| 12 | **MySQL 迁移 `foreign key constraint fails`** | 自引用外键（如 `modules.parent_id`）插入顺序问题，SQLite 不强制外键但 MySQL 强制 | 迁移脚本先 `SET FOREIGN_KEY_CHECKS=0`，完成后再开启 |
| 13 | **MySQL `ping() missing 'reconnect'` → API 500** | aiomysql 的 `ping()` 与 SQLAlchemy `pool_pre_ping=True` 不兼容 | MySQL 连接禁用 `pool_pre_ping`，改用 `pool_recycle=3600`（见 `database.py`） |

详见 `HANDOFF.md` 第五节，V2 部署踩坑详见 `HANDOFF_V2部署升级.md`。

---

## 文档体系

PRD 与进度文档全部在 `Docs/PRD/自动化测试平台/`，遵循工作流：

```
PRD 需求文档 → (prd-plan skill) → 计划执行文档 → (prd-code skill) → 代码
```

| 文档 | 用途 |
|------|------|
| `_PRD_平台自动化测试可视化系统需求文档.md` | 主 PRD |
| `_PRD_..._计划执行.md` | 分阶段执行计划 |
| `_开发进度报告_20260709.md` | 进度 + 完整 API 清单 + Phase 5 待办 |
| `当前进度记录.md` | 26 个用例测试结果 + 关键决策 |
| `测试结果汇总报告.md` | 执行结果详细数据 |
| `HANDOFF.md` | 会话交接（由 /Handoff skill 生成） |

**修改 PRD 或新增功能时**：先写 PRD → 走 prd-plan → 走 prd-code，保持文档与代码同步。

---

## Git 工作流

- **当前分支**：`platform-auto-test`，主分支：`main`
- **提交规范**：Conventional Commits（`feat:` / `fix:` / `docs:` / `test:` / `refactor:`）
- **提交工具**：使用 `/GitCommit` skill（三重门控 + 分支检查 + 推送确认）
- **提交后缀**：所有 commit message 结尾加 `Co-Authored-By: Claude <noreply@anthropic.com>`
- **未在用户明确要求时不要自动 commit/push**

---

## 可用 Skills（`.claude/skills/`）

| Skill | 用途 |
|-------|------|
| `CreateCMD` | 在当前目录打开 N 个 CMD 窗口运行 Claude |
| `GitCommit` | 代码提交辅助（审查 + 生成 commit + add/commit/push） |
| `Handoff` | 会话结束生成 HANDOFF.md 交接文档 |
| `prd-plan` | PRD 需求文档 → 执行计划文档 |
| `prd-code` | 执行计划文档 → 代码 |

---

## 当前进度与待办

- **Phase 1-4** 全部完成（基础框架、核心功能、执行与可视化、分析与报告）
- **Phase 5** 进行中（约 30%）— 已完成 Excel 导入、执行引擎调通、数据库锁修复、用例依赖管理、选择器优化、CI/CD
- **Phase 5 剩余 P0**：Settings.vue 功能实现、Pinia 状态管理、单元测试
- **远期规划**：迁移 PostgreSQL、用户权限系统、分布式执行、多浏览器录制

### 已知风险

- **SQLite 并发瓶颈** — 多用户并发场景可能 `database is locked`，远期迁移 PostgreSQL
- **Windows 子进程限制** — 当前用同步 + 线程池规避，非完美方案
- **无用户权限系统** — 当前无认证/授权，仅限内网使用

---

## 代码风格约定

- 后端 Python 文件头部注释模板：模块名称、模块描述、作者、创建日期、最后修改日期
- 前端 Vue/TS 文件头部注释：组件/文件名称、描述、@author、@date
- 命名：后端用 snake_case，前端用 camelCase，类型用 PascalCase
- API 路径统一 `/api/{模块}` 前缀
- 数据库 ID 使用 UUID（`utils/id_generator.py`）

---

*本文件由 Claude Code 维护，修改项目结构或新增约束时请同步更新。*