# 核心概念与边界

> 核验版本：1.1.0；通道：stable；文档 ID：overview.concepts

本页帮助你判断**该改哪个对象**，以及**由哪一层权限控制**。理解模型不需要账号；查看实际项目需要平台会话和项目成员资格，编辑内容需要项目 `developer` 或以上，发布需要项目 `admin` 或 `owner`。

## 实例、项目与端点树

**实例**是一套服务端部署，拥有平台账号、激活状态、服务配置和 PostgreSQL 平台数据库。多个服务进程可以共享该数据库；创建项目不等于再部署一台服务器。

**项目**拥有自己的 API 资产和协作者成员关系。slug 在实例内唯一。对外前缀为 `/p/<slug>`，管理路由使用 `/projects/<slug>`。项目 slug 不是访问凭据。

**端点树**组织项目路由。新项目有一个挂载于根路径的 `default` 树。目录节点组织后代，可调用叶节点具有 HTTP 方法和目标。路径片段不一定是脚本名；同一脚本可以绑定多个端点，分别使用不同方法和访问规则。

例如：

| 对象 | 示例 | 含义 |
| --- | --- | --- |
| 实例基础 URL | `https://api.example.com` | 要连接的部署；请替换成自己的 URL |
| 项目 slug | `hello-lab` | 项目命名空间 |
| 脚本资产 | `hello` | 可复用的执行定义 |
| 端点 | `POST /hello` | 项目内已发布的 HTTP 契约 |
| 调用 URL | `https://api.example.com/p/hello-lab/hello` | 完整对外请求地址 |

反向代理挂载前缀也应包含在实例基础 URL 中。CLI 登录的 server URL 不要包含 `/ui` 或 `/p/<slug>`。

## 三个身份平面，不是一张角色表

| 平面 | 代表谁 | 如何决定访问 |
| --- | --- | --- |
| 平台用户 | 登录控制台、CLI 或原生应用的人 | 平台角色：`owner`、`admin`、`developer`、`operator` |
| 项目协作者 | 加入某个项目的平台用户 | 独立成员角色：`owner`、`admin`、`developer`、`operator` |
| 项目终端用户 / 机器调用者 | 消费已发布项目 API 的用户或程序 | 项目认证器、终端用户角色和属性，以及授权模型 |

平台 `operator` 可以同时是项目 `owner`。平台 `owner` 不会自动成为每个项目的协作者。改变平台角色不会改变项目成员角色；添加终端用户也不会赋予控制台访问权限。

`viat user` 管平台人员，`viat project member` 管协作者，`viat p-user`、`viat role`、`viat authorizer` 管项目调用者身份。完整流程见[平台用户](../instance/platform-users.md)与[创建项目并协作](../projects/create-and-collaborate.md)。

## 脚本、工作流与资源

**脚本**是有名称、语言和版本的可执行资产。**工作流**编排执行目标与控制流，并不是端点目录。草稿测试执行当前定义，可能产生真实副作用，不会自动变成离线模拟。

**资源**保存可复用连接或平台管理的能力，如数据库、HTTP API、存储、邮件服务或密码学密钥。资源配置区分非秘密的 `plain` 数据和秘密字段。普通管理读取会脱敏秘密值，平台代理的资源操作会在平台侧应用凭据。

但这**不是 1.1.0 所有脚本资源视图均不含凭据的保证**：部分旧式数据库、缓存、消息和 S3 投影仍包含带凭据的字段。优先使用代理 helper，切勿返回或打印资源对象，并查看各类型的[资源参考](../assets/resources/index.md)。有意提供秘密值的 `secret` / `config` 资源，与提供商认证凭据属于不同契约。

不要把保存业务表的 PostgreSQL 资源与 PostgreSQL **平台数据库**混为一谈。`sqlite` 资源访问经过允许的服务端文件，也不能替代平台数据库。

## 草稿、发布与回滚

编辑端点目标、认证或输入契约，改变的是**草稿**。对外分发读取**当前已发布快照**。发布捕获路由契约和目标定义；测试运行不等于发布。执行 `viat publish apply` 前，先看 `viat publish plan`。

依赖处理需要特别注意：

- 已发布的**脚本端点**，在整个依赖图没有 `(live)` 引用时，会捕获普通 Python/TypeScript `uses:` 导入。
- 1.1.0 的工作流步骤脚本是例外：主脚本源码在发布时固定，但其 `uses:` 依赖（含嵌套工作流步骤）仍在每次运行工作流前实时解析。
- `# uses: shared/util (live)` 这样的指令每次运行读取实时源码，并使用新工作进程，而不是预热工作池路径。
- 草稿测试和直接调度的目标实时解析依赖，因为它们不执行端点的冻结快照。
- 没有冻结依赖数据的旧快照也会退回实时解析。升级旧端点后，如需明确冻结依赖图，应重新发布。

所以不能笼统承诺“所有导入都是实时的”，也不能说“所有依赖都会随回滚恢复”。实际结果取决于端点快照和依赖模式。资源凭据和上游配置仍是实时状态；轮换凭据不是部署端点代码。

发布在所有部署设置下都不保证运行环境已准备成功。默认同步构建，但 `VIAT_PUBLISH_BUILD_BLOCK=0` 允许依赖构建失败后仍发布；`VIAT_PUBLISH_BUILD_ASYNC=1` 允许后台构建。判断发布健康前，应检查构建结果。

## 认证不等于授权

**认证器**回答“调用者是谁”。端点向上继承时，最近一层明确声明的认证器列表会**替换**祖先列表，并不是把父节点允许的凭据类型全部合并。

**授权门禁**（`authz_gates`，元素为 `{type, action}`）回答“已识别的调用者能否调用路由”。门禁沿树**累积**，直到 `override_permissions` 停止继承。它们在业务对象尚不存在时，对 subject 做判断；对象和行权限还属于授权模型及具体业务操作。

内置 `anonymous` 认证器允许明确公开的路由，但不能代替敏感业务数据的权限检查。控制台登录令牌不能与项目终端用户令牌或 API key 互换。

## 执行与证据

执行记录包含 `request_id`、状态、耗时等元数据，行日志是目标捕获的输出。端点拒绝也可能生成执行记录而不启动工作进程。日志受配置的存储后端和保留策略影响，不能当永久备份。

完成[第一个端点](../getting-started/first-endpoint.md)中的登录和项目选择后，可以只读检查：

```sh
viat project list
viat endpoint list --json
viat publish plan --json
viat logs query --limit 10 --json
```

预期分别获得可访问项目、可编辑端点记录、待发布变更，以及包含 `items` 和 `next_before` 的执行分页。新项目返回空列表是正常情况。这些命令不会发布或运行脚本。

## 定位边界误用

| 现象 | 检查方向 |
| --- | --- |
| 平台 Admin 看不到项目 | 将账号加入项目；平台角色不绕过成员检查 |
| Developer 可编辑但不能发布 | 请项目 Owner/Admin 操作，不只是平台 Admin |
| 有效终端用户令牌收到 `403` | 检查已发布认证器列表和所有继承门禁 |
| 草稿响应变了，调用响应没变 | 发布，并核对实例、项目和活动快照 |
| 回滚没有恢复上游凭据 | 凭据是实时资源状态，不是快照内容 |
| 配了 `sqlite`，服务仍要求 PostgreSQL | 资源数据库和平台持久化是两层概念 |

清理实验时，先取消发布路由，再删除端点及执行目标。移除项目成员不会删除其项目内容；清空 CLI 会话也不会删除项目。具体清理步骤见[第一个端点](../getting-started/first-endpoint.md)。

## 核验依据

契约源码 `03751a67`：`crates/viat-core/src/types/{project,script,resource,snapshot}.rs`、`crates/viat-db/src/projects.rs`、`crates/viat-db/src/endpoints.rs`、`crates/viat-api/src/handlers/snapshots.rs`、`crates/viat-cli/src/main.rs`。
