app-cli
运维脚本仓库。不放业务代码,只放「怎么跑起来、怎么检查、怎么上线」的操作入口。
三个业务仓各自独立,本仓库通过路径引用它们:
<project>/
├─ 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/ 里的东西不在开发机跑。混在一起就会出现「为了本地方便给生产脚本加了个开关」这类事故。
本地开发怎么用
首次:
cd <project>/app-cli
copy config\local.env.example config\local.env # 可选,不填也能跑(自动探测同级目录)
.\dev\doctor.ps1 # 先体检
日常:
.\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 只管启动。合并成一个会出现「想查问题时它顺手改了环境」。
下一步
check/check.ps1:go build+go vet+go test ./internal/...+astro check一条命令deploy/:把现在散落在前端仓的docker-compose.yml、nginx/、deploy.sh、init-db.sh迁进来,改成build: context: ../backend/../test/testdocs/:把「上线后 5 处点检」和常见故障对照表写成文档