Files
logan 0c0423d3a1 docs: 锁定 apps/desktop 目录权威与 SDD 短模板
- AGENTS/architecture:目录权威改为 apps/desktop + packages/* + apps/server;根 src 标误迁
- sdd-template:补何时必填与 FR→AC,保留 Shell/DB 短模板体;细流程仍 docs/specs/
- 安全三行钉死;HANDTEST/README 已无浏览器 :5173 工作台口径
2026-10-19 21:27:13 +08:00

153 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpsxAPI
给运维和开发用的专业接口工作台 —— 对标 Apifox / Apipost 的自研替代。
**HTTP · GraphQL · WebSocket · SSE · Socket.IO · MQTT,一个工作台全搞定;数据全在本地。**
```
apps/desktop 桌面操作(Tauri;./run.sh gui)
packages/* 共享 UI / 传输 / 领域
apps/server Gin(官网托管与本机 API)
homepage/ 官网 + 文档(浏览器只看这里)
```
根目录 `src/`、`src-tauri/` 是误迁,不是目录权威。详见 [docs/architecture.md](docs/architecture.md)。
核心原则:**一套 UI、一份请求契约;浏览器只看官网/docs,操作只走桌面。**
## 功能总览
### 协议
- **HTTP/REST**:GET/POST/PUT/PATCH/DELETE/HEAD/OPTIONS;Params / Body(JSON·XML·Text·HTML·x-www-form-urlencoded·form-data)/ Headers / Cookies / Auth(Bearer·Basic·APIKey)
- **GraphQL**:Query + Variables 编辑、独立响应面板
- **WebSocket**:消息日志(收/发/系统分色)、快捷发送、握手 Header(经 Gin 隧道,绕开浏览器限制)
- **SSE**:断点续传(Last-Event-ID)、直连失败自动切 Gin 代理、事件按 `event:` 分发
- **Socket.IO**:事件监听(可 onAny)、emit 参数 JSON、path/transports/auth 连接选项
- **MQTT**:wss broker、主题订阅(通配符)、发布、QoS 0/1/2、自动重连
### 导入(粘贴 / 文件 / URL 三种来源,格式自动识别)
| 格式 | 说明 |
| --- | --- |
| OpenAPI 3.0 / 3.1 / Swagger 2.0 | JSON 或 YAML;Apifox 导出同格式直接可用 |
| Swagger URL | 经本地 Gin 代理拉取,避开 CORS |
| Postman Collection v2.0 / v2.1 | 含鉴权、变量、GraphQL body |
| Apipost 项目 | `api_collection` 宽容解析 |
| cURL | 引号 / 续行 / -d / -F / -u / --data-urlencode 全支持 |
| HAR 抓包 | 按域名分组、去重 |
| Insomnia 导出 | v3 / v4(workspace/group 层级) |
| Hoppscotch 集合 | 数组或单对象 |
| Markdown 接口文档 | 提取 ```curl 代码块 |
| OpsxAPI 备份 | 全量集合 + 环境 |
| YApi / Apidoc / Apizza / Eolink | 请先导出为 OpenAPI 或 Postman 格式再导入 |
导入后自动:tag→目录、`{path}` 参数→`{{变量}}` 并写入环境、schema→示例 body、security→鉴权配置。
### 导出
- OpenAPI 3.0(JSON / YAML,带 tag 分组)· Postman v2.1 · Markdown 接口文档 · 全量备份
- 单请求代码生成:cURL / JavaScript fetch / Python requests / Go net/http
### 工作台
集合树(搜索 / 右键菜单 / 拖拽移动 / 复制 / 重命名)· 多标签页 · 历史记录(点击回跳)
· 环境变量(多环境切换、`{{var}}` 全局替换)· 明暗双主题 · localStorage 自动持久化
## 怎么跑
```bash
make install
./run.sh web # 官网 + docs → http://127.0.0.1:8787/
./run.sh gui # 桌面操作入口(推荐)
./run.sh stop | status
```
打开 http://127.0.0.1:8787/ 看落地页;操作只走 `./run.sh gui`。不要用浏览器打开 Vite 开发源当工作台。
## 官网 / 文档 / 定价(homepage/,纯静态)
官网(落地页 + `/docs` + `/pricing`)已拆分为独立静态站:源在 `homepage/`,与后端/GUI 解耦;后端仅在本地静态托管产物 `homepage/dist`(nginx 直接托管同一目录)。构建入口 `scripts/build-homepage.sh`(= `make homepage`),工具在独立 Go module `tools/homepage-build/`。
- 源结构:
- `homepage/index.html` 落地页;`homepage/pricing.html` 定价页;`homepage/terms.html` 服务条款
- `homepage/docs.html` 文档模板;`homepage/content/*.md` + `manifest.json`(20 篇,6 分组)
- `homepage/assets/`(官网资源,产物落 `dist/site/assets/`);`homepage/docs-assets/`(文档资源,产物落 `dist/docs/assets/`)
- 产物 `homepage/dist/`(结构固定):`index.html`、`docs/index.html`、`docs/<slug>/index.html`、`docs/search-data.json`、`pricing.html` + `pricing/index.html`、`site/assets/*`
- 本地预览:`./run.sh web` → 落地页 `http://127.0.0.1:8787/`、文档 `http://127.0.0.1:8787/docs`、定价 `http://127.0.0.1:8787/pricing`
- `.gitignore` 含 `dist/`,产物默认不入库;如需入库 `git add -f homepage/dist`
- 交付前替换:联系邮箱 `hello@opsxapi.dev`(`homepage/index.html`)
## 服务端端点(server/)
| 端点 | 用途 |
| --- | --- |
| `GET /health` | 健康检查 |
| `POST /v1/proxy/http` | HTTP 代理(绕 CORS,全方法) |
| `POST /v1/proxy/http/stream` | NDJSON 流式代理(SSE / chunked) |
| `POST /v1/proxy/ws/connect` | WS 隧道:拨号目标(带自定义 Header),返回 sessionId |
| `GET /v1/proxy/ws/attach` | WS 隧道:浏览器 attach,双向桥接 |
| `POST /v1/proxy/ws/close` | 关闭隧道会话 |
浏览器直连 WS 无法带自定义 Header 时,transport 层自动走隧道;SSE 直连 CORS 失败自动切代理。
## 架构决策
- **一套 UI**:集合 / 编辑器 / 对话框全部在 `src`,Web 与桌面零分叉
- **判别联合数据模型**:`node.kind === "http"` 自动收窄 `node.data` 类型
- **实时会话不落盘**:WS/SSE/Socket.IO/MQTT 会话存模块级注册表,消息(500 条上限)与状态进 store
- **zustand 选择器必须返回稳定引用**:`?? []` 会触发 useSyncExternalStore 无限重渲染(踩过的坑)
## 测试
```bash
npm test # core / transport / features 全量测试
cd server && go test ./...
```
## P0 自动化演示(本地)
1. `./run.sh gui` → 桌面操作入口(本机 Gin 默认 `:8787`)
2. 进入自动化测试 → **装载回归示例** → **运行**(依赖本机 Gin `:8787/v1/echo`)
3. AI:**保存并运行** 与手动/定时共用同一执行器与报告
4. 定时:支持 5 段 Cron 或间隔;应用保持打开;见 `docs/HANDTEST-P0.md`
## 开发布局
目录权威是 `apps/desktop`、`packages/*`、`apps/server`。浏览器只看 `homepage/` 的站和文档;操作入口 `./run.sh gui`。根目录 `src/` 不算权威。边界见 [docs/architecture.md](docs/architecture.md)。
```bash
npm install
npm run build # 先类型检查,再构建前端
npm test # 全量前端单测
cargo test --manifest-path src-tauri/Cargo.toml --lib
./run.sh gui # 编译当前 Rust 后启动桌面,默认附带本地 Gin
```
`./run.sh gui` 每次通过 Cargo 增量编译当前源码,不再回退到旧 release。只运行原生桌面可用 `OPSXAPI_GUI_WITH_SERVER=0 ./run.sh gui`。标准 Tauri 开发热重载入口为 `npm run dev:desktop`。
## 请求代理与内网 Mock
### API 文档与 OpenAPI 同步
侧栏「文档」以现有集合为项目,按 OpenAPI 标签分组浏览 HTTP 接口,显示参数、请求体、响应示例及说明。导入入口支持 OpenAPI 3.0/3.1、Swagger 2.0 的 JSON/YAML 文件、粘贴内容与 URL;导入时选择新建、按同名项目合并、或覆盖。合并按 HTTP 方法和相对路径更新同一接口,保留没有出现在本次导入里的接口;手动编辑并保存的说明与文档字段会在下次合并时保留。覆盖会移除该项目未导入的接口,使用前先检查选择。文档字段与请求一起保存在工作区备份;选择云端空间时也遵循现有工作区同步规则。
侧栏按「接口 → 文档 → Mock → 测试」排列。文档详情可直接打开请求页试用,或从 2xx 响应 example/schema 生成 Mock 草稿;已有相同方法和具体路径的 Mock 会显示关联状态并直接打开编辑,不覆盖手动修改的模拟响应。生成时把路径参数示例实例化为具体路径(例如 `/pets/{id}` 和 `id=42` 对应 `/pets/42`);发布后文档详情和内网只读文档快照均可展示对应 Mock 地址(快照需重新发布才会更新)。当前 Mock 服务只支持完整路径匹配,暂无动态路径匹配、请求体条件或多响应规则。
「发布当前项目」会将所选项目的名称、接口说明、参数和示例生成单独的本机 SQLite 只读快照;鉴权、环境变量及运行历史不会加入快照。分享地址是 `<IP或域名>:8798/docs/<随机令牌>`,和 Mock 响应共用独立监听与来源限制。修改文档后需点「更新分享快照」;「撤销分享」立即令旧链接失效。公开访问需明确配置 `OPSXAPI_MOCK_ALLOW_PUBLIC=1`,自行处理 DNS/端口映射/HTTPS。分享页面不提供请求执行或编辑入口。
- 顶栏仅保留环境管理和环境切换;请求代理在「设置 → 网络」配置。支持自动检测、自定义 HTTP/HTTPS 代理、不使用代理、绕过主机和代理认证。配置仅存本机,不进入工作区同步/导出;适用于桌面 HTTP、GraphQL 及自动化测试,实时协议不受此设置控制。
- 侧栏「Mock」是独立接口管理页面:新建接口 → 选择方法与路径 → 编辑 JSON/文本响应、状态码、延迟 → 保存草稿 → 发布全部已保存接口。也可在 HTTP 编辑器通过「创建 Mock」或「用响应创建 Mock」复制为独立接口,不修改原请求。
- 草稿与未保存编辑缓存在本机浏览器存储;发布结果保存在本机 SQLite,不因登录而切换到团队或公网存储。发布会替换此本机服务的全部接口,禁用/删除接口需发布后生效;未保存编辑不参与发布。接口页提供已发布地址、复制和试运行。
- Mock 页面顶部可直接启用或关闭 HTTP 响应,并可一键创建 `GET /demo` 示例;保存草稿后点击「发布全部已保存接口」,在已发布版本中试运行。设置 → Mock 服务保留相同开关及分享地址、环境关联配置。关闭后返回 503,保留数据和监听端口;彻底停止进程使用 `./run.sh stop`。随机数据生成规则位于「设置 → 数据生成」。
- 第一版使用单服务、方法 + 完整路径匹配(忽略尾斜杠),暂不支持路径参数、多响应条件及请求体匹配。JSON 可使用已有 `@integer` 等模板表达式;文本响应原样返回。
- `./run.sh gui` 默认启动本机管理服务 `127.0.0.1:8787` 和独立 Mock 响应监听 `0.0.0.0:8798`。后者默认仅接受回环/私有网段来源,不注册账号、发布或代理管理路由;内网同事按实际 HTTP 方法访问 `http://本机内网IP:8798/mock/<token>/接口路径`。
- Mock 页的路径输入框只填写 `/example` 等相对路径;保存并发布后,编辑器顶部会显示可复制的完整地址。浏览器里的 Vite 开发源(含 `/mock/...`)不是 Mock 响应,也不是工作台入口。默认无需额外 Header,完整地址包含随机地址令牌。若要进一步限制已获知地址的访问,可在「设置 → Mock 服务 → 访问验证」生成并保存 Bearer 密钥;访问者须发送 `Authorization: Bearer <密钥>`,服务只保存密钥摘要。浏览器地址栏无法设置此 Header,请使用接口请求页或 curl;试运行框可临时填写密钥。
- 分享域名需由内网 DNS/hosts 解析到运行本机服务的机器;HTTPS 由内网反向代理提供,可将域名解析到内网 IP,也可自行端口映射或反向代理至公网 IP;数据仍保存在自有机器。输入分享地址不会自动修改 DNS、监听或部署。
- 若只允许本机访问,启动前设置 `OPSXAPI_MOCK_ADDR=127.0.0.1:8798`;更改监听配置需停止后重新启动。设置页会显示配置的监听地址及本机地址候选;访问仍需端口可达。
- 更新后运行 `./run.sh gui` 会检查 Mock 管理接口,并在本项目旧后端缺少该接口时重启服务;也可手动运行 `./run.sh stop && ./run.sh gui`。不要把 Vite 开发源当成内网 Mock 入口或浏览器工作台。已发布示例的分享地址为 `http://本机内网IP:8798/mock/<随机令牌>/demo`;令牌可在 Mock 页面「已发布版本」中复制。`homepage/` 不参与 Mock 数据保存。
### 环境地址联动与自定义域名
请求建议保存 `/pet/1` 等相对路径,环境分别填写前置 URL(例如本地 `http://127.0.0.1:3000`、正式 `https://api.example.com`)。顶栏切换环境会同时改变地址栏前缀、实际请求和代码生成地址;方法及接口路径不变。完整 URL 保持固定,可通过「关联环境」把匹配已知环境前缀的 URL 转为相对路径。
Mock 设置支持「使用此 Mock 环境」,生成前置 URL `<分享地址>/mock/<token>`,同一接口路径即可在本地、正式、自托管 Mock 之间切换。下线后 token 失效,重新发布后需再次更新 Mock 环境。
分享地址支持自定义域名,用户自行配置 DNS、端口映射或反向代理及 HTTPS。若需要公网来源直接访问 Mock 响应端口,先停止服务,再运行 `OPSXAPI_MOCK_ALLOW_PUBLIC=1 ./run.sh gui`。此开关仅影响独立 Mock 响应端口,不开放发布、账号、工作区或代理管理接口,也不改变本地数据存储方式。