文档
历史档案文档OceanWay 架构平台与产品内部管理员平台

历史 · 管理员平台与运维控制面

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

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

OceanWay 管理员平台不是服务器日志查看器,也不是把用户、模型、账单和 Gateway 管理页拼在一起。它是一套以业务执行链为中心的内部控制面:从一个用户可提供的 Request ID 出发,定位身份、预算、Run、网关、Provider、资产和账务事实,判断影响范围,执行受控处置,并留下可复核证据。

本章定义 admin.oceanway.tech 的产品定位、身份边界、运行数据契约、页面结构、处置权限与交付顺序。可靠投递、投影和查询的实现边界见 ADR-030,首个界面契约见 Run Explorer;具体模型执行状态见调度、执行与模型网关池,账务事实见钱包与商业系统,客户与内部权限边界见权限、安全与治理

正式决策

事项正式选择含义
内部入口admin.oceanway.techOceanWay 员工、值班与审计人员的内部管理入口,不进入客户应用启动器
首期实现复用现有 OceanWay /admin 作为代码基座不另起项目重写;通过 Host Surface、模块边界和权限逐步收敛
仓库边界oceanway-admin 独立 Git 与发布边界现有 /admin 是迁移来源;目标仓不复制 Core 事实或直接访问 Gateway 数据库
产品形态一个后台外壳、按角色呈现工作区首期不再拆一套 ops 系统;查询与命令在同一产品内保持独立边界
身份边界Workforce SSO Client + Host-only Session可以复用同一个底层 IdP,但不能复用客户 Session 或普通企业角色
客户管理与 OceanWay 内部管理员平台分离企业 Owner、Billing Admin 等只管理自己的组织,不进入内部控制面
实施顺序先只读诊断,后开放运维命令没有完整关联、错误确定性、权限和审计前,不开放危险写操作
数据访问领域事实、规范化事件、运维读模型和 Telemetry Query控制面不直连 Text/Media Gateway 数据库,也不通过直接改表处置故障
Operations Owneroceanway-core Operations 模块唯一拥有 Outbox Dispatcher/Consumer/Projector、Operations Read Model、Observation accepted source 与 Private Query API
Admin Owneroceanway-admin只拥有 Workforce Session、Admin BFF 与 UI,不拥有或复制 Operations 投影事实
首期部署同一 Core image:core-api + 单一 managed core-operations-worker使用 PostgreSQL Outbox;不引入 Kafka、NATS、Redis 或新的业务服务
当前上线状态契约已冻结,尚未实现Public Admission 与公共 Operations API 继续禁用,不把文档目标写成现有能力

Admin 与客户 Surface 的仓库边界已经建立;独立构建/发布、Workforce Session、Admin BFF 与 UI 迁移仍是 A1/A2 的目标,尚未形成已验收运行能力。业务事实和 Command Owner 始终位于 oceanway-core。依据 ADR-030,Outbox Dispatcher、Consumer、Projector、Operations Read Model、Observation accepted source 与 Private Query API 统一由 oceanway-core Operations 模块拥有;oceanway-admin 最终只拥有 Workforce Session、BFF 与 UI。首期目标使用同一 Core image 的两个 Process Role,并且每个环境只有一个 managed Worker,不创建新服务或第二份投影事实。

当前实现基线与处置

现有后台已经拥有可复用的业务骨架,但尚未形成平台级运维控制面:

当前能力目标归属处置
经营概览与用户管理经营分析、客户支持复用只读信息架构;写路由需对应 Domain Command 验收后逐项开放
商品、订单、促销、优惠券、邀请商品运营与财务管理复用产品工作流设计;逐步改接统一 Product、Billing Account 和追加式账本,遗留写路由不随迁移上线
积分、钱包、支付、CDK 与支付对账财务管理复用诊断界面;人工修复必须迁入已注册 Billing Command,只有两种正式 Billing sourceScope 可进入 Reconciliation Case
模型渠道、模型配置与 Agent Skills上游配置复用只读配置视图;重构为 Offering 发布、Text Pool 与 Media Pool 供应运维后再逐项开放命令
调用记录运行记录保留为有生命周期的业务记录,不能冒充不可变审计日志
生成运维、Worker、Heartbeat、Lease 与人工确认Run Explorer 与执行对账只复用查询与信息架构;遗留人工确认/修复写路由默认禁用
站点、邮件、存储与备份系统管理复用只读视图;动作按风险拆分权限并完成命令审计后逐项开放
作品、公告和公共提示词内容运营复用领域界面,不与模型运行值班权限混合;写路由仍需独立命令验收
Audit API 与管理员行为记录审计中心补齐正式页面、查询范围与服务主体审计
后台帮助和更新记录运维知识与变更记录关联 Runbook、Incident、发布版本与回滚说明

迁移不是简单改域名。以下当前做法只能作为过渡:普通用户 Session 加 role=admin、大粒度 system.manage/generation.manage、可以删除的“日志”、孤立的人工补录按钮,以及通过页面各自查询数据后由管理员自行拼接因果关系。

两类管理员必须分离

对象OceanWay 内部管理员企业客户管理员
入口admin.oceanway.techconsole.oceanway.tech 或对应客户产品
身份Workforce PrincipalCustomer Identity + Organization Membership
管理范围OceanWay 平台、供应、运行、财务、内容与安全自己的 Organization、Workspace、Project 和合同范围
可见数据按岗位脱敏后的跨租户运行信息仅本组织资源、成员、预算、账单、Key 和审计
特权动作JIT、职责分离、Incident/Case 约束组织策略允许的客户自助动作
内容访问默认无权;Case-scoped Debug Grant按组织角色和资源授权

企业 Owner、Organization Admin、Billing Admin 和 Security Admin 不是 OceanWay 内部管理员。OceanWay 客服也不能因为能够搜索客户账户,就自动获得 Prompt、媒体原件、Provider Secret 或账务修改权限。

管理员角色基线

内部角色主要职责明确不自动获得
Business Operator经营、商品、订单和客户运营Gateway Secret、客户内容、生产处置命令
Support Operator账号和请求排障、客户沟通Secret、直接改账、完整 Prompt 和媒体原件
Model / Supply OperatorOffering、Deployment、Channel/Supply 和 Provider 运行用户钱包修改、客户内容和组织权限
Platform SRE / On-call告警、Incident、队列、Worker、Deployment 缓解Secret 明文、任意退款、内容读取
Asset Operator结果取回、校验、落盘与引用修复Provider Credential、用户余额调整
Billing ReconcilerReservation、Settlement、Release、Refund 对账Prompt、媒体内容、Provider Secret
Content Operator作品、公告和公共内容治理生产运行命令、供应配置、账务处置
Security AdministratorWorkforce、策略、授权、凭据撤销与访问审查客户内容、付款操作、凭据明文
Auditor只读查看审计、变更、Incident 和账务证据任何写操作
Incident Commander协调影响范围、处置和沟通自动获得其他岗位的技术或财务权限

“全权限管理员”只用于受控 Break-glass,不是日常岗位。Incident Commander 是协调责任,不是权限叠加器。

目标控制面拓扑

Host-only Workforce Cookie/Session 只在 Admin BFF 本地终止,绝不转发到 Core。Admin Query BFF 的普通运维与 Audit 投影读取只通过 Core Private Operations Query API,聚合经授权的读模型、低敏 Audit Projection 与 Telemetry Reference;它使用独立 Workload Principal、绑定该 Workload 的 Core Signed Query Grant 与 private, no-store 响应。Audit 原始存储没有独立的 BFF 直连路径,Core 按 Grant 的 Tenant/Resource/Action/Field Scope 裁剪后返回,并以受控 Audit Append Procedure 记录敏感查询。只有操作员在活跃 Incident/Reconciliation Case 中显式展开受限原始内容时,BFF 才能走第二条独立的 Authorized Telemetry Query:使用面向 Telemetry Audience 的短期 Workload JWT、由 Core Authorization 签发且绑定基础 Query Grant/同一 BFF Workload 的 SensitiveDebugGrant,并对 query.authorized → query.released | query.not_found | query.inconclusive | query.failed 执行 fail-closed Audit。两条路径使用不同 Client/Audience/Scope 和网络策略;普通 Query Grant 不能解引用 Telemetry,Telemetry Query 也不能读取 Operations/Audit 数据库或返回范围外内容。BFF 不持有任何数据库身份,也没有连接 Core/Gateway 数据库的网络权限。只有 Core Operations Query Role 可以读取批准的只读 View,并执行受控 Audit Append Procedure。Admin Query 与未来 Command Gateway 不共享身份或网络权限。Admin Command Gateway 只接受明确的领域命令,不能执行任意 SQL、任意 HTTP 转发或绕过 Text/Media Gateway 的状态机。

一条可还原的业务执行链

管理员需要同时看到关系图与真实时间轴。标准业务顺序是:

Public Request
→ Identity / Policy Decision
→ Quote / Billing Reservation
→ Run / RunStep / Execution Attempt
→ Gateway Dispatch
→ Text Gateway Invocation 或 Media Gateway Task
→ Provider Attempt / Provider Evidence Reference / Observation
→ Result Fetch / Validation / AssetVersion
→ Usage Path:Execution/Output Eligibility + Usage Evidence → canonical MeterEvent
→ Billing:eligible MeterEvent + frozen Price/Policy → Settlement / Release / Refund
↘ Cost Path:Attempt + Binding/Route + Cost Evidence → ProviderCostFact → Margin / Provider Reconciliation
→ Product Binding / Customer Webhook

账务预占发生在外部调度前;Settlement 由具结算资格的 canonical MeterEvent、准入时冻结的 Price/Billing Policy 与对应可信 Execution/Output Eligibility 决定,失败/取消是否收费不能只看终态。ProviderCostFact 不要求成功 Output、Asset、MeterEvent 或 Settlement,且绝不进入客户扣款链。Gateway 只拥有不可变 ProviderUsageEvidence / ProviderCostEvidence 与 source ref,Observation 只可引用 Evidence;二者都不能生成规范 Fact 或触发结算。页面不能为了画出一条直线而改变真实因果顺序。某一环没有可信事实时显示“未知/未观测”,不能按时间接近、相同模型或相似 Prompt 猜测关联。

ID 与关联契约

长任务不能让一个 traceId 承担所有身份语义:

ID生命周期用途
requestId一次入口或服务请求客户可提供的公开排障编号;每次请求不同
traceId / spanId一次分布式 Trace同步调用关系、延迟和错误位置
correlationId一条跨事件业务流程连接异步事件、回调、恢复和补偿
operationId一次可能产生副作用的逻辑操作幂等、计费和外部动作身份,不能重复复用
runId / runStepId / executionAttemptIdOceanWay 执行生命周期用户目标、步骤、实际执行与业务重试
gatewayInvocationId / gatewayTaskId / providerAttemptId私有网关执行生命周期Text Invocation、Media Task 和真实 Provider 尝试;三者命名空间独立
deliveryAttemptIdOutbox 投递生命周期一次受 Lease/Fencing 保护的投递尝试,不得与 Execution Attempt 混用
assetVersionId资产版本生命周期正式结果、血缘与产品绑定
reservationId / meterEventId / providerCostFactId / ledgerEntryId账务生命周期预占、规范计量/供应成本与追加式账本
alertId / incidentId / reconciliationCaseId运维处置生命周期异常聚合、事故和善后案件

规则:

  • OceanWay 在调用私有网关前固定 correlationId + operationId + executionAttemptId
  • 网关接收标准 traceparent 和不透明 OceanWay Operation Reference;Text Gateway 产生 gatewayInvocationId,Media Gateway 产生 gatewayTaskId,两者可关联独立 providerAttemptId
  • Provider 不支持 Trace 透传时,由 Gateway 保存本地映射;不得伪造 Provider 已支持 Trace。
  • Poll、未来 Callback、队列恢复和人工命令通常形成新的 Trace,通过 Span Link、correlationId 和稳定领域 ID 关联原操作。
  • Asset 登记保存来源 RunStep、Execution Attempt、严格 Gateway Execution Anchor(Text Invocation 或 Media Task)和可用的 Provider Attempt 引用。
  • Reservation 保存 operationId 与价格快照;结算只关联 Metering 写入的可信规范 MeterEvent,Provider Cost Evidence/Fact 不单独决定客户费用。
  • Public Request ID 只能通过授权查询解析到内部 ID,不能用连续编号或可猜测 URL 暴露跨租户信息。

运维读模型

Operational Read Model 是可重建的跨域投影,不是新的万能事实库。它至少提供:

OperationSummary
  request / correlation / operation
  actor / tenantKind / tenantId / workspace / project?
  product / surface / capability
  run / step / execution attempt
  gateway pool / deployment
  gateway execution anchor = { kind=text_invocation; gatewayInvocationId }
                           | { kind=media_task; gatewayTaskId }
  provider attempt summary
  asset persistence summary
  billing reservation / settlement summary
  current error / alert / incident / reconciliation links
  latest trustworthy boundary
  first_accepted_observation_at? / latest_accepted_observation_at?

它由 Core Operations Projector 消费领域 Outbox 和 Core Intake 已接受的规范化 Observation 更新。控制面不读取 Core/Gateway 私有表,也不复制 Provider Credential、完整请求、原始媒体或用户账本。读模型滞后时页面同时显示投影版本、新鲜度、Source Snapshot anti-join、Revision Gap、Quarantine、完整性和 accepted health window,不能把“尚未同步”误判成“业务不存在”。首期不使用全局递增位置或其他标量水位证明完整性;详细契约见 ADR-030

所有运维时间线统一使用五值 evidenceKinddomain_factoperational_observationoperations_runtimetelemetry_referencederived_summary。Delivery、Attempt、Receipt、Checkpoint(仅版本/快照状态)、Source Snapshot、Revision Gap 与 Quarantine 统一属于 operations_runtime;Gateway、Asset、Metering 与 Settlement 尚无对应领域事实时只显示“未接入/未知”,不能从 Observation、Logs、Trace 或相邻时间推断。

统一错误模型

错误不能只保存 status + message。每个 ErrorOccurrence 包含下列公共字段:

errorId
occurredAt? / sourceClaimedObservedAt? / acceptedAt? / derivedAt?
source / evidenceKind
layer / phase
normalizedCode / severity
certainty
retryDisposition
compensationDisposition
messageTemplateKey / sanitizedParameters
causeErrorId?
requestId? / traceId? / correlationId? / operationId?
runId? / runStepId? / executionAttemptId?
gatewayPool? / gatewayDeploymentId?
gatewayInvocationId? / gatewayTaskId?(严格互斥)
attemptRouteBindingRef? / attemptRouteBindingSchemaVersion?
attemptRouteBindingDigestAlgorithmVersion? / attemptRouteBindingDigest?
gatewayRouteSnapshotRef? / gatewayRouteSnapshotSchemaVersion?
gatewayRouteSnapshotDigestAlgorithmVersion? / gatewayRouteSnapshotDigest?
logicalModelId? / modelDeploymentId? / configRevision?
assetVersionId? / reservationId? / meterEventId?

未认证、准入前或尚未接入下游的错误必须让未知关联字段保持缺失;不能为了满足 Schema 伪造 Tenant、Operation、Run、Gateway、Model、Asset 或 Billing 引用。

evidenceKind 是严格判别项。只有 operational_observation 且来源为同一条 Core Accepted Error Observation 时,才必须携带 observationId + acceptedAt + source.service + surface + errorNormalizationPolicyVersion + errorFingerprintVersion + errorFingerprintsource.service 是该分支唯一规范服务字段,不另设顶层 servicedomain_fact | operations_runtime | telemetry_reference | derived_summary 禁止出现三个 Fingerprint/Policy 字段,也不进入 v1 Fingerprint Group。不能把五类 Evidence 的公共展示 DTO 误当成同一套指纹输入。

operational_observation 的 Gateway执行字段只能从同一条已接受 ErrorOccurrence@1.gatewayExecution展平,不能从同 Run、相近时间或相邻 GatewayDiagnostic补入。存在该分支时,runId + runStepId + executionAttemptId + gatewayPool + gatewayDeploymentId + AttemptRouteBinding完整四元组 + GatewayRouteSnapshot完整四元组与一个且仅一个 Invocation/Task Anchor必须完整并已被 Core验证;任一四元组半缺、未知算法、同 Ref/Schema异 Digest或错配都进入隔离,不进入普通 Error DTO。规范 Pool字段只有 gatewayPool=text|media,不接受 gatewayPoolId

时间字段按 evidenceKind 条件约束:domain_factoperations_runtime 使用各自 Owner 写入的 occurredAtoperational_observation 必须使用 Core Intake 注入的 acceptedAt 并只把可选 sourceClaimedObservedAt 当作来源声明,telemetry_referencederived_summaryderivedAt 只表示引用或摘要的生成时间。四者不得互相回填。Observation 的列表顺序、首次/最近时间、accepted health window、Retention 和 Freshness 一律从 acceptedAt 计算;claimed time 只进入 Timeline 展示。完整矩阵见可观测性与错误链

错误展示只允许 Contracts 注册的模板 Key 和逐字段白名单、限长、按输出上下文编码的参数;任意“已脱敏”自由文本不能进入普通 Error、日志或页面。Accepted Error Observation 的 Fingerprint 只能由 Core Operations Projector 按 Contracts 的版本化 canonicalization 与固定测试向量计算,Producer 值不被接受;其他 Evidence Kind 不计算 v1 Fingerprint。backendModelId、Provider Model/Credential、Supply/Channel 和 Provider Attempt 详情只允许通过 Case/JIT 受控证据引用查看,不进入普通 Error 或 Operations DTO。原始技术细节只保存 Case-scoped Reference。

错误层级

稳定层级至少覆盖:

edge
identity_policy
billing_preflight
execution
gateway_dispatch
gateway_protocol
provider
poll_reconciliation
result_fetch
media_validation
asset_persistence
billing_settlement
customer_webhook
mcp
internal_worker

未来启用 Provider Callback 后,可以增加 provider_callback,但不能提前把它写成当前主链路能力。

提交确定性

certainty 是判断能否重试的关键字段:

rejected_before_dispatch
not_submitted
submitted
provider_accepted
unknown
  • rejected_before_dispatch/not_submitted 可以依据同一 Operation 的安全语义恢复。
  • submitted/provider_accepted 只能继续查询、取回结果或等待终态。
  • unknown 必须进入 Reconciliation,禁止自动换 Gateway、Supply 或 Provider 重发。
  • 用户主动“再次生成”创建新的业务 Attempt,不能覆盖旧错误或复用旧经济身份。

错误内容分层

内容面向对象规则
customerMessage用户与开发者安全、可执行,不暴露 Provider、渠道、堆栈和内部策略
operatorSummary获得对应权限的运维人员脱敏阶段、确定性、影响和建议动作
technicalDetailRef获得临时调试授权的人员指向受限原始证据,不复制进普通页面和 Incident 备注

Error Fingerprint v1 只能由 Core Operations Projector 使用同一条 Accepted Error Observation 的 errorFingerprintVersion + errorNormalizationPolicyVersion + source.service + surface + layer + phase + normalizedCode 七项计算;UTF-8 NFC、RFC 8785、SHA-256 与固定向量以事件契约为唯一来源。不能从相邻记录补入 Pool、Deployment、Provider、模型或函数位置。完整错误正文、Request/Tenant/User ID、Prompt 或 Provider 动态任务号不能参与指纹。

Error、Alert 与 Incident 的关系

Error Occurrence
→ Error Fingerprint Group
→ SLO / Rule Evaluation
→ Alert Instance
→ Incident(存在实际或高风险客户影响时)
→ Mitigation / Recovery
→ Reconciliation Cases
→ Postmortem / Follow-up
  • 一次错误不必产生告警。
  • 相同 Fingerprint 的错误按受影响产品、Pool、Deployment、组织数和时间窗聚合。
  • Alert 是需要值班确认的信号,不等于已经发生客户事故。
  • Incident 是有人负责、需要协同处置和沟通的影响事件。
  • Incident 关闭前必须扫描受影响的 Run、Asset、Reservation 和 Webhook,不能只看成功率恢复。

Logs、Metrics、Trace、业务事实与 Audit

数据面主要用途是否权威事实关键限制
Logs单服务诊断与上下文结构化、脱敏、可按保留策略清理
Trace跨服务调用关系、阶段和延迟可以采样;异步边界使用 Span Link
Metrics趋势、SLO、容量和告警标签保持低基数,不放用户或请求 ID
Run/Gateway/Asset/Billing Fact任务、资产和经济状态由各领域唯一写入并按状态机演进
Audit Event谁以什么权限执行了什么是,治理证据追加写入,普通管理员不可修改或删除
Incident / Reconciliation Timeline运维判断与处置证据是,运维治理证据追加事件修正旧结论,不覆盖历史

结构化日志

普通日志使用结构化字段,至少包含服务、环境、版本、时间、严重度、规范化错误码和可用的 Trace/Correlation 引用。不得记录:

  • Prompt、System Prompt、内部规划和完整模型输出;
  • 图片、视频、音频、Base64 和文档正文;
  • API Key、Cookie、Session、Authorization Header;
  • Provider Credential、Callback Secret、支付凭据;
  • 长效或短期签名 URL;
  • 未脱敏的 Provider 错误页和完整 Callback Payload;
  • 不必要的用户邮箱、手机号或支付信息。

Telemetry 写入失败不能阻塞正常模型调用。确需保存原始 Provider 证据时,只能进入加密、限时、Case-scoped 的受限存储,并在普通日志中保存不可逆 Digest 和受控引用。

Trace

建议的 Span 语义:

http.request
identity.authorize
billing.quote
billing.reserve
run.step
gateway.dispatch
gateway.accept
provider.submit
provider.poll
result.fetch
asset.persist
billing.settle / release / reconcile
customer_webhook.deliver

Trace 采样不能让经济事实丢失。Reservation、Usage、Ledger、未知提交、人工处置和特权动作无论是否采样,都必须进入自己的领域事实或 Audit。

Metrics 与 SLO

Metrics 标签只使用低基数维度,例如 service、region、surface、capability、pool、deployment、model family、provider、status 和 normalized error code。禁止把 userIdtenantIdrequestIdtraceIdrunIdupstreamTaskId 放进标签。

首轮指标至少覆盖:

  • 请求量、成功率和延迟;
  • Text Pool 与 Media Pool 独立健康;
  • Provider 429、5xx、超时和未知提交;
  • 排队时长、任务停留、Worker Lease 与恢复;
  • Provider 成功但结果未取回、Asset 校验与落盘失败;
  • 未终态 Reservation 数量、金额和停留时长;
  • reconciliation_required 数量、金额与最旧案件;
  • Gateway Provider Evidence、Metering 规范 MeterEvent / ProviderCostFact 与 OceanWay Settlement 差异;
  • Webhook 延迟、失败和重放;
  • Telemetry、Outbox 与 Read Model 的摄取缺口。

SLO、告警阈值、容量和保留期来自客户合同、Provider 公开约束、容量测试和管理员配置。架构文档不写无依据的固定次数、延时或百分比。

运行指挥台

后台首页同时回答“现在是否异常、影响谁、从哪里开始处理”:

  • OceanWay Edge、Identity、Billing、Execution、Asset 和 MCP 状态;
  • Text Pool、Media Pool、每个 Gateway Deployment 和 Provider 的独立状态;
  • 队列、Worker、Lease、未知提交、结果落盘和对账积压;
  • 当前 SLO Burn、Open Alerts、Open Incidents;
  • 受影响 Surface、Offering、Organization 数量和预计经济影响;
  • 最近 Deployment、模型、路由、价格和 Secret 变更;
  • Telemetry 与读模型自身的新鲜度。

一个 Provider 异常不能让首页把整个 OceanWay 显示为“全部不可用”。平台健康、产品健康、Pool 健康和单一 Deployment 健康必须分层展示。

全局检索与 Run Explorer

本节说明目标范围;当前 Outbox 纵切只实现 Public API 准入的 Operation、Run、Reservation 与 Event,并严格停在 reserved。页面级查询、权限、完整性和空状态见 Run Explorer

全局检索支持精确输入:

  • 用户公开账号 ID、受限邮箱或企业名称;
  • Public Request ID、Trace ID、Correlation/Operation ID;
  • Run、RunStep、Execution Attempt;
  • Gateway Execution Anchor(Text Invocation 或 Media Task)、Provider Attempt 或上游任务 ID;
  • Asset、AssetVersion、Storage Key;
  • Reservation、Meter Event、Ledger Entry;
  • Alert、Incident、Reconciliation Case。

模糊搜索只能返回获得权限的脱敏摘要;内部 UUID 不得作为用户信息缺失时的回退展示。上游任务 ID、Storage Key 和财务 ID 的查询需要对应职责,不能因为能搜索 Run 就自动扩展权限。

Run Explorer 详情页至少包括:

  1. 请求摘要、客户影响和当前可信状态;
  2. 身份、组织、Workspace、Project 与付款方;
  3. Quote、Reservation 和预算判断;
  4. Run、Step、Attempt 与 Execution Manifest Revision;
  5. Pool、Gateway Deployment、模型和配置版本;
  6. Provider Attempt、Poll/Observation 与提交确定性;
  7. Result Fetch、媒体校验、AssetVersion 和产品 Binding;
  8. Usage、Settlement、Release、Refund 与 Margin Fact;
  9. 规范化错误、关联 Logs/Trace、Alert 和 Incident;
  10. 人工命令、审批与 Audit Timeline。

原始 Prompt、参考素材和生成结果默认不展示。需要内容诊断时,必须从具体 Incident 或 Reconciliation Case 申请临时只读访问。

Error Center

Error Occurrence、Fingerprint、evidenceKind 证据边界、确定性与分阶段门禁见 Error Center。本能力是 Run Explorer 之后的目标阶段,不能写成当前已实现。

Error Center 按 Fingerprint 聚合并展示:

  • 首次与最近发生时间、趋势和代表性脱敏 Trace;
  • 影响的产品、Surface、Pool、Deployment、模型、Provider 和配置版本;
  • 影响的用户、Organization、Run、Asset 和金额摘要;
  • 提交确定性、可重试性和待补偿类型;
  • 与最近发布、路由或 Secret 变更的时间相关性;
  • 是否已有 Alert、Incident、Runbook 或已知问题;
  • 当前 Owner 和下一步动作。

页面只能表达“相关”,不能因为错误恰好出现在发布之后,就自动宣称该发布是根因。

Gateway 与执行运行中心

Text Pool 与 Media Pool 使用同一导航层级,但保留不同运行语义:

视图Text Gateway PoolMedia Gateway Pool
主要对象Invocation、Channel、Stream、Token UsageTask、Provider Attempt、Poll/Reconcile、Result
健康维度协议、首 Token、断流、429/5xx、Token 计量提交确定性、队列、停留、轮询、结果取回和落盘
路由详情UUMI/new-api Deployment 与 Channel 摘要Media Gateway Deployment、Supply 与 Adapter 摘要
不可见内容Provider Credential、客户 PromptCredential Version 明文、Provider 原始 Payload、客户媒体

Text Gateway 如果尚不能提供可信 Provider Attempt,只显示 Gateway Invocation 和“Provider 未观测”,不能由中央控制面读取 new-api 数据库后猜测。Media Gateway 通过自己的 Task/Attempt Registry 输出规范化 Observation;中央读模型只保存必要摘要和不透明引用。

Alert 与 Incident 中心

Incident 的追加式时间线、关闭条件以及与对账案件的边界见 Incident 与 Reconciliation

Alert 生命周期建议保持简单:

open → acknowledged → mitigating / silenced → resolved

Silence 必须绑定 Owner、原因、范围和有效期;Maintenance Window 与异常静默分开。通知失败本身可观测,告警正文不得包含 Prompt、用户邮箱、Secret 或签名 URL。

Incident 至少记录:

incidentId / severity / status
commander / participants / owners
detectedAt / startedAt / mitigatedAt / resolvedAt
affectedProducts / surfaces / pools / deployments / offerings
affectedOrganizations / runs / assets / billing exposure summary
linkedAlerts / errorGroups / traces / changes / cases
timeline / decisions / mitigations / validation
customerCommunicationStatus
rootCause / followUps / postmortemStatus

Incident Timeline 追加写入;后续修正通过新事件补充,不覆盖旧判断。一次标准处置流程是:

Signal
→ Triage
→ Incident
→ Impact Analysis
→ Minimal Mitigation
→ Metrics Recovery Validation
→ Run / Asset / Billing Scan
→ Reconciliation
→ Customer Communication
→ Postmortem / Follow-up

Reconciliation 工作台

Reconciliation 工作台可以汇总执行、资产、Usage 与账务核对信号,但“需要核对”不等于“已经创建正式 Case”。以下异常首先属于 Owner 本地状态、Blocked Work、Error/Alert 或 Incident:

  • 无法确认 Provider 是否创建任务;
  • Provider 成功但 OceanWay 没有取得结果;
  • 结果已落盘但 AssetVersion 或 Run 未完成;
  • Run 已完成但 Reservation 未结算或未释放;
  • Usage 缺失、超出预占或与 Provider 账单不一致;
  • Poll 与未来 Callback 报告冲突终态;
  • 重复 Provider Attempt、重复资产或疑似重复结算;
  • 用户已退款但 Provider 成本已经发生;
  • 客户 Webhook 未送达,但业务与账务已经终态。

首期 Operations Reconciliation Case 只接受严格 sourceScope 联合:late_settlement_dimensionbilling_finalization_run。前者由 Billing 的正差额 Exposure 请求打开,后者由 Billing Finalization Decision 请求打开。Provider、Gateway、Execution、Asset、Webhook 或普通客户计量异常没有 Canonical Case Event/Mandatory Delivery/Owner Read/终态 Authority 时,只能显示为明确标注不完整的诊断信号,禁止伪造第三种 Case。

案件状态:

open
investigating
awaiting_external_evidence
resolution_proposed
approval_required
resolving
resolved
rejected

resolved | rejected 是 Case 状态集合中的终态。维度级 late_settlement_dimension 只能由 BillingCaseResolutionApplied@1 驱动终态,Run 级 billing_finalization_run 只能由 FinalizationReconciliationResolutionApplied@1 驱动终态。两种来源在对应 Fact 到达前,Operations/Admin 都只允许停留在调查、补证、提案、审批或 resolving,不得本地写入 resolved | rejected | no_action。当前没有“平台承担/供应损失/核销”的 Billing Disposition 契约,因此也不能让 Operations 与账本各自决定终态。

当前 Case-scoped 领域命令只有两类:

  • late_settlement_dimension,基于 Current Exposure、Funding Decision、审批/JIT 和一次性 Grant 执行已注册的 Late Settlement Command;
  • billing_finalization_run,基于 Current Case/Decision、调查引用与一次性 Grant 请求 Billing 重新读取 Owner 状态并重评,不能覆盖任何 Owner Fact。

查询原任务、结果恢复、投影重建或 Webhook 重放可在未来作为独立 Incident-scoped Domain Command 进入,但不能复用 Billing Case Scope 或当前 Grant Specialization。每类新增命令必须先发布自己的 Target Owner、Expected Revision、幂等 Result 和 Audit 契约。

禁止直接编辑 Gateway Execution Anchor(Text Invocation 或 Media Task)状态、AssetVersion、Reservation 或 Ledger 行。账务修复只追加分录,未知提交不通过“重试看看”解决。

两种 Billing Case 的状态机测试必须分别覆盖本地终态命令与新 Exposure/Watermark、Billing Applied Fact 的并发:本地 resolved/rejected/no-action 命令始终 fail closed,只有完整验证的来源专属 Owner Applied Fact 可以收敛终态;Applied 与 Case Request/Create 乱序也不得产生第二 Owner、错关另一代 Case 或把已解决 Case 恢复为 Open。

Admin Command Gateway

所有带写效果的运维动作通过 Admin Command Gateway。授权边界冻结以下两个严格契约;@1 内禁止增删字段、改变类型或改变摘要语义,任何演进必须发布新的 @N+1 Schema,并让未知版本 fail closed。

ImpactPreview@1 {
  schemaVersion: "ImpactPreview@1"
  adminCommandId: string
  commandType: registered command enum
  target: { targetType: registered target enum, targetId: string, expectedRevision: string }
  caseScope:
    | { kind: "incident", incidentId: string, expectedIncidentRevision: string }
    | { kind: "reconciliation", reconciliationCaseId: string, expectedCaseRevision: string }
    | { kind: "none" }
  requestedScope: registered scope enum[]
  policyRevisionId: string
  sourceFacts: StrictPreviewSourceFact@1[]
  affectedResources: StrictAffectedResource@1[]
  predictedEffects: StrictPredictedEffect@1[]
  riskLevel: "low" | "medium" | "high" | "critical"
  approvalRequirement:
    | { kind: "not_required", approvalPolicyRevisionId: string }
    | { kind: "required", approvalPolicyRevisionId: string, requirementSetDigest: Sha256Hex }
  evaluatedAt: RFC3339 UTC timestamp
  digestAlgorithmVersion: "jcs-sha256-v1"
  impactPreviewDigest: Sha256Hex
}

AdminCommandCandidate@1 {
  adminCommandCandidateRef: string
  schemaVersion: "AdminCommandCandidate@1"
  adminCommandId: string
  commandType: registered command enum
  actorWorkforcePrincipalId: string
  boundWorkload: registered workload identity
  target: { targetType: registered target enum, targetId: string, expectedRevision: string }
  caseScope: ImpactPreview@1.caseScope
  requestedScope: registered scope enum[]
  reasonCode: registered reason enum
  reason: non-empty string
  idempotencyKey: string
  commandRequest: {
    ref: string
    schemaVersion: registered command request schema version
    payload: strict discriminated command payload
    digestAlgorithmVersion: "jcs-sha256-v1"
    commandRequestDigest: Sha256Hex
  }
  impactPreview: {
    schemaVersion: "ImpactPreview@1"
    previewRef: string
    digestAlgorithmVersion: "jcs-sha256-v1"
    impactPreviewDigest: Sha256Hex
  }
  approval:
    | { kind: "not_required", approvalPolicyRevisionId: string, requirementSetDigest: Sha256Hex }
    | {
        kind: "required"
        approvalPolicyRevisionId: string
        requirementSetDigest: Sha256Hex
        approvalDecisionRef: string
        approvalDecisionSchemaVersion: string
        expectedApprovalRevision: string
        records: StrictApprovalRecord@1[]
        approvalSetDigestAlgorithmVersion: "jcs-sha256-v1"
        approvalSetDigest: Sha256Hex
      }
  jitAuthorization:
    | { kind: "not_required", jitPolicyRevisionId: string }
    | {
        kind: "required"
        jitGrantRef: string
        jitGrantSchemaVersion: string
        expectedJitGrantRevision: string
        jitScopeDigestAlgorithmVersion: "jcs-sha256-v1"
        jitScopeDigest: Sha256Hex
      }
  candidateDigestAlgorithmVersion: "jcs-sha256-v1"
  adminCommandCandidateDigest: Sha256Hex
}

SignedWorkforceCommandExecutionGrant@1 {
  commandGrantRef / commandGrantSchemaVersion
  commandGrantDigestAlgorithmVersion = "jcs-sha256-v1"
  commandGrantDigest
  iss / aud / sub / boundWorkload / jti / iat / nbf / exp
  adminCommandId / commandType
  targetType / targetId / expectedTargetRevision
  caseScope  # 含 Expected Revision 的严格联合
  approval =
    { kind=not_required; approvalPolicyRevisionId; requirementSetDigest }
    | { kind=required; approvalPolicyRevisionId; requirementSetDigest;
        approvalDecisionRef / approvalDecisionSchemaVersion / expectedApprovalRevision;
        approvalSetDigestAlgorithmVersion / approvalSetDigest }
  jitAuthorization  # 与 Candidate 的严格联合逐项相等
  previewSchemaVersion / previewDigestAlgorithmVersion / impactPreviewDigest
  requestRef / requestSchemaVersion / requestDigestAlgorithmVersion / commandRequestDigest
  candidateRef / candidateSchemaVersion / candidateDigestAlgorithmVersion / commandDigest
  commandSpecialization =
    { kind=none }
    | { kind=late_settlement;
        reconciliationCaseRef; expectedCaseRevision; caseGeneration;
        reconciliationCaseIdentityReservationRef / reconciliationCaseIdentityReservationSchemaVersion;
        reconciliationCaseIdentityReservationDigestAlgorithmVersion / reconciliationCaseIdentityReservationDigest;
        lateSettlementExposureRef / lateSettlementExposureSchemaVersion;
        lateSettlementExposureDigestAlgorithmVersion / lateSettlementExposureDigest / exposureRevision;
        fundingDecisionRef / fundingDecisionSchemaVersion;
        fundingDecisionDigestAlgorithmVersion / fundingDecisionDigest / fundingDecisionJti;
        fundingPolicyRevisionId; positiveDeltaDecimal;
        settlementEconomicIdentity =
          { kind=credits }
          | { kind=entitlement; entitlementKey; unit }
          | { kind=money; currency } }
    | { kind=finalization_reconciliation_resolution;
        resolutionOperationId;
        tenantKind / tenantId / workspaceId / projectId?;
        billingAccountId / billingReservationId / runId / billingFinalizationFenceId;
        reconciliationCaseRef / reconciliationGeneration;
        expectedCaseRevision / expectedResolutionRevision=1;
        finalizationCaseIdentityReservationRef / finalizationCaseIdentityReservationSchemaVersion;
        finalizationCaseIdentityReservationDigestAlgorithmVersion / finalizationCaseIdentityReservationDigest;
        caseRequestEventId / caseRequestEventType / caseRequestEventSchemaVersion;
        caseRequestEventEnvelopeDigestAlgorithmVersion / caseRequestEventEnvelopeSha256;
        finalizationReconciliationResolutionCommandRequestRef / finalizationReconciliationResolutionCommandRequestSchemaVersion;
        finalizationReconciliationResolutionCommandRequestDigestAlgorithmVersion / finalizationReconciliationResolutionCommandRequestDigest;
        resolutionDecisionRef / resolutionDecisionSchemaVersion;
        resolutionDecisionDigestAlgorithmVersion / resolutionDecisionDigest;
        action=reevaluate_current_owner_state;
        investigationEvidenceReferenceCount;
        investigationEvidenceReferences[] }
  authorizationLinearizedAt
}

StrictPreviewSourceFact@1StrictAffectedResource@1StrictPredictedEffect@1StrictApprovalRecord@1 和每个命令的 Payload 都必须是 Contracts 仓库注册的封闭判别联合:拒绝未知字段、未知枚举和未注册子类型,不能用开放 map<string, any> 承载授权语义。caseScopeapprovaljitAuthorization 必须分别精确命中一个分支,缺失值与 null 不等价,解析时不得静默补默认值。Required Approval 使用一个不可变 Aggregate Approval Decision 收敛多条按序 Record;Decision Ref/Schema/Expected Revision、Records 和 Approval Set Digest 必须互相验证,不能让领域命令从 Record 中自行挑选“足够的批准”。

摘要算法统一为 jcs-sha256-v1:输入必须是严格 Schema 校验后的 UTF-8 JSON;拒绝重复 Key、无效 Unicode,以及任何 Key/字符串不是 NFC 或 NFC 归一化后发生 Key 冲突的输入,摘要路径不得静默改写文本;集合数组先拒绝重复元素,再按 Contracts 规定的稳定排序键排序,之后执行 RFC 8785 JCS,最后对 canonical bytes 计算 SHA-256,输出小写 64 位十六进制。requestedScope 按枚举值排序;Source/Resource/Effect 分别按 Contracts 注册的复合键排序;Approval Record 按 approvalRequirementId + approverWorkforcePrincipalId + decisionRevision 排序。JCS 只规范对象 Key、不重排数组,因此任何未注册数组顺序都必须拒绝。Contracts 仓库必须发布原始 JSON、canonical bytes 和摘要的 Golden Vector,Gateway、Core 与所有 Domain 实现共用并通过同一组向量。

摘要字段集不可由实现自行选择:impactPreviewDigest = SHA256(JCS(ImpactPreview@1 去除Repository-owned Ref/Time与摘要自身))commandRequestDigest = SHA256(JCS(commandRequest 去除Repository-owned Ref/Time与摘要自身))approvalSetDigest = SHA256(JCS(approval.records))adminCommandCandidateDigest = SHA256(JCS(AdminCommandCandidate@1 去除Repository-owned Ref/Time与摘要自身))adminCommandCandidateDigest 就是授权协议中的唯一完整 commandDigest,两者必须逐字节相等。因此 Command Digest 覆盖 Actor、Workload、Command、Target/Revision、Case/Revision、Scope、Reason、Idempotency Key、Request完整四元组、Preview Digest、Aggregate Approval/Set 与 JIT 联合;只签若干散列字段或动态挑选字段不是合法实现。

SignedWorkforceCommandExecutionGrant@1 是 Core Authorization 签发、只允许目标 Domain 消费一次的执行凭证,不是需要在 Domain 提交前再次远程查询的普通 Session。除标准主体与时间声明外,它完整绑定 Workload、Command、Target/Revision、Case/Revision、Approval Decision/Set、JIT、Preview、Request 与 Candidate Digest;sub 唯一表示 actorWorkforcePrincipalIdcommandDigest 必须逐字节等于 adminCommandCandidateDigestcommandSpecializationcommandType 是双向 Refinement:Late Settlement Command 必须且只能使用 late_settlement,逐项回显 Case/Generation/Identity、Current Exposure、Funding Decision/Policy、正差额和严格经济身份;Finalization 重评命令必须且只能使用 finalization_reconciliation_resolution,逐项回显 Run/Fence、Case/Generation/Revisions、Identity、Case Request Event、Request、Resolution Decision、唯一 Action 与调查引用集合,并绑定由完整 Decision 四元组确定性派生的 resolutionOperationId;其余注册命令才使用 none。这些字段必须与严格 Request、caseScope、Operations Identity Reservation、Candidate、Decision 和 Billing 当前 Case Link 逐项相等。Specialization 不替代完整 Request/Candidate Digest,而是让 Billing 显式拒绝跨 Case 代际、Bucket/Currency、Fence、Decision 或 Evidence 集合的 Grant 重放。Grant 只能绑定最终 Candidate;Preview、Approval、JIT、Case Revision/Generation/Reservation、Funding/Exposure、Finalization Decision 或 Request 任一变化都必须生成新 Candidate 并重新换取 Grant。Grant Ref/Schema/Digest 与 JTI 成组持久化,未知 Schema/Algorithm、缺 Claims、宽泛 Audience、分支混合或 Bearer 式转用必须拒绝。

命令执行流程:

  1. Admin Command BFF 在本地重新验证 Workforce Session、职责权限与 JIT/Case 状态;
  2. 先固定命令专属严格Request业务Payload及完整四元组;跨域Request只使用注册reasonCode,不携带自由理由;
  3. 读取目标当前Revision和影响事实,以该Request为输入生成并持久化不可变ImpactPreview@1。危险动作等待职责分离审批并冻结Approval Set/JIT;最后才由Request、Preview、Approval/JIT与Actor/Workload等全部输入生成唯一AdminCommandCandidate@1完整四元组与Digest,不得在Candidate后回填或替换Request;
  4. Admin Command BFF 以自身短期 Workload JWT,加 Workforce IdP/Identity Authorization 唯一签发或交换的防重放 Actor Assertion,调用精确 Audience 的 Command Grant Exchange。Assertion 至少绑定 iss/aud/subauth_timeacr/amr、Session/Authn Version、boundWorkload、包含完整 Candidate 四元组与 Digest 的 Command Exchange Request Digest/Nonce、jtiiat/nbf/exp;不能复用 Query/Admin Audience Token,也不能由 BFF 自报、签发或转签 Actor。CommandGrantExchangeResult@1.actorAssertionIssuer + actorAssertionJti分别逐字节等于已验证Assertion的iss + jticommandGrantExchangeOperationId 由 Contracts 固定 Namespace 仅按这两个Result字段确定性派生;Candidate 不进入 Operation ID,而作为必须 insert-or-compare 的正文,从而让同 JTI 偷换 Candidate 明确成为冲突;
  5. Core Authorization 先认证当前 BFF Workload、验证 Assertion 签名/Issuer/Audience 与 boundWorkload,再按 commandGrantExchangeOperationId 读取不可变 Grant Issuance Result。found 且 Assertion 身份、Workload、Request Digest/Nonce、Candidate 完整四元组及 Digest 全等时返回首次 Grant,即使 Assertion 已过期或 JTI 已消费;同 Operation 绑定任何不同正文时返回 conflicting。只有 not_found 才执行当前时间、Session、Approval/JIT/Case 与 JTI 未消费校验,严格解析 Candidate并重算 Preview、Approval、JIT、Request/Candidate Digest;随后在同一 Core 事务一次性消费 Assertion JTI、持久化 Grant Issuance Result 与 SignedWorkforceCommandExecutionGrant@1 完整四元组、追加签发 Audit,再返回 Grant。任一步失败都不返回 Grant;唯一约束竞争后必须回到首次 Result 读取分支。该提交时刻是外部 Approval/JIT/Case 授权的线性化边界。Workforce Cookie/Session 只留在 Admin Host,Assertion 与 Grant 都不能进入浏览器;
  6. Admin Command Gateway 在调用领域命令前耐久追加 command.authorized,事件必须携带 Grant JTI、完整 Candidate Digest 和各子摘要;若授权 Audit 失败则不调用 Domain;
  7. Admin Command Gateway 以独立 Workload JWT、Execution Grant、完整 Candidate、所引用的 Preview/Approval/JIT、原始严格 Request 和幂等键调用唯一拥有数据的 Domain Command Service;任何请求字段都不能覆盖 Candidate;
  8. Domain Service先认证当前调用 Workload并确认等于 Grant.boundWorkload,强制 Candidate.actorWorkforcePrincipalId == Grant.sub,严格解码全部输入、验证 Grant签名完整性/Issuer/Audience/Ref/Schema/Digest并重算 Candidate,然后按 Contracts由 commandType + commandRequestSchemaVersion + domainIdempotencyKey推导稳定 domainCommandResultKey。它必须在检查 Grant当前时间窗、JTI未消费或 Target当前 Revision之前查询已提交 Result;若同 Key的 Result完整绑定同一 Candidate/Grant/JTI则直接返回首次结果,即使响应丢失后 Grant已过期,若 Key绑定不同候选则冲突;
  9. 只有 Result不存在时,Domain Service才检查 Grant当前时间窗、JTI未消费,并逐项比对 Grant内 Actor、Command、Target Type/ID/Expected Revision、Case/Revision、Approval Decision/Policy/Requirement/Set、JIT联合、各子摘要与完整 Candidate Digest;随后只在自己的 Repository中锁定并重验它所拥有的 Target Revision、Case(若该 Case归本 Domain)、Funding/Quota和业务不变量。不得在本地事务前后远程回查 Core Approval/JIT Current状态并假装原子。Core Grant签发边界后的撤销不追溯取消这个已授权动作,签发前撤销必须阻止 Grant;需要对已签发动作硬停止时,必须新增由目标 Domain所有、可在同一事务消费的版本化 Revocation Fence;
  10. 通过全部新执行校验后,Domain Service在一个领域事务内以 Result Key与 Grant JTI唯一约束原子写入 CommandGrantConsumption、业务事实、命令结果事实和 Audit Outbox;任一必需写入失败则整体回滚。唯一约束竞争失败后重新读取 Result并完整比较,不能重新按当前时间窗把已经提交的成功改成失败。后续失败和完成通过追加事实/Audit表达,再通过正常查询路径验证结果,不把前端成功提示当作完成证据。

所有拒绝路径均 fail closed:Grant Exchange 失败追加 command.authorization_rejected;Domain 校验失败通过自身 Audit Outbox 追加 command.rejected,且不得产生业务事实;授权后执行失败追加 command.failed。若拒绝 Audit/Outbox 本身无法耐久写入,只能返回不含敏感细节的失败并保持零业务副作用,不能降级为执行后补记。Audit 事件记录 Actor、Workload、Grant JTI、Candidate Digest、各子摘要、失败阶段和稳定 Failure Code,不复制密钥、Cookie、Assertion 或完整敏感 Payload。

Command Grant Exchange 与 Domain契约测试必须至少覆盖:错误 Audience/Workload、过期或撤销 Session、签发前 Approval/JIT/Case撤销、签发后撤销不追溯、Assertion JTI同 Candidate重放与异 Candidate冲突、Core 已提交 Grant Issuance/签发 Audit 但 HTTP 响应丢失,重试跨过 Assertion 到期仍返回同一 Grant、Grant JTI同 Candidate响应丢失重放与异 Candidate偷换、有效期内 Domain 提交成功后响应丢失并跨过 Grant到期重放、Exchange/Result Key唯一竞争、并发双消费、Grant.sub与 Candidate Actor不同、Target Type/ID或 Expected Revision被替换、Case/Revision被删除/切换/关闭、审批记录增删或 Aggregate Decision Revision变化、JIT联合变化、Preview内容/Schema/Policy/Source与摘要不符、Request Payload/Schema与摘要不符、Candidate任一字段与完整摘要不符、Late Settlement Specialization缺失/混合或 Case Ref/Expected Revision/Generation/Identity Reservation/Exposure/Funding Policy/金额/Credits/Entitlement Key/Unit/Currency任一错配、Finalization Resolution Specialization 缺失/混合或 Fence/Case/Generation/Revisions/Identity/Event/Request/Decision/Operation/Action/Evidence 任一错配、未知摘要算法、重复 Key、未知字段、null冒充缺失值、非 NFC/归一化冲突、数组顺序未规范化,以及授权 Audit、Consumption、业务写入或 Domain Audit Outbox失败。每个用例都必须断言至多一个业务效果并存在相应 Audit;Query Grant与 Command Execution Grant使用不同 Audience、Scope、Workload Credential和 JTI消费域,不能相互替代。

控制面不得提供任意 SQL、任意 Provider 请求、任意文件删除或通用“强制成功”按钮。健康检查也不能偷偷发起付费模型调用;需要合成探测时,必须有独立预算、模型、环境和可识别的 Probe Principal。

敏感调试访问

普通运维默认不读取客户 Prompt、原始媒体和完整输出。确需内容诊断时创建 SensitiveDebugGrant

grantId
iss / aud / sub / boundWorkload / jti
baseQueryGrantId / baseQueryGrantJti
requester / approver
incidentId 或 reconciliationCaseId
tenantKind / tenantId / workspaceId / resourceIds[]
allowedFields / purpose
sessionVersion / policyRevision / mfaAssurance
issuedAt / notBefore / expiresAt / revokedAt?

规则:只有 Core Authorization/Policy 模块可以签发 Grant;Admin BFF、IdP 与人工配置不能自行生成。SensitiveDebugGrant.jti 必须是独立唯一值,不得复用父 Query Grant JTI;它通过 baseQueryGrantId + baseQueryGrantJti 建立可撤销父链,并要求 Issuer/Audience、Workload Binding、Session/Policy/MFA 与时间约束兼容。实际权限取当前父 Grant、活跃 Case 和已完成审批的交集;父子任一撤销/过期即失效,相同 JTI、错误父链或 Workload 错配都 fail closed。它不是可转移 Bearer,浏览器不能取得。每次内容释放仍执行 query.authorized → query.released | query.not_found | query.inconclusive | query.failed 两阶段 Audit fail-closed,任一必需 Audit 追加失败都不返回数据。测试覆盖 JTI 复用、错误/不存在父链、父 Grant 撤销和权限交集。Grant 必须最小只读范围、明确理由、限时、审批、不可转授并全量 Audit。内容不能复制到普通日志、Alert、Incident Note、工单标题或聊天工具。Break-glass 使用独立流程,并在事后通知、复核和撤销。

后台信息架构

现有后台继续按商业 SaaS 职责分组,不把所有新能力平铺成一条长菜单:

分组目标内容
经营分析角色化首页、经营与客户摘要、跨产品用量和支持入口
商品运营商品、套餐、促销、优惠券和邀请
财务管理订单、支付、CDK、钱包、Ledger、账务对账和财务审批
上游配置Model Offering、Text/Media Deployment、Channel/Supply、价格证据和 Agent Skills
系统管理Run Explorer、Error Center、Alert/Incident、队列/Worker、Telemetry、Audit、身份、存储和备份
内容运营作品、公告、案例和公共提示词治理

不同岗位进入同一个后台,但首页、默认页面、字段和动作不同。On-call 首先看到运行与 Incident;财务首先看到金额暴露与对账;内容运营不会因为共享后台而加载供应 Secret 或技术 Trace。

数据存储与保留

PostgreSQL 适合保存:

  • Operation 关系索引和摘要;
  • Error Occurrence 与 Fingerprint;
  • Alert Rule/Instance;
  • Incident、Timeline 与 Follow-up;
  • Reconciliation Case、Evidence Link 与 Resolution;
  • Admin Command、Approval 与 Audit;
  • Gateway 规范化 Observation 投影;
  • Outbox、Delivery/Receipt、Observation accepted source 与版本化完整性快照。

PostgreSQL 不应长期承载全量高频日志、全部 Span Payload、时序 Metrics、完整 Provider Callback、Prompt 或媒体内容。Logs、Metrics 和 Trace 通过 OpenTelemetry-compatible Collector 进入专门后端;PostgreSQL 只保存稳定对象和受控查询引用。

保留期按数据类型、环境、合同、监管和存储配置制定,不在架构中写死天数。运行时 API、Admin BFF、Worker 普通路径和人工 SQL 角色不能原地 UPDATE/DELETE Outbox Event Envelope/Payload、Delivery Attempt Start/Finish、Applied Receipt、Accepted Observation、Observation ID Registry/Purge Marker、Audit 和必要 Incident/Reconciliation 证据;Dispatcher 不直接更新 published_at,只能调用在同一 Lease-fenced 确认事务验证冻结 Destination→Consumer、Mandatory Delivery terminal 状态和匹配 Receipt 引用全集后首次置值的数据库函数。到期归档/删除只允许专用、受审计的 Retention/Archive Procedure 在满足恢复基线、Legal Hold、数据分类和 accepted health window 边界后执行,且绝不原地改写历史内容。Source Snapshot 与 Projection State Snapshot 都不能替代 Canonical Source;Outbox Event 离开热表后,完整 Envelope/Payload、Digest 与 Delivery Set Definition 必须进入 Rebuild/Verifier 每次读取的批准归档 Source View,并完成固定 Schema/运行时的隔离 Restore Drill。Active/Shadow、Delivery Ack 引用及仍有可重放 Source 的 Receipt 禁删;回滚窗、Pointer、Delivery、Quarantine 与 Legal Hold 全部解除后,只能成组清理退休版本 Receipt 与派生 Projection,不能删除归档 Canonical Event Source。Accepted Observation 的 Retention/Archive 资格和 accepted health window 边界只能依据 Core acceptedAt,不得使用 Producer 的 sourceClaimedObservedAt。Observation Payload 可按版本化 Retention Source 范围清除,但低敏 ID Registry 与已存在 Purge Marker 必须保留,或迁入 Intake 每次接受前都检查的不可变完整性归档;Retention 不得删除、重绑或绕过它们。普通 Telemetry 可以按热查询、冷归档和删除策略处理。

Projection、Timeline、Exact Identifier Index 与派生摘要继承源字段的 Lineage、Data Classification、Expiry 和 Legal Hold;源 Observation 到期删除后,所有仅由其派生的副本必须同步清除或降级,不能通过读模型绕过原始保留策略。

从现有 /admin 演进

A0:冻结边界

  • 盘点现有 Section、API、权限、人工操作和数据源。
  • 明确调用记录、运行事实、Audit 和 Ledger 的不同保留语义。
  • 冻结 admin.oceanway.tech、内部管理员与企业客户管理员边界。
  • 禁止新增通过直接改表完成的后台操作。
  • 立即对全部遗留 Mutation Route、Server Action 和直接数据库写入口执行服务端 default-deny:不打包、关闭或统一拒绝;生成明确路由清单并以 HTTP/权限负向测试证明不可达,不能只隐藏 UI。后续只有对应 Domain Command 与完整身份/授权/审计门禁验收后才能逐项加入 allowlist。

A1:建立独立 Surface

  • 将现有 OceanWay /admin UI/BFF 迁入独立 oceanway-admin 仓库并由 admin.oceanway.tech 单独发布。
  • canvas.oceanway.tech/adminai.oceanway.tech/admin 不提供内部后台。
  • 引入 Workforce Client、Host-only Session、MFA 和独立 Audience。
  • 当前 role=admin 只作为迁移映射,不作为长期授权模型。
  • 迁移 UI/BFF/Session 时持续执行 A0 的路由级 allowlist/default-deny,不得因代码搬迁恢复任何遗留写入口。只有对应 Domain Command、独立 Command Workload、定向 Grant、幂等、审批与 Audit 已验收的动作,才可在后续阶段逐项加入 allowlist。

A2:只读诊断控制台

  • 冻结 ID、Error Envelope 和 Gateway Observation Contract。
  • 将现有生成运维升级为 Run Explorer。
  • 增加全局 ID 搜索、Error Fingerprint 和 Text/Media Pool 独立状态。
  • 补齐 Audit UI,关联现有调用、资产和财务记录。
  • 继续只发布明确枚举的 Query Route;遗留钱包/支付、模型配置、人工确认、备份恢复等 Mutation Route 必须保持服务端不可达。CI 以路由清单和 HTTP 负向测试证明写入口未部署/被拒绝,不能把“页面没有按钮”当作安全门禁。

A3:Alert 与 Incident

  • 建立 SLO、Alert Rule/Instance、值班 Owner 和 Maintenance Window。
  • 建立 Incident、追加式 Timeline、影响分析和客户沟通状态。
  • 接入发布、配置、路由和 Secret 变更记录。
  • 通过 Admin Command Gateway 开放少量最小缓解动作。

A4:统一对账

  • 自动发现未知提交、结果/资产不一致、Reservation 未终态和 Usage 差异,并区分 Owner-local Conflict/Blocked、Incident Signal 与正式 Case。
  • 首期只为 late_settlement_dimension | billing_finalization_run 建立 Reconciliation Case、Evidence、Proposal、Approval 和幂等 Resolution;其他来源必须先通过独立契约准入。
  • 将现有人工补录、退款与结果恢复迁入领域命令。
  • Incident 关闭前自动生成受影响对象扫描结果。

A5:规模化运维

  • 建设完整 OpenTelemetry Pipeline 与独立 Logs/Metrics/Trace 后端。
  • 完善 On-call、SLO/Error Budget、容量、成本和多区域视图。
  • 为企业提供受限状态、审计导出和支持案件视图。
  • 根据真实容量与故障域决定是否把 Admin BFF 和 Operational Read Model 作为独立部署单元;仍留在既定 Admin/Core 仓库边界内,不新建零散 Git 仓库。

管理员平台总体验收门禁

下列清单覆盖 Run Explorer、Gateway、Asset、Billing、Incident 与写命令的完整目标,不是当前 Outbox 纵切的一次性退出门禁。当前阶段只按 ADR-030Run Explorer 验收;后续能力逐项接入后再勾选对应条目。

  • admin.oceanway.tech 不进入客户应用启动器,客户 Session 不能直接获得内部后台会话。
  • 企业客户管理员和 OceanWay Workforce 权限模型完全分离。
  • 一个 Public Request ID 可以定位到授权范围内的 Run、Gateway、Asset 和 Billing 摘要。
  • requestIdtraceIdcorrelationIdoperationId 和领域 ID 不再混用。
  • Text 与 Media Pool 独立展示健康、Deployment、任务和错误。
  • 未观测的 Provider 事实明确显示未知,不按时间或模型猜测。
  • Error 记录阶段、提交确定性、重试与补偿语义。
  • unknown 提交不能自动重试或跨网关切换。
  • Provider 成功、Asset 成功和 Billing 成功是可独立核验的事实。
  • Logs/Trace/Metrics 不作为任务或账务事实源。
  • 普通 Telemetry 不含 Prompt、Secret、签名 URL 和完整媒体。
  • Metrics 不使用用户和请求高基数标签。
  • 控制面不直连 Text/Media Gateway 数据库。
  • 所有列表按权限、状态、时间窗和分页定向查询。
  • 所有运维写操作通过 Domain Command,幂等、有理由、有 Audit。
  • ImpactPreview@1AdminCommandCandidate@1、命令 Request 和 Approval 使用严格 Schema;三类子摘要与完整 Candidate Digest 均按 jcs-sha256-v1 可跨服务复算,并通过统一 Golden Vector。
  • Command Grant 的 sub 与 Candidate Actor 相等,Grant 绑定完整 Candidate Digest;Domain 对 Actor、Target/Revision、Case、Approval、Preview、Request 和 Candidate 逐项复算校验,任何差异均 fail closed。
  • 授权、拒绝、执行失败和完成均具备耐久 Audit;command.authorized 或领域 Audit Outbox 写入失败时无 Domain 调用或业务副作用,并有负向测试证明。
  • 账务修复只追加 Ledger,不覆盖历史。
  • 内容调试访问限时、最小、只读并可审计。
  • Telemetry 或后台故障不会阻断客户正常模型调用。

不可妥协的规则

  1. 内部管理员平台和企业客户管理是两个身份与授权边界。
  2. 当前 /admin 是迁移基座,不是目标权限与运维模型的最终形态。
  3. 管理员首先通过稳定业务 ID 和事实链排障,而不是在多套日志中猜测。
  4. correlationId/operationId 连接长期业务流程,traceId 描述一次调用链;异步边界使用 Span Link。
  5. 错误必须表达发生层级、提交确定性、重试和补偿语义。
  6. Text Pool 与 Media Pool 独立观测;中央控制面不侵入其私有数据库。
  7. Logs、Metrics 和 Trace 是诊断证据,不是 Run、Asset、账本或审计事实源。
  8. 普通运维无权读取客户内容和 Secret;调试访问必须 Case-scoped、限时并审计。
  9. 运维动作只能通过幂等 Domain Command,不能直接改表、强制改状态或盲目重提。
  10. Incident 恢复后必须检查受影响的任务、资产、账务和 Webhook,不能只关闭告警。

非目标

首期不做:

  • 为了形式完整立即拆出独立 Admin、Ops、Alert、Incident 和 Trace 微服务;
  • 在 PostgreSQL 中自建全量高频日志和时序数据库;
  • 用一个“大盘正常”掩盖单个 Pool、Provider 或产品故障;
  • 让后台直接调用 Provider、读取 Gateway 数据库或编辑 Ledger 行;
  • 把完整 Prompt、媒体和 Provider 原始 Payload复制到 Incident;
  • 在没有关联、权限、审计和幂等前开放“一键修复”;
  • 允许日常使用永久全权限超级管理员。

On this page