Files
ERP/docs/superpowers/specs/2026-07-15-run-command-design.md
T
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

4.6 KiB
Raw Blame History

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
  • JARoa-backend/build/libs/oa-backend-0.1.0.jar
  • ngrok:优先使用 $HOME/bin/ngrok,否则回退到 PATH 中的 ngrok
  • 日志:写入 ${TMPDIR:-/tmp}/kaidi-erp-run/,不污染 Git 工作区。

缺少 Java、JAR、ngrok、curllsofpython3 时立即给出可操作错误并退出。

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. 生命周期与清理

  • INTTERMEXIT 使用同一清理函数。
  • 只向脚本保存的 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 回归测试全部通过。