# 使用案例：把项目的运行要求转换成配置

每个项目首次接入时执行一次 `nas-deploy init`，再根据 Dockerfile、旧脚本和实际 NAS 环境调整配置并纳入版本管理。后续代码更新直接 `nas-deploy release`；不用再次初始化。

下面参考两个项目说明不同部署方式。它们是文档案例，CLI 不识别项目名称，也不提供项目专用初始化选项。端口、路径、变量和 UID/GID 应以你正在接入的项目为准。

## 案例一：端口映射 + 镜像内置健康检查

以 plot-assistant 为例，服务在容器内监听 3001，数据写入 `/app/data`，Dockerfile 已定义 HEALTHCHECK，采集功能通过 `INGEST_TOKEN` 控制。

### 首次配置

```bash
npx --no-install nas-deploy init
```

把生成的 `nas-deploy.config.json` 调整为：

```json
{
  "project": "plot-assistant",
  "platform": "linux/amd64",
  "remote": {
    "directory": "/volume1/docker/plot-assistant",
    "sudo": "auto",
    "legacyScp": true
  },
  "container": {
    "ports": [{ "host": 3001, "container": 3001 }],
    "mounts": [{
      "source": "/volume1/docker/plot-assistant/data",
      "target": "/app/data",
      "owner": "1000:1000"
    }],
    "env": {
      "NODE_ENV": "production",
      "HOST": "0.0.0.0",
      "PORT": "3001",
      "DATA_DIR": "/app/data"
    },
    "envFrom": ["INGEST_TOKEN"]
  },
  "health": { "timeout": 120 },
  "cleanup": { "retainPrevious": 0, "localArchive": true, "localImages": true }
}
```

这里的配置依据是：

- `ports` 映射 NAS 的 3001 到容器的 3001。要改外部访问端口，只改 host；应用的 PORT 仍保持容器端口。
- `HOST=0.0.0.0` 让服务可通过容器网络访问。
- mounts 显式绑定持久化目录；owner 来自该镜像运行用户的 UID/GID，不是工具对所有应用的要求。
- 镜像已有 HEALTHCHECK，所以只配置等待超时，不重复写检查命令。
- envFrom 只列变量名，令牌值放在本地环境文件中。

复制 `.env.deploy.example` 为 `.env.deploy`，填写连接信息并补充变量：

```dotenv
NAS_HOST=nas.example.local
NAS_USER=nas
INGEST_TOKEN=
```

此案例中令牌留空会关闭采集写入。启用时在本地填写真实值，不提交到仓库。init 只生成通用连接变量示例；应用专属变量需要由项目维护者补充到示例和本地配置中。

## 案例二：host 网络 + 配置中定义健康检查

以 blood-games 为例，保留旧部署的 host 网络，服务监听 8787，SQLite 位于 `/app/data/rooms.sqlite`，应用提供 `/health` 端点，但镜像没有内置 HEALTHCHECK。

### 首次配置

```bash
pnpm exec nas-deploy init
```

编辑生成的配置：

```json
{
  "project": "blood-games",
  "platform": "linux/amd64",
  "remote": {
    "directory": "/volume1/docker/blood-games",
    "sudo": "auto",
    "legacyScp": true
  },
  "container": {
    "network": "host",
    "mounts": [{
      "source": "/volume1/docker/blood-games/data",
      "target": "/app/data",
      "owner": "1000:1000"
    }],
    "env": {
      "NODE_ENV": "production",
      "PORT": "8787",
      "BLOOD_GAMES_STATIC_ROOT": "/app/apps/web/dist",
      "SQLITE_DB_PATH": "/app/data/rooms.sqlite",
      "AI_TIMEOUT_MS": "16000",
      "AI_MAX_RETRIES": "1"
    },
    "envFrom": ["OPENAI_API_KEY", "OPENAI_BASE_URL", "MODEL_NAME"]
  },
  "health": {
    "command": "node -e \"fetch('http://127.0.0.1:8787/health').then(async r=>{if(!r.ok || !(await r.json()).ok)process.exit(1)}).catch(()=>process.exit(1))\"",
    "timeout": 120
  },
  "cleanup": { "retainPrevious": 0, "localArchive": true, "localImages": true }
}
```

从通用配置调整时，注意：

- 切换为 host 网络时**删除原来的 ports 字段**，不能同时保留端口映射。
- 容器共享 NAS 网络，应用 PORT 直接决定监听端口，发布前确认没有冲突。
- 健康命令在容器内执行，使用镜像中已有的 Node.js，检查 HTTP 状态以及返回的 `ok` 值。
- SQLite 和静态文件路径属于应用运行契约，由项目配置提供。
- 模型参数值可以为空，但 envFrom 列出的变量必须在发布时存在。

本地 `.env.deploy`：

```dotenv
NAS_HOST=nas.example.local
NAS_USER=nas
OPENAI_API_KEY=
OPENAI_BASE_URL=
MODEL_NAME=
```

这些空值对应本案例应用的本地策略；其他应用是否允许空值，应按应用自身要求判断。

## 配置完成后：验证一次，后续直接发布

在应用 package.json 中配置：

```json
{
  "scripts": {
    "build:image": "nas-deploy build",
    "deploy": "nas-deploy deploy",
    "release": "nas-deploy release"
  }
}
```

首次先检查计划和环境：

```bash
npx --no-install nas-deploy release --dry-run
npx --no-install nas-deploy doctor
```

确认目标、端口、数据挂载和健康检查正确后，在授权的部署范围内执行 `npm run release`；pnpm 项目使用 `pnpm run release`。后续发布继续使用同一份配置，只有运行要求变化时才修改。

默认新容器健康后，只保留当前成功版本并清理归档及本项目闲置镜像。两个案例都不能替代真实 NAS 验收；对于已有旧脚本容器，首次切换还需按 [迁移教程](../agent/migration.md) 处理容器名称、数据备份和恢复路径。

完整参数见 [README](../README.md)，AI 按需阅读入口见 [AGENT_GUIDE](../AGENT_GUIDE.md)。
