# Tencent IP Port Dev Deploy Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 将当前 ForgeFlow ERP 前后端部署到腾讯云 1Panel Ubuntu 服务器,临时开启动态加载,通过 `公网 IP + 端口` 访问,数据库继续连接阿里云 MySQL。 **Architecture:** 临时测试阶段不走域名、HTTPS、Nginx/OpenResty 反代。浏览器访问 Vite dev server `http://腾讯云公网IP:5173`,前端请求 FastAPI `http://腾讯云公网IP:8000/api`,后端连接阿里云 MySQL `121.40.97.156:3306`。稳定后再切到正式生产架构:前端静态构建、OpenResty 反代 `/api`、HTTPS、后端仅监听本机。 **Tech Stack:** Ubuntu 22.04/1Panel, Python 3, FastAPI/Uvicorn, Vue 3/Vite, Node.js 20, MySQL on Aliyun. --- ## Phase 0: 部署边界确认 本计划只做临时测试部署,不代表最终生产配置。 临时测试访问方式: ```text 浏览器 -> http://<腾讯云公网IP>:5173 Vite dev server,支持前端热更新 前端 API 请求 -> http://<腾讯云公网IP>:8000/api FastAPI/Uvicorn,使用 --reload 支持后端动态加载 后端数据库连接 -> 121.40.97.156:3306 阿里云 MySQL ``` 需要提前准备的信息: ```bash export TENCENT_IP="<腾讯云服务器公网IP>" export ALIYUN_MYSQL_HOST="121.40.97.156" export ALIYUN_MYSQL_PORT="3306" export ERP_DB_NAME="jiaheng_erp" export ERP_DB_USER="<数据库用户名>" export ERP_DB_PASSWORD="<数据库密码>" ``` 本阶段必须接受的临时风险: - `5173` 和 `8000` 会临时暴露在公网,只适合测试期。 - Vite dev server 和 `uvicorn --reload` 不是最终生产运行方式。 - 如果直接连现有阿里云数据库,腾讯云上的操作会真实写入同一个库。 - 数据库账号不要长期使用 `root`,至少正式前要换成 ERP 专用账号。 --- ## Phase 1: 腾讯云服务器基础准备 ### Task 1: 登录服务器并确认系统 - [ ] **Step 1: SSH 登录腾讯云服务器** ```bash ssh root@<腾讯云公网IP> ``` Expected: ```text 成功进入 Ubuntu shell ``` - [ ] **Step 2: 确认系统版本和架构** ```bash uname -a lsb_release -a || cat /etc/os-release ``` Expected: ```text Linux VM-0-14-ubuntu ... Ubuntu ... x86_64 ``` ### Task 2: 安装基础依赖 - [ ] **Step 1: 更新 apt 包索引** ```bash sudo apt update ``` Expected: ```text Reading package lists... Done ``` - [ ] **Step 2: 安装 Python、构建工具、Git、MySQL 客户端** ```bash sudo apt install -y git curl build-essential python3 python3-venv python3-pip mysql-client tmux ``` Expected: ```text git, curl, python3, python3-venv, mysql-client, tmux 安装完成 ``` - [ ] **Step 3: 安装 Node.js 20** 如果当前没有 Node,或者 `node -v` 低于 20,执行: ```bash curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt install -y nodejs ``` 验证: ```bash node -v npm -v ``` Expected: ```text v20.x.x 10.x.x 或更高 ``` --- ## Phase 2: 网络和防火墙放行 ### Task 3: 腾讯云安全组放行临时端口 - [ ] **Step 1: 在腾讯云控制台安全组放行 TCP 端口** 放行入站规则: ```text TCP 5173 来源:你的办公公网 IP/32 TCP 8000 来源:你的办公公网 IP/32 TCP 22 来源:你的办公公网 IP/32 ``` 如果测试人员公网 IP 不固定,临时可用: ```text TCP 5173 来源:0.0.0.0/0 TCP 8000 来源:0.0.0.0/0 ``` 但这只能用于短期测试,稳定后必须收口。 Expected: ```text 外网可以访问 5173 和 8000,不再被腾讯云安全组拦截 ``` ### Task 4: 1Panel 或 Ubuntu 防火墙放行端口 - [ ] **Step 1: 如果使用 1Panel 防火墙,在 1Panel 面板中放行** ```text 端口:5173/tcp 端口:8000/tcp ``` - [ ] **Step 2: 如果服务器启用了 ufw,执行放行** ```bash sudo ufw allow 5173/tcp sudo ufw allow 8000/tcp sudo ufw status ``` Expected: ```text 5173/tcp ALLOW 8000/tcp ALLOW ``` ### Task 5: 阿里云 MySQL 放行腾讯云公网 IP - [ ] **Step 1: 在阿里云服务器或 RDS 安全组中放行腾讯云公网 IP** 放行规则: ```text 入站 TCP 3306 来源:<腾讯云公网IP>/32 ``` - [ ] **Step 2: 在腾讯云服务器测试 MySQL 连通性** ```bash mysql -h 121.40.97.156 -P 3306 -u <数据库用户名> -p -e "SELECT NOW() AS db_time;" ``` Expected: ```text +---------------------+ | db_time | +---------------------+ | 2026-... | +---------------------+ ``` 如果报错: ```text ERROR 2003 Can't connect to MySQL server ``` 处理方向: ```text 优先检查阿里云安全组、MySQL bind-address、防火墙、账号 Host 权限。 ``` --- ## Phase 3: 部署项目代码 ### Task 6: 准备项目目录 - [ ] **Step 1: 创建部署目录** ```bash sudo mkdir -p /opt/ForgeFlow-ERP sudo chown -R $USER:$USER /opt/ForgeFlow-ERP ``` Expected: ```text /opt/ForgeFlow-ERP 可由当前用户读写 ``` ### Task 7: 上传或拉取代码 推荐方式 A:服务器可以访问 Git 仓库时使用 `git clone`。 - [ ] **Step 1A: 克隆项目** ```bash cd /opt git clone ForgeFlow-ERP cd /opt/ForgeFlow-ERP git status ``` Expected: ```text On branch ... working tree clean ``` 推荐方式 B:如果仓库暂时不方便从服务器拉取,就从 Mac 同步代码。 - [ ] **Step 1B: 在 Mac 上执行 rsync 上传** ```bash rsync -av --delete \ --exclude 'frontend/node_modules' \ --exclude 'backend/.venv' \ --exclude '.git' \ /Users/souplearn/Gitlab/py/ForgeFlow-ERP/ \ root@<腾讯云公网IP>:/opt/ForgeFlow-ERP/ ``` Expected: ```text 代码同步到 /opt/ForgeFlow-ERP ``` - [ ] **Step 2: 在服务器确认目录结构** ```bash cd /opt/ForgeFlow-ERP ls -la ls -la backend frontend ``` Expected: ```text backend/ frontend/ README.md ``` --- ## Phase 4: 后端动态加载部署 ### Task 8: 配置后端 `.env` - [ ] **Step 1: 创建后端环境变量文件** ```bash cd /opt/ForgeFlow-ERP/backend cp .env.example .env ``` - [ ] **Step 2: 编辑 `.env`** ```bash nano /opt/ForgeFlow-ERP/backend/.env ``` 推荐内容: ```env APP_NAME=Baihua Hardware ERP API APP_ENV=staging-dev APP_HOST=0.0.0.0 APP_PORT=8000 MYSQL_HOST=121.40.97.156 MYSQL_PORT=3306 MYSQL_DATABASE=jiaheng_erp MYSQL_USER=<数据库用户名> MYSQL_PASSWORD=<数据库密码> ALLOWED_ORIGINS=http://<腾讯云公网IP>:5173 AUTH_SECRET_KEY=<生成一串至少32位的随机字符串> AUTH_TOKEN_EXPIRE_MINUTES=480 ``` 生成随机密钥: ```bash python3 - <<'PY' import secrets print(secrets.token_urlsafe(48)) PY ``` Expected: ```text 输出一串随机字符串,将它填入 AUTH_SECRET_KEY ``` 注意: ```text 不要把正式数据库密码、AUTH_SECRET_KEY 发到聊天或提交到 Git。 ``` ### Task 9: 安装后端依赖 - [ ] **Step 1: 创建虚拟环境** ```bash cd /opt/ForgeFlow-ERP/backend python3 -m venv .venv ``` - [ ] **Step 2: 安装依赖** ```bash cd /opt/ForgeFlow-ERP/backend . .venv/bin/activate pip install -U pip pip install -r requirements.txt ``` Expected: ```text Successfully installed fastapi uvicorn sqlalchemy pymysql ... ``` ### Task 10: 临时启动后端动态加载 - [ ] **Step 1: 用 tmux 启动后端** ```bash tmux new -s forgeflow-backend ``` 在 tmux 窗口内执行: ```bash cd /opt/ForgeFlow-ERP/backend . .venv/bin/activate uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload ``` Expected: ```text Uvicorn running on http://0.0.0.0:8000 Started reloader process ``` 退出 tmux 但保留进程: ```text 按 Ctrl+B,然后按 D ``` - [ ] **Step 2: 服务器本机验证后端** ```bash curl -s http://127.0.0.1:8000/ | python3 -m json.tool curl -s http://127.0.0.1:8000/api/system/health | python3 -m json.tool ``` Expected: ```json { "app": "ok", "database": { "connected": true } } ``` - [ ] **Step 3: Mac 或浏览器外网验证后端** ```bash curl -s http://<腾讯云公网IP>:8000/api/system/health ``` Expected: ```text 能返回 app ok,database connected true ``` --- ## Phase 5: 前端动态加载部署 ### Task 11: 配置前端 `.env` - [ ] **Step 1: 创建前端环境变量文件** ```bash cd /opt/ForgeFlow-ERP/frontend cp .env.example .env ``` - [ ] **Step 2: 修改 API 地址** ```bash nano /opt/ForgeFlow-ERP/frontend/.env ``` 内容: ```env VITE_API_BASE_URL=http://<腾讯云公网IP>:8000/api ``` Expected: ```text 前端所有 API 请求都会打到腾讯云后端 8000 端口 ``` ### Task 12: 安装前端依赖 - [ ] **Step 1: 安装 npm 依赖** ```bash cd /opt/ForgeFlow-ERP/frontend npm install ``` Expected: ```text added ... packages ``` ### Task 13: 临时启动前端动态加载 - [ ] **Step 1: 用 tmux 启动前端** ```bash tmux new -s forgeflow-frontend ``` 在 tmux 窗口内执行: ```bash cd /opt/ForgeFlow-ERP/frontend npm run dev -- --host 0.0.0.0 --port 5173 ``` Expected: ```text VITE v5.x.x ready Local: http://localhost:5173/ Network: http://<内网IP>:5173/ ``` 退出 tmux 但保留进程: ```text 按 Ctrl+B,然后按 D ``` - [ ] **Step 2: 服务器本机验证前端** ```bash curl -I http://127.0.0.1:5173 ``` Expected: ```text HTTP/1.1 200 OK ``` - [ ] **Step 3: 浏览器访问** ```text http://<腾讯云公网IP>:5173/login?redirect=/ ``` Expected: ```text 出现 ERP 登录页 ``` --- ## Phase 6: 测试期进程守护 tmux 适合第一天快速验证。如果需要测试环境持续跑几天,建议改成 systemd 管理,但仍然保留动态加载。 ### Task 14: 创建后端 dev systemd 服务 - [ ] **Step 1: 创建服务文件** ```bash sudo nano /etc/systemd/system/forgeflow-backend-dev.service ``` 内容: ```ini [Unit] Description=ForgeFlow ERP Backend Dev Reload After=network.target [Service] Type=simple WorkingDirectory=/opt/ForgeFlow-ERP/backend ExecStart=/opt/ForgeFlow-ERP/backend/.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload Restart=always RestartSec=3 Environment=PYTHONUNBUFFERED=1 [Install] WantedBy=multi-user.target ``` - [ ] **Step 2: 启动服务** ```bash sudo systemctl daemon-reload sudo systemctl enable forgeflow-backend-dev sudo systemctl start forgeflow-backend-dev sudo systemctl status forgeflow-backend-dev --no-pager ``` Expected: ```text Active: active (running) ``` - [ ] **Step 3: 查看日志** ```bash journalctl -u forgeflow-backend-dev -f ``` Expected: ```text Uvicorn running on http://0.0.0.0:8000 ``` ### Task 15: 创建前端 dev systemd 服务 - [ ] **Step 1: 查出 npm 路径** ```bash which npm ``` Expected: ```text /usr/bin/npm ``` - [ ] **Step 2: 创建服务文件** ```bash sudo nano /etc/systemd/system/forgeflow-frontend-dev.service ``` 如果 `which npm` 输出 `/usr/bin/npm`,内容如下: ```ini [Unit] Description=ForgeFlow ERP Frontend Vite Dev Server After=network.target [Service] Type=simple WorkingDirectory=/opt/ForgeFlow-ERP/frontend ExecStart=/usr/bin/npm run dev -- --host 0.0.0.0 --port 5173 Restart=always RestartSec=3 Environment=NODE_ENV=development [Install] WantedBy=multi-user.target ``` - [ ] **Step 3: 启动服务** ```bash sudo systemctl daemon-reload sudo systemctl enable forgeflow-frontend-dev sudo systemctl start forgeflow-frontend-dev sudo systemctl status forgeflow-frontend-dev --no-pager ``` Expected: ```text Active: active (running) ``` - [ ] **Step 4: 查看日志** ```bash journalctl -u forgeflow-frontend-dev -f ``` Expected: ```text VITE v5.x.x ready ``` --- ## Phase 7: 动态加载更新流程 ### Task 16: 代码更新后验证热加载 - [ ] **Step 1: 更新代码** 如果使用 Git: ```bash cd /opt/ForgeFlow-ERP git pull ``` 如果使用 rsync,在 Mac 重新执行同步命令: ```bash rsync -av --delete \ --exclude 'frontend/node_modules' \ --exclude 'backend/.venv' \ --exclude '.git' \ /Users/souplearn/Gitlab/py/ForgeFlow-ERP/ \ root@<腾讯云公网IP>:/opt/ForgeFlow-ERP/ ``` - [ ] **Step 2: 如果只改后端 Python 代码** Expected: ```text uvicorn --reload 自动重载,无需手动重启 ``` 验证: ```bash journalctl -u forgeflow-backend-dev -n 80 --no-pager ``` - [ ] **Step 3: 如果改前端 Vue/CSS/JS** Expected: ```text Vite dev server 自动热更新浏览器页面 ``` 验证: ```bash journalctl -u forgeflow-frontend-dev -n 80 --no-pager ``` - [ ] **Step 4: 如果改了依赖** 后端依赖变更: ```bash cd /opt/ForgeFlow-ERP/backend . .venv/bin/activate pip install -r requirements.txt sudo systemctl restart forgeflow-backend-dev ``` 前端依赖变更: ```bash cd /opt/ForgeFlow-ERP/frontend npm install sudo systemctl restart forgeflow-frontend-dev ``` Expected: ```text 依赖安装成功,服务重启成功 ``` --- ## Phase 8: 功能验收清单 ### Task 17: 登录和基础页面验收 - [ ] **Step 1: 打开登录页** ```text http://<腾讯云公网IP>:5173/login?redirect=/ ``` Expected: ```text 登录页正常渲染,浏览器控制台无 CORS 报错 ``` - [ ] **Step 2: 登录 ERP** Expected: ```text 登录成功,进入首页 ``` - [ ] **Step 3: 打开浏览器开发者工具 Network** Expected: ```text API 请求地址是 http://<腾讯云公网IP>:8000/api/... 状态码不是 CORS error ``` ### Task 18: 核心业务验收 - [ ] **Step 1: 基础资料页面** 验证: ```text 供应商名录、客户名录、原材料名录、产品需规清单能打开 ``` - [ ] **Step 2: 订单与采购页面** 验证: ```text 销售订单列表、采购订单、到货入库、质量校验能打开 ``` - [ ] **Step 3: 仓库页面** 验证: ```text 百华仓库六大库能打开,出入库弹窗能打开 ``` - [ ] **Step 4: 生产执行页面** 验证: ```text 工单台账、工序报工能打开 ``` - [ ] **Step 5: 发货概览页面** 验证: ```text 发货台账能打开 ``` ### Task 19: Excel 导入导出验收 - [ ] **Step 1: 测试导出** 验证: ```text 供应商名录、原材料名录、客户名录、仓库期初模板、盘库清单导出正常 ``` - [ ] **Step 2: 测试导入** 验证: ```text 上传 Excel 时无 413、CORS、权限、临时目录报错 ``` - [ ] **Step 3: 检查响应头** Expected: ```text 浏览器能识别 Content-Disposition,下载文件名正常 ``` 说明: ```text 后端 CORS 已 expose Content-Disposition,只要 ALLOWED_ORIGINS 配对即可。 ``` --- ## Phase 9: 常见故障处理 ### Task 20: 前端页面打不开 - [ ] **Step 1: 检查 Vite 服务** ```bash sudo systemctl status forgeflow-frontend-dev --no-pager journalctl -u forgeflow-frontend-dev -n 120 --no-pager ``` Expected: ```text Active: active (running) VITE ready ``` - [ ] **Step 2: 检查端口监听** ```bash ss -lntp | grep 5173 ``` Expected: ```text 0.0.0.0:5173 ``` 如果只看到 `127.0.0.1:5173`,说明没有绑定公网网卡,需要加: ```bash npm run dev -- --host 0.0.0.0 --port 5173 ``` ### Task 21: 后端接口打不开 - [ ] **Step 1: 检查后端服务** ```bash sudo systemctl status forgeflow-backend-dev --no-pager journalctl -u forgeflow-backend-dev -n 120 --no-pager ``` - [ ] **Step 2: 检查端口监听** ```bash ss -lntp | grep 8000 ``` Expected: ```text 0.0.0.0:8000 ``` - [ ] **Step 3: 本机 curl** ```bash curl -s http://127.0.0.1:8000/api/system/health ``` Expected: ```text 本机通则进程正常;外网不通则优先查腾讯云安全组和 1Panel 防火墙。 ``` ### Task 22: 登录时报 CORS - [ ] **Step 1: 确认前端访问地址** ```text http://<腾讯云公网IP>:5173 ``` - [ ] **Step 2: 确认后端 `.env`** ```bash grep ALLOWED_ORIGINS /opt/ForgeFlow-ERP/backend/.env ``` Expected: ```env ALLOWED_ORIGINS=http://<腾讯云公网IP>:5173 ``` - [ ] **Step 3: 修改后重启后端** ```bash sudo systemctl restart forgeflow-backend-dev ``` ### Task 23: 数据库连接失败 - [ ] **Step 1: 用 mysql 客户端直连** ```bash mysql -h 121.40.97.156 -P 3306 -u <数据库用户名> -p -e "SELECT 1;" ``` Expected: ```text 返回 1 ``` - [ ] **Step 2: 如果 MySQL 客户端通,但后端 health 不通** 检查: ```bash grep MYSQL /opt/ForgeFlow-ERP/backend/.env journalctl -u forgeflow-backend-dev -n 120 --no-pager ``` 处理方向: ```text 数据库名、账号、密码、账号 Host 权限、SQLAlchemy 连接字符串。 ``` --- ## Phase 10: 临时阶段转正式生产阶段 临时测试稳定后,再做以下切换。 ### Task 24: 正式化前端 - [ ] **Step 1: 生产构建** ```bash cd /opt/ForgeFlow-ERP/frontend npm run build ``` Expected: ```text dist/ 构建成功 ``` - [ ] **Step 2: 用 1Panel OpenResty/Nginx 托管 dist** 站点根目录: ```text /opt/ForgeFlow-ERP/frontend/dist ``` ### Task 25: 正式化后端 - [ ] **Step 1: 后端改为只监听本机** 正式阶段后端不再暴露公网端口: ```text 127.0.0.1:8000 ``` - [ ] **Step 2: systemd 去掉 `--reload`** 正式命令: ```bash /opt/ForgeFlow-ERP/backend/.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000 ``` ### Task 26: 正式化反向代理 - [ ] **Step 1: 配置 OpenResty/Nginx** 核心规则: ```nginx location /api/ { proxy_pass http://127.0.0.1:8000/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location / { try_files $uri $uri/ /index.html; } ``` - [ ] **Step 2: 前端正式环境 API 改为相对路径** ```env VITE_API_BASE_URL=/api ``` ### Task 27: 正式化安全策略 - [ ] **Step 1: 关闭临时公网端口** 腾讯云安全组和服务器防火墙关闭: ```text 5173/tcp 8000/tcp ``` 只保留: ```text 80/tcp 443/tcp 22/tcp ``` - [ ] **Step 2: 配置域名和 HTTPS** ```text ERP 正式访问地址:https://<正式域名> ``` - [ ] **Step 3: 数据库账号最小权限** 正式账号只给 ERP 所需库权限: ```sql CREATE USER 'forgeflow_erp'@'<腾讯云公网IP>' IDENTIFIED BY '<强密码>'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, REFERENCES ON jiaheng_erp.* TO 'forgeflow_erp'@'<腾讯云公网IP>'; FLUSH PRIVILEGES; ``` --- ## Final Verification - [ ] 腾讯云服务器能访问阿里云 MySQL。 - [ ] `http://<腾讯云公网IP>:8000/api/system/health` 返回后端和数据库正常。 - [ ] `http://<腾讯云公网IP>:5173/login?redirect=/` 能打开登录页。 - [ ] 登录后页面 API 请求没有 CORS 报错。 - [ ] Excel 导入导出正常。 - [ ] 基础资料、订单、采购、仓库、生产、发货页面都能打开。 - [ ] 修改前端代码后 Vite 能热更新。 - [ ] 修改后端代码后 Uvicorn 能自动 reload。 - [ ] 测试期结束后有明确计划关闭公网 `5173` 和 `8000`。 --- ## Recommended Execution Mode 先用 `tmux` 跑通当天部署,再切 `systemd` 守护。 原因: ```text tmux 启动最快,排错最直观;确认前后端、数据库、跨域都通后,再用 systemd 固化。 ``` 如果需要我来执行,建议按这个顺序: ```text 1. 先要腾讯云公网 IP、SSH 登录方式、数据库测试账号。 2. 执行 Phase 1 到 Phase 5,让系统先能访问。 3. 执行 Phase 8 做业务验收。 4. 验收没问题后执行 Phase 6,把进程挂 systemd。 5. 等测试稳定后,再执行 Phase 10 转正式生产配置。 ```