Files
ERP/docs/superpowers/specs/2026-07-15-run-command-design.md
Qiufeng 672569f199 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
2026-07-15 15:26:42 +08:00

85 lines
4.6 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.
# `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 回归测试全部通过。