openxiangda-skill-kit 2.0.0-alpha.32 → 2.0.0-alpha.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,40 @@
1
+ # App API 用户委托数据访问
2
+
3
+ ## 问题证据
4
+
5
+ - 平台网关已经把浏览器当前 Principal、RoleSession 和精确请求摘要签入短期 Gateway Assertion,`OpenXiangdaAuthzGuard` 也把验证后的用户上下文写入请求作用域。
6
+ - 官方采购示例的用户 App API 却注入了 `OpenXiangdaApplicationDataApiService`。该 facade 明确用于无 HTTP 请求的 Worker/Scheduler,并用 workload OAuth2 应用身份及空 RoleSession 调用 Data API。
7
+ - prod-1 preproduction 验收中,用户上传并完成的托管文件由应用身份事务绑定,平台以 `OPENXIANGDA_NATIVE_DATA_FILE_OWNERSHIP_MISMATCH` 拒绝;同一路径还会让业务数据策略从当前用户漂移到应用身份。
8
+
9
+ ## 决策
10
+
11
+ ### 能力所有者
12
+
13
+ - 平台网关和经验证的 NestJS 请求作用域是用户 App API 身份的唯一所有者。
14
+ - `OpenXiangdaDataApiService` 是用户 HTTP 请求内访问 Data API 的唯一 facade,必须原样转发 Gateway invocation authorization 和 RoleSession。
15
+ - `OpenXiangdaApplicationDataApiService` 仅属于没有用户 HTTP 上下文的 Worker、Scheduler、事件消费者和显式服务调用,继续使用平台托管 OAuth2 workload identity。
16
+
17
+ ### 稳定不变量与受影响合同
18
+
19
+ 1. 用户 App API 的 capability、数据权限、审计 actor、托管文件所有权和事务幂等主体始终是同一个已验证 RoleSession。
20
+ 2. 应用后端不得从正文、查询或自定义 header 构造用户身份;只使用全局 transport guard 写入的请求作用域。
21
+ 3. 本轮不增加委托 token、额外数据库状态或新平台接口,只修正官方模板的 facade 选择和文档。
22
+ 4. Worker/Scheduler 的 OAuth2、Native Data API 路径、稳定字段值、1.0 应用、流程和自动化合同不变。
23
+
24
+ ### 失败、并发、安全与资源边界
25
+
26
+ - 缺少 Gateway invocation 或 RoleSession 时,请求作用域 Data API fail closed;不能自动回退应用身份。
27
+ - 每个请求使用自己的 NestJS request scope,不缓存或跨请求复用用户 RoleSession;应用 OAuth token 缓存仍只属于 workload facade。
28
+ - 文件上传、完成和业务事务必须使用同一用户 RoleSession;后台任务如需处理文件,必须先以应用身份自行创建该文件,不能接管用户未绑定文件。
29
+
30
+ ### 回滚边界
31
+
32
+ - 模板和示例应用可独立回滚到上一提交;平台 API 和数据库无需回滚。
33
+ - 已发布旧 2.0 测试应用不自动改写。2.0 当前没有兼容承诺,新生成应用直接采用正确 facade。
34
+
35
+ ## 可证伪验收
36
+
37
+ 1. 模板测试断言用户 App API 注入 `OpenXiangdaDataApiService`,并拒绝重新引入 `OpenXiangdaApplicationDataApiService`。
38
+ 2. Nest SDK 的现有测试继续证明 request-scoped facade 转发 RoleSession,workload facade 使用空 RoleSession 且只在 401 后刷新一次。
39
+ 3. prod-1 真实应用完成“用户上传 → App API 事务绑定 → Data API 读取 → 受保护下载”,文件 UUID、稳定附件值和审计主体保持一致。
40
+ 4. 同一记录继续完成 Workflow prepare/start,并在部门管理员角色工作中心可见。
@@ -18,7 +18,7 @@
18
18
 
19
19
  | 能力主题 | 唯一事实来源 | 当前状态 | 已有证据 | 尚缺内容与下一道门 |
20
20
  | --- | --- | --- | --- | --- |
21
- | 按需生产环境与运行启停 | Platform Server Native 环境 registry + Environment Head + DeploymentRun;K3s 只执行平台期望状态 | 已实现待线上验收 | provision 仅创建预发、promotion 惰性创建唯一生产、`runtime_state` CAS、start/stop durable run、停止网关 503、ReplicaFailure 快速诊断、CLI/MCP/Contracts 与能力协商均已实现;平台 targeted 测试、构建、101 migration 静态校验和 47 Native migration 真实 PostgreSQL 幂等应用通过 | 完成工具链正式发包和 prod-1 migration/image 部署;以全新应用证明初始无 production、预发 stop→0/start→ready、首次 promotion 才出现 production,并停止闲置旧测试环境释放配额 |
21
+ | 按需生产环境与运行启停 | Platform Server Native 环境 registry + Environment Head + DeploymentRun;K3s 只执行平台期望状态 | 已交付 | provision 仅创建预发、promotion 惰性创建唯一生产、`runtime_state` CAS、start/stop durable run、停止网关 503、ReplicaFailure 快速诊断、CLI/MCP/Contracts 与能力协商均已实现;工具链正式包和平台版本已部署 prod-1;全新应用证明初始只有 preproduction、stop→0/start→1 Ready/stop→0,以及首次 promotion 才创建 production,并且两环境使用完全相同的 AppVersion 与包摘要;reference legacy HGY 入口回归 200 | 后续启停策略、闲置环境自动停止和资源诊断分别按独立运维主题演进;不得让客户端或 `kubectl scale` 成为第二状态源 |
22
22
  | OAuth2 外部应用身份 | Platform Server OAuth2 服务与数据库;Nest SDK 只消费 token | 已交付 | Client Credentials、租户/应用/环境/scope 绑定、一次性 Secret、轮换宽限、撤销、审计、跨环境拒绝、应用 Principal;平台 unit/持久化/真实 HTTP 和 Nest 测试通过 | 后续只按新 scope 或凭据策略单独设计,不与 Admin 用户会话混合 |
23
23
  | 平台托管后端运行凭据 | Platform Server credential 状态 + Environment Head/DeploymentRun | 已交付功能基线,E4 激活语义待收敛 | CAS 暂存、同 AppVersion 滚动部署、旧凭据宽限、重试幂等、CLI 不获得明文;真实 HTTP 两轮通过 | 当前候选凭据仍可能在 Head 前进入可用链路。E4 改为 pending→active→retiring→revoked,业务 token/后台 lease 只授予当前 Head 对应 run;配额、告警另做运维主题 |
24
24
  | 应用 Secret | Platform Server Secret 版本与审计表 + runtime activation policy | 已交付功能基线,active-only 注入待收敛 | 环境级 AAD、只写值、不可变版本、CAS 幂等、required/optional 部署语义、删除和审计测试 | P0 只校验所需版本存在,不向 pending runtime 提前注入 active-only Secret;E4 通过短时 runtime identity 按需读取并受 egress policy 约束。KMS 替换保持同一协议,不在应用端增加第二套存储 |
@@ -0,0 +1,18 @@
1
+ # Native 托管文件闭环
2
+
3
+ ## 决策记录
4
+
5
+ | 维度 | 决策 |
6
+ | --- | --- |
7
+ | 问题证据 | Devkit、Nest SDK 与本地平台已经使用 `/native/data/**`,但 prod-1 的真实 `files/uploads/initiate` 返回 404;平台能力发现仍声明 `data.managed-files`,Field Kit 因而在运行时才失败。 |
8
+ | 能力所有者 | Platform Server Native Data API 唯一拥有文件元数据、绑定、下载授权和对象存储访问;Platform Storage 拥有签名与对象操作;Field Kit 只拥有稳定附件值适配和 UI。 |
9
+ | 稳定不变量 | 业务字段继续保存既有 `name/url/size/type/provider/fileId/...` 稳定附件项;`DataFileRef` 只用于 initiate/complete 传输。2.0 只调用 Native 路径,不回退旧 `/data/**`。 |
10
+ | 受影响合同 | 既有 initiate、complete、delete、content 客户端方法获得真实 Native 服务端实现;Field Kit 保存的受保护 URL 改为 Native 路径;能力名与 DTO 不变。 |
11
+ | 失败与并发 | 上传绑定创建时的 Environment Head;Head 改变后未绑定文件拒绝完成/绑定。业务创建、更新、受限事务和文件绑定同事务提交;重复完成幂等,并发绑定只有一个记录成功。 |
12
+ | 安全与资源 | 用户请求必须携带当前 RoleSession;应用身份上传/删除要求 `data:write`、下载要求 `data:read`。服务端校验字段权限、数据权限、大小、数量和类型;未绑定/孤立对象由有界租约清理。 |
13
+ | 回滚边界 | 工具包只修正 2.0 Native URL 和本地同构实现;无 1.x 代码。平台表独立于旧文件表,回滚包不会改变旧应用数据。 |
14
+ | 可证伪验证 | 包测试逐字节断言所有文件 URL 为 Native;本地真实 PostgreSQL 完成上传、绑定、下载和清理;prod-1 使用同一 AppVersion 验证 OAuth2/RoleSession、Data、文件与 Workflow 全链路。 |
15
+
16
+ Platform Server 的持久化与运行边界详见根编排仓库
17
+ `docs/architecture/2026-08-16-openxiangda-native-managed-files.md`。本仓库不得用旧
18
+ Data API fallback 掩盖平台未就绪,也不得把对象存储凭据暴露给应用代码。
@@ -1,6 +1,6 @@
1
1
  # OpenXiangda 2.0 按需正式环境
2
2
 
3
- 状态:2026-08-16 已实现平台与工具链候选,等待正式发包和 prod-1 在线验收。
3
+ 状态:2026-08-16 已正式发包并完成 prod-1 全新应用在线验收。
4
4
 
5
5
  ## 问题证据
6
6
 
@@ -85,3 +85,18 @@
85
85
  - K3s 执行器只缩放当前 Head 指向的 Deployment。状态只在目标副本就绪或归零且 Head 未变化后提交;停止后的 App API 返回稳定的 503 错误码。
86
86
  - CLI 提供 `environment status/start/stop`;MCP 提供只读环境资源以及 `environment_status`、`start_environment`、`stop_environment` 三个工具。
87
87
  - AppPackage 自动要求 `environment.on-demand-production` 与 `environment.runtime-lifecycle`,旧平台会在上传制品前被能力协商拒绝。
88
+
89
+ ## prod-1 在线证据
90
+
91
+ - 全新应用 `openxiangda-v2-lifecycle-acceptance` provision 后只存在
92
+ `preproduction`;AppVersion 为 `7c931943-1335-479b-93fb-5facb9bf49c3`,
93
+ 包摘要为 `05460ac2e35bd08e36fe289436002d5dc00d6967b2634c70488a95725f34b113`。
94
+ - 同一预发环境完成 stop→0、start→1/1 Ready、再次 stop→0,三次操作都由
95
+ Durable DeploymentRun 驱动,未重建 AppPackage,也未手工修改 Deployment。
96
+ - 首次显式 promotion 才创建唯一 production 环境
97
+ `6cacce98-43cb-4055-99d5-2c8782d01835`;promotion run
98
+ `e54bfd7b-7320-4bbc-9d44-8f96aa1e0a16` 激活上述同一 AppVersion 与包摘要。
99
+ - 验收结束时预发为 stopped/0 副本,正式为 running/1 Ready Pod;应用池仍受
100
+ 原 `2.5 CPU/4Gi` 配额约束,没有为通过验收临时提高资源上限。
101
+ - 正式 `/view/openxiangda-v2-lifecycle-acceptance/admin`、reference app 和
102
+ legacy HGY Admin 均返回 HTTP 200,证明新生命周期没有进入 1.x 路径。
package/docs/backend.md CHANGED
@@ -20,9 +20,11 @@ src/health liveness/readiness
20
20
 
21
21
  用户身份必须绑定 RoleSession;应用身份绑定 tenant、app、environment、client、credentialVersion 和 scopes。业务 controller 使用生成的 `appOperations` 和 `@OpenXiangdaOperation()` 同时绑定不可变 operation contract 与 capability;`OpenXiangdaAuthzGuard` 对服务身份要求 `app:invoke` 和完全匹配的 operation capability。`@RequireCapability()` 只保留给官方 SDK 内部与非业务适配层,应用 controller 不应散写 capability 字符串。应用身份可以调用授权的 App API/Data API,但 Workflow 客户端拒绝没有用户 RoleSession 的上下文。
22
22
 
23
+ 用户发起的 App API 必须注入请求作用域的 `OpenXiangdaDataApiService`。它沿用网关已验证的 authorization 和 RoleSession,使 capability、数据策略、审计 actor、文件上传所有权与后端事务保持同一用户身份;缺少 RoleSession 时必须拒绝,不能静默回退 workload 应用身份。
24
+
23
25
  Application 2.0 的远程运行环境只有 `preproduction`、`production` 两条固定通道,`environmentKey` 是 Principal、RoleSession、事件、Workflow、App API 和运行容器共同使用的稳定身份键,并与通道名一致;`environmentId` 是 Native registry 中必须参与授权和防串联校验的稳定 UUID。`local` 是 CLI 管理的 loopback 运行模式,不是 environmentKey,也不创建远程 OAuth、Secret、Head 或 RoleSession。需要同类多环境时必须升级发布契约,不能把 UUID 或任意字符串临时当成 `environmentKey`。
24
26
 
25
- Worker、Scheduler 或事件消费者没有浏览器请求上下文时,注入 `OpenXiangdaApplicationDataApiService`。每个已部署后端的应用环境都有一个平台托管的 workload OAuth2 client;平台自动创建或复用客户端,并通过 Kubernetes Secret 注入 `OPENXIANGDA_OAUTH_CLIENT_ID`、`OPENXIANGDA_OAUTH_CLIENT_SECRET` 和 `OPENXIANGDA_OAUTH_SCOPES`,这些保留变量不写入 `backend.secrets`。本地开发时 CLI 自动创建 workspace runtime client,并只向 NestJS 进程注入同名变量;前端进程、生成 manifest、日志和 AppPackage 都不包含原始 Secret。
27
+ Worker、Scheduler 或事件消费者没有浏览器请求上下文时,才注入 `OpenXiangdaApplicationDataApiService`。每个已部署后端的应用环境都有一个平台托管的 workload OAuth2 client;平台自动创建或复用客户端,并通过 Kubernetes Secret 注入 `OPENXIANGDA_OAUTH_CLIENT_ID`、`OPENXIANGDA_OAUTH_CLIENT_SECRET` 和 `OPENXIANGDA_OAUTH_SCOPES`,这些保留变量不写入 `backend.secrets`。本地开发时 CLI 自动创建 workspace runtime client,并只向 NestJS 进程注入同名变量;前端进程、生成 manifest、日志和 AppPackage 都不包含原始 Secret。
26
28
 
27
29
  运行凭据的状态只包含 clientId、当前版本、hint、宽限期和待激活轮换元数据,不返回 Secret。`openxiangda oauth runtime rotate --environment <key> --idempotency-key <key>` 使用当前版本 CAS 暂存新凭据,并自动对当前激活 AppVersion 创建一次同版本滚动部署;部署准备阶段才把待激活凭据提升为当前凭据。旧 Pod 使用的上一版本在指定宽限期内仍可换 token,因此轮换不依赖同时重启全部副本。失败或重复请求不会生成第二份凭据,运维重试必须复用幂等键。
28
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda-skill-kit",
3
- "version": "2.0.0-alpha.32",
3
+ "version": "2.0.0-alpha.34",
4
4
  "description": "Validation and deterministic packaging for OpenXiangda 2.0 AI skills.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",