Files
carlandCursor 0136c15274 Initial commit: Plane 自部署与 gptproto AI 集成
包含本地/远程部署脚本、AI Agent 服务、Dashboard 与 QA 验证。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 11:37:41 +08:00

144 lines
8.2 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.
# plane-gptproto-integration
Plane v1.3.0(AGPL-3.0 开源项目管理)自部署 + gptproto.com(OpenAI 兼容聚合 API)AI Agent 集成。本地 mac docker 验证后再上 YOUR_SERVER_IP 生产。
## 双环境部署架构
| 环境 | Web 入口 | AI 端点 | compose 路径 | 端口绑定 |
|---|---|---|---|---|
| 本地 mac | http://localhost:8090 | http://localhost:8100 | `deploy/local/` + `src/` git clone | `0.0.0.0:8090/8100` |
| 生产 YOUR_SERVER_IP | https://YOUR_SERVER_IP:8445 | https://YOUR_SERVER_IP:8446 | `/opt/plane/` (1Panel + OpenResty) | `127.0.0.1:8092/8101` |
生产走 1Panel + OpenResty 反代 + ufw + 自签 SSL(`/opt/1panel/www/ssl/luma/luma.{crt,key}`,已存在)。**容器只绑 127.0.0.1**,公网入口由 OpenResty `/opt/1panel/www/conf.d/plane.conf` 反代。生产端口规划遵循 `~/dev/PRODUCTION_DEPLOY_TEMPLATE.md`:公网用 8445/8446/8447 段,内部用 8090+。**8090 已被 1Panel openresty 占用**,本地 mac 用 8090 OK,生产改 8092。
## 常用命令
```bash
# 本地启停
cd deploy/local
docker compose -f src/deployments/cli/community/docker-compose.yml -f docker-compose.override.yml --env-file .env up -d --pull never
bash ../../qa/verify-local.sh # 6 项健康检查,exit=0 全过
# 生产 (ssh + docker compose)
ssh root@YOUR_SERVER_IP 'cd /opt/plane && docker compose -f src/deployments/cli/community/docker-compose.yml -f docker-compose.override.yml --env-file .env restart'
# AI Agent 改 main.py 后同步生产 + rebuild
rsync -az --exclude=.venv --exclude=__pycache__ ai-agent/ root@YOUR_SERVER_IP:/opt/plane/ai-agent/
ssh root@YOUR_SERVER_IP 'cd /opt/plane && docker compose -f src/deployments/cli/community/docker-compose.yml -f docker-compose.override.yml --env-file .env up -d --build --force-recreate plane-ai'
# pytest 本地 TDD
cd ai-agent && source .venv/bin/activate && pytest -v
```
## 非显然坑点(必读,本次会话血泪验证)
### 1. Plane v1.3.0 compose 路径变了
官方 selfhost 入口从旧版 `src/deploy/selfhost/docker-compose.yml` 搬到 `src/deployments/cli/community/docker-compose.yml`。Worker 用旧路径会 `no such file or directory`。
### 2. Docker Desktop 自动捕获 macOS 系统代理 → TLS bug
mac 上 `docker pull` 报 `tls: bad record MAC` / `version 300 vs 303` 几乎一定是你 Clash/V2Ray 占着 `127.0.0.1:1082`,Docker Desktop 自动用了它,本地代理拆 TLS 失败。修法:Docker Desktop → Settings → Resources → Proxies → **打开 Manual** 但三栏全留空 → **Quit Docker Desktop**(完整退出,Restart 不够,要 Quit)→ 重开。`http.docker.internal:3128` 在 `docker info` 里永远显示,是 Docker 内置 forwarder,跟你的代理设置无关。
### 3. OpenResty 反代 FastAPI uvicorn 必须显式 HTTP/1.1
```nginx
proxy_pass http://127.0.0.1:8101;
proxy_http_version 1.1;
proxy_set_header Connection "";
```
缺这两行 → uvicorn 等 keepalive 不释放 → 30s 必 ReadTimeout。已修进 `deploy/remote/plane.conf` 8446 server block。
### 4. gptproto 部分 model 当前不可用
`claude-sonnet-4-6` 60s timeout(gptproto 端挂),改用 `claude-sonnet-4-5-20250929` 或 `claude-haiku-4-5-20251001`。`chatgpt-4o-latest` 可能 503 overloaded。`.env` 里 `GPTPROTO_MODEL` 决定。
### 5. Anthropic 不支持 OpenAI 的 `response_format: json_object`
gptproto 转发给 Anthropic 时该参数被忽略,模型可能返回 ```` ```json ... ``` ```` 围栏或纯文本。`ai_agent/main.py::_extract_json` 已用 regex 兜底(先抓围栏再抓 `{...}`)。
### 6. plane-ai 进程残留死连接
切 model 或修 .env 后 ReadTimeout 不消失,必须 `docker compose up -d --force-recreate plane-ai`。普通 `restart` 或 `up -d` 不彻底。
### 7. `rsync --delete` 会清生产 src/
本地 staging 目录没 src/ 时,`rsync -az --delete /tmp/staging/ /opt/plane/` 会删服务器 git clone 的 src/。**绝不在生产路径用 --delete**,或显式 `--exclude=src/`。
### 8. 非标端口部署:OpenResty 必须用 `$http_host` 不是 `$host`
Plane backend `storage.py` 用 `request.get_host()` 构造 MinIO presigned upload URL。两层反代(OpenResty → Caddy → Django)必须把**带端口**的 Host 头透传到底:
- nginx `$host` 不带端口(`YOUR_SERVER_IP`)
- nginx `$http_host` 带端口(`YOUR_SERVER_IP:8445`)
错误用 `$host` → Django 得到 host 没端口 → presigned URL `https://YOUR_SERVER_IP/uploads`(走 443 撞别的服务) → CORS blocked。
正确:
```nginx
location / {
proxy_pass http://127.0.0.1:8092;
proxy_set_header Host $http_host; # ← 必须 $http_host 不是 $host
...
}
```
`APP_DOMAIN=YOUR_SERVER_IP:8445` 也要(影响 Plane CORS allow-origin 等),但单独改它不够,必须配合 OpenResty 修。
## Plane v1.3.0 数据库/安全实测
- `users.password` PBKDF2 哈希 ✅ 标准
- `api_tokens.token` **明文**存储 ⚠️ 任何 PG 读权限可枚举所有 token
- `instance_configurations` 加密字段(如 LLM_API_KEY)通过 GET `/api/instances/configurations/` 时被 `InstanceConfigurationSerializer.to_representation` **decrypt 后明文回吐**给前端 → F12 Network 可见
- 真 `GPTPROTO_API_KEY` 仅放 `.env`(chmod 600)+ 容器 env,**不入 Plane DB**
- god-mode AI Settings 永远留空(我们走独立 plane-ai 服务,Plane backend 用不到这个 key)
## API 端点 (FastAPI plane-ai)
| 端点 | 输入 | 行为 |
|---|---|---|
| `GET /healthz` | — | `{"status":"ok"}`,Dockerfile healthcheck 用 |
| `POST /ai/create-issue` | `{prompt, project_id, workspace_slug}` | gptproto 解析 → POST Plane `/api/v1/.../issues/` |
| `POST /ai/summarize` | `{issues:[...]}` | gptproto 中文摘要 |
| `POST /ai/search` | `{query, workspace_slug}` | Plane `/issues/search/?search=` + gptproto 排序 |
注意 search 用 `/issues/search/`(v1 public 端点)不是 `/search/`(internal app 端点要 session auth)。
## 文件清单
```
CLAUDE.md 本文件
AGENTS.md worker 共享上下文(开发期产物)
README.md 对外简介
docs/PLAN.md 完整设计 + 后门/隐私评估
docs/USER_GUIDE.md 给领导/团队的使用说明
deploy/local/.env 本地密钥(600, .gitignore)
deploy/local/docker-compose.override.yml 本地端口 0.0.0.0:8090/8100
deploy/local/pull-plane.sh git clone v1.3.0(idempotent)
deploy/local/src/ Plane 源码(git, .gitignore)
deploy/remote/docker-compose.override.yml 生产端口 127.0.0.1:8092/8101
deploy/remote/plane.conf OpenResty 反代(8445/8446 → 8092/8101,含 HTTP/1.1 修复)
ai-agent/ai_agent/main.py 4 端点 + _extract_json + httpx async
ai-agent/tests/ pytest TDD,respx mock 不真联网
qa/verify-local.sh 6 项健康检查
qa/checklist.md worker 签名 + 人工验收项
```
## 红线
- 不在 god-mode → AI Settings 填真 GPTPROTO_API_KEY(Plane backend 用不到 + 解密回显有 leak 风险)
- 不直接绑容器到 0.0.0.0:80(违反 `~/dev/PRODUCTION_DEPLOY_TEMPLATE.md`)
- 不 ssh 手动改生产 .env 不同步本地(本地 `deploy/remote/` 是 source of truth)
- 不拉 Plane master/latest,锁 `v1.3.0` + GitHub Release tag
- 不在生产路径用 `rsync --delete`
## 升级流程(Plane 出新版后)
```bash
ssh root@YOUR_SERVER_IP
cd /opt/plane/src
git fetch --depth 1 origin refs/tags/vX.Y.Z:refs/tags/vX.Y.Z
git checkout vX.Y.Z
cd ..
sed -i 's/^APP_RELEASE=.*/APP_RELEASE=vX.Y.Z/' .env
docker compose -f src/deployments/cli/community/docker-compose.yml -f docker-compose.override.yml --env-file .env pull
docker compose -f src/deployments/cli/community/docker-compose.yml -f docker-compose.override.yml --env-file .env up -d
# 本地同步: 改 deploy/remote/.env.template 的 APP_RELEASE
# 验证: 镜像无 :latest, ufw 无变, openresty conf 无需改
```
## 服务器现状 (YOUR_SERVER_IP, 1Panel v2.1.10)
8 核 / 31GB / 387GB(余 360GB+),Hostinger VPS。已部署兄弟项目:Luma 主站(443/8088)、harvester(8443/8089)、领航 BI(8444)、VideoFlow(9080-9443)。新增 Plane 占 8445(web)/8446(ai),内部 8092/8101。