@lark-base-open/base-database-cli 1.1.1 → 1.3.8

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.
Files changed (199) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/LICENSE +6 -0
  3. package/README.md +47 -27
  4. package/dist/ai-functions.d.ts +53 -0
  5. package/dist/ai-functions.d.ts.map +1 -0
  6. package/dist/ai-functions.js +436 -0
  7. package/dist/ai-functions.js.map +1 -0
  8. package/dist/archive.d.ts +21 -0
  9. package/dist/archive.d.ts.map +1 -1
  10. package/dist/archive.js +69 -10
  11. package/dist/archive.js.map +1 -1
  12. package/dist/auth.d.ts +5 -0
  13. package/dist/auth.d.ts.map +1 -1
  14. package/dist/auth.js +26 -3
  15. package/dist/auth.js.map +1 -1
  16. package/dist/check.d.ts +74 -0
  17. package/dist/check.d.ts.map +1 -0
  18. package/dist/check.js +283 -0
  19. package/dist/check.js.map +1 -0
  20. package/dist/dependency-policy.d.ts +10 -0
  21. package/dist/dependency-policy.d.ts.map +1 -0
  22. package/dist/dependency-policy.js +162 -0
  23. package/dist/dependency-policy.js.map +1 -0
  24. package/dist/deploy.d.ts +5 -0
  25. package/dist/deploy.d.ts.map +1 -1
  26. package/dist/deploy.js +141 -176
  27. package/dist/deploy.js.map +1 -1
  28. package/dist/environment-variables.d.ts +52 -0
  29. package/dist/environment-variables.d.ts.map +1 -0
  30. package/dist/environment-variables.js +563 -0
  31. package/dist/environment-variables.js.map +1 -0
  32. package/dist/environment.d.ts +1 -1
  33. package/dist/environment.js +1 -1
  34. package/dist/environment.js.map +1 -1
  35. package/dist/function-input-types.d.ts +10 -0
  36. package/dist/function-input-types.d.ts.map +1 -0
  37. package/dist/function-input-types.js +160 -0
  38. package/dist/function-input-types.js.map +1 -0
  39. package/dist/function-schema.d.ts.map +1 -1
  40. package/dist/function-schema.js +89 -36
  41. package/dist/function-schema.js.map +1 -1
  42. package/dist/init-field-retry.d.ts +17 -0
  43. package/dist/init-field-retry.d.ts.map +1 -0
  44. package/dist/init-field-retry.js +127 -0
  45. package/dist/init-field-retry.js.map +1 -0
  46. package/dist/init-journal.d.ts +98 -0
  47. package/dist/init-journal.d.ts.map +1 -0
  48. package/dist/init-journal.js +492 -0
  49. package/dist/init-journal.js.map +1 -0
  50. package/dist/init-schema.d.ts +8 -0
  51. package/dist/init-schema.d.ts.map +1 -0
  52. package/dist/init-schema.js +423 -0
  53. package/dist/init-schema.js.map +1 -0
  54. package/dist/init.d.ts +15 -1
  55. package/dist/init.d.ts.map +1 -1
  56. package/dist/init.js +884 -261
  57. package/dist/init.js.map +1 -1
  58. package/dist/lark-cli-error.d.ts +47 -0
  59. package/dist/lark-cli-error.d.ts.map +1 -0
  60. package/dist/lark-cli-error.js +201 -0
  61. package/dist/lark-cli-error.js.map +1 -0
  62. package/dist/lark-cli.d.ts +1 -1
  63. package/dist/lark-cli.d.ts.map +1 -1
  64. package/dist/lark-cli.js +78 -18
  65. package/dist/lark-cli.js.map +1 -1
  66. package/dist/mutation-schema.d.ts +146 -0
  67. package/dist/mutation-schema.d.ts.map +1 -0
  68. package/dist/mutation-schema.js +153 -0
  69. package/dist/mutation-schema.js.map +1 -0
  70. package/dist/mutation.d.ts +10 -0
  71. package/dist/mutation.d.ts.map +1 -0
  72. package/dist/mutation.js +131 -0
  73. package/dist/mutation.js.map +1 -0
  74. package/dist/npm.d.ts +1 -0
  75. package/dist/npm.d.ts.map +1 -1
  76. package/dist/npm.js +2 -2
  77. package/dist/npm.js.map +1 -1
  78. package/dist/preview-receipt.d.ts.map +1 -1
  79. package/dist/preview-receipt.js +15 -5
  80. package/dist/preview-receipt.js.map +1 -1
  81. package/dist/process.d.ts +3 -1
  82. package/dist/process.d.ts.map +1 -1
  83. package/dist/process.js +16 -4
  84. package/dist/process.js.map +1 -1
  85. package/dist/program.d.ts.map +1 -1
  86. package/dist/program.js +246 -42
  87. package/dist/program.js.map +1 -1
  88. package/dist/project-build.d.ts +25 -0
  89. package/dist/project-build.d.ts.map +1 -0
  90. package/dist/project-build.js +229 -0
  91. package/dist/project-build.js.map +1 -0
  92. package/dist/project-context.d.ts +344 -0
  93. package/dist/project-context.d.ts.map +1 -0
  94. package/dist/project-context.js +485 -0
  95. package/dist/project-context.js.map +1 -0
  96. package/dist/project-layout.d.ts +5 -0
  97. package/dist/project-layout.d.ts.map +1 -0
  98. package/dist/project-layout.js +24 -0
  99. package/dist/project-layout.js.map +1 -0
  100. package/dist/public-sql-error.d.ts +25 -0
  101. package/dist/public-sql-error.d.ts.map +1 -0
  102. package/dist/public-sql-error.js +65 -0
  103. package/dist/public-sql-error.js.map +1 -0
  104. package/dist/pull.d.ts +1 -0
  105. package/dist/pull.d.ts.map +1 -1
  106. package/dist/pull.js +67 -15
  107. package/dist/pull.js.map +1 -1
  108. package/dist/site-readme.d.ts +3 -0
  109. package/dist/site-readme.d.ts.map +1 -0
  110. package/dist/site-readme.js +83 -0
  111. package/dist/site-readme.js.map +1 -0
  112. package/dist/workspace-fingerprint.d.ts +21 -1
  113. package/dist/workspace-fingerprint.d.ts.map +1 -1
  114. package/dist/workspace-fingerprint.js +81 -2
  115. package/dist/workspace-fingerprint.js.map +1 -1
  116. package/package.json +2 -1
  117. package/skills/lark-base-database/SKILL.md +86 -52
  118. package/skills/lark-base-database/references/ai-function.md +479 -0
  119. package/skills/lark-base-database/references/base-capability-routing.md +7 -7
  120. package/skills/lark-base-database/references/base-sql-errors.generated.md +403 -0
  121. package/skills/lark-base-database/references/database-function-limitations.md +29 -0
  122. package/skills/lark-base-database/references/database-function.md +323 -0
  123. package/skills/lark-base-database/references/development.md +166 -33
  124. package/skills/lark-base-database/references/environment-variables.md +55 -0
  125. package/skills/lark-base-database/references/faas.md +46 -53
  126. package/skills/lark-base-database/references/file-transfer.md +25 -25
  127. package/skills/lark-base-database/references/frontend-design-guide.md +151 -65
  128. package/skills/lark-base-database/references/mutations.md +295 -0
  129. package/skills/lark-base-database/references/notifications.md +9 -9
  130. package/skills/lark-base-database/references/permission-design.md +24 -24
  131. package/skills/lark-base-database/references/release.md +57 -30
  132. package/skills/lark-base-database/references/style-guide.md +10 -67
  133. package/skills/lark-base-database/references/verification.md +19 -13
  134. package/skills/lark-base-database/references/workspace.md +57 -17
  135. package/templates/database-starter/README.md +34 -4
  136. package/templates/database-starter/database-functions/README.md +8 -0
  137. package/templates/database-starter/gitignore +7 -0
  138. package/templates/database-starter/mutations/README.md +19 -0
  139. package/templates/database-starter/page/README.md +25 -19
  140. package/templates/database-starter/page/package-lock.json +8 -16
  141. package/templates/database-starter/page/package.json +2 -3
  142. package/templates/database-starter/page/src/App.tsx +23 -3
  143. package/templates/database-starter/page/src/components/UserSelectorEditor/index.tsx +32 -4
  144. package/templates/database-starter/page/src/components/UserSelectorPanel/index.tsx +104 -34
  145. package/templates/database-starter/page/src/components/UserSelectorPanel/user-search.test.ts +55 -11
  146. package/templates/database-starter/page/src/components/UserSelectorPanel/user-search.ts +68 -25
  147. package/templates/database-starter/page/src/components/database-runtime-ready.tsx +1 -1
  148. package/templates/database-starter/page/src/components/database-user-menu/index.tsx +4 -7
  149. package/templates/database-starter/page/src/components/feedback/page-state.tsx +40 -5
  150. package/templates/database-starter/page/src/components/floating-button/assets/edit-active.svg +3 -0
  151. package/templates/database-starter/page/src/components/floating-button/assets/edit-default.svg +3 -0
  152. package/templates/database-starter/page/src/components/floating-button/assets/toast-close.svg +3 -0
  153. package/templates/database-starter/page/src/components/floating-button/assets/toast-info.svg +5 -0
  154. package/templates/database-starter/page/src/components/floating-button/assets/tooltip-caret.svg +3 -0
  155. package/templates/database-starter/page/src/components/floating-button/index.tsx +193 -113
  156. package/templates/database-starter/page/src/components/floating-button/utils/project-meta.test.ts +107 -37
  157. package/templates/database-starter/page/src/components/floating-button/utils/project-meta.ts +13 -50
  158. package/templates/database-starter/page/src/components/ui-language.test.tsx +101 -0
  159. package/templates/database-starter/page/src/examples/ai-function/ImageTaskOperation.tsx +202 -0
  160. package/templates/database-starter/page/src/examples/ai-function/README.md +14 -0
  161. package/templates/database-starter/page/src/examples/ai-function/TextStreamOperation.tsx +184 -0
  162. package/templates/database-starter/page/src/examples/ai-function/ai-copy.ts +173 -0
  163. package/templates/database-starter/page/src/examples/ai-function/ai-delta.test.ts +30 -0
  164. package/templates/database-starter/page/src/examples/ai-function/ai-delta.ts +26 -0
  165. package/templates/database-starter/page/src/examples/ai-function/ai-language.test.tsx +86 -0
  166. package/templates/database-starter/page/src/examples/ai-function/ai-media-panel.test.ts +201 -0
  167. package/templates/database-starter/page/src/examples/ai-function/ai-media-panel.tsx +382 -0
  168. package/templates/database-starter/page/src/lib/attachment-image.tsx +144 -0
  169. package/templates/database-starter/page/src/lib/database-function-inputs.generated.ts +4 -0
  170. package/templates/database-starter/page/src/lib/database-runtime-attachment.test.ts +180 -76
  171. package/templates/database-starter/page/src/lib/database-runtime.test.ts +130 -10
  172. package/templates/database-starter/page/src/lib/database-runtime.ts +484 -51
  173. package/templates/database-starter/page/src/lib/date-time.ts +61 -0
  174. package/templates/database-starter/page/src/lib/ui-language.ts +86 -0
  175. package/templates/database-starter/page/src/main.tsx +1 -1
  176. package/templates/database-starter/page/tsconfig.json +2 -2
  177. package/templates/database-starter/page/vite.config.ts +1 -2
  178. package/templates/database-starter/prettierignore +1 -1
  179. package/templates/database-starter/server-functions/README.md +2 -2
  180. package/templates/database-starter/server-functions/package-lock.json +4 -4
  181. package/templates/database-starter/server-functions/package.json +1 -1
  182. package/dist/agent-guide.d.ts +0 -19
  183. package/dist/agent-guide.d.ts.map +0 -1
  184. package/dist/agent-guide.js +0 -31
  185. package/dist/agent-guide.js.map +0 -1
  186. package/dist/database-skill.d.ts +0 -24
  187. package/dist/database-skill.d.ts.map +0 -1
  188. package/dist/database-skill.js +0 -148
  189. package/dist/database-skill.js.map +0 -1
  190. package/skills/lark-base-database/references/base-sql-unsupported.md +0 -42
  191. package/skills/lark-base-database/references/database-capability-skill.md +0 -40
  192. package/skills/lark-base-database/references/sql-function.md +0 -289
  193. package/templates/database-capability/SKILL.md.tmpl +0 -58
  194. package/templates/database-starter/page/src/components/floating-button/chatbot-entry.test.ts +0 -23
  195. package/templates/database-starter/page/src/components/floating-button/chatbot-entry.tsx +0 -873
  196. package/templates/database-starter/page/src/components/floating-button/local-chat-panel.test.ts +0 -25
  197. package/templates/database-starter/page/src/components/floating-button/local-chat-panel.tsx +0 -197
  198. package/templates/database-starter/page/src/components/floating-button/utils/env.ts +0 -18
  199. package/templates/database-starter/sql/README.md +0 -8
@@ -1,6 +1,6 @@
1
1
  # Base Database 权限与访问设计
2
2
 
3
- 本文负责应用的访问与权限设计:在平台权限模块之外,用 bindings、SQL Function 和 FaaS 校验把「谁能看什么、谁能做什么」设计成可验证的事实。用法是「访问模型先行」:理解需求时先形成访问模型,再让它约束 binding、SQL 与写入链路的实现。实现层协议见[FaaS 协议](faas.md)与 [SQL Function 专项](sql-function.md);原生多维表格侧的角色与高级权限配置见[原生 Base 能力发现与路由](base-capability-routing.md)。
3
+ 建模前确定访问范围、读取权限与写入风险。Database Function 内完成可信身份和读取范围判定;绑定表的写入风险见[绑定范围](#绑定范围)。基础写入与业务校验的分工见[写入方式选择](mutations.md#写入方式选择),实现层协议见[FaaS 协议](faas.md)与 [Database Function 专项](database-function.md);原生多维表格侧的角色与高级权限配置见[原生 Base 能力发现与路由](base-capability-routing.md)。
4
4
 
5
5
  本文内容分两层:**平台安全模型**是当前平台的事实,不是设计选项,所有方案都必须在它成立的前提下推导;**设计默认路径**(成员表配方、分表方式等)是被验证过的出发点而非唯一解——可以按业务另择实现,但替换方案必须重新通过对应小节的判定问题。
6
6
 
@@ -9,10 +9,10 @@
9
9
  应用在飞书里是一篇多维表格文档。当前平台的权限事实:
10
10
 
11
11
  - **应用访问准入**:能打开 Prod 应用的人 = 对这篇应用文档有阅读权限的人。范围由文档分享设置决定,掌握在用户手里,应用代码无法收窄它。Preview 环境只有应用 owner 本人能访问。Prod/Preview 是发布态,与 CLI 的部署环境分别判定。
12
- - **数据访问以 owner 身份执行**:应用读写 Base 数据一律以应用 owner 的身份进行,访问者本人对底层 Base 有没有协作权限不参与判定。底表的原生高级权限(行列权限)不约束应用访问者的读取——原生权限管的是直接打开多维表格的人,应用是另一个入口,两边要分别设计;应用内的读取范围由 SQL Function 自己写了什么决定。
13
- - **调用面对全体访问者开放**:任何能打开应用的人都可以用任意参数调用任何已发布的 SQL/FaaS Function,并且可以对 bindings 内的每张表直接使用平台记录写入通道(批量创建、更新、删除),不经过页面 UI。UI 显隐、路由守卫和前端校验只是体验,不是边界。
14
- - **唯一可信身份在 SQL 层**:`CURRENT_USER_ID()` 是访问者身份唯一可信的来源,由平台服务端注入、页面无法伪造,且只能在 SQL Function 内使用。Page 和 FaaS 的业务代码拿不到可信的访问者 user id,任何「当前用户是谁」的判断都必须落到 SQL。
15
- - **FaaS 不是更高权限**:FaaS 与 Page 的数据读写权限完全相同。FaaS 的安全价值是提供「访问者改不了的校验位置」,不是提权。
12
+ - **数据访问以 owner 身份执行**:应用读写 Base 数据一律以应用 owner 的身份进行,访问者本人对底层 Base 有没有协作权限不参与判定。底表的原生高级权限(行列权限)不约束应用访问者的读取——原生权限管的是直接打开多维表格的人,应用是另一个入口,两边要分别设计;应用内的读取范围由 Database Function 自己写了什么决定。
13
+ - **调用边界**:访问者可绕过 UI 调用已发布 Function。Mutation 固定表、操作、字段和值来源,不声明或执行角色规则,调用沿用应用统一准入;自定义角色与统一行列权限后续接入。配套服务端已关闭三个浏览器直接记录 CRUD 入口;受 FaaS ticket 保护的记录与附件回调保留兼容,必须逐个审查已发布 FaaS 的固定输入与校验。UI 显隐、路由守卫和前端校验只是体验,不是边界。
14
+ - **可信身份**:Database Function 使用服务端注入的 `CURRENT_USER_ID()`;Mutation 的 `current_user` 同样由服务端注入,可用于写入人员字段。两者都不能由调用参数覆盖。Page/FaaS 的业务参数不能自报可信身份;FaaS 通过固定 Database Function 检查身份。
15
+ - **FaaS 不是更高权限**:FaaS 与 Page 的数据读写权限完全相同。
16
16
 
17
17
  由此得出应用的威胁模型:**应用的真实安全边界 = 已发布的 Function 集合 + bindings 声明的表,面对的是分享范围内权限最低、且可能绕过 UI 直调接口的访问者**。每个 Function、每张 bind 的表都按这个假设设计。
18
18
 
@@ -28,41 +28,41 @@
28
28
 
29
29
  ## 绑定范围
30
30
 
31
- **原则**:一张表 bind 进应用,等于把 owner 权限内该表的全部行列同时置于两个暴露面之下——读的一侧是「SQL Function 写什么就能查什么」,写的一侧是「平台写入通道全开」。未 bind 的表读写都会被服务端拒绝:bindings 是当前唯一有平台强制力的收窄手段。
31
+ **原则**:一张表 bind 进应用,等于把 owner 权限内该表的全部行列同时置于两个暴露面之下——读的一侧是「Database Function 写什么就能查什么」,写的一侧是「已发布 Mutation / FaaS 允许的写入」。未 bind 的表读写都会被服务端拒绝;Mutation 可进一步收窄操作和可写字段,并声明记录 ID 参数来源。
32
32
 
33
33
  **判定**:对每张要 bind 的表问——它最敏感的字段被分享范围内任何人读到、最关键的记录被任何人改掉或删掉,业务能否接受?
34
34
 
35
- **设计目标与当前限制**:绑定范围应只包含业务可接受暴露的表。当前 CLI init 会绑定目标 Base 全部表,不支持选表初始化;执行前按[工程与环境](workspace.md#需求与-base-定位)核对范围。不能将“只绑定必要表”当成现有 CLI 参数。读判定不通过时,重新选择可整体绑定的数据范围;当前 init 不支持在同一 Base 内仅将敏感字段分表后排除绑定。写判定不通过时要清楚:FaaS 校验只约束走 FaaS 的路径,挡不住直调平台写入通道的访问者。这条绕过路径不能由页面或 FaaS 校验阻止。这是当前平台的已知残余风险:是否可接受由数据敏感度和分享面共同决定,不可接受时不把该数据放进应用,或与用户确认收窄分享面,并把结论写进交付说明。
35
+ **设计目标与当前限制**:绑定范围应只包含业务可接受暴露的表。当前 CLI init 会绑定目标 Base 全部表,不支持选表初始化;执行前按[工程与环境](workspace.md#需求与-base-定位)核对范围。不能将“只绑定必要表”当成现有 CLI 参数。读判定不通过时,重新选择可整体绑定的数据范围;当前 init 不支持在同一 Base 内仅将敏感字段分表后排除绑定。写判定不通过时,审查每个已发布 Mutation/FaaS:是否固定表和字段、是否核验可信身份、是否允许修改角色来源。不能暴露通用 patch 或动态路由。部署到尚未关闭浏览器 CRUD 的旧服务端时,仍存在绕过声明的直接写入风险,不能仅凭 CLI 版本承诺已经收口。
36
36
 
37
- ## 读路径:SQL Function 就是策略面
37
+ ## 读路径:Database Function 就是策略面
38
38
 
39
- **原则**:Page 只能调用发布时固化的 SQL Function,因此 SQL Function 集合就是应用事实上的数据访问策略——SELECT 的列清单是列级权限,`CURRENT_USER_ID()` 过滤是行级权限。
39
+ **原则**:Page 只能调用发布时固化的 Database Function,因此 Database Function 集合就是应用事实上的数据访问策略——SELECT 的列清单是列级权限,`CURRENT_USER_ID()` 过滤是行级权限。
40
40
 
41
41
  **判定**:分享范围内权限最低的访问者,用任意参数调用这个 Function,返回的每一行每一列都是他该看的吗?
42
42
 
43
43
  **默认路径**:
44
44
 
45
- - 「我的 X」一律在 SQL 内用 `CURRENT_USER_ID()` 与人员字段比较过滤(写法见 [SQL Function 专项](sql-function.md)),不通过参数传 user id。**参数是过滤器,不是权限**:任何参数值都可能被任意访问者传入。
46
- - 按角色区分可见性时,在查询 SQL 中关联成员表完成判定(见下节),而不是发布「高权限版」和「低权限版」两个 Function 靠前端选择调用。
45
+ - 「我的 X」一律在查询中用 `CURRENT_USER_ID()` 与人员字段比较过滤(写法见 [Database Function 专项](database-function.md)),不通过参数传 user id。**参数是过滤器,不是权限**:任何参数值都可能被任意访问者传入。
46
+ - 按角色区分可见性时,在查询语句中关联成员表完成判定(见下节),而不是发布「高权限版」和「低权限版」两个 Function 靠前端选择调用。
47
47
  - 敏感列不进 SELECT 就不会泄露;不用「全量查出、前端隐藏」。
48
48
 
49
49
  ## 操作权限:成员表方案
50
50
 
51
51
  需要「某些人能、其他人不能」时的默认路径(不是唯一解,但替换方案必须同样以 `CURRENT_USER_ID()` 为判定源):
52
52
 
53
- 1. **成员表**:一张成员表,人员字段存用户、受控单选存角色,bind 进应用。注意成员表自身就是典型的写敏感表,同样处于上节的残余风险之下;是否可接受须结合明确的业务风险与访问范围判断,不能仅凭“团队内使用”推断;无法保护角色来源时,不承诺严格角色隔离。
54
- 2. **whoami**:一个固定 SQL Function 按 `CURRENT_USER_ID()` 查成员表,返回当前访问者的成员记录与角色;查不到按「无角色」处理,业务层默认拒绝。
53
+ 1. **成员表**:一张成员表,人员字段存用户、受控单选存角色,bind 进应用。注意成员表自身就是典型的写敏感表,必须约束其所有已发布写入能力;是否可接受须结合明确的业务风险与访问范围判断,不能仅凭“团队内使用”推断;无法保护角色来源时,不承诺严格角色隔离。
54
+ 2. **whoami**:一个固定 Database Function 按 `CURRENT_USER_ID()` 查成员表,返回当前访问者的成员记录与角色;查不到按「无角色」处理,业务层默认拒绝。
55
55
  3. **前端显隐**:页面用 whoami 的结果决定入口与视图的显隐——这是体验优化,真正的边界在读写路径。
56
- 4. **角色敏感写入走 FaaS**:FaaS 先调用含 `CURRENT_USER_ID()` 的固定校验 SQL(角色、归属、状态尽量并入一次查询,见[FaaS 协议](faas.md#远程调用与写入链路设计)),通过后再执行写入,不通过返回稳定业务码。
57
- 5. **操作者与审计**:写入需要记录「谁做的」时,操作者身份取自可信 SQL 的查询结果,不取页面传值;需要审计的 operation 在业务字段中显式记录操作者与时间。
56
+ 4. **角色敏感写入**:需要校验管理员、记录归属、状态或自定义成员角色时走 FaaS。Mutation 的记录 ID 条件不执行这些校验。FaaS 先调用含 `CURRENT_USER_ID()` 的固定 Database Function(角色、归属、状态尽量并入一次查询,见[FaaS 协议](faas.md#远程调用与写入链路设计)),通过后再执行写入,不通过返回稳定业务码。
57
+ 5. **操作者与审计**:写入需要记录「谁做的」时,Mutation 用 `current_user` / `now`,FaaS 取可信 Database Function 的查询结果,不取页面传值;需要审计的 operation 在业务字段中显式记录操作者与时间。
58
58
 
59
- owner 身份采用平台下发的 `isOwner` 信号(缺失按 false 处理),不能由页面自行比较用户 ID。身份判定与入口显示条件分别处理:starter 的“编辑应用”入口仅在 `isOwner === true && getDatabaseContext().env === 'prod'` 时显示;Preview 中 owner 身份为 true,不代表需要展示该入口。其他业务管理功能是否允许在 Preview 使用取决于需求,不能一律套用 Prod 限制。上述页面显隐不替代服务端授权。
59
+ owner 身份采用平台下发的 `isOwner` 信号(缺失按 false 处理),不能由页面自行比较用户 ID。身份判定与入口显示条件分别处理:starter 的“编辑应用”入口仅在 `allowEdit === true && getDatabaseContext().env === 'prod'` 时显示;`allowEdit` 来自 `invoke_get` 的 `site`,由服务端按当前用户的站点管理权限判定。旧服务端未下发该字段时,starter 仅为兼容现有 Owner 入口而回退到 `isOwner === true`;显式 `allowEdit: false` 不得回退。Preview 不展示该入口。其他业务管理功能是否允许在 Preview 使用取决于需求,不能一律套用 Prod 限制。上述页面显隐不替代服务端授权。
60
60
 
61
61
  ### 实现示例
62
62
 
63
- 以报销应用为例:全员可提交报销单,管理员可见全部并审批,普通成员只能看自己的。示例展示默认路径的关键写法;角色档位、判定并入查询还是拆分按业务调整,但判定源必须是 `CURRENT_USER_ID()`,SQL 语法约束以 [SQL Function 专项](sql-function.md)为准。
63
+ 以报销应用为例:全员可提交报销单,管理员可见全部并审批,普通成员只能看自己的。示例展示默认路径的关键写法;角色档位、判定并入查询还是拆分按业务调整,但判定源必须是 `CURRENT_USER_ID()`,查询语法约束以 [Database Function 专项](database-function.md)为准。
64
64
 
65
- 成员表 schema——人员字段显式声明 `"multiple": false`(默认为 true),单人字段在 SQL 中才是标量 `USER`,可以直接比较子字段;多人字段是集合,要按专项走 `UNNEST`:
65
+ 成员表 schema——人员字段显式声明 `"multiple": false`(默认为 true),单人字段在查询中才是标量 `USER`,可以直接比较子字段;多人字段是集合,要按专项走 `UNNEST`:
66
66
 
67
67
  ```json
68
68
  {
@@ -85,7 +85,7 @@ whoami(无参数 Function)——查不到行即「无角色」,前端据
85
85
  ```sql
86
86
  SELECT rec_id AS member_id, "姓名" AS name, "角色" AS role
87
87
  FROM "成员"
88
- WHERE "用户".userId = CURRENT_USER_ID()
88
+ WHERE ("用户").id = CURRENT_USER_ID()
89
89
  LIMIT 1
90
90
  ```
91
91
 
@@ -94,24 +94,24 @@ LIMIT 1
94
94
  ```sql
95
95
  SELECT rec_id AS record_id, "标题" AS title, "金额" AS amount, "状态" AS status
96
96
  FROM "报销单"
97
- WHERE "申请人".userId = CURRENT_USER_ID()
97
+ WHERE ("申请人").id = CURRENT_USER_ID()
98
98
  ORDER BY rec_id DESC
99
99
  LIMIT 50
100
100
  ```
101
101
 
102
- FaaS 需要判断管理员身份时,可以调用固定的无参数 SQL:
102
+ FaaS 需要判断管理员身份时,可以调用固定的无参数 Database Function:
103
103
 
104
104
  ```sql
105
105
  SELECT COUNT(rec_id) AS admin_count
106
106
  FROM "成员"
107
- WHERE "用户".userId = CURRENT_USER_ID() AND "角色" = '管理员'
107
+ WHERE ("用户").id = CURRENT_USER_ID() AND ("角色").name = '管理员'
108
108
  ```
109
109
 
110
110
  该查询只证明当前访问者的角色;写入前仍要验证目标记录、合法状态和业务要求。能在支持集内合并的检查可合并,不能为了减少一次调用使用未经支持的聚合派生表 JOIN。
111
111
 
112
- 按角色返回不同数据范围的读取,必须在每个已发布查询内部完成身份与范围判定。不能由 FaaS 先查角色后调用一个对所有访问者开放的无过滤“管理员查询”来实现读取隔离。角色关系无法用当前 SQL 支持集表达时,报告该方案的能力限制,不发布可绕过的查询。上述示例不承诺成员表不可被平台写入通道修改,仍受绑定范围一节的限制。
112
+ 按角色返回不同数据范围的读取,必须在每个已发布查询内部完成身份与范围判定。不能由 FaaS 先查角色后调用一个对所有访问者开放的无过滤“管理员查询”来实现读取隔离。角色关系无法用当前查询支持集表达时,报告该方案的能力限制,不发布可绕过的查询。上述示例不自动保护成员表;不得同时发布可由普通访问者调用的角色修改 Mutation/FaaS。
113
113
 
114
- FaaS 调用 SQL 与写入的协议见[FaaS 协议](faas.md#faas-开发)。
114
+ FaaS 调用 Database Function 与写入的协议见[FaaS 协议](faas.md#faas-开发)。
115
115
 
116
116
  ## 常见权限设计错误
117
117
 
@@ -1,30 +1,61 @@
1
1
  # 发布与交付
2
2
 
3
- 发布任务进入本流程。故障定位和用户明确要求的专项验收见[诊断与验收](verification.md)。环境与命令前缀见[工程与环境](workspace.md);本流程适用于一方与三方。
3
+ 发布任务进入本流程。故障定位和用户明确要求的专项验收见[诊断与验收](verification.md)。环境与命令前缀见[工程与环境](workspace.md)。
4
+
5
+ ## 站点 README
6
+
7
+ 新建站点时,先从用户原始建站 Prompt 的主要自然语言确定 README 语言:支持中文、日文、英文;其他语言或无法判断主要语言时使用英文。用户明确指定 README 使用这三种语言之一时按其指定语言填写;指定其他语言时仍使用英文。初始化生成的项目根目录 `README.md` 是英文模板,须按选定语言改写全部面向人的标题与正文,替换全部 `{{...}}` 占位内容;命令、路径和代码标识符保留原样。修改已有站点时沿用现有 README 语言,除非用户明确要求切换。README 是生成时确定的源码文档,不随 Site 运行时的宿主或浏览器语言变化。
8
+
9
+ 四个必要章节使用下表中所选语言的标题;CLI 接受这三组标题,并只检查结构、占位符和章节是否非空,不判断正文语言或业务描述是否属实:
10
+
11
+ | English | 中文 | 日本語 |
12
+ | --- | --- | --- |
13
+ | `Background` | `需求背景` | `背景` |
14
+ | `Requested features` | `用户希望的功能` | `ユーザーが求める機能` |
15
+ | `Implemented capabilities` | `站点已提供的能力` | `提供済みの機能` |
16
+ | `Status and limitations` | `当前状态与边界` | `現状と制約` |
17
+
18
+ **每次调用 `deploy` 前**,重新读取 README、用户需求及本次变更的 Page/Function,核对下列内容;描述与当前实现不一致或业务能力发生变化时先更新 README,再运行部署命令。无法确认时保留当前工程并说明待核对项,不发布。保留必要的本地运行说明,但先让阅读者理解站点:
19
+
20
+ - **目标与使用者**:用户希望解决的问题、目标用户和使用场景。忠实概括原始需求,不把推测写成用户要求。
21
+ - **用户希望的功能**:归纳原始需求中的核心业务能力和预期结果,便于后续对照样例,不把尚未实现的功能写成已交付。
22
+ - **已提供的能力**:按业务流程说明页面入口、核心操作、数据对象和结果;涉及角色或权限时说明谁能做什么。只写已实现的能力,计划中或受平台限制的能力单独标明。
23
+
24
+ README 不放客户真实数据、凭证、token 或内部调试日志。CLI 在本地 `check` 和部署前检查 README 是普通文件、已删除模板占位内容且包含非空的必要业务章节;未通过时不会上传。通过后将 README 放入 `site.zip` 的根路径,远端 `pull` 可恢复。Prod 复用 Preview 的同一制品,不重新打包上传;调用 `deploy --production` 前也要核对 README,若需修改则先更新并重新发布 Preview,再取得针对新制品的确认。README 是源码制品的一部分,不会自动显示在站点页面上。
4
25
 
5
26
  ## 发布前
6
27
 
7
- 确认工程与 应用 一致、保留需求外 Function,完成本次修改的静态检查。涉及视觉的变更按[前端设计指导](frontend-design-guide.md#交付前自检)检查;涉及通知先按[通知集成](notifications.md)确定路由、资源范围和启停策略。
28
+ 确认工程与应用一致并保留需求外 Function。涉及视觉的变更按[前端设计指南](frontend-design-guide.md#交付前自检)检查;涉及通知先按[通知集成](notifications.md)确定路由、资源范围和启停策略。
8
29
 
9
- 依赖安装使用 CLI 随包固定的 npm,不受宿主 PATH 中 npm 版本影响。安装失败时保留子项目路径、npm 版本与原始错误:lock 不一致先核对本次 `package.json` 变更,按 CLI 错误提示修复该子项目的 lock 并检查差异,再重试一次;网络或权限错误先解决对应原因。不要盲删 lock、循环切换 npm 版本,也不要用 `--no-install` 掩盖安装失败;重试仍失败时保留证据并定位原因,不自动报告部署成功。
30
+ 实现完成后,在项目根目录使用唯一受支持的本地检查入口:
31
+
32
+ ```bash
33
+ base-database-cli check --json
34
+ ```
35
+
36
+ 该命令先按本地 Database Function/Mutation/FaaS metadata 更新 Page Function 输入类型,再可能安装 Page/FaaS 依赖并写入本地构建输出;不要手改生成类型,不要猜测 `node_modules` 路径或分别运行子项目安装命令。`--json` 保证成功和失败都返回一个结构化 JSON 文档;成功结果用 `functions["database-functions"]`、`functions["mutation-functions"]` 和 `functions["server-functions"]` 计数。失败时按 `error.stage`、`error.diagnostics` 和 `nextActions` 修复一次,再重新运行同一命令。成功的 Page/FaaS 构建会分开缓存,重试只重建输入变化或上次失败的一侧,不要为了重试默认添加 `--force-build`。它不调用应用 API、不发布,也不执行服务端查询语法、Catalog/binding 或业务运行态验证;这些仍由 `deploy` 及后续验收完成。
37
+
38
+ 依赖安装使用 CLI 随包固定的 npm,不受宿主 PATH 中 npm 版本影响。CLI 在安装前获取目标应用的服务端依赖策略,并校验最终制品范围内全部 `package.json`;受限来源、非法 manifest 或策略查询失败时不会安装、构建或上传。添加依赖时的查询与判断见[第三方依赖策略](development.md#第三方依赖策略)。安装失败时保留子项目路径、npm 版本与原始错误:lock 不一致先核对本次 `package.json` 变更,按 CLI 错误提示修复该子项目的 lock 并检查差异,再重试一次;网络或权限错误先解决对应原因。不要盲删 lock、循环切换 npm 版本,也不要用 `--no-install` 掩盖安装失败;重试仍失败时保留证据并定位原因,不自动报告部署成功。
10
39
 
11
40
  ## Preview
12
41
 
42
+ 第三方 Agent 的首次 Preview 在执行 `deploy` 前,先根据 FaaS 源码和用户需求判断是否需要环境变量。没有自定义环境变量引用、且用户未要求查询或配置环境变量时,跳过环境变量流程,直接继续本节发布,不执行 `environment-variables list` 或额外询问配置。有引用或用户明确要求时,再按[环境变量协议](environment-variables.md)收集引用、声明缺失定义并核对 Preview 值。缺少必填值时一次性询问,保留工程与当前会话;收到完整回复后保存并自动继续首次 Preview。CLI 在构建前校验声明,Artifact 上传与源码回读后、Preview 发布前再次校验必填值。普通更新和 Prod 仍按本流程的制品与授权契约执行。
43
+
13
44
  在含 `base-database.jsonc` 的目录执行:
14
45
 
15
46
  ```bash
16
47
  base-database-cli deploy
17
48
  ```
18
49
 
19
- CLI 负责 Function metadata、全量 SQL 校验、必要依赖安装、Page/FaaS build、归档、Functions 全量更新、Artifact 上传与源码回读、Preview 发布和轮询。SQL 校验失败时不会继续构建;依赖指纹未变且 node_modules 有效时可跳过安装,但仍 build。安装选项仅在有相应排障依据时使用,不通过跳过校验掩盖失败。
50
+ CLI 负责 Function metadata、全量查询校验、必要依赖安装、Page/FaaS build、归档、Functions 全量更新、Artifact 上传与源码回读、Preview 发布和轮询。查询校验失败时不会继续构建;依赖指纹未变且 node_modules 有效时可跳过安装,但仍 build。安装选项仅在有相应排障依据时使用,不通过跳过校验掩盖失败。本地没有 `ai/` 声明时 deploy 不调用 AI Function 接口,未涉及 AI 的应用不需要开通 AI Function;需要让本次发布完全不动 AI Function 时显式加 `--skip-ai-functions`,并在交付报告中说明 AI Function 未同步且未验证(见[诊断与验收](verification.md))。
20
51
 
21
52
  等待命令完成,进程仍在运行不代表失败,不重复启动部署。只有发布成功响应中的顶层 `baseAppUrl` 是可信交付入口,制品大小、SHA-256 和 publish ID 用于追溯。不能用历史 URL、管理后台、Catalog 或内部 `staticUrl` 替代缺失入口。
22
53
 
23
54
  发布成功后按顺序处理:
24
55
 
25
- 1. 本次创建新 Base:完成下述示例数据验证;复用已有 Base 或修改 应用 不擅自写示例记录。
56
+ 1. 本次创建新 Base:完成下述示例数据验证;复用已有 Base 或修改应用不擅自写示例记录。
26
57
  2. 本次涉及原生通知:完成[通知入口与状态收尾](notifications.md),保留原有启停状态。
27
- 3. 按下述[应用能力 Skill 安装](#应用能力-skill-安装)读取安装结果,再汇总已验证范围、业务成果和未完成项,交付 Preview 并等待体验。
58
+ 3. 汇总已验证范围、业务成果和未完成项,交付 Preview 并等待体验。
28
59
 
29
60
  普通建站的自动运行态验证限定为示例数据闭环;Page 写入、UI 交互和多角色行为未测试时明确列为未验证,不宣称 E2E 通过。用户明确要求验收或排障时进入[诊断与验收](verification.md),而不是受本次交付停止条件限制。
30
61
 
@@ -32,29 +63,29 @@ CLI 负责 Function metadata、全量 SQL 校验、必要依赖安装、Page/Faa
32
63
 
33
64
  ## 从零建站示例数据验收
34
65
 
35
- 本节只适用于本次创建了新 Base 的从零建站;复用已有 Base、修改已有 应用 时不得擅自添加示例记录。先设计小而完整的非敏感示例,覆盖核心对象、典型状态和必要关联,在可见业务主字段使用稳定的“示例”标记,不新增仅用于播种的字段。构造记录 payload 前读取当前 lark-base 的 CellValue 协议,不能直接复用 FaaS 下游请求的字段格式;两条链路可能有不同的输入归一化。
66
+ 本节只适用于本次创建了新 Base 的从零建站;复用已有 Base、修改已有应用时不得擅自添加示例记录。先设计小而完整的非敏感示例,覆盖核心对象、典型状态和必要关联,在可见业务主字段使用稳定的“示例”标记,不新增仅用于播种的字段。构造记录 payload 前读取当前 lark-base 的 CellValue 协议,不能直接复用 FaaS 下游请求的字段格式;两条链路可能有不同的输入归一化。
36
67
 
37
68
  示例数据使用 lark-cli 的输入契约。`+record-batch-create --help` 提供常用格式,完整类型与日期时间支持形态按当前 lark-base 的 CellValue 文档核对;文档位置通过 `lark-cli skills read lark-base` 的路由查找。下表区分两条链路,执行前仍核对安装版本的协议与真实字段:
38
69
 
39
- | 字段 | 开发期 lark-cli 写入 | FaaS 应用记录 写入 |
70
+ | 字段 | 开发期 lark-cli 写入 | FaaS 应用记录写入 |
40
71
  | --- | --- | --- |
41
- | 单选 | `["待处理"]`,数组最多一项 | `"待处理"`,合法选项名字符串 |
72
+ | 单选 | `"待处理"`,选项名字符串(字段 `multiple=false`) | `"待处理"`,合法选项名字符串 |
42
73
  | 多选 | `["标签一", "标签二"]` | 同为选项名数组 |
43
- | 人员 | `[{"id":"ou_..."}]`,由当前 CLI 通讯录查询取得 open_id | `[{"id":"内部 user_id"}]`,由 starter 人员选择器的 `User.user_id` 取得 |
44
- | 日期时间 | 按当前 lark-base CellValue 文档确认带时区文本、Base 时区文本或毫秒值的支持形态;命令帮助只提供常用文本示例 | 按[FaaS CellValue](faas.md#base-读写协议)格式提交 |
74
+ | 人员 | `[{"id":"ou_..."}]`,由当前 CLI 通讯录查询取得 open_id | `[{"id":"User.user_id"}]`,由 starter 人员选择器的 `User.user_id` 取得 |
75
+ | 日期时间 | 按当前 lark-base CellValue 协议确认支持形态 | 按[FaaS CellValue](faas.md#base-读写协议)格式提交 |
45
76
 
46
77
  两条写入链路的格式不能直接互用,也不能仅替换 ID 前缀。最小 CLI 请求示例(字段名、选项和 ID 均需替换为真实查询结果):
47
78
 
48
79
  ```json
49
- {"create_records":[{"任务名称":"示例:准备评审","状态":["待处理"],"负责人":[{"id":"ou_example"}]}]}
80
+ {"create_records":[{"任务名称":"示例:准备评审","状态":"待处理","负责人":[{"id":"ou_example"}]}]}
50
81
  ```
51
82
 
52
83
  1. 从 `catalog.json` 读取真实 `baseToken`、table ID、字段类型和选项。先通过项目路由执行 `base-database-cli lark-cli -- base +field-list --base-token <base-token> --table-id <table-id>` 核对可写字段,再使用 `base-database-cli lark-cli -- base +record-batch-create --base-token <base-token> --table-id <table-id> --json '<payload>'` 写入已经设计的示例数据。当前环境提供等价的 Base Database CLI 命令时只替换命令前缀,不改变 `lark-cli` shortcut、参数或 payload;没有项目级路由时才直接执行同名 `lark-cli base +... --as user`。只写存储字段,单批不超过 200 条,不写 formula、lookup、系统字段或附件。
53
84
  2. `--json` 使用 `{"create_records":[{...}]}`;成功必须返回与请求数量一致的 `record_id_list`,并检查可选 `ignored_fields`。多表或有关联记录时按真实依赖串行写入,后续关联只使用前一步返回的 record ID。
54
- 3. 存在列表、详情、看板、统计等业务数据展示时,通过项目路由调用页面实际使用的 SQL Function,而不是用 `+record-list` 代替展示链路验收:`base-database-cli lark-cli -- api POST /open-apis/base/v3/sites/<app-token>/invoke_function/<function-id> --params '{"env":"preview"}' --data '{"params":[...]}' --json`。检查 Function 顶层业务码与 ResultJSON,并确认刚写入的示例记录、关系和统计真实可见。
55
- 4. 重复验证或修复后重试前,先用同一 SQL Function 按稳定示例标记或已返回的 record ID 确认当前状态,只补写缺失数据。创建结果未知时禁止盲目重试,避免生成重复记录。
56
- 5. `lark-cli` 写入失败、返回记录数不符、SQL Function 返回非零业务码、响应结构不符合契约,或查询不到已确认写入的数据,都视为示例数据闭环未完成。保存脱敏错误和 LogID;写入问题检查 Catalog、字段、CellValue、关联 ID 和权限,查询问题检查 SQL、参数及响应解析。实现问题修复后重新 `deploy`,再从本节第 1 步验证。
57
- 6. 只有认证、权限或平台服务存在证据充分的外部阻塞时才标记 `blocked`;不得声称示例数据或整体从零建站已完成。示例写入与 SQL 回读均通过后,才进入通知 workflow 收尾并向用户交付 Preview。
85
+ 3. 存在列表、详情、看板、统计等业务数据展示时,通过项目路由调用页面实际使用的 Database Function,而不是用 `+record-list` 代替展示链路验收:`base-database-cli lark-cli -- api POST /open-apis/base/v3/sites/<app-token>/invoke_function/<function-id> --params '{"env":"preview"}' --data '{"params":[...]}' --json`。CLI 输出外层是 lark-cli 的 `ok`/`data`:`ok:true` 时 `data` 才是 Function 的 `{code,msg,data}` 信封,非零业务码会变成 `ok:false` 并在 `error` 中给出;判定方式见[开发期与运行态输出](development.md#开发期与运行态输出)。检查 Function 顶层业务码与 ResultJSON,并确认刚写入的示例记录、关系和统计真实可见。
86
+ 4. 重复验证或修复后重试前,先用同一 Database Function 按稳定示例标记或已返回的 record ID 确认当前状态,只补写缺失数据。创建结果未知时禁止盲目重试,避免生成重复记录。
87
+ 5. `lark-cli` 写入失败、返回记录数不符、Database Function 返回非零业务码、响应结构不符合契约,或查询不到已确认写入的数据,都视为示例数据闭环未完成。保存脱敏错误和 LogID;写入问题检查 Catalog、字段、CellValue、关联 ID 和权限,查询问题检查查询语句、参数及响应解析。实现问题修复后重新 `deploy`,再从本节第 1 步验证。
88
+ 6. 只有认证、权限或平台服务存在证据充分的外部阻塞时才标记 `blocked`;不得声称示例数据或整体从零建站已完成。示例写入与 Database Function 回读均通过后,才进入通知 workflow 收尾并向用户交付 Preview。
58
89
 
59
90
  该闭环不需要浏览器,也不替代用户对 Page 真实写入流程、交互状态和 UI 的 E2E 验收,更不构成 Prod 发布授权。不得读取、输出或代填用户凭证。
60
91
 
@@ -66,24 +97,20 @@ CLI 负责 Function metadata、全量 SQL 校验、必要依赖安装、Page/Faa
66
97
  base-database-cli deploy --production --yes
67
98
  ```
68
99
 
69
- CLI 读取 `.base-database-cli/state/preview.json`,校验 应用 appToken、Artifact SHA-256 与工作区输入指纹,发布同一份制品,不重建或上传替代品。缺少 Preview 记录、旧回执缺少指纹、制品或源码/配置/文件结构变化时,重新生成 Preview 并取得针对新制品的确认。`--yes` 只是向 CLI 传递已有授权。
70
-
71
- Prod 发布不会自动更新 Base workflow。存在通知集成时,按 Preview 留存的清单逐个完成[生产入口切换](notifications.md#生产入口切换)。切换失败则明确报告“Prod 已发布,但通知入口切换未完成”,保存失败对象与证据;不重复发布 应用 来掩盖外部配置失败。
100
+ CLI 读取 `.base-database-cli/state/preview.json`,校验应用 appToken、Artifact SHA-256 与工作区输入指纹,发布同一份制品,不重建或上传替代品。缺少 Preview 记录、旧回执缺少指纹或未经过 README 校验、制品或源码/配置/文件结构变化时,重新生成 Preview 并取得针对新制品的确认。`--yes` 只是向 CLI 传递已有授权。
72
101
 
73
- ## 应用能力 Skill 安装
102
+ Prod 发布不会自动更新 Base workflow。存在通知集成时,按 Preview 留存的清单逐个完成[生产入口切换](notifications.md#生产入口切换)。切换失败则明确报告“Prod 已发布,但通知入口切换未完成”,保存失败对象与证据;不重复发布应用来掩盖外部配置失败。
74
103
 
75
- 普通 deploy 在本次 Preview / Prod 轮询成功后,CLI 自动从模板生成并安装/更新本应用专属 Skill,到当前执行用户的 `$CODEX_HOME/skills`(未配置时为 `~/.codex/skills`)。同一 应用 和平台环境使用固定目录,只更新本工具管理的 SKILL.md,不覆盖附加文件或其他 Skill;不需要 Agent 另行重复安装。
76
-
77
- 交付时先读取 `agentGuide.skill.status`:installed/updated 时报告 name、path 与入口;failed 时只报告 error,不读取不存在的 name 或宣称已安装。结合 agentGuide.message 说明使用条件;先确认路径属于目标客户端的 Skill 发现目录,目录正确但未刷新时再提示刷新或开启新会话。Preview 安装的 Skill 仍只发现正式版,不代表本次 Preview,也不授权自动发现、调用 Function 或发布 Prod。
78
-
79
- 通过 deployments status(含 --wait)确认成功,仅证明原发布任务成功;该命令不安装本应用 Skill,也不返回 agentGuide。缺少安装证据时报告“安装状态未确认”,需要补装时使用[应用能力 Skill 安装命令](database-capability-skill.md#安装与恢复),不重新 deploy。
104
+ ## 交付结果
80
105
 
81
- 安装失败不会撤销已成功的发布,单独报告原因。修复、重新生成或安装到其他客户端时读取[应用能力 Skill](database-capability-skill.md),不重新部署掩盖安装问题。托管环境的执行用户目录不等于终端用户电脑,不能把沙箱安装描述成已安装到用户本机。
106
+ 默认按用户使用顺序交付,内容以本次实际完成和验证的范围为准:
82
107
 
83
- ## 交付结果
108
+ 1. **状态与入口**:说明是 Preview 还是已获授权的 Prod,以及完成、部分完成或阻塞状态。访问链接只使用本次成功发布的 CLI 返回的 `baseAppUrl`;发布未成功或入口缺失时不猜测链接。`staticUrl`、制品地址和 Builder iframe 地址仅用于内部预览与追溯。
109
+ 2. **业务结果与体验**:列出本次实现的功能或变更,以及用户可直接执行的体验步骤。新建 Base 的示例数据说明覆盖的业务对象和页面 Database Function 回读结果;复用或修改已有应用时不声称添加了示例数据。
110
+ 3. **验证与待处理项**:逐项说明实际通过的检查及其范围;未执行的页面交互、角色权限或生产验证标为未验证。失败、结果未知、通知未完成时,给出具体影响和下一步,不把 Preview 发布成功等同于整个任务完成。
84
111
 
85
- 默认提供访问链接、业务功能或本次变更、用户可执行的体验步骤、实际通过的验证以及影响使用的限制。示例数据要说明覆盖的业务对象和回读结果;命令、Function ID、制品摘要、workflow 清单保留为可追溯证据,按研发或排障需要展示,不要求业务用户检查 header 或 SDK 协议。
112
+ 命令、Function ID、制品摘要和 workflow 清单保留为可追溯证据,按研发或排障需要展示,不要求业务用户检查 header 或 SDK 协议。
86
113
 
87
- 明确区分发布成功、验证通过、整体完成;未验证不等于失败,也不等于通过。示例数据或关键业务检查未完成时,不报告整体完成:可交付部分结果标记 partial,存在外部阻塞才标记 blocked;定义见[完成条件](../SKILL.md#完成条件)。
114
+ 交付状态按[完成条件](../SKILL.md#完成条件)判定;示例数据或本次约定的关键业务检查未完成时,不报告整体完成。
88
115
 
89
- 普通 Preview 交付后等待用户体验;后续用户提出修改或诊断时继续相应工作。Prod 交付使用本次生产 `baseAppUrl`,附件需求按[文件传输](file-transfer.md)核对目标环境支持范围,不把尚未开通或未验证的能力写成已实现。
116
+ Prod 交付使用本次生产 `baseAppUrl`,附件需求按[文件传输](file-transfer.md)核对目标环境支持范围,不把尚未开通或未验证的能力写成已实现。
@@ -1,6 +1,6 @@
1
1
  # Base Database 工程质量
2
2
 
3
- 本文汇总业务系统、数据、后端与前端的稳定设计原则。具体平台命令见[工程与环境](workspace.md),Page 协议见[Page 开发](development.md),写入协议见[FaaS](faas.md),视觉设计见[前端设计指导](frontend-design-guide.md)。
3
+ 本文汇总业务系统、数据、后端与前端的稳定设计原则。具体平台命令见[工程与环境](workspace.md),Page 协议见[Page 开发](development.md),基础写入见[Mutation](mutations.md#写入方式选择),FaaS 写入协议见[FaaS](faas.md),视觉设计见[前端设计指南](frontend-design-guide.md)。
4
4
 
5
5
  ## 业务与数据设计
6
6
 
@@ -13,74 +13,17 @@
13
13
 
14
14
  信息不完整时推导最小、自洽的设计,并在交付中说明关键假设。只有数据所有权、权限、安全或核心流程存在实质歧义时才询问用户。
15
15
 
16
- ## 数据链路
16
+ ## 实现协议
17
17
 
18
- - Base 是业务事实源,不在 Page 或 FaaS 维护同一份主数据。
19
- - 读取优先使用 SQL Function;搜索、筛选、分页、关联和聚合下推到 SQL。
20
- - SQL Function 按一次用户操作同步需要的数据包划分,不按表或页面区块机械拆分;前一个 SQL 只为后一个 SQL 提供关联 ID 时优先合并。
21
- - SQL 能完成的计算不放进 FaaS,也不拉全表到 Page 再计算;避免整表读取和 N+1 查询。
22
- - 创建、更新、删除、权限校验和状态转换使用 FaaS。
23
- - FaaS 需要读取时复用固定 SQL Function;页面和 FaaS 不使用 Base records 读 OpenAPI。
24
- - 公式和 lookup 只承载需要长期显示在 Base 中的派生结果,避免重复保存易漂移数据。
18
+ - Database Function 查询、分页、聚合与结果合并按[Database Function](database-function.md);公式和 lookup 只承载需要长期显示在 Base 中的派生结果,避免重复保存易漂移数据。
19
+ - FaaS 写入的一致性、调用依赖、部分成功与重试按[FaaS 协议](faas.md#远程调用与写入链路设计);Mutation 的结果见[调用与结果](mutations.md#调用与结果)。
20
+ - 读写权限分别按[权限设计](permission-design.md);布局、控件与交互状态按[前端设计指南](frontend-design-guide.md)。
25
21
 
26
- ## FaaS 一致性与调用链
22
+ ## 工程与交付
27
23
 
28
- - 每个写入 operation 先定义成功条件、一致性要求、是否允许部分成功和失败后的重试边界,再选择实现方式。
29
- - 实现前列出远程调用及依赖;无依赖的 SQL、用户信息等无副作用读取先同时启动,在共同消费结果的位置汇合。
30
- - 使用满足业务语义的最短远程调用链。写前查询、写后回读和补偿请求只有在能够降低明确且不可接受的业务风险时才加入。
31
- - 同一张表的多条操作优先使用批量接口;不同表或不同请求之间没有数据依赖时并发执行,只有后一步依赖前一步结果时才串行。
32
- - 允许弱一致性时,可以复用页面已经取得的非安全敏感状态;身份、权限、租户隔离和其他关键约束必须由服务端可信数据确认。
33
- - Base 不具备事务、唯一约束或原子条件更新能力时,不用“先查再写”、失败回滚等多次请求模拟强一致性;业务依赖这些能力时记录限制;只有用户明确同意改变后端架构时才采用其他存储。
34
- - 多路写入必须区分全部成功、部分成功和全部失败。未知结果或非幂等创建不自动整体重试,避免产生重复记录。
35
-
36
- ## 后端与安全
37
-
38
- - 一个 FaaS Function 对应一个明确业务动作;输入从 `unknown` 校验。
24
+ - 修改现有系统时保留需求外 operation、框架、包管理器、锁文件、路径别名和 CSS 体系。
39
25
  - 应用 appToken、table ID、字段名、origin、method、project ID 和 function ID 固定在代码中。
40
- - 按 operation 契约校验身份、权限、字段、状态转换和批量数量;只有底层存在可靠幂等原语时才承诺严格幂等,失败返回稳定业务码与可读信息。
41
- - 当前访问者的查询权限使用 SQL `CURRENT_USER_ID()`,不相信页面传入的用户 ID。
26
+ - 保持 Vite 相对路径部署配置;production build 关闭 source map,公开制品不包含凭证、调试信息、`node_modules` 或嵌套 `dist`。
42
27
  - 不记录或返回 token、secret、cookie 和不必要的敏感数据。
43
- - 修改现有系统时保留需求外 operation、包管理器、锁文件和目录结构。
44
-
45
- ## 前端工程
46
-
47
- - 按业务能力组织页面、组件和 operation;组件不同时承担路由、请求、表单和复杂展示。
48
- - 修改现有页面时保留框架、包管理器、锁文件、路径别名和 CSS 体系。
49
- - 只引入解决当前问题的依赖;简单格式化、日期转换或局部状态不增加重型库。
50
- - 导航、标题、筛选、主要操作和内容容器优先渲染;远端区域分别处理 loading、empty、error、forbidden 和 success。
51
- - 互不依赖的请求并行;详情、历史、弹窗和非当前 tab 按需加载。
52
- - 搜索防抖并取消过时请求;旧响应不能覆盖新筛选状态。
53
- - 写入期间禁用重复提交;成功后只刷新受影响的列表、指标或详情。
54
- - 轮询设置停止条件、最大时长和卸载清理。
55
-
56
- ### React
57
-
58
- - 可从 props/state 推导的值不放进 Effect 或重复 state;用户动作由事件处理器触发。
59
- - 状态放在最接近使用的位置;列表使用稳定业务 ID。
60
- - 确认性能瓶颈后再使用 `memo`、`useMemo` 或 `useCallback`。
61
- - 大列表使用服务端分页、窗口化或分段渲染;低频重型功能按需加载。
62
-
63
- ### 资源、性能与安全
64
-
65
- - 保持 Vite 相对路径部署配置;production build 关闭 source map。
66
- - 非首屏图片懒加载并声明尺寸;字体只加载实际字重和字符集;第三方脚本不进入首屏。
67
- - 公开制品不包含凭证、调试信息、`node_modules` 或嵌套 `dist`。
68
- - 脱敏真实响应可作为布局 fixture,但不能替代用户对 Preview 的体验。
69
-
70
- ## 可访问性与交互状态
71
-
72
- - 使用语义化 HTML;表单有可感知 label,图标按钮有 accessible name,错误提示关联对应字段。
73
- - 核心任务支持键盘和清晰焦点;弹窗管理焦点进入、陷阱和关闭恢复。
74
- - 颜色不是唯一状态信号;正文和控件保持可读对比度,点击目标适合触屏。
75
- - 窄屏下主要列表、表单和操作可到达;尊重 `prefers-reduced-motion`。
76
- - loading、空、部分数据、错误、无权限和成功都有明确 UI。
77
- - 图片类附件的缩略图可点击查看大图,查看入口与下载入口分开;换更高清晰度而非取原文件,实现见[文件传输](file-transfer.md)。
78
-
79
- ## 验收质量
80
-
81
- - Preview 的 production build、SQL 编译校验和发布状态由 `base-database-cli deploy` 统一完成。
82
- - 检查核心 operation 中连续出现的远程 `await`:后一个调用必须真实依赖前一个响应;仅用于取得关联 ID 的串行 SQL 优先合并,输入已确定的无副作用请求必须并发。
83
- - 首屏和核心交互检查远程往返次数;在实现评审中说明实际依赖和必要拆分,不将内部调用拓扑作为普通用户必读的交付内容。
84
- - 页面无 starter 文案、无效按钮、伪成功状态和未使用依赖。
85
-
86
- 参考:[React Effect 边界](https://react.dev/learn/you-might-not-need-an-effect)、[Vite 性能](https://vite.dev/guide/performance)。
28
+ - 页面无 starter 文案、无效按钮和伪成功状态。脱敏响应可用于布局 fixture;实际验证范围与完成状态按[发布与交付](release.md)。
29
+ - 图片附件的预览与下载按[文件传输](file-transfer.md);缩略图提供查看大图入口,查看与下载分开。
@@ -4,21 +4,21 @@
4
4
 
5
5
  ## 确定范围
6
6
 
7
- 记录目标 应用、环境、工程来源、出错动作和预期结果。优先复用已有工程与日志;资源不明时按[工程与环境](workspace.md)定位。区分构建/SQL 校验、发布、Page 加载、Function 执行、原生配置及权限问题,再读取对应协议。
7
+ 记录目标应用、环境、工程来源、出错动作和预期结果。优先复用已有工程与日志;资源不明时按[工程与环境](workspace.md)定位。区分构建/查询校验、发布、Page 加载、Function 执行、原生配置及权限问题,再读取对应协议。
8
8
 
9
9
  | 失败阶段 | 首先检查 | 恢复边界 |
10
10
  | --- | --- | --- |
11
11
  | 命令或认证 | 当前版本、help、身份与具体授权错误 | 按当前 CLI 文档恢复原身份,不自动切 bot |
12
12
  | 初始化/恢复 | 已创建资源、宿主来源、配置和本地文件 | 创建结果未知先确认现状,不以重跑 init 掩盖失败 |
13
- | SQL 校验 | Catalog、参数声明、失败节点与支持集 | 缩小到具体错误,不通过猜参数类型绕过 |
13
+ | 查询校验 | Catalog、参数声明、失败节点与支持集 | 缩小到具体错误,不通过猜参数类型绕过 |
14
14
  | 构建 | Page/FaaS 编译错误、依赖与模板调用契约 | 修复实现,不伪造类型让错误协议编译通过 |
15
15
  | 发布 | publish ID、真实状态、制品与返回入口 | 使用[发布任务查询](#发布任务查询)确认现状,不盲目启动第二次发布 |
16
- | Page/Function | HTTP 状态、业务码、输入输出与 invoke LogID | 按 [Page](development.md)、[SQL](sql-function.md)、[FaaS](faas.md) 分层定位;旧工程或 CSRF 失败按[专项检查](#旧工程与-csrf-排查)处理 |
16
+ | Page/Function | HTTP 状态、业务码、输入输出与 invoke LogID | 按 [Page](development.md)、[Database Function](database-function.md)、[Mutation](mutations.md)、[FaaS](faas.md) 分层定位;旧工程或 CSRF 失败按[专项检查](#旧工程与-csrf-排查)处理 |
17
17
  | 通知与原生配置 | 目标资源完整定义、入口、状态与失败节点 | 按[通知状态](notifications.md#状态与失败处理)保留授权范围 |
18
18
 
19
19
  ## 发布任务查询
20
20
 
21
- 部署输出已给出 publish ID,但等待超时或进程中断时,在该 应用 的工程目录执行:
21
+ 部署输出已给出 publish ID,但等待超时或进程中断时,在该应用的工程目录执行:
22
22
 
23
23
  ```bash
24
24
  base-database-cli deployments status <publish-id>
@@ -27,22 +27,28 @@ base-database-cli deployments status <publish-id> --wait
27
27
 
28
28
  首条查询一次,`--wait` 轮询至成功或失败/超时。命令也接受第二个位置参数作为工程目录,并读取其中的 `base-database.jsonc`。publish ID 来自本次部署输出或已确认属于该任务的记录,不能以历史回执中的其他 ID 代替。
29
29
 
30
- 状态 `0/1` 表示处理中,`10` 表示成功,`20` 表示失败。查询成功不等于发布成功,按 status 判断;成功后使用返回的 `baseAppUrl`。失败、未知状态或再次超时先保存证据,再决定修复,不自动再次 deploy。没有 publish ID 时先检查已有输出和任务记录,不通过创建新发布寻找结果。
31
-
32
- 状态查询不安装或更新应用能力 Skill,也不返回 `agentGuide`。恢复发布成功后按[安装与恢复](database-capability-skill.md#安装与恢复)处理安装证据;不能把发布成功当作已安装,也不能为补安装重新 deploy。
30
+ 返回的 `statusText` 为 `pending`、`processing`、`succeeded`、`failed` 或 `unknown`,对应数字 `status` 的 `0`、`1`、`10`、`20`。查询成功不等于发布成功,按 `statusText` 判断;成功后使用返回的 `baseAppUrl`。失败、未知状态或再次超时先保存证据,再决定修复,不自动再次 deploy。没有 publish ID 时先检查已有输出和任务记录,不通过创建新发布寻找结果。
33
31
 
34
32
  ## 旧工程与 CSRF 排查
35
33
 
36
- 1. 先区分浏览器请求、父页面代理与 FaaS 下游失败,排除登录、资源权限和业务参数问题。单独的 403 不足以判定为 CSRF,也不是无条件升级依赖的依据。
37
- 2. 检查恢复工程的 `page/vite.config.ts` 是否从 `@lark-base-open/base-site-js/vite` 引入并配置 `createArgusCsrfPlugin()`,以及当前依赖是否实际导出该函数。插件缺失时按当前 starter 接入;依赖不具备该能力时升级到与 starter 兼容的版本并更新锁文件,不复制插件实现。
38
- 3. 核对构建后的 HTML 是否注入 Argus Runtime,并在可用浏览器中检查脚本是否加载成功。请求缺少 `x-secsdk-csrf-token` 时沿插件配置、依赖能力、构建注入和运行时加载定位;已正确接入却仍失败时保留诊断证据,继续检查加载或平台问题,不反复升级。
39
- 4. 修复配置或依赖后重新构建并发布 Preview,按授权范围复验对应写入路径。没有运行态条件时仅报告已完成的静态修复和待验证项,不宣称问题已解决;Prod 仍需针对新制品确认。
34
+ 更新 CLI 或 Skill 不会自动改写已有工程;`pull` 恢复的是应用保存的源码,可能仍包含旧依赖和构建配置。
35
+
36
+ 1. 迁移旧工程时,先确认业务 HTTP、Function 和附件调用均通过 `page/src/lib/database-runtime.ts` 接入 `@lark-base-open/base-site-channel/runtime`,按当前 starter 补齐宿主接入,保留业务逻辑。
37
+ 2. 移除 `page/vite.config.ts` 中来自 `@lark-base-open/base-site-js/vite` 的导入和 `createArgusCsrfPlugin()`,确认没有其他旧 SDK 引用后删除 `page/package.json` 中的 `@lark-base-open/base-site-js` 并更新锁文件。清理旧工程自行复制的 Argus 注入代码或 HTML 脚本,构建配置以当前 starter 为准。
38
+ 3. 请求失败时,区分 Page 到父页面的代理通信、父页面实际发出的请求和 FaaS 下游失败,核对登录、资源权限、业务参数、HTTP/业务码与 LogID。业务请求的身份与 CSRF 处理属于宿主;单独的 403 不足以判定为 CSRF,也不是向 Page 补装旧 SDK 或注入 CSRF 脚本的依据。
39
+ 4. 修改后重新安装依赖、构建并发布 Preview,在实际宿主页面中按授权范围复验受影响的读取、写入和附件调用。没有运行态条件时报告本地验证结果和待验证项;Prod 仍需针对新制品确认。
40
40
 
41
- 不得手写 `x-secsdk-csrf-token`、复制插件实现、读取或输出用户凭证来绕过检查。
41
+ Page 不读取宿主 Cookie、不手写 CSRF Header,也不通过直连业务域名绕过宿主。宿主请求仍失败时保留脱敏证据继续定位,不把构建通过当作运行态验证通过。
42
42
 
43
43
  ## 验证方法
44
44
 
45
- 静态检查、构建、SQL 编译、部署成功分别证明对应阶段,不证明完整业务链路。新建 Base 的常规验证或发布后补齐示例数据,先完整读取并执行[示例数据验收](release.md#从零建站示例数据验收),其中包含 CLI 写入格式和页面 SQL 回读的实际路径;用户明确要求运行态验收时可以追加本次范围内的只读 SQL 调用和可用浏览器检查。
45
+ 通过 `base-database-cli lark-cli -- api ... --json` 调用 Function 时,输出外层是 lark-cli 的 `ok`/`data`;`ok:true` 时 `data` 才是 Function 的 `{code,msg,data}` 信封,非零业务码会以 `ok:false` 加 `error` 返回。按[开发期与运行态输出](development.md#开发期与运行态输出)逐层判定,不把外层 `ok` 当作业务成功,也不因缺少顶层 `code` 判定协议不符。
46
+
47
+ 静态检查、构建、查询编译、部署成功分别证明对应阶段,不证明完整业务链路。新建 Base 的常规验证或发布后补齐示例数据,先完整读取并执行[示例数据验收](release.md#从零建站示例数据验收),其中包含 CLI 写入格式和页面 Database Function 回读的实际路径;用户明确要求运行态验收时可以追加本次范围内的只读 Database Function 调用和可用浏览器检查。
48
+
49
+ `base-database-cli check` 只覆盖项目结构、Database Function/FaaS metadata、依赖锁与 Page/FaaS 本地构建,不调用远端 `ai-functions validate`,也不校验 `ai/<functionKey>/meta.json` 的配置合法性;即使 `check` 通过,也只能报告 Page/FaaS 本地可编译,不能声称 AI Function 配置已验证。每个本地 AI Function 都要单独执行 `ai-functions validate <functionKey>`,得到 `is_success: true` 才算完成静态校验;缺少认证/model_profiles 时报告未验证项并继续。
50
+
51
+ `deploy` 按本地 `ai/` 全集同步 AI Function;空 `ai/` 时自动跳过,不调 AI Function 接口,未涉及 AI 的应用无需开通。需要让本次发布完全不动 AI Function 时加 `--skip-ai-functions`(Preview、Prod 均适用),并在交付或验收报告中说明 AI Function 未同步且未验证,不宣布其已上线。
46
52
 
47
53
  写入验收先确认目标、测试数据和用户授权,尤其已有 Base、业务通知和不可逆操作。不得仅为测试而创建生产业务记录或外发消息。用户要求的写入验证完成后,清理仍遵守同一资源操作的授权要求。
48
54