文档
历史档案文档OceanWay 架构平台与产品OceanWay Developer

历史 · 应用、服务身份与凭据

重构前档案,仅供追溯,不作为新版本执行指令

历史档案 · 2026-09-11 重构前快照。 本文中的“当前”“已冻结”和实施顺序属于旧基线。新版本以现行总览实施计划为准。

Developer App 是 OceanWay API 产品中的业务容器。所有机器调用都必须归属明确的 App、Environment 和 Service Account;API Key 只是 Credential,不是用户、钱包或独立权限主体。登录后管理界面统一位于 console.oceanway.tech/aiai.oceanway.tech 公开 Developer Center 不读取或修改这些资源。

正式资源层级

Organization / Personal Space
└── Developer App
    └── Environment
        └── Service Account
            └── Credential
对象职责不负责
Organization / Personal Space资源所有权、成员关系和付款上下文保存应用运行密钥
Developer App产品接入边界、授权范围和用量聚合充当执行身份或钱包
Environment隔离开发、测试、生产配置与风险复制 Organization 成员体系
Service Account非交互式 Principal、Scope 和策略主体保存明文 Secret、拥有独立余额
Credential证明 Service Account 身份单独决定权限、价格或付款方

Workspace 与可选 Project 是 App 或 Service Account 的授权绑定,不插入上述身份父子层级。Billing Account 由 Personal Space 或 Organization 的付款规则解析;App、Environment、Service Account 和 Credential 只能拥有预算与限额,不能拥有子钱包。

唯一 Command Owner

Developer Access Domain 是四层资源的唯一 Command Owner:

DeveloperAccess.create/update/disable/deleteApp
DeveloperAccess.create/update/disableEnvironment
DeveloperAccess.create/update/disableServiceAccount
DeveloperAccess.issue/rotate/revokeCredential

这个边界独立于部署方式。首期可以在共享后端中实现为模块化领域服务,但必须满足:

  • Console AI BFF 只校验页面请求、调用领域 Command 和组合读模型,不直接写领域表;
  • Console 顶层安全/治理页面可以发起停用或撤销 Command,不复制 Credential 状态;
  • Public API Edge 只校验 Credential 和读取不可变 Access Snapshot,不创建或修改四层资源;
  • Developer Center 只读取公开内容,不接收任何客户资源 Command;
  • Text/Media Gateway 不认识 App 层级,不保存 Developer Credential;
  • 所有状态变化使用同一事务、并发约束、审计和 Outbox 事件。

Developer 是逻辑产品与领域,不是第二客户后台。Customer Identity、Organization、Membership、Workspace、Project、Billing Account 和 Audit 继续由共享客户控制面拥有。

个人默认空间与默认应用

每个个人用户首次进入 Console AI 专业空间时,Developer Access Domain 以幂等方式确保存在:

Personal Space
└── 默认 Developer App
    └── 默认 Environment
        └── 默认 Service Account

这个默认链路用于降低第一次调用门槛,但底层仍使用完整资源模型:

  • 用户可以直接创建第一枚 Credential,而不必手工创建四层资源;
  • UI 可以把默认层级折叠为“我的应用”,不能在数据库中继续把 Key 直接绑定 User;
  • 默认对象有稳定 ID、审计和生命周期,不通过名称识别;
  • 用户创建第二个 App、加入企业或启用高级策略后,再展开完整层级;
  • 个人默认资源始终属于 Personal Space,不会因用户加入企业而自动转为企业资产。

企业用户必须在当前 Organization 上下文中创建 App。员工离职只撤销 Membership 和其交互式访问,Organization 拥有的 App、Service Account、Credential、Run 与用量保持有效,除非企业策略明确停用或轮换。

Developer App

Developer App 表示一个客户应用或集成,例如网站后端、内部自动化、移动应用服务端或数据处理任务。

建议核心字段:

developerAppId
ownerType = personal_space | organization
ownerId
workspaceId?
projectId?
name / description
status
allowedOfferingIds[]?
defaultBudgetPolicyId?
createdBy / createdAt / updatedAt

规则:

  • App 只能属于一个 Personal Space 或 Organization;
  • 企业 App 的管理权限来自 Membership 和 Developer 角色,不来自任意持有 Key 的用户;
  • App 可以绑定一个 Workspace 和可选 Project,以获得 Asset、Agent、MCP 和 Project Context;
  • 绑定只扩大到明确授权的资源,不等于 App 可以读取整个 Organization;
  • App 停用后拒绝新请求,但历史 Run、Usage 和 Audit 保持可查询;
  • App 删除必须先处理活跃 Credential、Webhook、保留策略和不可变账务记录,不能级联擦除历史事实。

Environment

Environment 将同一 App 的配置、凭据、Webhook、限额和运行历史隔离。典型显示名可以是开发、测试和生产,但系统使用稳定 environmentId,不把名称写成固定权限规则。

environmentId
developerAppId
name / slug
riskClass
status
allowedOfferingIds[]?
rateLimitPolicyId?
budgetPolicyId?
dataPolicyId?
createdAt / updatedAt

环境规则:

  • Credential、Webhook Endpoint 和 Run 必须固定一个 Environment;
  • 不允许把测试环境 Key 静默提升为生产环境 Key;
  • Environment 的模型、区域或数据策略只能收窄 App 与 Organization 策略;
  • 生产环境的高风险变更可以要求再认证、双人审批或延迟生效;
  • 删除环境前必须撤销 Credential,并保留历史 Run 和计费解释所需快照。

Service Account

Service Account 是非交互式权限主体。它唯一归属一个 Environment,并继承 App 与所有者上下文。

serviceAccountId
principalId
environmentId
tenantKind = organization | personal_space
tenantId
name
status
scopes[]
allowedOfferingIds[]?
workspaceBindings[]
projectBindings[]
assetPermissions[]
agentDeploymentPermissions[]
mcpConnectionGrants[]
rateLimitPolicyId?
budgetPolicyId?
createdBy / createdAt / disabledAt?

Service Account 不登录 Console,不持有 Customer Session,也不能成为 Organization 成员。Customer User 通过 Console AI 专业空间管理它;Public API 根据 Credential 解析它。

principalId 是 Principal Registry 中 kind=service_account 的稳定 Principal ID,与 serviceAccountId 组成不可变的一对一绑定。二者属于不同命名空间:同一 Principal 不能绑定多个 Service Account,同一 Service Account 也不能更换、复用或借用另一个资源的 Principal。停用或删除 Service Account 只改变资源生命周期并撤销 Credential,不回收其 Principal ID;历史 Run、授权和计量继续引用原 Principal。创建、读取和准入必须验证 Principal Registry 的 Kind、Tenant 与 Service Account 归属完全一致,禁止把 Customer User、Workload Principal 或另一个 Tenant 的 Principal 绑定进来。

生产自动化必须使用 Service Account Credential,不能依赖某位员工的个人交互式 Session 或个人 Key。Service Account 权限采用最小授权:未声明的 Scope、Offering、Workspace、Project、Asset、Agent 或 MCP Tool 默认拒绝。

Credential 与 API Key

第一阶段客户 Developer Credential 类型为 API Key;未来正式发布的 OAuth Client 或客户侧短期 Token 只有经独立 ADR 批准后,才可以扩展同一开发者凭据抽象。OceanWay 内部 Workload Principal/Credential 属于独立信任边界,不复用 Developer Credential 的类型、Audience、Secret 或轮换记录。

developerCredentialId
serviceAccountId
type = api_key
prefix / lastFour
secretHash
status
expiresAt?
notBefore?
ipAllowlist[]?
rateLimitOverrideId?
createdBy / createdAt
lastUsedAt?
rotatedFromId?
revokedAt?

安全规则:

  1. Secret 使用密码学安全随机源生成,只在创建响应中完整返回一次。
  2. 服务端只持久化校验所需 Hash、前缀和尾号,不保存可逆密文。
  3. 列表、详情、审计、日志和支持工具永不回显完整 Secret。
  4. 轮换创建新 Credential,通过 rotatedFromId 建立关系;旧 Key 在明确宽限期后撤销。
  5. Credential 泄漏只需撤销 Credential,不改变 Service Account、App、钱包或历史 Run 身份。
  6. Developer Key 只在 api.oceanway.tech Edge 鉴权,不转发给 Text/Media Gateway 或 Provider。

身份类型与登录边界

Principal认证或委托方式可以做什么
Customer UserOceanWay Customer Identity / Console Host-only Session登录 Console AI、提交有权执行的 Developer Access Command
Service AccountDeveloperCredential;Playground 由短期 Grant 委托作为唯一 Public API 执行主体,不登录任何客户 UI
OceanWay Workload Principal短期 Workload Credential 或 mTLS assertionOceanWay 服务间调用和私有网关访问
OceanWay Workforce独立 Workforce Identity进入内部 Admin 和运维读模型

DeveloperCredential 与 Playground Execution Grant 都是认证或授权证据,不是 Principal。Playground 不创建第五类持久主体:Customer User 是业务发起人,目标 Service Account 是唯一 API 执行主体,Grant 只证明该用户在受限条件下可以委托该 Service Account 执行。

Customer Session、DeveloperCredential、Playground Execution Grant、Workload Credential 和 Workforce Session 必须使用不同 Audience。Developer Center 不需要 Customer Session;Console Session 不能被 Public API、私有网关或 Admin 接受。Workload Identity 是内部信任体系的统称;实现中必须区分稳定 Workload Principal 与它使用的短期 Workload Credential。

Playground Execution Grant

Playground 不创建、读取或复用长期 Developer Credential。浏览器携带 Console Session 调用 Console AI BFF;BFF 从 Developer Access Domain 取得目标 App、Environment 与 Service Account 的 Access Snapshot,再向 Authorization/Policy Token Issuer 申请短期、受限的 Execution Grant,并由服务端调用 Public API Edge。BFF 只能申请和持有 Grant,不能自行签发。

Grant 必须绑定 Customer User Actor、目标 Service Account、App、Environment、允许的 Offering/操作、有效期、使用约束和审计身份。它不是持久 Credential,不能执行四层资源命令,也不得暴露给浏览器 JavaScript、本地存储、URL 或客户端日志。API Edge 接受 Grant Audience,但仍不接受 Customer Session。

授权解析

每个 Public API 请求按固定顺序计算有效权限。正式客户程序集成使用 Developer Credential;Console Playground 使用短期受限 Grant:

Developer Credential 有效或 Playground Grant 有效
∩ 目标 Service Account 启用且 Scope 允许
∩ Environment 启用且策略允许
∩ Developer App 启用且应用授权允许
∩ Organization / Personal Space 有效
∩ Workspace / Project / Asset / Agent / MCP Grant
∩ Model Offering 已发布到 api Surface
∩ Entitlement、预算、限额和区域/数据策略

任何一层拒绝即停止执行。前端传入的 Organization、App 或 Project ID 只能作为选择提示,服务端必须从 Developer Credential 或 Playground Grant 重新解析所有权和允许范围。

授权结果进入不可变 RunAdmissionManifest@N。Run 上的 executionManifestRef 专门指向这份准入清单,executionManifestSchemaVersion 固定其严格 Schema Version;二者都不指向某次 Attempt 或网关私有路由快照。本页只列出 RunAdmissionManifest 中 Developer Access 相关的必要字段;完整字段表以调度与网关架构为准:

actorPrincipalId
executionPrincipalId
authentication =
  { kind=developer_credential; developerAppId; environmentId; serviceAccountId; developerCredentialId }
  | { kind=playground_execution_grant; developerAppId; environmentId; serviceAccountId;
      playgroundExecutionGrantId; playgroundExecutionGrantSchemaVersion;
      playgroundExecutionGrantClaimsDigestAlgorithmVersion; playgroundExecutionGrantClaimsDigest }
tenantKind / tenantId
workspaceId / projectId?
billingAccountId
source = { surface=developer_api|developer_playground; apiVersion; operation }
product = developer_api | developer_playground
authorizationDecisionId / authorizationDecisionSchemaVersion
authorizationDecisionInputDigestAlgorithmVersion / authorizationDecisionInputDigest
authorizationEvidenceEvaluationSetRef / authorizationEvidenceEvaluationSetSchemaVersion
authorizationEvidenceEvaluationSetDigestAlgorithmVersion / authorizationEvidenceEvaluationSetDigest
authorizationEvidenceArchiveCutRevision
authorizationEvidenceEvaluationCount
authorizationEvidenceEvaluations[] = sorted {
  evidenceKind;
  authorizationEvidenceEvaluationRef / authorizationEvidenceEvaluationSchemaVersion;
  authorizationEvidenceEvaluationDigestAlgorithmVersion / authorizationEvidenceEvaluationDigest;
  archiveRevision
}
executionAuthorization = {
  authorizationScopeSnapshotRef / authorizationScopeSnapshotSchemaVersion
  authorizationScopeSnapshotDigestAlgorithmVersion / authorizationScopeSnapshotDigest
  allowedAssetVersionRefs[] / allowedModelOfferingRevisionIds[] / allowedToolVersionRefs[]
  authorizationActionIds[]=sorted
  authorizationActionCount
}
modelOfferingRevisionId / logicalModelId
modelDeploymentId  # 准入时冻结的 initial target
modelRoutingPolicyRevisionId
gatewayPool = text | media
pricingSnapshotId / billingPolicyRevisionId / billingReservationId

modelDeploymentIdRunAdmissionManifest 中只表示准入时的 initial target。每次实际执行由独立不可变的 AttemptExecutionManifest@N 冻结 Attempt 与实际 Deployment;重试只能在已冻结的 modelRoutingPolicyRevisionId 允许时更换 Deployment,且不得改写 RunAdmissionManifest

合法组合只有两种:

正式 API:actorPrincipalId = serviceAccountPrincipalId
          executionPrincipalId = serviceAccountPrincipalId
          authentication.serviceAccountId = ServiceAccount 资源 ID
          developerCredentialId = required

Playground:actorPrincipalId = customerUserPrincipalId
            executionPrincipalId = serviceAccountPrincipalId
            authentication.serviceAccountId = ServiceAccount 资源 ID
            playgroundExecutionGrantId + Schema Version + Claims Digest = required

Principal ID 与 ServiceAccountId 属于不同命名空间,不能按字符串相等。Core 必须通过受信 Developer Access/Identity 关系验证 authentication.serviceAccountId → serviceAccountPrincipalId;正式 API 的 Actor/Execution Principal相等,Playground的 Customer User Actor与 Service Account Execution Principal不相等。两种认证引用不得同时存在,也不得同时为空;Playground Grant与 Authorization Decision的版本化摘要必须在不可变 Authorization Evidence Archive中验证。Core必须以同一 Operation一次提交完整期望成员、Authorization Scope Snapshot完整四元组、排序去重的 authorizationActionIds[]authorizationActionCount,由 Archive通过与撤销 Writer共用的 Revision Fence在单一事务用服务端时间签发内容寻址 AuthorizationEvidenceEvaluationSet@1,再将 Set四元组、统一 Archive Cut、Scope/Action Count/Action成员和严格成员集合固定到 Manifest:正式 API恰好包含 Authorization Decision Evaluation,Playground恰好包含 Authorization Decision + Playground Grant Evaluation。Count必须等于Action数组长度并参与摘要,但不能替代精确成员;Scope Snapshot/Action Count/Action集合必须与 Set、run.created@2.0及 Manifest的 executionAuthorization逐项相等,缺失/错误Count、重复Action、含义未定义的 scopes[]或展示标签都不能替代 Action ID。调用方不得逐成员签发、传入过去的评估时间或拼接不同 Archive Revision;先提交的撤销必须进入新 Set并阻止 Valid。历史重放先以冻结 Set/Scope/Action读取,再读取其成员,不按当前撤销 Timeline重新解释。source.surface == product,两个分支分别固定为 developer_api | developer_playground。Console BFF的 Workload Principal只记录在服务跳转与 Invocation Audit中,不能覆盖业务 Actor或执行主体。

幂等身份必须和上述 Actor/Execution 分离规则一致。当前已验收的 execution.run-admission.v1 只允许 Organization + Developer Credential,不能直接接收 Playground。启用 Playground 前必须切换到 Contracts 发布的多 Actor Operation/Idempotency 版本,其规范身份至少包含 tenantKind + tenantId + authentication.kind + product + actorPrincipalId + executionPrincipalId + developerAppId + environmentId + serviceAccountId + operation + Idempotency-Key。因此正式 API 与 Playground、或两个 Customer User 即使共用同一 Service Account、Key 与相同请求,也不会返回彼此的 Run;Credential 轮换则因为稳定 Actor/Execution/Access 资源身份未变,仍可返回原 Run。跨 Actor/认证/Product 合并、客户端覆盖身份和缺失任一身份字段必须在创建 Run/Reservation 前拒绝,并由并发负测证明。

Scope 与资源授权

Scope 表示动作权限,例如模型执行、Run 查询、结果读取或 Webhook 管理;它不能代替资源级权限。

建议将权限分为:

  • API 动作:models:readruns:createruns:readoutputs:read
  • 能力范围:文本、Embedding、Rerank、图像、视频等;
  • Offering 白名单:允许的公开模型或 Family;
  • 上下文范围:Workspace、Project 与数据区域;
  • 生态资源:固定 Asset Revision、Agent Deployment、MCP Connection Grant;
  • 商业约束:预算、并发、速率、合同权益和成本中心。

最终 Scope 名称和粒度需要进入 API 版本契约;实现不得用一个泛化 all 永久绕过策略层。

生命周期

App、Environment 和 Service Account 可以停用并恢复;Credential 只允许 active → revoked/expired,撤销后不可恢复。删除是受治理的资源终止,不得删除 Ledger、Usage、Run、Audit 或历史 Offering/价格快照。

状态传播规则:

  • 父资源停用立即阻止所有子 Credential 发起新请求;
  • 已在执行的 Run 按已冻结 Manifest 和安全策略继续、取消或人工处置,不能由前端猜测;
  • 恢复父资源不会恢复已撤销或已过期 Credential;
  • Membership 撤销影响用户管理权限,不自动删除企业 Service Account;
  • Credential 状态变化发布审计事件并失效鉴权缓存。

预算、计费与用量归属

每次调用同时记录以下维度:

billingAccountId
tenantKind / tenantId
authentication.kind
authentication.developerAppId / authentication.environmentId / authentication.serviceAccountId
authentication.developerCredentialId | authentication.playgroundExecutionGrantId + Schema Version + Claims Digest(由 kind 严格选择)
authorizationDecisionId / Schema Version / Input Digest
product
workspaceId / projectId?
runId / executionAttemptId
modelOfferingRevisionId / pricingSnapshotId / billingPolicyRevisionId

tenantKind + tenantId 是严格判别联合,不再同时携带 organizationId? / personalSpaceId?;个人请求不能伪造 Organization。预算和限额可以设置在 Organization/Personal Space、Workspace、App、Environment 或 Service Account,并按“上层上限与下层上限取更严格者”计算。它们不是余额复制。企业请求余额不足时不得自动改扣员工个人钱包。

Console AI 专业空间展示 API 与 Playground 维度;Console 顶层展示全平台 Billing Account、订阅和账本;Developer Center 只展示公开列表价;Admin 展示脱敏的内部诊断与供应成本。

Webhook 所有权

Webhook Endpoint 归属一个 Environment,事件投递使用 App/Environment 上下文,并在 Console AI 专业空间管理。签名材料使用独立的 WebhookSigningSecretVersion,采用一次显示、版本化轮换和 Vault 托管,不属于 Service Account 的 Developer Credential,也不复用 Public API Key。

Service Account 可以拥有管理 Webhook 的 Scope,但 Webhook Endpoint 不是 Service Account 子对象,以免轮换或停用某个调用身份时错误删除整个应用的事件出口。

审计不变量

以下动作必须记录 Actor、Owner、App、Environment、目标资源、前后状态、原因、Request/Trace ID 和时间:

  • App、Environment、Service Account 的创建、停用、恢复和删除;
  • Credential 创建、轮换、撤销、过期与高风险使用;
  • Scope、模型白名单、Workspace/Project Binding 和预算策略变更;
  • Webhook Secret 轮换、Endpoint 停用与事件重放;
  • 企业成员对生产资源的访问和权限提升。

审计不得包含完整 Secret、完整 Prompt、媒体二进制或 Provider Credential。

遗留 oceanway-vozeb 实现基线

oceanway-vozebdeveloper_api_keys 直接保存 user_id,支持名称、到期、IP 列表、速率和并发字段。服务会保存可逆密文,并允许登录用户之后再次回显 Secret;该迁移来源中尚无 Developer App、Environment、Service Account、Organization/Membership 或相应资源授权表。独立 Core/API Edge 已验收四层 Snapshot 与 Hash-only 验证,但仅覆盖受控 Organization-backed Admission;不能用旧实现描述覆盖这项新基线。

这套实现可以支撑个人 MVP,但不能作为企业生产身份模型继续扩展。

目标状态

目标态中,每个正式客户程序请求都能从 Credential 唯一解析到 Service Account、Environment、Developer App、所有者、Workspace/Project、Billing Account 和策略决策;Playground 请求从受限 Grant 解析到同等业务上下文及 Customer User Actor。员工身份与生产服务身份分离;个人用户仍能通过自动创建的默认层级快速开始。四层资源只有 Developer Access Domain 可以修改,Console AI 只是专业任务入口,公开 Center 没有客户私有状态。

实施阶段

阶段交付退出条件
ID0 模型冻结数据模型、唯一 Command Owner、角色、Scope、生命周期和审计事件不再新增直接归属 User 或由 BFF 直写的 Key 功能
ID1 默认个人链路Personal Space、默认 App/Environment/Service Account新个人用户从 Console AI 无需理解层级即可创建一次性 Key
ID2 企业链路Organization Membership、Developer 角色、Workspace/Project Binding成员离职不影响企业生产身份
ID3 Credential 收口Hash-only Secret、轮换、撤销、缓存失效和审计任意接口均无法再次回显 Secret
ID4 Playground Grant短期受限授权、Console BFF 服务端转发与审计浏览器无长期 Key,API Edge 无 Customer Session
ID5 策略与商业Scope、Offering 白名单、预算、限额和 Billing Account 解析每个请求都有完整且可解释的授权决策

验收标准

  1. 新用户首次进入 Console AI 后自动拥有且只拥有一套幂等创建的默认开发者链路。
  2. 每枚 API Key 唯一归属一个 Service Account,并可追溯到 Environment、App 和 Owner。
  3. 完整 Secret 只在创建或轮换响应中出现一次,数据库、日志和查询接口均无法恢复。
  4. 停用 App、Environment 或 Service Account 后,全部子 Credential 立即拒绝新请求。
  5. 企业成员离职后不能管理企业 App,但未依赖该成员身份的生产调用不被删除。
  6. 服务端忽略伪造的 Organization/Workspace/Project 上下文,并按 Credential 重新授权。
  7. API 用量可按 App、Environment、Service Account 和 Credential 聚合,金额仍归统一 Billing Account。
  8. 私有网关只接收 OceanWay Workload Principal 使用的短期 Workload Credential,不接收 Customer Session 或 Developer Key。
  9. Developer Center 无四层资源读写接口;Console BFF 和 API Edge 均不能直接写领域存储。
  10. Playground 的浏览器网络、页面状态与本地存储中不存在长期 Developer Credential。
  11. Contracts/Repository 负向测试拒绝 Principal Registry Kind 错误、跨 Tenant 绑定、同一 Principal 绑定多个 Service Account、同一 Service Account 换绑或复用 Principal,以及把 serviceAccountId 当作 principalId;停用后历史 Run 仍能解析原不可变绑定。

延伸阅读

On this page