# setup-worktree.sh 留下的「手工尾巴」与公网域名访问的连锁问题

**日期**: 2026-04-29
**触发**: 在 site-attend-duration worktree 加 Caddy 公网域名后，用户从浏览器登录看到 `localhost:3301 net::ERR_CONNECTION_REFUSED`，随后又遇到 itadmin 不存在导致 401。
**适用**: 任何"看似 setup 完了，实际还得手动收尾才能跑"的开发脚本

## 现象链

1. `bash scripts/dev/setup-worktree.sh ... ` 全程 OK
2. `npm run dev` 起服务，前后端日志都正常
3. 浏览器开 `https://<domain>` → 页面加载成功（Caddy 反代到 :3300 ✓）
4. 点登录 → **`localhost:3301 net::ERR_CONNECTION_REFUSED`**
5. 修 `NEXT_PUBLIC_API_URL`、重启前端 → 登录请求发出 → **401 Invalid credentials**
6. 查 DB → itadmin 不存在 → 跑 `npm run init:itadmin` → 才好

## 根因：setup-worktree.sh 留下了 4 条手工尾巴

| 尾巴 | 当前状态 | 触发症状 |
|------|---------|---------|
| Redis 容器 | `.env` 里写了 `REDIS_PORT=33xx` 但脚本不起容器 | 后端启动 `RedisService` 连接错误刷屏 |
| db:seed | 只 `prisma db push`，不灌种子 | 角色/权限/AI grants 全空，init:itadmin 后续会失败 |
| init:itadmin | 不跑（CLAUDE.md 误标 db:seed 会做） | 登录 401 |
| .env 公网映射 | `NEXT_PUBLIC_API_URL=http://localhost:3301`、`CORS_ORIGIN=http://localhost:...` 永远指本地 | Caddy 公网域名场景下 API 不可达 |

前 3 条在没启用 Caddy 域名时也一样有问题（用户走 SSH 隧道访问 localhost:3300 → 同样登录不了）。第 4 条是 Caddy 自动化引入后才暴露的连锁问题。

## 关键认识

**「自动化只做了一半」比「啥都不自动」更糟**。

- 啥都不自动 → 用户从一开始就知道要手动跑 N 步，按文档照着走
- 一半自动 → 用户以为 setup 完了，遇到错误才发现还有遗漏，错误消息（`ECONNREFUSED`、`Invalid credentials`）跟根因（"setup 没起 Redis"、"itadmin 没种"）相隔好几层，调试代价 5–10 倍

判断「自动化要做到哪儿」的标准：**用户跑完脚本后立刻能做的下一步是否成功**。本例下一步是 `npm run dev → 浏览器登录`，所以 Redis、seed、itadmin 都必须在 setup 内完成；公网域名则是把"打开浏览器就能用"这条线补到位的最后一公里。

## 修复方向（已应用到 setup-worktree.sh，见下个 PR）

```
setup_database
  ├── docker run/start postgres
  ├── 等 pg_isready
  ├── npm run install:all
  ├── prisma db push
  ├── 【新增】docker run/start redis（容器名 ffws-wt-redis-<port>）
  ├── 【新增】npm run db:seed
  └── 【新增】npm run init:itadmin

setup_caddy_domain（已在）
  └── 【新增】sed -i 改 .env / backend/.env / frontend/.env：
       NEXT_PUBLIC_API_URL=https://<domain>/api/v1
       CORS_ORIGIN=https://<domain>,http://localhost:<fe-port>
```

幂等性：
- Redis / Postgres：先 `docker ps -a` 看容器是否存在，存在则 `start`，不存在则 `run`
- db:seed / init:itadmin：脚本内自带 idempotent 检查（已存在则跳过）
- env 改写：用 sed 整行替换，重复跑无副作用

## 为什么 CLAUDE.md 的 db:seed 段错了

CLAUDE.md「本地启动约定」写：
> `cd backend && npm run db:seed` ← 首次/空库必须：种入权限/角色/组织/测试用户（含 itadmin）

但实测 `seed.ts` 只做角色/权限/AI tool grants，不建用户。itadmin 由独立的 `scripts/backend/init/init-itadmin.ts` 创建，被 CLAUDE.md 同段标为「已废弃」。

文档与实现漂移，两个都得修：要么让 seed.ts 真的建 itadmin，要么 CLAUDE.md 明写「先 db:seed 再 init:itadmin」。本次 PR 选后者（小改动），并把这两步写进 setup-worktree.sh 自动跑。

## 应用到其他「自动化脚本」

凡是声称"一键准备开发环境"的脚本，验收标准都用同一条：**跑完脚本立刻打开浏览器/客户端能正常完成至少一个完整业务动作**（本例：登录）。把这条作为 setup 类脚本的 acceptance test，能挡住绝大多数"自动化只做了一半"的坑。
