Document the one-command startup contract
Constraint: macOS double-click launch must keep one Terminal window alive Rejected: LaunchAgent | hides process ownership and complicates safe cleanup Confidence: high Scope-risk: narrow Directive: Keep cleanup scoped to processes started by run.command Tested: Spec self-review for placeholders, contradictions, ambiguity, and scope Not-tested: Launcher implementation pending written-spec review
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# `run.command` 一键启动器设计
|
||||
|
||||
日期:2026-07-15
|
||||
状态:用户已确认设计方向,等待书面规格复核
|
||||
|
||||
## 目标
|
||||
|
||||
在 macOS Finder 中双击项目根目录的 `run.command`,用一个持续打开的终端窗口启动并监督当前 ERP 主链路:
|
||||
|
||||
- Spring Boot 单体应用监听 `8091`,同时提供 Vue 前端和 `/api/oa/*` 后端。
|
||||
- ngrok 固定域名 `https://resonant-elated-launder.ngrok-free.dev` 转发到 `8091`。
|
||||
- 两项服务就绪后自动打开公网地址。
|
||||
- 用户按 `Ctrl+C` 或关闭终端时,只停止本次脚本启动的进程。
|
||||
|
||||
不启动已弃用的 OFBiz、独立 Vite 开发服务器、PostgreSQL 或 nginx;当前可交付预览已包含在 Spring Boot JAR 中。
|
||||
|
||||
## 启动体验
|
||||
|
||||
1. 脚本以自身所在目录作为项目根目录,不依赖 Finder/Terminal 的当前工作目录。
|
||||
2. 终端逐步显示“环境检查、后端启动、ngrok 启动、公网验证、运行中”。
|
||||
3. 后端通常约 15 秒就绪;脚本按真实 HTTP 状态等待,不使用固定时长假定成功。
|
||||
4. 成功后显示本地地址、公网地址、日志路径和停止方法,并调用 macOS `open` 打开公网地址。
|
||||
5. 终端保持运行并监控服务;任一由脚本启动的子进程意外退出时,脚本报告错误并输出对应日志末尾。
|
||||
|
||||
## 组件与流程
|
||||
|
||||
### 1. 环境与路径
|
||||
|
||||
- 项目根目录:由 `run.command` 的绝对路径推导。
|
||||
- 后端工作目录:固定为 `<项目>/oa-backend`,确保相对数据源 `./data/oa.db` 始终指向 `oa-backend/data/oa.db`。
|
||||
- Java:优先使用项目内 `.jdks/jdk-17.0.19+10/Contents/Home/bin/java`。
|
||||
- JAR:`oa-backend/build/libs/oa-backend-0.1.0.jar`。
|
||||
- ngrok:优先使用 `$HOME/bin/ngrok`,否则回退到 `PATH` 中的 `ngrok`。
|
||||
- 日志:写入 `${TMPDIR:-/tmp}/kaidi-erp-run/`,不污染 Git 工作区。
|
||||
|
||||
缺少 Java、JAR、ngrok、`curl`、`lsof` 或 `python3` 时立即给出可操作错误并退出。
|
||||
|
||||
### 2. 后端复用与启动
|
||||
|
||||
- 若 `8091` 无监听进程,脚本从 `oa-backend` 目录启动 Java,并记录为“本脚本拥有”。
|
||||
- 若 `8091` 已监听,脚本请求根路径并核对页面标题“凯迪协同办公平台”:匹配则复用;不匹配则报端口冲突,不杀进程。
|
||||
- 启动后最多等待 60 秒,要求首页 HTTP 200 且登录接口能返回标准 JSON;超时或进程提前退出时显示后端日志末尾。
|
||||
|
||||
### 3. ngrok 复用与启动
|
||||
|
||||
- 查询本地 ngrok API `127.0.0.1:4040/api/tunnels`。
|
||||
- 若已有固定公网域名且目标为 `http://localhost:8091`,直接复用,不再启动第二个 ngrok。
|
||||
- 若 `4040` 被占用但不存在正确隧道,安全报错,不覆盖现有隧道。
|
||||
- 否则启动 `ngrok http --url=resonant-elated-launder.ngrok-free.dev 8091`,记录为“本脚本拥有”,最多等待 30 秒确认隧道登记成功。
|
||||
|
||||
### 4. 公网验证与浏览器
|
||||
|
||||
- 使用 `ngrok-skip-browser-warning: true` 请求公网首页,必须返回 HTTP 200 且标题正确。
|
||||
- 验证成功后自动打开公网地址。
|
||||
- 环境变量 `ERP_RUN_NO_OPEN=1` 可禁止自动打开,供测试或无界面环境使用。
|
||||
|
||||
### 5. 生命周期与清理
|
||||
|
||||
- `INT`、`TERM`、`EXIT` 使用同一清理函数。
|
||||
- 只向脚本保存的 Java/ngrok PID 发送 `TERM`,等待短时间后才对仍未退出的自有 PID 使用 `KILL`。
|
||||
- 复用的既有服务 PID 不写入“自有 PID”,因此 `Ctrl+C` 不会误杀它们。
|
||||
- 运行阶段周期性检查本地首页和公网隧道;异常时提示并保留日志证据。
|
||||
|
||||
## 可测试性
|
||||
|
||||
脚本使用 Bash 函数组织,并仅在直接执行时进入 `main`;测试可 `source run.command` 后单独验证函数。
|
||||
|
||||
新增 `tests/run-command.test.sh`,覆盖:
|
||||
|
||||
1. `bash -n run.command` 语法检查。
|
||||
2. 脚本从任意当前目录都能解析正确项目根目录。
|
||||
3. 已存在且健康的 `8091` 服务会被复用。
|
||||
4. 非本项目进程占用 `8091` 时返回错误且不会发送终止信号。
|
||||
5. 清理函数只停止记录为本脚本启动的 PID,不停止外部 PID。
|
||||
6. `ERP_RUN_NO_OPEN=1` 时不调用浏览器。
|
||||
7. 实机冒烟:运行启动器,确认本地首页、公网首页、登录和受保护业务接口均成功;随后 `Ctrl+C` 验证自有进程退出。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- Finder 双击一次即可完成后端、ngrok、公网验证和浏览器打开。
|
||||
- 重复双击不会产生第二个 Java/ngrok,也不会杀死已运行实例。
|
||||
- 成功路径明确显示两个地址和 `Ctrl+C` 停止说明。
|
||||
- 失败路径在 60 秒内结束等待,说明失败阶段并展示相关日志。
|
||||
- `run.command` 与测试脚本具有可执行权限,Shell 回归测试全部通过。
|
||||
Reference in New Issue
Block a user