|
| 1 | +# container-image-delivery Specification |
| 2 | + |
| 3 | +## Purpose |
| 4 | +TBD - created by archiving change build-and-push-container-images. Update Purpose after archive. |
| 5 | +## Requirements |
| 6 | +### Requirement: GitHub Actions 构建并推送生产容器镜像 |
| 7 | + |
| 8 | +系统 MUST 使用 GitHub Actions 在 GitHub runner 上构建 cnode-next 生产容器镜像,并推送到 GitHub Container Registry。workflow MUST 只负责镜像构建和推送,不得连接生产服务器执行部署。 |
| 9 | + |
| 10 | +#### Scenario: API 镜像发布到 GHCR latest |
| 11 | +- **WHEN** GitHub Actions 在主分支运行容器镜像发布 workflow |
| 12 | +- **THEN** workflow MUST 使用 `apps/api/Dockerfile` 构建 API 镜像 |
| 13 | +- **AND** workflow MUST 推送 `ghcr.io/cnodejs/cnode-api:latest` |
| 14 | + |
| 15 | +#### Scenario: Web 镜像发布到 GHCR latest |
| 16 | +- **WHEN** GitHub Actions 在主分支运行容器镜像发布 workflow |
| 17 | +- **THEN** workflow MUST 使用 `apps/web/Dockerfile` 构建 Web 镜像 |
| 18 | +- **AND** workflow MUST 推送 `ghcr.io/cnodejs/cnode-web:latest` |
| 19 | + |
| 20 | +#### Scenario: Workflow 不部署远程服务器 |
| 21 | +- **WHEN** GitHub Actions 完成镜像推送 |
| 22 | +- **THEN** workflow MUST NOT SSH 登录生产服务器 |
| 23 | +- **AND** workflow MUST NOT 执行远程 `docker compose pull` 或 `docker compose up` |
| 24 | + |
| 25 | +### Requirement: 生产服务器只拉取并运行镜像 |
| 26 | + |
| 27 | +生产 docker-compose 编排 MUST 只引用已发布镜像,服务器部署流程 MUST 通过 `pull` 和 `up --no-build` 启动服务,避免在同机运行的 nodeclub、PostgreSQL、Redis 旁边执行镜像构建。 |
| 28 | + |
| 29 | +#### Scenario: Compose 不包含本地构建定义 |
| 30 | +- **WHEN** 运维查看 `docker-compose.prod.yml` |
| 31 | +- **THEN** `api`、`web`、`worker`、`migrate-schema`、`migrate-data`、`reconcile` 服务 MUST NOT 包含 `build:` 配置 |
| 32 | +- **AND** 这些服务 MUST 使用 `image:` 引用 GHCR 镜像 |
| 33 | + |
| 34 | +#### Scenario: 手动部署拉取最新镜像 |
| 35 | +- **WHEN** 运维在生产服务器部署新版本 |
| 36 | +- **THEN** 运维 MUST 执行 `docker compose -f docker-compose.prod.yml pull api web worker` |
| 37 | +- **AND** 运维 MUST 执行 `docker compose -f docker-compose.prod.yml up -d --no-build api web worker` |
| 38 | +- **AND** 该流程 MUST NOT 在服务器上执行 Docker build |
| 39 | + |
| 40 | +#### Scenario: Migration 任务使用 API 镜像 |
| 41 | +- **WHEN** 运维执行 `migrate-schema`、`migrate-data` 或 `reconcile` |
| 42 | +- **THEN** 这些一次性任务 MUST 使用 `CNODE_API_IMAGE` 指向的 API 镜像 |
| 43 | +- **AND** 这些任务 MUST NOT 在服务器上通过 compose build migration target |
| 44 | + |
| 45 | +### Requirement: Web 镜像使用运行时 API 配置 |
| 46 | + |
| 47 | +Web 镜像 MUST 不依赖构建时 API base URL。SSR 侧和浏览器侧 API 请求都 MUST 根据服务器运行时环境变量决定 API 地址。 |
| 48 | + |
| 49 | +#### Scenario: SSR 使用内部 API 地址 |
| 50 | +- **WHEN** React Router loader 在 Web 容器服务端执行 API 请求 |
| 51 | +- **THEN** 系统 MUST 优先使用 `APP_API_INTERNAL_BASE_URL` |
| 52 | +- **AND** 在生产 compose 中该值 MUST 指向 `http://api:3001` |
| 53 | + |
| 54 | +#### Scenario: 浏览器使用公开 API 地址 |
| 55 | +- **WHEN** 浏览器侧交互调用 `apiFetch` 或上传客户端请求 API |
| 56 | +- **THEN** 系统 MUST 使用从服务器运行时 `.env` 注入到页面的 `APP_API_BASE_URL` |
| 57 | +- **AND** 浏览器侧 MUST NOT 依赖 `VITE_APP_API_BASE_URL` 或其他构建时变量决定 API base URL |
| 58 | + |
| 59 | +#### Scenario: 同一 Web 镜像可复用到不同运行环境 |
| 60 | +- **WHEN** 同一个 `ghcr.io/cnodejs/cnode-web:latest` 镜像在不同服务器环境启动 |
| 61 | +- **THEN** 浏览器侧 API base MUST 随该环境的 `.env` 变化 |
| 62 | +- **AND** 不得要求为不同 API 域名重新构建 Web 镜像 |
| 63 | + |
0 commit comments