---

## name: setup-project
description: >
  当用户首次克隆项目后需要初始化开发环境时使用。
  自动完成环境变量配置、依赖安装、Docker 启动、数据库初始化的全流程，
  每步带检查点，失败时诊断并恢复。
  触发短语：初始化项目、搭建环境、把项目跑起来、setup project、
  init project、第一次跑、环境搭建。
  不触发：已有环境需要新建 worktree（用 start-feature）、
  仅启动服务（直接用 dev.sh）。

# 项目初始化技能

## 目标

在用户克隆项目后，自动完成从零到可运行的全部环境配置，让用户可以立即开始开发。

## 前置条件（由人完成）

- 已克隆项目仓库并 `cd` 进入项目根目录

## 执行流程

按以下顺序逐步执行，**每步执行前先检查是否已完成，已完成则跳过**。

完整步骤：第 0 步（系统依赖）→ 1（git hooks）→ 2（依赖）→ 3（.env）→ 4（Docker）
→ 5a/5b/5c（db:push / db:seed / init:itadmin）→ 6（启动应用）→ 7（8/8 验收门禁）
→ **8（默认跑 pool-init + 生成 .code-workspace）**。第 8 步是项目标准开发模式入口，
不是可选步骤，详见文档底部。

### 第 0 步：检测系统依赖

逐项检测，缺失时按平台给出安装命令。能自动执行的直接装，需要 GUI 或权限的引导用户操作。

#### Git

**检查**��`git --version`
**通常已有**：用户需要 git 才能克隆项目，走到这步时一般已安装。
**如缺失**：
- Linux：`sudo apt install git` 或 `sudo yum install git`
- macOS：`xcode-select --install`

#### Node.js 18+

**检查**：`node --version`，确认版本 >= 18
**如缺失或版本过低**：
- 推荐用 fnm（跨平台）：`curl -fsSL https://fnm.vercel.app/install | bash && fnm install 20`
- 或 nvm：`curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash && nvm install 20`
- 安装后需要重新加载 shell：`source ~/.bashrc` 或 `source ~/.zshrc`

#### Docker

**检查**：`docker --version` 且 `docker info` 不报错（daemon 在运行）
**如缺失**：
- Linux：`curl -fsSL https://get.docker.com | sudo sh && sudo usermod -aG docker $USER`（需重新登录生效）
- macOS / Windows：需安装 Docker Desktop（GUI），引导用户访问 https://www.docker.com/products/docker-desktop/ 下载安装
**如已安装但 daemon 未运行**：
- Linux：`sudo systemctl start docker`
- macOS / Windows：提示用���启动 Docker Desktop

> 注意：Linux 上安装 Docker 需要 sudo 权限。如果当前用户无 sudo，告知用户联系管理员安装。

### 第 1 步：安装 Git Hooks

**检查**：`git config --local --get core.hooksPath` 输出 `.githooks`
**执行**：`npm run hooks:install`
**验证**：再次检查 `core.hooksPath` 已设置

### 第 2 步：安装依赖

**检查**：`backend/node_modules/.package-lock.json` 和 `frontend/node_modules/.package-lock.json` 存在
**执行**：`npm run install:all`
**验证**：上述文件存在且无报错

### 第 3 步：配置环境变量

**检查**：根目录 `.env` 文件存在
**执行**：

1. 如果 `.env` 不存在，从 `.env.example` 复制：`cp .env.example .env`
2. **自动生成安全值**——替换 `.env` 中的占位符为随机字符串：
   ```bash
   # 生成 JWT_SECRET（64 位随机 hex）
   sed -i "s|^JWT_SECRET=__GENERATE_RANDOM__|JWT_SECRET=$(openssl rand -hex 32)|" .env
   # 生成 AUDIT_SECRET_KEY（64 位随机 hex）
   sed -i "s|^AUDIT_SECRET_KEY=__GENERATE_RANDOM__|AUDIT_SECRET_KEY=$(openssl rand -hex 32)|" .env
   # 生成 POSTGRES_PASSWORD（16 位随机 hex）
   NEW_PG_PASS=$(openssl rand -hex 8)
   sed -i "s|^POSTGRES_PASSWORD=__GENERATE_RANDOM__|POSTGRES_PASSWORD=$NEW_PG_PASS|" .env
   # 同步 DATABASE_URL 中的密码
   sed -i "s|ffoa_dev:__GENERATE_RANDOM__|ffoa_dev:$NEW_PG_PASS|" .env
   # 生成 REDIS_PASSWORD（16 位随机 hex）
   sed -i "s|^REDIS_PASSWORD=__GENERATE_RANDOM__|REDIS_PASSWORD=$(openssl rand -hex 8)|" .env
   ```
3. 为子目录创建软链接：`ln -sf ../.env backend/.env`、`frontend/.env`、`docker/.env`

**验证**：
- `.env`、`backend/.env`、`frontend/.env`、`docker/.env` 均存在
- `grep __GENERATE_RANDOM__ .env` 无匹配（所有占位符已替换）

**告知用户**：`.env` 已生成随机安全值，核心功能可正常运行。如需 SSO 登录、邮件通知、钉钉同步等外部集成功能，请编辑 `.env` 中对应的 `[可选]` 配置项。

### 第 4 步：启动 Docker 服务

**检查**：`docker ps` 中有项目的 PostgreSQL 容器在运行
**执行**：`bash scripts/dev/dev.sh up`
**验证**：`bash scripts/dev/dev.sh status` 显示服务正常

**失败恢复**：

- 如果 Docker 未运行，提示用户启动 Docker Desktop 或 Docker daemon
- 如果端口被占用，提示用户检查 `.env` 中的端口配置或停止冲突服务

### 第 5 步：初始化数据库

> **三个子步骤都必须跑**。只跑 `db:push` 服务能起来但**登不进去**——
> 因为 `db:seed` 不创建 itadmin 用户（2026-05 实测确认），必须额外跑 `init:itadmin`。

#### 5a. 同步 schema（`db:push`）

**检查**：`bash scripts/dev/dev.sh db:push` 的输出显示 "already in sync"
**执行**：`bash scripts/dev/dev.sh db:push`
**验证**：命令成功完成

**注意**：使用 `db:push` 而非 `migrate deploy`，因为 `db:push` 对全新数据库更稳健。

#### 5b. 灌种子数据（`db:seed`）

**为什么必须**：种入权限 / 角色 / 岗位 / 默认部门等基础数据。跳过这步即使后端能起，
登录和权限校验全部失败。

**执行**：`cd backend && npm run db:seed`
**验证**：命令以 0 退出，输出含 "seed completed" 或类似成功信息
**幂等性**：可重复跑（内部走 upsert）

#### 5c. 创建 itadmin 用户（`init:itadmin`）

**为什么必须**：`db:seed` **不创建** itadmin 用户。必须额外跑这一步首次登录才能成功。

**执行**：`cd backend && npm run init:itadmin`
**验证**：命令以 0 退出，输出含 "created" 或 "already exists"
**默认凭据**：用户名 `itadmin`，密码见 `scripts/backend/init/init-itadmin.ts` 顶部
（默认 `Admin@2024`，**首次登录后请改密码**）

### 第 6 步：启动应用

**执行**：

- 启动后端：`npm run dev:backend`（后台运行）
- 启动前端：`npm run dev:frontend`（后台运行）
- 或同时启动：`npm run dev`

**验证**：

- 后端健康检查：`curl http://localhost:${BACKEND_PORT}/api/v1/health` 返回 200
- 前端可访问：`curl -s -o /dev/null -w "%{http_code}" http://localhost:${FRONTEND_PORT}` 返回 200 或 302

### 第 7 步：验收门禁

启动前后端后，逐项检查以下条件。**全部通过才算初始化成功**，任一失败则定位原因并修复后重新检查。

```bash
# 从 .env 读取端口
source .env
BACKEND=${BACKEND_PORT:-3001}
FRONTEND=${FRONTEND_PORT:-3000}
```

| # | 检查项 | 命令 | 通过标准 |
|---|--------|------|----------|
| 1 | Docker 容器健康 | `docker ps` | PostgreSQL 和 Redis 状态为 `healthy` |
| 2 | 数据库 schema 同步 | `bash scripts/dev/dev.sh db:push` | 输出含 `already in sync` |
| 3 | 种子数据已灌入 | `cd backend && npm run db:seed` | 第二次跑应是 idempotent，无报错 |
| 4 | itadmin 用户存在 | `cd backend && npm run init:itadmin` | 第二次跑输出含 `already exists` 或 `已存在` |
| 5 | 后端健康检查 | `curl -s http://localhost:${BACKEND}/api/v1/health` | 返回 `{"success":true,...,"status":"healthy"}` |
| 6 | 前端可访问 | `curl -s -o /dev/null -w "%{http_code}" http://localhost:${FRONTEND}` | HTTP 200 或 302 |
| 7 | Git 推送权限 | `git push --dry-run origin develop 2>&1` | 无 permission denied 错误（`Everything up-to-date` 或正常输出） |
| 8 | .env 无占位符残留 | `grep -v '^#' .env \| grep __GENERATE_RANDOM__` | 无输出 |

**输出格式**：

```
=== 初始化验收 ===
[PASS] Docker 容器健康
[PASS] 数据库 schema 同步
[PASS] 种子数据已灌入
[PASS] itadmin 用户存在
[PASS] 后端健康检查 → http://localhost:3001/api/v1
[PASS] 前端可访问 → http://localhost:3000
[PASS] Git 推送权限
[PASS] 环境变量完整

结果：8/8 通过，初始化成功。
下一步：用 @start-feature 开始第一个功能开发。
```

如果有失败项，格式为：
```
[FAIL] 后端健康检查 → Connection refused
       原因：后端未启动或端口不匹配
       修复：检查 .env 中 BACKEND_PORT，重新执行 npm run dev:backend
```

## 失败处理原则

- 每步失败后先诊断原因，不要盲目重试
- 优先用 `dev.sh` 提供的命令（`status`、`logs`、`health`、`env:check`）排查
- 如果是缺少外部依赖（Docker 未安装等），明确告知用户需要手动安装什么
- 记录失败原因，方便后续改进此 skill 或 `dev.sh`

## 与其他 skill 的关系

- **start-feature**：本 skill 完成后，用户可用 `start-feature` 开新任务（自动 claim agent pool slot 或回落 setup-worktree.sh）
- **database-main**：如果需要运行迁移而非 `db:push`，转交 `database-main`

## 第 8 步：初始化 agent pool（默认跑）

主仓库验收通过后，**默认跑** `pool-init`——这是项目的标准开发模式（多 agent 并行 + VSCode multi-root 入口）。

```bash
bash scripts/dev/agent-pool/pool-init.sh
```

**预期产出**（约 5 分钟，占 ~9 GB 磁盘 + 200 MB 内存）：
- `<repo-parent>/<repo-name>-wt/.agent-pool/slot-{1,2,3}/` 三个预热 worktree
- `<repo-parent>/<repo-name>.code-workspace` —— VSCode multi-root 入口文件，列 main + 全部 slot

**完成后告诉用户**：

```
agent pool 已就绪（3 slot）。下一步：

1. 本地 VSCode → Remote-SSH 连开发机
2. File → Open Workspace from File... → 选 <repo-parent>/<repo-name>.code-workspace
3. 一个窗口同时看到 main + slot-1/2/3 → 多 agent 并行开发的入口

后续每次 `start-feature` 会自动 claim 一个 slot（秒级）。
```

### 何时跳过 pool-init

- `FFOA_AGENT_POOL_ENABLED=false` 已 export（CI / 资源紧张机器） → 自动跳过，提示用户走 `setup-worktree.sh` 旧路
- 用户**显式**说"我现在不要池"/"先不开池" → 跳过，告知"以后 `bash scripts/dev/agent-pool/pool-init.sh` 单独跑"

### 何时改默认 size

- 资源足够 + 高频并行（5+ agent） → `pool-init.sh --size 5`
- 笔记本 / 资源紧 → `pool-init.sh --size 2`

详见 `scripts/dev/agent-pool/README.md`。

