# app-cli 运维脚本仓库。**不放业务代码**,只放「怎么跑起来、怎么检查、怎么上线」的操作入口。 三个业务仓各自独立,本仓库通过路径引用它们: ``` / ├─ app-cli/ ← 本仓库:脚本与部署编排 ├─ backend/ ← Go 后端(8090 公开 / 8091 SSG / 8092 后台) ├─ test/test/ ← Astro 前端 └─ fashion-siglip/ ← CLIP 向量服务(可选,仅后台「疑似同款」用) ``` ## 为什么单独一个仓库 | 理由 | 具体好处 | |---|---| | 脚本不跟业务版本绑在一起 | 改部署流程不用动业务仓,回滚业务代码不会把脚本一起回滚掉 | | 一处放全部「怎么运行」的知识 | 换机器只 clone 这个仓库 + 配一份 `config/local.env` | | 服务器只需拉这一个仓库 | 蓝绿部署时槽位切换、备份、健康检查都在这里 | 代价是**目录必须同级**(脚本要能按 `../backend` 找到业务仓)。路径不一致时在 `config/local.env` 里显式写死。 --- ## 目录结构(当前进度) ``` app-cli/ ├─ dev.cmd # 双击启动(转发给 dev/dev.ps1) ├─ config/ │ ├─ local.env.example # 路径/端口覆盖模板(复制成 local.env) │ └─ local.env # 本机实际值,不入库 ├─ lib/ │ └─ common.ps1 # 公共函数:路径探测/端口/进程/HTTP(已在用) ├─ dev/ # ★ 本地环境(第一版已完成) │ ├─ dev.ps1 # 一键启动:后端 + 前端(可选 CLIP) │ ├─ stop.ps1 # 按 PID 登记停止,支持 -Force 清残留 │ ├─ status.ps1 # 端口 / PID / 健康检查一览 │ └─ doctor.ps1 # 体检:版本/路径/依赖/数据库/端口/CORS └─ vision/ └─ vision.ps1 # CLIP 服务 start/stop/restart/status/logs # 下面是规划中的目录,本轮还没建: # ├─ check/ # 提交前检查:go build+vet+test、astro check # ├─ deploy/ # 生产部署:docker-compose、nginx、deploy.sh、init-db.sh # └─ docs/ # 排障手册 ``` ## 脚本分四类 | 类别 | 目录 | 运行在哪 | 现在 | |---|---|---|---| | 本地环境 | `dev/` | 开发机 Windows | ✅ 已完成 | | 视觉服务 | `vision/` | 开发机 / 服务器 | ✅ 已完成 | | 提交前检查 | `check/` | 开发机 | 待建 | | 生产部署 | `deploy/` | Linux 服务器 | 待迁入(现在散在前端仓) | 分界的意义:`dev/` 里的东西**永远不在生产跑**,`deploy/` 里的东西**不在开发机跑**。混在一起就会出现「为了本地方便给生产脚本加了个开关」这类事故。 --- ## 本地开发怎么用 首次: ```powershell cd /app-cli copy config\local.env.example config\local.env # 可选,不填也能跑(自动探测同级目录) .\dev\doctor.ps1 # 先体检 ``` 日常: ```powershell .\dev\dev.ps1 # 后端 + 前端 .\dev\dev.ps1 -Vision -Open # 连 CLIP 一起起,并打开浏览器 .\dev\dev.ps1 frontend # 只起前端(后端已在跑) .\dev\dev.ps1 -Force # 端口被占时先杀掉占用者 .\dev\status.ps1 # 看状态 .\dev\stop.ps1 # 停掉 ``` 也可以双击 `dev.cmd`(自动带 `-ExecutionPolicy Bypass`,绕开脚本执行策略限制)。 ### 端口约定 | 端口 | 服务 | 谁能访问 | |---|---|---| | 8090 | 后端公开 API | 前端浏览器直连(dev 模式下 `baseApi` 写死这个地址) | | 8091 | 后端 SSG 内部接口 | 仅构建期取数用 | | 8092 | 管理后台 `/admin` | 本机 | | 4321 | Astro dev server | 浏览器 | | 8900 | CLIP 向量服务 | 仅 127.0.0.1 | **4321 不是随便选的**:后端 `cors.allow_origins` 里放行的就是 `http://localhost:4321`。 而前端 `astro.config.mjs` 的 `server.port` 是 **3000**(那是给容器内 node 常驻用的), 所以直接 `npm run dev` 会起在 3000 —— 浏览器请求会被 CORS 拦掉,页面表现为「没数据」。 `dev.ps1` 用 `--port 4321` 显式覆盖,并在启动后**自检 CORS 回显**,不一致直接告警。 ### 为什么后端是「先编译再运行」而不是 `go run` `go run` 会派生一个 `main.exe` 子进程,PID 杀掉 `go run` 父进程后子进程可能还在,端口继续被占——正是「明明关了服务 8090 还能通」的成因。 `dev.ps1` 用 `go build -o .bin/fashionapi-dev.exe` 再直接运行,进程树干净,`stop.ps1` 能准确回收。 ### 日志与状态 ``` .logs/backend.log .logs/backend.err.log .logs/frontend.log .logs/frontend.err.log .logs/vision.log .logs/vision.err.log .run/backend.pid .run/frontend.pid .run/vision.pid ``` `stop.ps1` 优先按 PID 停;端口上还有本脚本管不到的进程(比如手动 `go run` 留下的)时只报告不硬杀,加 `-Force` 才清。 --- ## 设计取舍 **1. 不用 pm2 / 不用 supervisor(本地)** 进程管理交给脚本 + PID 登记。引入 pm2 只是多一层要维护的状态,而失败场景(谁占着端口、为什么没起来)反而变难查。 **2. 只做 PowerShell,不做 .sh 双份** 开发机是 Windows。生产是 Linux,那边用 `deploy/` 的 bash 脚本,本来就该分开写——同一套逻辑写两遍,最后一定是两份都只测过一份。 **3. 路径自动探测 + 显式覆盖** 默认按同级目录找,用标记文件(`cmd\server\main.go` / `astro.config.mjs` / `app.py`)校验。写错路径会在启动前报错,不会静默启动到空目录。 **4. 体检和启动分离** `doctor.ps1` 只读不写,可以随时跑;`dev.ps1` 只管启动。合并成一个会出现「想查问题时它顺手改了环境」。 --- ## 下一步 1. `check/check.ps1`:`go build` + `go vet` + `go test ./internal/...` + `astro check` 一条命令 2. `deploy/`:把现在散落在前端仓的 `docker-compose.yml`、`nginx/`、`deploy.sh`、`init-db.sh` 迁进来,改成 `build: context: ../backend` / `../test/test` 3. `docs/`:把「上线后 5 处点检」和常见故障对照表写成文档