# 完整构建与部署链路

从项目主线发布不可变语义版本，完成 Environment 绑定、版本部署与验证。

具体参数以本机 CLI 和当前平台版本为准。开始前先发现可用命令：

```bash
baijimu --version
baijimu hosted-service --help
baijimu hosted-service project --help
```

版本使用严格 SemVer，并与 `Cargo.toml` 的 `package.version` 完全一致。首次请求固定源码；失败、取消或请求中断后的重试沿用原版本来源，主线变化不会换源。修改源码必须发布新版本。SHA 只用于内部来源追溯，不再作为构建输入。

## 标准生命周期

```text
后端 Project 与指定 Cargo package.version
  -> Release Operation
  -> 不可变 hosted_service_release Artifact
  -> Project Environment
  -> Slot 计算资源
  -> Database/Object Storage Provider Binding 与 Secret
  -> Deployment
  -> 稳定 Endpoint
  -> 健康、鉴权与真实业务验证
```

Project 是后端应用身份，Environment 保存环境配置和资源引用，Slot 提供运行计算，Provider Binding 选择已经
创建的基础资源，Deployment 把已发布项目版本运行在目标 Environment。Hosted Service 是这条托管能力，不是
还要额外创建的业务资源。

## 准备项目

构建前确认：

- 项目属于目标工作区。
- 待发布源码已经合并到平台 Project 的主线 HEAD。
- 根 `Cargo.toml` 的 `package.version` 是本次要发布的规范 SemVer 2.0.0。
- 项目在平台构建环境中能够完成依赖安装、测试和构建。
- 密钥和环境配置没有写入源码。
- 每个声明的 HTTP Endpoint listener 都实现固定的 `GET /healthz`，并在可接收业务流量时返回 2xx。
- 已通过 [Rust 服务设计约束](/development/backend-development/rust-service-design/) 中的类型所有权、
  JSON 边界、显式转换、契约测试和 CI 检查。

## 项目版本 Artifact 契约

项目版本发布生成的 Artifact 类型固定为 `hosted_service_release`。项目根目录必须提供
`hosted-service.toml`；发布器首次从平台主线校验并固定源码，把二进制、`hosted-service.manifest.json`、
版本身份和同源迁移声明封装成一个不可变项目版本。

历史 `rust_binary`、`rust_bundle` 和 `hosted_service_bundle` 都不是项目版本发布制品，不能传给
`deploy-version`。不要恢复按 `artifactId` 部署的旧入口，也不要通过开放旧类型、复制 Secret 到 Artifact
或绕过部署校验来恢复服务。

## 创建 `hosted-service.toml`

Manifest 属于项目源码，必须放在项目根目录并随待构建 commit 一起提交。可以直接让 CLI 生成一个经过
平台同源契约校验的模板：

```bash
baijimu hosted-service manifest init \
  --entrypoint target/release/example-service
baijimu hosted-service manifest validate hosted-service.toml
```

默认不会覆盖已有文件；确认覆盖时显式增加 `--force`。需要让 AI、编辑器或代码生成器发现完整结构时，
使用以下命令取得机器可读 JSON Schema：

```bash
baijimu hosted-service manifest schema
```

不依赖 CLI 时，可以从下面的最小模板开始：

```toml
contract_version = "4.0.0"

[service]
entrypoint = "target/release/example-service"
database_bindings = {}

[[service.endpoints]]
name = "http"
protocol = "http"
auth_mode = "token"
primary = true
required = true
```

字段和约束如下；未知字段会被拒绝：

| 字段                          | 是否必填 | 约束                                                                     |
| --------------------------- | ---- | ---------------------------------------------------------------------- |
| `contract_version`          | 是    | 当前必须精确为 `4.0.0`，使用严格 SemVer 字符串。                                       |
| `service.entrypoint`        | 是    | 项目内非空相对路径；不能是绝对路径，不能包含 `.` 或 `..` 路径段。若构建命令同时传 `--binary-path`，两者必须相同。 |
| `service.database_bindings` | 是    | 按 migrationKey 指定目标环境的数据库绑定名；无迁移时使用 `{}`。缺少或未使用的映射会在构建时报错。             |
| `service.endpoints`         | 是    | 1–32 个 Endpoint，名称不能重复。                                                |
| `name`                      | 是    | 1–63 个字符；小写字母开头，只能包含小写字母、数字和连字符，并以小写字母或数字结尾。                           |
| `protocol`                  | 是    | 当前只支持 `http`。                                                          |
| `auth_mode`                 | 是    | 只能是 `none` 或 `token`。                                                  |
| `primary`                   | 否    | 默认 `false`；整个 Manifest 必须且只能有一个 `primary = true`。                      |
| `required`                  | 否    | 默认 `true`；primary Endpoint 必须是 required。                               |

`none` 表示 Runtime 不校验 Hosted Service consumer token；`token` 表示只接受绑定到当前 Endpoint 的
consumer token。Hosted Service 不解释 Endpoint 名称、调用方或业务用途，`token` 不承载租户、管理或其他
业务语义。业务应用需要的租户鉴权必须由应用自己的协议和数据源实现。不要在 Manifest 中写端口、域名、
`base_url`、Secret 或环境差异配置。Runtime 会在每次部署时分配监听端口，并按 Endpoint 名称注入
`APP_ENDPOINT_<NORMALIZED_NAME>_PORT`；后端在 `127.0.0.1` 上使用对应变量绑定 listener。完整运行时字段和变量转换规则见
[配置、Endpoint 与服务鉴权](/development/backend-development/configuration-and-auth/)。平台不提供 `APP_PORT` 兼容注入。
健康路径同样不在 Manifest 或 Environment 中声明：Hosted Service 固定请求每个 listener 的 `GET /healthz`，
任何健康路径覆盖字段都会被拒绝。

一个进程可以声明多个 Endpoint，例如在上述 primary `http` Endpoint 后追加管理入口：

```toml
[[service.endpoints]]
name = "management"
protocol = "http"
auth_mode = "token"
primary = false
required = true
```

需要让多租户业务随 Bundle 安装、升级、配置和卸载自动管理时，还要实现并登记平台调用的生命周期入口。
完整的 `api / management / lifecycle` 清单、命名端口变量、插件凭据与执行地址接入流程见
[业务、管理与插件生命周期入口](/development/backend-development/configuration-and-auth/#业务管理与插件生命周期入口)。
Endpoint 声明只负责部署入口，不会自动注册插件或实现租户生命周期。

## 发布并等待项目版本

```bash
baijimu hosted-service project release <projectId> \
  --workspace-id <workspaceId> \
  --version <projectVersion> \
  --json
```

命令不接收任意 commit、版本或 Artifact ID。平台读取当前主线 HEAD 和根 `Cargo.toml` 的
`package.version`，并返回 `releaseOperationId`。使用该 ID 查询状态：

```bash
baijimu hosted-service project release-status <releaseOperationId> \
  --workspace-id <workspaceId> \
  --json
```

只有 Release Operation 进入 `SUCCEEDED`，对应 `hosted_service_release` 已登记后，该
`projectVersion` 才能部署。相同 Project 与版本只能绑定一个主线 commit；源码变化后再次发布必须先按 SemVer
提升 `package.version` 并重新合并主线。

Artifact 元数据由独立 Artifact Service 持有。需要恢复或核对项目制品时使用 CLI 查询：

```bash
baijimu rust-build artifact list <workspaceId> --project-id <projectId>
```

Artifact 查询仅用于审计和故障定位；正常部署以 `projectId + projectVersion` 解析不可变制品，不接受
`artifactId`。`rust-build artifact` 是 CLI 的查询分组，不改变 Artifact Service 的所有权。

## 为项目创建环境

```bash
baijimu hosted-service env create <workspaceId> \
  --project-id <projectId> \
  --name <environmentName>
```

Project 是唯一部署身份，不再额外创建 Hosted Service 资源。外部仓库也必须先登记为平台 Project，
再使用真实 `projectId` 创建 Environment；不要把展示名或列表第一项当作资源 ID。

## 准备并分配 Slot

Environment 本身不提供计算资源。部署前先读取工作区已有 Slot 和当前可用目录：

```bash
baijimu hosted-service slot list <workspaceId> --json
baijimu hosted-service slot types <workspaceId> --json
```

工作区尚未领取基础 Slot 时，可以幂等创建或返回该基础 Slot：

```bash
baijimu hosted-service slot create \
  --workspace-id <workspaceId> \
  --json
```

需要购买付费 Slot 时，必须使用 `slot types` 返回的当前已发布 Offer，不得在脚本或文档中固定 SKU、价格或
Offer ID。取得真实 `slotId` 后分配给 Environment：

```bash
baijimu hosted-service slot assign \
  --workspace-id <workspaceId> \
  --environment-id <environmentId> \
  --slot-id <slotId>
```

Slot 可以承载多个相互隔离的 Environment，但它不包含数据库或对象存储。资源关系、计费和停止/退役边界见
[Project、Environment、Slot、Endpoint 与数据库](/development/backend-development/hosted-services-and-databases/)。

## 创建并绑定基础资源（按需）

数据库和对象存储必须先通过各自的工作区资源入口创建，Environment 再保存对应 Profile 的稳定引用。
Resource Binding 不负责购买或创建资源，也不会把资源所有权转移给 Project。

1. 从当前 Runtime 或工作区资源入口确认可用能力。
2. 按当前方法定义申请 Database Profile 或 Object Storage Profile。
3. 使用返回的 `profileRef` 创建数据库绑定；数据库 Provider 不要求独立 Token。连接凭据由平台受控解析，不写入项目 Git、Artifact 或普通配置。
4. 从当前 Hosted Service Provider 目录确认 Environment 支持目标 Provider。
5. 使用真实 `profileRef` 创建配置绑定。

先读取动态 Provider 目录和命令参数：

```bash
baijimu hosted-service config-provider --help
baijimu hosted-service config-binding --help
```

创建绑定时使用 Provider 返回的真实 `providerKey`、资源返回的真实 `profileRef`，不要从示例推导：

```bash
baijimu hosted-service config-binding create \
  --workspace-id <workspaceId> \
  --environment-id <environmentId> \
  --name <bindingName> \
  --provider-key <providerKey> \
  --profile-ref <profileRef>
```

消费者支持范围以当前 Hosted Service Provider 目录为准。看到某项 Runtime 基础能力，不代表 Hosted Service
一定支持把它绑定到 Environment。数据库、对象存储的申请与 Profile 边界见
[基础能力与 Resource Binding](/features/resource-bindings/)。

## 写入环境 Secret（按需）

第三方 API 密钥等不由 Provider 解析的敏感值，写入 Environment Secret snapshot。先读取当前键名和
Environment Revision，再通过显式 patch 更新；查询不会回显 Secret 明文：

```bash
baijimu hosted-service env secret-get \
  --workspace-id <workspaceId> \
  --environment-id <environmentId>

baijimu hosted-service env secret-update \
  --workspace-id <workspaceId> \
  --environment-id <environmentId> \
  --expected-version <environmentRevision> \
  --upserts-json-file ./secrets.json \
  --change-reason "configure production service"
```

Secret 文件必须放在权限受控的临时位置且不进入 Git。普通非敏感配置、Provider 投影字段、Secret 更新和冲突
处理见[环境配置与服务鉴权](/development/backend-development/configuration-and-auth/)。

## 部署项目版本

```bash
baijimu hosted-service project deploy-version <projectId> \
  --workspace-id <workspaceId> \
  --environment-id <environmentId> \
  --version <projectVersion> \
  --json
```

部署请求返回后继续查询部署记录：

```bash
baijimu hosted-service project deployments <projectId> \
  --workspace-id <workspaceId> \
  --environment-id <environmentId>
```

只有 deployment 进入成功运行状态、Endpoint 健康且真实业务请求通过，发布才算完成。

部署完成后应保存并核对这组可追踪身份：

```text
sourceCommitId
  -> releaseOperationId
  -> projectVersion
  -> artifactId
  -> environmentId
  -> deploymentId
  -> Endpoint baseUrl
```

先检查每个声明 Endpoint 的固定 `GET /healthz`，再按其 `authMode` 使用真实 consumer token 或业务认证完成请求。
只看到进程运行、部署请求返回成功或 Endpoint URL 已生成，都不能单独证明发布完成。完整检查项和恢复流程见
[发布验证与故障排查](/development/backend-development/verification-and-troubleshooting/)。

## 配置和 Secret 变更何时生效

Environment 配置和 Secret 在启动业务进程时解析。更新 Secret 只会改变环境的配置源事实，不会修改已经
运行的进程环境，也不会修改不可变 Artifact；因此现有进程不会自动读取新值。更新后必须通过平台支持的
重启操作，或者重新部署一个已经发布的项目版本，再验证新进程、健康检查和真实业务请求。

历史 deployment 可能仍引用 `rust_binary`、`rust_bundle` 或 `hosted_service_bundle`。它们只用于审计，不能
作为新版本部署输入。应把对应源码纳入当前项目主线、设置新的规范 `package.version`，再执行项目版本发布。

需要变更数据库时，不要在服务启动脚本中执行迁移，也不要让 Bundle、Module、`baijimu-agent` 或
Control Plane 参与迁移。Schema 与 Data Migration 必须和运行程序一起从同一个项目版本发布，并由发布清单
声明；完整流程见
[数据库迁移](/development/backend-development/database-migrations/)。

> **发布操作不是部署版本**
>
> `releaseOperationId` 只能查询发布过程；部署必须使用成功发布后返回的 `projectVersion`。

> **不要恢复 deploy-artifact**
>
> `deploy-artifact` 已退出当前 CLI 和项目版本协议。旧 `hosted_service_bundle` 即使 Manifest 合法，也不能代替
> `hosted_service_release`；应先发布项目版本，再用 `deploy-version` 部署。
