@lark-apaas/coding-miaoda-sandbox-skills 0.1.0-dev.28c4f05 → 0.1.0-dev.4e64c13

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 (140) hide show
  1. package/miaoda/animation-skill/SKILL.md +348 -0
  2. package/miaoda/authz-cli/SKILL.md +1 -0
  3. package/miaoda/charts-skill/SKILL.md +264 -0
  4. package/miaoda/creative-to-fullstack/SKILL.md +157 -0
  5. package/miaoda/creative-to-fullstack/references/artifact-signals.md +46 -0
  6. package/miaoda/creative-to-fullstack/references/ui-to-function.md +134 -0
  7. package/miaoda/data-analysis/SKILL.md +151 -0
  8. package/miaoda/data-analysis/references/json-output-specification.md +277 -0
  9. package/miaoda/data-analysis/references/post-analysis-guide.md +77 -0
  10. package/miaoda/data-analysis/references/python-analysis-reference.md +272 -0
  11. package/miaoda/data-analysis/references/tmp-file-management-guide.md +100 -0
  12. package/miaoda/debug-investigation/SKILL.md +21 -18
  13. package/miaoda/extract-json-schema/SKILL.md +147 -0
  14. package/miaoda/lark-apps/SKILL.md +37 -0
  15. package/miaoda/lark-apps/references/openapi-key.md +80 -0
  16. package/miaoda/lark-apps-authz/SKILL.md +292 -0
  17. package/miaoda/lark-apps-authz/references/permission-points.md +39 -0
  18. package/miaoda/lark-apps-authz/references/role.md +122 -0
  19. package/miaoda/lark-apps-db/SKILL.md +226 -0
  20. package/miaoda/lark-apps-db/references/full-reference.md +302 -0
  21. package/miaoda/lark-apps-file/SKILL.md +216 -0
  22. package/miaoda/lark-apps-ops/SKILL.md +62 -0
  23. package/miaoda/lark-apps-ops/references/lark-apps-access-scope-get.md +30 -0
  24. package/miaoda/lark-apps-ops/references/lark-apps-access-scope-set.md +40 -0
  25. package/miaoda/lark-apps-ops/references/lark-apps-cache.md +62 -0
  26. package/miaoda/lark-apps-ops/references/lark-apps-env.md +46 -0
  27. package/miaoda/lark-apps-ops/references/lark-apps-local-dev.md +25 -0
  28. package/miaoda/lark-apps-ops/references/lark-apps-member.md +93 -0
  29. package/miaoda/lark-apps-ops/references/lark-apps-observability.md +46 -0
  30. package/miaoda/lark-apps-ops/references/lark-apps-plugin-install.md +36 -0
  31. package/miaoda/lark-apps-ops/references/lark-apps-plugin-list.md +23 -0
  32. package/miaoda/lark-apps-ops/references/lark-apps-plugin-uninstall.md +25 -0
  33. package/miaoda/lark-apps-ops/references/lark-apps-release-create.md +30 -0
  34. package/miaoda/lark-apps-ops/references/lark-apps-release-get.md +28 -0
  35. package/miaoda/lark-apps-ops/references/lark-apps-release-list.md +31 -0
  36. package/miaoda/lark-apps-ops/references/lark-apps-update.md +30 -0
  37. package/miaoda/lark-apps-ops/references/openapi-key.md +80 -0
  38. package/miaoda/miaoda-file/SKILL.md +1 -0
  39. package/miaoda/miaoda-sql/SKILL.md +6 -2
  40. package/miaoda/performance-review/SKILL.md +144 -0
  41. package/miaoda/performance-review/references/business-analyzer.md +139 -0
  42. package/miaoda/performance-review/references/examples.md +107 -0
  43. package/miaoda/reviewer-usage/SKILL.md +111 -0
  44. package/miaoda/testing-guide/SKILL.md +218 -0
  45. package/miaoda-design/lark-apps-comment/SKILL.md +110 -0
  46. package/miaoda-design/lark-apps-ops/SKILL.md +45 -0
  47. package/miaoda-design/lark-apps-ops/references/lark-apps-release-create.md +51 -0
  48. package/miaoda-design/lark-apps-ops/references/lark-apps-release-get.md +28 -0
  49. package/miaoda-design/lark-apps-ops/references/lark-apps-release-list.md +31 -0
  50. package/miaoda-design/lark-apps-ops/references/lark-apps-update.md +33 -0
  51. package/{shared → miaoda-modern}/lark-apps/SKILL.md +5 -5
  52. package/miaoda-modern/lark-apps/references/openapi-key.md +80 -0
  53. package/miaoda-modern/lark-apps-ops/SKILL.md +62 -0
  54. package/miaoda-modern/lark-apps-ops/references/lark-apps-access-scope-get.md +30 -0
  55. package/miaoda-modern/lark-apps-ops/references/lark-apps-access-scope-set.md +40 -0
  56. package/miaoda-modern/lark-apps-ops/references/lark-apps-cache.md +62 -0
  57. package/miaoda-modern/lark-apps-ops/references/lark-apps-env.md +46 -0
  58. package/miaoda-modern/lark-apps-ops/references/lark-apps-local-dev.md +25 -0
  59. package/miaoda-modern/lark-apps-ops/references/lark-apps-member.md +93 -0
  60. package/miaoda-modern/lark-apps-ops/references/lark-apps-observability.md +46 -0
  61. package/miaoda-modern/lark-apps-ops/references/lark-apps-plugin-install.md +36 -0
  62. package/miaoda-modern/lark-apps-ops/references/lark-apps-plugin-list.md +23 -0
  63. package/miaoda-modern/lark-apps-ops/references/lark-apps-plugin-uninstall.md +25 -0
  64. package/miaoda-modern/lark-apps-ops/references/lark-apps-release-create.md +30 -0
  65. package/miaoda-modern/lark-apps-ops/references/lark-apps-release-get.md +28 -0
  66. package/miaoda-modern/lark-apps-ops/references/lark-apps-release-list.md +31 -0
  67. package/miaoda-modern/lark-apps-ops/references/lark-apps-update.md +30 -0
  68. package/{shared/lark-apps → miaoda-modern/lark-apps-ops}/references/openapi-key.md +3 -3
  69. package/miaoda-modern/memory/SKILL.md +86 -0
  70. package/package.json +1 -1
  71. package/shared/lark-cli/SKILL.md +221 -0
  72. package/shared/lark-cli/lark-base/README.md +56 -0
  73. package/shared/lark-cli/lark-base/references/lark-base-commands.md +108 -0
  74. package/shared/lark-cli/lark-calendar/README.md +158 -0
  75. package/shared/lark-cli/lark-calendar/references/lark-calendar-meeting.md +30 -0
  76. package/shared/lark-cli/lark-calendar/references/lark-calendar-room-find.md +108 -0
  77. package/shared/lark-cli/lark-calendar/references/lark-calendar-suggestion.md +120 -0
  78. package/shared/lark-cli/lark-contact/README.md +35 -0
  79. package/shared/lark-cli/lark-contact/references/lark-contact-get-user.md +13 -0
  80. package/shared/lark-cli/lark-contact/references/lark-contact-search-user.md +121 -0
  81. package/shared/lark-cli/lark-doc/README.md +67 -0
  82. package/shared/lark-cli/lark-doc/references/lark-doc-fetch.md +138 -0
  83. package/shared/lark-cli/lark-doc/references/lark-doc-history.md +61 -0
  84. package/shared/lark-cli/lark-drive/README.md +129 -0
  85. package/shared/lark-cli/lark-drive/references/lark-drive-files-list.md +183 -0
  86. package/shared/lark-cli/lark-im/README.md +84 -0
  87. package/shared/lark-cli/lark-im/references/lark-im-chat-list.md +140 -0
  88. package/shared/lark-cli/lark-im/references/lark-im-chat-members-list.md +84 -0
  89. package/shared/lark-cli/lark-im/references/lark-im-chat-search.md +135 -0
  90. package/shared/lark-cli/lark-im/references/lark-im-reactions.md +232 -0
  91. package/shared/lark-cli/lark-minutes/README.md +51 -0
  92. package/shared/lark-cli/lark-minutes/references/lark-minutes-download.md +130 -0
  93. package/shared/lark-cli/lark-sheets/README.md +173 -0
  94. package/shared/lark-cli/lark-sheets/references/lark-sheets-changeset.md +105 -0
  95. package/shared/lark-cli/lark-sheets/references/lark-sheets-chart.md +45 -0
  96. package/shared/lark-cli/lark-sheets/references/lark-sheets-conditional-format.md +42 -0
  97. package/shared/lark-cli/lark-sheets/references/lark-sheets-filter-view.md +49 -0
  98. package/shared/lark-cli/lark-sheets/references/lark-sheets-filter.md +42 -0
  99. package/shared/lark-cli/lark-sheets/references/lark-sheets-float-image.md +43 -0
  100. package/shared/lark-cli/lark-sheets/references/lark-sheets-formula-verify.md +64 -0
  101. package/shared/lark-cli/lark-sheets/references/lark-sheets-history.md +70 -0
  102. package/shared/lark-cli/lark-sheets/references/lark-sheets-pivot-table.md +44 -0
  103. package/shared/lark-cli/lark-sheets/references/lark-sheets-read-data.md +216 -0
  104. package/shared/lark-cli/lark-sheets/references/lark-sheets-search-replace.md +67 -0
  105. package/shared/lark-cli/lark-sheets/references/lark-sheets-sheet-structure.md +52 -0
  106. package/shared/lark-cli/lark-sheets/references/lark-sheets-sparkline.md +47 -0
  107. package/shared/lark-cli/lark-sheets/references/lark-sheets-workbook.md +69 -0
  108. package/shared/lark-cli/lark-sheets/scripts/sheets_df.py +32 -0
  109. package/shared/lark-cli/lark-slides/README.md +86 -0
  110. package/shared/lark-cli/lark-slides/references/lark-slides-history.md +105 -0
  111. package/shared/lark-cli/lark-slides/references/lark-slides-xml-presentation-slide-get.md +108 -0
  112. package/shared/lark-cli/lark-slides/references/lark-slides-xml-presentations-get.md +77 -0
  113. package/shared/lark-cli/lark-task/README.md +93 -0
  114. package/shared/lark-cli/lark-task/references/lark-task-get-my-tasks.md +57 -0
  115. package/shared/lark-cli/lark-task/references/lark-task-get-related-tasks.md +49 -0
  116. package/shared/lark-cli/lark-task/references/lark-task-search.md +36 -0
  117. package/shared/lark-cli/lark-task/references/lark-task-tasklist-search.md +35 -0
  118. package/shared/lark-cli/lark-vc/README.md +40 -0
  119. package/shared/lark-cli/lark-vc/references/lark-vc-recording.md +31 -0
  120. package/shared/lark-cli/lark-whiteboard/README.md +35 -0
  121. package/shared/lark-cli/lark-whiteboard/references/lark-whiteboard-export.md +59 -0
  122. package/shared/lark-cli/lark-wiki/README.md +50 -0
  123. package/shared/lark-cli/lark-wiki/references/lark-wiki-node-get.md +59 -0
  124. package/shared/lark-cli/lark-wiki/references/lark-wiki-node-list.md +95 -0
  125. package/shared/lark-cli/lark-wiki/references/lark-wiki-space-list.md +68 -0
  126. package/miaoda-design/attachment/SKILL.md +0 -58
  127. /package/{shared → miaoda}/memory/SKILL.md +0 -0
  128. /package/{shared → miaoda-modern}/animation-skill/SKILL.md +0 -0
  129. /package/{shared → miaoda-modern}/charts-skill/SKILL.md +0 -0
  130. /package/{shared → miaoda-modern}/data-analysis/SKILL.md +0 -0
  131. /package/{shared → miaoda-modern}/data-analysis/references/json-output-specification.md +0 -0
  132. /package/{shared → miaoda-modern}/data-analysis/references/post-analysis-guide.md +0 -0
  133. /package/{shared → miaoda-modern}/data-analysis/references/python-analysis-reference.md +0 -0
  134. /package/{shared → miaoda-modern}/data-analysis/references/tmp-file-management-guide.md +0 -0
  135. /package/{shared → miaoda-modern}/extract-json-schema/SKILL.md +0 -0
  136. /package/{shared → miaoda-modern}/performance-review/SKILL.md +0 -0
  137. /package/{shared → miaoda-modern}/performance-review/references/business-analyzer.md +0 -0
  138. /package/{shared → miaoda-modern}/performance-review/references/examples.md +0 -0
  139. /package/{shared → miaoda-modern}/reviewer-usage/SKILL.md +0 -0
  140. /package/{shared → miaoda-modern}/testing-guide/SKILL.md +0 -0
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: lark-apps-db
3
+ description: "Use when 在妙搭沙箱里用 `lark-cli apps +db-*` 管理【当前这个已存在的】妙搭应用的 PostgreSQL 数据库:建表/改表、写或排查 RLS policy、用 +db-execute 执行 SQL(SELECT/DML/DDL)、灌 mock 数据、数据导入导出、dev/online 多环境初始化与发布、DDL 变更历史(changelog)、行级审计(audit)、PITR 时间点恢复、DB 配额。触发词:应用数据库, SQL, 建表, 改表, mock 数据, 示例数据, 数据审计, 变更历史, 数据恢复, PITR, 时间点恢复, 多环境发布, RLS, policy, pgPolicy, 行级权限, 权限策略, 42501, +db-, db-table-list, db-execute."
4
+ metadata:
5
+ requires:
6
+ bins: ["lark-cli"]
7
+ cliHelp: "lark-cli apps --help; lark-cli apps +db-table-list --help(各 +db-* 子命令同理)"
8
+ control-by-feature-ab: true
9
+ # AppInit 只做需求理解与概要设计,不建表灌数;且其触发词(建表 / mock 数据 / 示例数据)
10
+ # 在概要设计阶段极易误命中,把「读飞书资源」的意图抢走。
11
+ unavailable-agents:
12
+ - AppInit
13
+ gate-tools:
14
+ - tool: bash
15
+ when-contains:
16
+ command: "lark-cli apps +db"
17
+ ---
18
+
19
+ # lark-apps-db
20
+
21
+ 妙搭应用数据库操作速查(`lark-cli apps +db-*` 通道):优先用 `+db-*` 专用子命令,只有 DDL / DML / SELECT 才手写 SQL 走 `+db-execute`。
22
+
23
+ ## 沙箱约定(先读)
24
+
25
+ - **命令名**:一律 `lark-cli apps +db-*`;命令/flag 细节以 `--help` 为准。
26
+ - **app_id 走环境变量**:所有 `+db-*` 都必填 `--app-id "$app_id"`;应用已存在、id 在环境变量 `app_id` 里,不要自行获取、解析或选择。
27
+ - **鉴权自动**:apps 域请求由运行环境自动打到 innerAPI 并注入鉴权头。**不要** `auth login` / `config init` / `--as`。
28
+ - **不要裸连数据库**:不要从环境变量里取连接串直连数据库;本地调试同样走 `+db-execute`。
29
+ - **失败处理**:命令失败时把 `error.hint` 转述给用户,别原样甩 envelope JSON。
30
+
31
+ ### 高风险写操作审批(exit 10)
32
+
33
+ `risk: high-risk-write` 的命令(`+db-env-create` / `+db-data-import` / `+db-env-migrate` / `+db-recovery-apply` / `+db-execute`)不带 `--yes` 会 **exit 10** 并返回 `confirmation_required`。处理:
34
+
35
+ 1. 识别 exit code=10 且 `error.type=="confirmation_required"`;
36
+ 2. 把 `error.risk.action` + 关键参数给用户,明确"高风险/不可逆",等显式同意;
37
+ 3. 同意 → 原始 argv 末尾加 `--yes` 重试;拒绝 → 终止;
38
+ 4. 想先看请求 → `--dry-run`(不触发门禁、不需 `--yes`);发布/恢复先跑对应预览命令(`+db-env-diff` / `+db-recovery-diff`)。
39
+
40
+ **绝不**看到 exit 10 就默认补 `--yes` 静默重试。
41
+
42
+ ## Quick Reference
43
+
44
+ | 场景 | 首选命令 | 关键规则 |
45
+ |---|---|---|
46
+ | 列表 / 查表结构 | `lark-cli apps +db-table-list --app-id "$app_id"` / `+db-table-get --app-id "$app_id" --table <table>` | 禁止用 `information_schema` / `pg_indexes` 模拟常规结构查询 |
47
+ | 执行 DDL / DML / SELECT | `lark-cli apps +db-execute --app-id "$app_id" --sql "<query>" --yes` | 不自动包事务,原子性自己写 `BEGIN…COMMIT` |
48
+ | 批量导入 CSV / JSON | `lark-cli apps +db-data-import --app-id "$app_id" --file ./<file> --table <table> --yes` | 目标表已存在;表头 / key 与列名完全一致;≤1 MB / ≤5000 行;无 upsert |
49
+ | 批量导出 | `lark-cli apps +db-data-export --app-id "$app_id" --table <table> --output ./<file>` | 格式由 `--output` 扩展名决定(.csv/.json/.sql);5000 行守卫 + 1 MB 上限 |
50
+ | 表结构变更历史 | `lark-cli apps +db-changelog-list --app-id "$app_id"` | DDL 维度:CREATE / ALTER / DROP / INDEX |
51
+ | 表数据变更历史 | `lark-cli apps +db-audit-status --app-id "$app_id"`;enable / disable / list 另需 `--table <table>` | DML 维度:INSERT / UPDATE / DELETE;需按表启用。两者都禁止直查 `pg_audit` 模拟 |
52
+ | 单库拆 dev/online 多环境(高危) | `lark-cli apps +db-env-create --app-id "$app_id" [--sync-data] --yes` | 不可逆;新建 full_stack 应用一般已自带多环境;执行后必须回读 `+db-table-list --environment dev` 确认结构已同步 |
53
+ | dev→online 结构发布(高危) | `lark-cli apps +db-env-diff --app-id "$app_id"` → `+db-env-migrate --app-id "$app_id" --yes` | 只发布 DDL |
54
+ | PITR 恢复(高危) | `lark-cli apps +db-recovery-diff --app-id "$app_id" --target <时间点>` → `+db-recovery-apply --app-id "$app_id" --target <时间点> --yes` | `--target` 必填;覆盖式不可逆;窗口最长 7 天 |
55
+ | DB 用量 | `lark-cli apps +db-quota-get --app-id "$app_id"` | 查容量、表数、视图数 |
56
+
57
+ **环境**:`--environment dev|online` **默认不传**——省略时由服务端按应用形态自动选分支(多环境应用走 `dev`,未开多环境的走 `online`);要固定环境才显式传。**唯一会报错的组合是对未开多环境的应用显式传 `--environment dev`**(无 `dev` 分支,报 `Invalid DB Branch`)。旧名 `--env` 已移除,一律用 `--environment`。`+db-env-diff` / `+db-env-migrate`(dev→online 语义)与 `+db-recovery-*`(作用于当前库)没有 `--environment`。
58
+
59
+ **何时打开 reference**:各命令完整 flags / 分页 / 输出契约、`+db-execute` 多语句与事务语义、导入导出边界与限额、audit/changelog/env/recovery/quota 参数、时间格式、系统表白名单、user_profile 唯一表达式、pg function、JSONB 复杂注释等长尾限制 → 见 [full-reference.md](references/full-reference.md)。
60
+
61
+ ## Hard Rules
62
+
63
+ | 规则 | 要求 |
64
+ |---|---|
65
+ | SQL 执行通道 | 只用 `+db-execute`,不要裸连数据库或调用其它 SQL 工具 |
66
+ | 查结构只认 DB | 表结构 / 字段 / 索引 / 约束一律 `+db-table-list` / `+db-table-get --table <table>`。`server/database/schema.ts` 只在写 TS 代码对齐类型时读,**不能用来回答结构问题**——它是生成产物,可能滞后于 DB |
67
+ | `schema.ts` 禁止手改 | DB 结构不对就改 DDL 后重跑 codegen;DB 正确但 `schema.ts` 渲染错误时同样不手改,向用户说明是 codegen bug |
68
+ | 变更历史只认 DB | 结构变更历史用 `+db-changelog-list`。`git log -- server/database/schema.ts` 只是代码侧痕迹,**不等价**,不能用来回答"做过哪些 DDL 改动" |
69
+ | 要数据就查库 | 用户要的是查询结果本身(计数 / 明细 / 统计)时,直接 `+db-execute` 查完把结果给用户;**不要为一次性查询去新增接口或 service 代码** |
70
+ | DDL 原子性 | CREATE TABLE + RLS + policy + COMMENT + INDEX 放在一次 `--sql` 调用;需要全回滚时显式 `BEGIN; ... COMMIT;` |
71
+ | 高风险授权 | DDL、DELETE/TRUNCATE、`+db-env-create` / `+db-env-migrate` / `+db-recovery-apply` 执行前必须向用户展示影响范围并取得明确授权;exit-10 按沙箱约定协议处理 |
72
+ | `--yes` 边界 | 只跳过 CLI 确认关卡,不能代替用户授权 |
73
+ | 线上发布 / 恢复 | `+db-env-migrate` / `+db-recovery-apply` 前先跑 `+db-env-diff` / `+db-recovery-diff` 预览并给用户确认 |
74
+ | 已有数据安全 | 已有表 / 已有数据禁止直接 DROP / DELETE;优先 ALTER / UPDATE;不确定先问用户 |
75
+ | 环境选择 | **默认不传 `--environment`**,由服务端自动选分支;只有已确认应用开了多环境时才显式传 `dev` 验写操作——对未开多环境的应用传 `dev` 必报错 |
76
+ | 平台保留对象 | 禁止创建或修改 `auth`、`users` 等平台保留表;禁止 DROP 平台审计列 |
77
+ | 业务人员字段 | 业务需要“创建人 / 负责人”字段时命名为 `creator` / `owner` / `author`,避免与审计列混淆 |
78
+ | 本地文件路径 | `--file` / `--output` 用工作目录内相对路径;绝对路径或经 `..`/符号链接越出工作目录会被拒 |
79
+
80
+ ## CREATE TABLE Template
81
+
82
+ 新建业务表必须包含 4 个审计列、启用 RLS、创建 4 条默认 policy。
83
+
84
+ ```sql
85
+ CREATE TABLE IF NOT EXISTS <table> (
86
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
87
+ -- ... business columns ...
88
+ name varchar(100) NOT NULL,
89
+ _created_at TIMESTAMP(3) WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
90
+ _created_by user_profile DEFAULT (
91
+ CASE
92
+ WHEN current_setting('app.user_id', TRUE) = '' THEN NULL
93
+ ELSE concat('(', current_setting('app.user_id', TRUE), ')')::user_profile
94
+ END
95
+ ),
96
+ _updated_at TIMESTAMP(3) WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
97
+ _updated_by user_profile DEFAULT (
98
+ CASE
99
+ WHEN current_setting('app.user_id', TRUE) = '' THEN NULL
100
+ ELSE concat('(', current_setting('app.user_id', TRUE), ')')::user_profile
101
+ END
102
+ )
103
+ );
104
+
105
+ ALTER TABLE <table> ENABLE ROW LEVEL SECURITY;
106
+
107
+ CREATE POLICY service_role_bypass_policy ON <table>
108
+ TO service_role USING (true);
109
+
110
+ CREATE POLICY "修改全部数据" ON <table>
111
+ AS PERMISSIVE FOR ALL TO authenticated USING (true);
112
+
113
+ CREATE POLICY "查看全部数据" ON <table>
114
+ AS PERMISSIVE FOR SELECT TO authenticated, anon USING (true);
115
+
116
+ CREATE POLICY "修改本人数据" ON <table>
117
+ AS PERMISSIVE FOR ALL TO authenticated USING (
118
+ (current_setting('app.user_id'::text) = ANY (ARRAY[]::text[]))
119
+ AND (current_setting('app.user_id'::text) = ((_created_by).user_id)::text)
120
+ );
121
+ ```
122
+
123
+ 建表流程:`+db-table-list/get` 确认不存在或需变更 -> 生成 DDL -> 用户授权 -> `+db-execute --sql "<ddl>" --yes` 执行 -> 插入 mock -> 必要时重跑 codegen 刷新 `schema.ts`。
124
+
125
+ ## DDL Rules
126
+
127
+ ### DDL Workflow
128
+
129
+ 1. 先 `lark-cli apps +db-table-list --app-id "$app_id"` 判断表是否存在;已有表再 `+db-table-get --app-id "$app_id" --table <table>` 看 DDL / columns / indexes / comments(`--format pretty` 直接给建表 DDL)。
130
+ 2. 生成 DDL 时只写裸表名,不写 `public.` 或 workspace schema。
131
+ 3. CREATE TABLE 必须带审计列、RLS、4 条默认 policy;JSONB 字段必须在同一次调用里写 `COMMENT ON COLUMN ... IS '@type { ... }'`。
132
+ 4. CREATE TABLE / CREATE INDEX / ALTER TABLE ADD COLUMN 必须带 `IF NOT EXISTS`,避免重复执行失败。
133
+ 5. 执行前向用户展示目标对象和变更内容;DROP / DROP COLUMN 还要说明数据丢失风险并取得明确授权。
134
+ 6. 执行:`lark-cli apps +db-execute --app-id "$app_id" --sql "<ddl>" --yes`。多条 DDL 是一个逻辑单元时放在一次调用;需要全回滚则显式包事务。
135
+
136
+ ### DDL Do / Don't
137
+
138
+ | 场景 | 做法 |
139
+ |---|---|
140
+ | 新建表 | 用本 skill CREATE TABLE Template,一次包含 RLS、policy、COMMENT、INDEX |
141
+ | 修改表 | `ALTER TABLE <table> ADD COLUMN IF NOT EXISTS ...`,相关 COMMENT 同次执行 |
142
+ | 加索引 | `CREATE INDEX IF NOT EXISTS idx_<table>_<cols> ON <table>(...)` |
143
+ | JSONB 类型 | `COMMENT ON COLUMN t.payload IS '@type { key: string }'`(会据此生成 ORM 代码中的 ts 类型) |
144
+ | 删除表 / 列 | 已有业务数据默认禁止;用户明确授权后才执行 |
145
+
146
+ ## SQL Pitfalls
147
+
148
+ | 陷阱 | 正确做法 |
149
+ |---|---|
150
+ | 表名带 schema 前缀 | 业务表一律裸表名:`SELECT ... FROM user_profile`,不要写 `public.t` |
151
+ | 保留字作标识符 | 避免 `user`、`order`、`desc`、`offset`、`references` 等 |
152
+ | `IF NOT EXISTS` 滥用 | 支持:CREATE TABLE / INDEX / EXTENSION、ALTER TABLE ADD COLUMN;不支持:CREATE TYPE / POLICY / ADD CONSTRAINT |
153
+ | 审计列写错 | 列名是 `_created_at` / `_updated_at` / `_created_by` / `_updated_by`,查询不要写 `created_at` |
154
+ | user_profile 未解引用 | 查询 / 过滤用 `(field).user_id`;raw SQL 不直接返回复合类型给前端 |
155
+ | user_profile 表达式索引 / 唯一性 | 索引用三重括号:`CREATE INDEX ... ON t (((owner).user_id))`;表达式唯一性用 `CREATE UNIQUE INDEX`,不要用 `ALTER TABLE ADD CONSTRAINT UNIQUE` |
156
+ | UUID 手写 | 主键用 `DEFAULT gen_random_uuid()`;INSERT 不手写 UUID,外键用子查询取父表 id |
157
+ | MySQL 方言 | 不用 `SHOW TABLES` / `DESCRIBE` / 内联 `COMMENT`;改用 `+db-table-list/get` 和 `COMMENT ON` |
158
+ | 空数组类型不明 | 写 `ARRAY[]::text[]` 或 `'{}'::text[]` |
159
+ | 标量子查询多行 | `VALUES((SELECT ...))` / `SET col=(SELECT ...)` 必须唯一或 `ORDER BY ... LIMIT 1` |
160
+ | 系统表查询 | 常规结构查询用 `+db-table-list/get`;系统表仅限 reference 中列出的白名单 |
161
+ | 多语句事务误判 | `A; B; C` 不自动包事务,B 失败时 A 不回滚;需要原子性用 `BEGIN/COMMIT` |
162
+
163
+ ## Data Types and Design
164
+
165
+ | 项目 | 规则 |
166
+ |---|---|
167
+ | 主键 | 默认 `id UUID PRIMARY KEY DEFAULT gen_random_uuid()`;人员实体表可用 `user_profile PRIMARY KEY` |
168
+ | 命名 | 单数、全小写、snake_case、无冗余后缀 |
169
+ | 短文本 | 分类 / 状态 / 枚举用 `varchar(255)`,值用小写英文 + 下划线 |
170
+ | JSONB | 必须 `COMMENT ON COLUMN ... IS '@type { ... }'` 声明 TypeScript 类型;复杂格式见 reference |
171
+ | 强约束 | UNIQUE / FOREIGN KEY / NOT NULL 默认谨慎,不确定时不用;加 NOT NULL 列必须带 `DEFAULT` 让存量行自动填默认值:`ALTER TABLE <table> ADD COLUMN <col> <type> NOT NULL DEFAULT <默认值>` |
172
+ | 附件 / 图片 | URL 用 `TEXT`,命名 `xxx_url`;图片 mock 遵循下方 generate_image 规则 |
173
+
174
+ ## Mock Data Rules
175
+
176
+ | 规则 | 要求 |
177
+ |---|---|
178
+ | 数量 | 新建表默认插 3-6 条(除非用户明确不要);现有表仅用户要求时造数据;要求更多时单表最多 20 条,再多走 `+db-data-import` |
179
+ | 字段一致性 | 页面 / 业务会读的同表字段必须都在 SQL mock 中提供,禁止一半 DB 一半代码拼 |
180
+ | user_id 来源 | 上下文明确 user_id > `env.userId` / `env.user.id` > 测试用户列表;禁止编造 |
181
+ | 图片 URL | 写入数据库的任何图片字段,包括 JSONB 内嵌图片,都按“用户上传图 -> 历史语义匹配图 -> `generate_image`”顺序处理;只有工具失败才用带 seed 的 Picsum 兜底 |
182
+ | 关联 | 外键 / 子查询引用的数据必须已存在;UUID 字段不用手写 |
183
+ | 审计列 | `_created_at` / `_updated_at` 可省略;需要归属时显式写 `_created_by` / `_updated_by` |
184
+
185
+ 测试用户(**只用于数据库 `user_profile` 列**):`1847292357012580` 张伟、`1847292986161210` 李明、`1838411738368010` 刘洋、`1847292458018820` 赵丽、`1847286122258458` 孙强、`1846114399229988` John Smith、`1847298549409911` Emma Johnson、`1847291727560708` Michael Brown、`1848568929333380` Robert Wilson、`1847751107397639` Maria Garcia。
186
+
187
+ > ⚠️ 这些是妙搭数字 user_id,**不是飞书 open_id**。禁止传给 `lark-cli apps +role-member-add` / `+role-member-remove` 的 `--users`(只收 `ou_` 开头的 open ID),也禁止传给任何需要 open_id 的飞书接口——传了会被直接拒绝。
188
+
189
+ ### `user_id` / `user_profile`
190
+
191
+ - `user_id` 是高频写入规则,不是长尾 reference:只能来自上下文明确给定、`env.userId` / `env.user.id`,或上方测试用户列表,禁止编造。
192
+ - 写入 `user_profile` 字段用 `ROW('<user_id>')::user_profile`;更新复合类型时替换整个字段。
193
+ - 查询、过滤、索引 `user_profile` 时只使用 `(field).user_id`;不要依赖 `name` / `email` / `avatar` / `status`。
194
+
195
+ ## SELECT Rules
196
+
197
+ 常规查询(含 `count(*)` 这类计数)直接用 `lark-cli apps +db-execute --app-id "$app_id" --sql "SELECT ..." --yes`,查完把结果给用户;查结构走 `+db-table-list/get`,不走 SELECT。
198
+
199
+ | 规则 | 要求 |
200
+ |---|---|
201
+ | 字段 | 禁止 `SELECT *`;只返回页面 / 逻辑需要的列 |
202
+ | 行数 | SELECT 返回 1000 行硬上限;必须显式 `LIMIT` 或聚合 |
203
+ | 分页 | 大表优先游标分页:`WHERE id > <last_id> ORDER BY id LIMIT n`,避免大 OFFSET |
204
+ | 统计 | 总数用 `count(*)`;分组用 `GROUP BY`;避免拉全量到 agent 侧统计 |
205
+ | 慢查询 | 用 `EXPLAIN (ANALYZE, BUFFERS)`;大表 Seq Scan 时考虑加索引 |
206
+ | PostgreSQL 函数 | `ROUND` 用 `ROUND(num::numeric, n)` 或 `ROUND(num::double precision)` |
207
+
208
+ ## DML Rules
209
+
210
+ | 操作 | 规则 |
211
+ |---|---|
212
+ | INSERT | NOT NULL 且无默认值的列必须提供,批量 INSERT 每行列数一致;需要幂等用 `ON CONFLICT ... DO NOTHING` / `DO UPDATE`(mock 数量、UUID / user_id 来源、审计列写法见 Mock Data Rules) |
213
+ | UPDATE | 必须有明确 WHERE,禁止无条件 UPDATE;用户说"修改 / 更新 / 改一下"数据时用 UPDATE,禁止 DELETE + INSERT;修改业务字段时同步 `_updated_at = CURRENT_TIMESTAMP` 和 `_updated_by`;影响范围不明先 `SELECT count(*)` 给用户确认 |
214
+ | DELETE / TRUNCATE | 当前会话中 Agent 自己插入的 mock 可删;已有表 / 已有数据默认禁止,必须先 `SELECT count(*)` 展示命中行数并取得用户明确授权;`TRUNCATE` 影响整表,视同高风险删除 |
215
+
216
+ ```sql
217
+ INSERT INTO task (title, status, assignee, _created_by, _updated_by)
218
+ VALUES
219
+ ('梳理需求', 'open', ROW('1847292357012580')::user_profile, ROW('1847292357012580')::user_profile, ROW('1847292357012580')::user_profile),
220
+ ('完成设计', 'doing', ROW('1847292986161210')::user_profile, ROW('1847292357012580')::user_profile, ROW('1847292357012580')::user_profile)
221
+ ON CONFLICT (title) DO NOTHING;
222
+ ```
223
+
224
+ ## Import / Export
225
+
226
+ 前置检查、值类型、冲突、限额与 `.sql` 回放写法见 [full-reference.md](references/full-reference.md)。
@@ -0,0 +1,302 @@
1
+ # lark-apps-db Reference
2
+
3
+ 本 reference 只承接 [`../SKILL.md`](../SKILL.md) 未展开的细节:`lark-cli apps +db-*` 各命令完整 flags、输出契约、错误处理、环境约定、时间格式、少见 PostgreSQL 限制、import/export 边界。DDL / SELECT / DML 的常用规则与沙箱约定(`$app_id`、鉴权、exit-10 审批)以 [`../SKILL.md`](../SKILL.md) 为准。运行时命令事实以 `lark-cli apps +<cmd> --help` 为准。
4
+
5
+ ## `+db-execute`(SQL 唯一执行通道)
6
+
7
+ 经妙搭服务端在应用数据库执行 SQL。不要从环境变量里取连接串裸连数据库;本地调试也走这个命令。
8
+
9
+ ### 命令骨架
10
+
11
+ - 必填:`--app-id`(沙箱里用 `"$app_id"`),以及 `--sql` / `--file` 二选一(互斥)。
12
+ - `--sql`:内联 SQL 文本;传 `-` 时从 stdin 读。绝对路径文件经 stdin 传入:`--sql - < <absolute-path>`(shell 解析路径,CLI 仅接收内容)。
13
+ - `--file`:`.sql` 文件路径,需为工作目录内的相对路径(如 `--file ./migration.sql`);绝对路径、或经 `..`/符号链接越出工作目录的路径会被拒绝。文件不在工作目录内时,改用 `--sql - < <文件路径>` 经 stdin 传入。
14
+ - risk 是 `high-risk-write`(SQL 可含 DML/DDL):任何执行都需 `--yes`,否则返回 `confirmation_required` / exit 10。`--dry-run` 预览不需要 `--yes`。
15
+ - **不会自动包事务,事务边界需自己在 SQL 里控制**:多语句默认逐条独立提交,中间某条失败时前序语句已生效、不会回滚;若需要「要么全部成功、要么全部回滚」的原子性,在 SQL 内显式写 `BEGIN … COMMIT`。
16
+
17
+ ```bash
18
+ lark-cli apps +db-execute --app-id "$app_id" --environment dev --sql "select * from orders limit 5" --yes
19
+ lark-cli apps +db-execute --app-id "$app_id" --environment dev --file ./migration.sql --dry-run
20
+ # 绝对路径文件 / cwd 不固定:经 stdin 传入
21
+ lark-cli apps +db-execute --app-id "$app_id" --environment dev --sql - --yes < /path/to/migrations/0001_init.sql
22
+ ```
23
+
24
+ ### 输出契约
25
+
26
+ - 成功默认 JSON 的 `data` 按 SQL 类型自适应(不透传后端原始串):
27
+ - 单 SELECT → `data` 是行数组 `[{...}]`(空 → `[]`),直接 `-q '.data[].col'` 取字段。
28
+ - 单 DML → `data = {command, rows_affected}`(如 `{"command":"INSERT","rows_affected":1}`)。
29
+ - 单 DDL → `data = {command}`(如 `{"command":"CREATE_TABLE"}`)。
30
+ - 多语句 → `data` 是元素数组:SELECT 为 `{command:"SELECT", rows:[...]}`,DML 为 `{command, rows_affected}`,DDL 为 `{command}`。
31
+ - pretty 会按 SELECT/DML/DDL 自适应渲染;多语句会逐条显示 Statement 摘要。
32
+ - 失败返回 typed `error`(`type:"api"`、`subtype:"server_error"`、`code`、`message`、`hint`):失败位置在 `message` 的「(at statement N of M)」;前序是否落地 / 是否整批回滚写在 `hint`——事务内失败「Transaction rolled back; no changes persisted.」;非事务多语句前序已落地「Earlier statements were committed and not rolled back; fix statement N and re-run the remaining statements.」;首句即失败(无前序落地)「No statements were applied; fix the SQL and re-run.」。据此决定整段重跑还是只跑剩余语句。
33
+
34
+ ### 执行规则
35
+
36
+ - 该命令为 high-risk-write,执行一律需 `--yes`;无 `--yes` 会返回 `confirmation_required` / exit 10。
37
+ - **只读查询、以及不删除/不丢失既有数据且可撤回的语句**:已授权时可直接带 `--yes` 执行。
38
+ - **会删除或丢失既有数据、或难以撤回的语句**:先 `--dry-run` 预览(无需 `--yes`),向用户确认后再带 `--yes` 执行;不要在用户不知情时自动补 `--yes`。
39
+ - 多语句失败时,失败前的语句可能已经 commit 落地。不要整批重跑;按错误 message/hint 修失败语句,并从剩余语句继续。
40
+ - `+db-execute` 完全透传 SQL:平台不会自动补审计列、RLS、policy、COMMENT 或 trigger。
41
+
42
+ ## 表与结构
43
+
44
+ **`+db-table-list`**:列出某环境的数据表。分页 `--page-size`(默认 20)/ `--page-token`(上一页 cursor)。每项给表名、描述、估算行数、大小、列数;要完整列定义 / 索引 / 约束用 `+db-table-get`。只知道业务对象名时,先用它定位可能的表名。
45
+
46
+ **`+db-table-get`**:看单张表的结构,`--table` 必填。默认 JSON 给结构化的字段 / 索引 / 约束 / 估算行数 / 大小;`--format pretty` 直接输出建表 DDL 文本(给用户看建表语句或做迁移参照时用)。
47
+
48
+ 常规结构查询禁止用 `information_schema.columns` / `pg_indexes` 手写模拟。
49
+
50
+ ```bash
51
+ lark-cli apps +db-table-list --app-id "$app_id" --environment dev --page-size 50
52
+ lark-cli apps +db-table-get --app-id "$app_id" --table orders
53
+ lark-cli apps +db-table-get --app-id "$app_id" --table orders --environment dev --format pretty
54
+ ```
55
+
56
+ ## 环境与通用约定
57
+
58
+ - **环境 `--environment dev|online`(可省略)**:看表、看结构、数据导入导出、变更追溯、审计、配额都按环境区分。省略 `--environment` 时 CLI 不带该参数、由服务端按应用形态自动选分支——多环境应用走 `dev`、未开多环境的走 `online`;要固定环境才显式传。**唯一会报错的组合:对未开多环境的应用显式传 `--environment dev`(无 `dev` 分支)**。写操作建议先在 `dev` 验(仅多环境应用有 `dev`)。旧名 `--env` 已**移除**:传入会报 validation 错(提示改用 `--environment`),一律用 `--environment`。`+db-env-diff`/`+db-env-migrate` 是「dev→online 发布」语义、`+db-recovery-*` 作用于当前库,二者**没有** `--environment`。
59
+ - **本地文件 / `--output` 用工作目录内相对路径**:导入 `--file ./orders.csv`、导出 `--output ./out.csv`;绝对路径、或经 `..`/符号链接越出工作目录的 `--output` 会被拒(validation / exit 2)。路径在别处先 `cd` 过去或改成相对路径。
60
+ - **高危操作必须带 `--yes`**:`+db-env-create`、`+db-data-import`、`+db-env-migrate`、`+db-recovery-apply`、`+db-execute` 缺省会被确认关卡拦下(exit 10);动手前先用对应的预览命令或 `--dry-run` 看清影响。
61
+ - 全局 `--format json|pretty` 只控制**命令自身输出**(成功摘要 / 错误信封)的渲染,**不影响导出文件的格式**。
62
+ - 服务端 SQL 错误码(如语法错误、表 / 列不存在、结果集超限、超时、命中禁用 SQL 等)经 typed `error` 的 `code` / `message` / `hint` 返回;`hint` 优先级高,先按 hint 修复再重试。
63
+
64
+ ## SQL 限制与服务端错误码
65
+
66
+ | 约束 | 说明 |
67
+ |---|---|
68
+ | SELECT 1000 行硬上限 | 超过报错,无隐式截断;用 LIMIT、聚合或游标分页 |
69
+ | 单语句 5000 行 / 1 MB 上限 | 超过需用 LIMIT、聚合或分批 |
70
+ | 多语句不自动包事务 | 需要原子性显式 `BEGIN/COMMIT`;失败定位与前序落地情况见上方 `+db-execute` 输出契约 |
71
+ | NULL 表达 | JSON 输出为原生 `null`;pretty / 管道输出为字面字符串 `NULL` |
72
+
73
+ 服务端错误码经 typed `error` 的 `code` 返回,`hint` 优先级高、先按 hint 修复再重试:
74
+
75
+ | 错误码 | 触发场景 |
76
+ |---|---|
77
+ | `SYNTAX_ERROR` | SQL 语法错误 |
78
+ | `TABLE_NOT_FOUND` | 表不存在 |
79
+ | `COLUMN_NOT_FOUND` | 列不存在 |
80
+ | `RESULT_SET_TOO_LARGE` | SELECT 超过 1000 行 |
81
+ | `STATEMENT_TIMEOUT` | 服务端超时强制中断 |
82
+ | `SQL_OPERATION_FORBIDDEN` | 命中平台禁用 SQL(见下文 Platform Forbidden SQL) |
83
+ | `EXTENSION_NOT_WHITELISTED` | `CREATE EXTENSION` 不在白名单 |
84
+ | `FILE_ALREADY_EXISTS` | 导出目标文件已存在;换一个不存在的 `--output` 路径重试(lark-cli 侧无 `--force` 覆盖选项) |
85
+ | `IMPORT_TABLE_NOT_FOUND` | 导入目标表不存在 |
86
+ | `IMPORT_COLUMN_MISMATCH` | CSV 表头 / JSON key 与表字段不匹配 |
87
+ | `IMPORT_PK_CONFLICT` | 导入主键冲突,已回滚 |
88
+ | `IMPORT_TYPE_MISMATCH` | 导入类型不匹配,已回滚 |
89
+ | `IMPORT_FORMAT_UNSUPPORTED` | 文件扩展名非 `.csv` / `.json` |
90
+ | `IMPORT_FILE_NOT_FOUND` | 本地导入文件不存在 |
91
+ | `AUDIT_ALREADY_ENABLED` | 重复启用同一表 audit |
92
+ | `AUDIT_NOT_ENABLED` | 未启用 audit 却 disable / list |
93
+ | `INVALID_TIMESTAMP` | recovery 时间格式不合法 |
94
+
95
+ ## 数据导入导出
96
+
97
+ **`+db-data-export`**:把一张表导出到本地文件。导出格式**只由 `--output` 的扩展名决定**——`.csv` / `.json` / `.sql`,缺省按 `<表名>.csv` 落在当前目录。`--output` 后缀必须是 `.csv/.json/.sql` 之一,否则报 validation 错误(exit 2),且不支持导出到 stdout。两道体量约束:
98
+
99
+ - `--limit`(1..5000,默认 5000)是**行数上限守卫**:表的行数超过它会被整体拒掉(不是「只导前 N 行」);
100
+ - 导出产物 >1 MB 也会被拒。
101
+
102
+ 超大表别硬导:先用 `+db-execute` 加 `WHERE` / `LIMIT` 缩小范围、分批导。
103
+
104
+ 若命中「导出成功但文件静默 0 行」且表名 / 列名含非纯 ASCII 字符(中文表名、中文列名等):workaround 是先把表 / 列 rename 成 ASCII,或改用 `+db-execute` 跑 `SELECT col AS ascii_alias ...` 取数后自行落盘。(该行为未实测,命中时再按此处理。)
105
+
106
+ **`+db-data-import`(高危,需 `--yes`)**:把本地 csv/json 文件的数据导进表。文件需是 `.csv`/`.json`、≤1 MB。目标表缺省取文件名去掉**最后一个**扩展名(如 `orders.csv`→`orders`,`orders.2026.csv`→`orders.2026`);文件名带点号时建议显式传 `--table` 以免落到意外的表名。
107
+
108
+ **导入/导出限额**:体积 ≤ **1 MB**、行数 ≤ **5000**,导入导出都一样,超限会被拒。超限就分批——导入拆成 ≤1 MB / ≤5000 行的多个文件,导出用 `WHERE` / `LIMIT` 缩小范围。
109
+
110
+ 导入前置与值类型:目标表已存在;CSV 表头 / JSON 顶层 key 与表字段名完全一致;JSON 空值用 `null`、CSV 空值留空单元格;`INTEGER` / `BIGINT` 在 JSON 中建议写字符串或改 CSV,避免裸数字 / 科学计数被当浮点拒收;CSV 每行列数必须与表头一致,含逗号 / 换行 / 引号的字段用双引号包裹;主键 / 唯一键冲突会整批回滚,先导前 SELECT 查重或改用 SQL `ON CONFLICT`。来源是 Excel 或其它格式时,先转 CSV 再导。
111
+
112
+ ```bash
113
+ lark-cli apps +db-data-export --app-id "$app_id" --table orders --output ./orders.csv
114
+ lark-cli apps +db-data-export --app-id "$app_id" --table orders --output ./orders.json --environment dev
115
+ lark-cli apps +db-data-import --app-id "$app_id" --table orders --file ./orders.csv --environment dev --yes
116
+ ```
117
+
118
+ SQL 格式回放:导出的 `.sql` 产物用 `+db-execute --file ./file.sql --yes`(或 `--sql - < file.sql`),不要走 `+db-data-import`。
119
+
120
+ ## 变更追溯与审计
121
+
122
+ **`+db-changelog-list`**:查表结构变更(DDL)历史——谁、什么时候、改了哪张表、做了什么(CREATE / ALTER / DROP TABLE、CREATE / DROP INDEX 等)。全应用默认开启,无需启用。可按 `--table` 过滤、按 `--change-id` 精确定位某条、用 `--since`/`--until` 圈时间区间,分页 `--page-size`/`--page-token`。禁止直接查询或模拟 `pg_audit`。
123
+
124
+ **`+db-audit-status`**:看审计开关状态。给 `--table` 看单表,不给则列出所有已配置的表(开没开、保留期)。
125
+
126
+ **`+db-audit-enable` / `+db-audit-disable`**:开 / 关某张表的行级变更审计。`--retention` 设保留期,取值 `7d`/`30d`/`180d`/`360d`/`forever`(默认 `7d`)。不要对已经开启审计的表重复 enable——不确定就先用 `+db-audit-status` 查。
127
+
128
+ **`+db-audit-list`**:列出表的行级变更事件(INSERT/UPDATE/DELETE 的前后值与操作人)。`--table` 必填、可重复传多张表;`--since`/`--until` 圈时间。
129
+ - **多表查询**:会先帮用户把不存在、或没开审计的表过滤掉再查,被过滤的表及原因列在结果的 `skipped` 里——据此告诉用户哪些表没纳入及为什么。
130
+ - **单表查询**:不预过滤,表不存在 / 未开审计会直接报错(按 `error.hint` 转述给用户,引导先 `+db-audit-enable`)。
131
+
132
+ ```bash
133
+ lark-cli apps +db-changelog-list --app-id "$app_id" --table orders --since 7d
134
+ lark-cli apps +db-audit-enable --app-id "$app_id" --table orders --retention 30d
135
+ lark-cli apps +db-audit-disable --app-id "$app_id" --table orders
136
+ lark-cli apps +db-audit-list --app-id "$app_id" --table orders --since 24h
137
+ lark-cli apps +db-audit-list --app-id "$app_id" --table orders --table users
138
+ ```
139
+
140
+ ## 多环境数据库(初始化 + 发布)
141
+
142
+ **`+db-env-create`(高危,需 `--yes`)**:把存量单库应用初始化为 dev/online 两套库,不可逆。`--environment` 目前只支持 `dev`(默认 `dev`);`--sync-data` 把现有 online 数据复制到新环境(不传则不复制)。新建的 full_stack 应用通常已自带多环境,重复初始化会返回冲突错误(应用已是多环境)——按 `error.hint` 转述状态即可,别重复初始化。
143
+
144
+ **`+db-env-diff`**:预览开发环境里待发布到线上的表结构变更,不落地。发布前先看这个。无待发布变更时明确返回「无变更」。
145
+
146
+ **`+db-env-migrate`(高危,需 `--yes`)**:把开发环境的结构变更正式发布到线上,不可逆,返回实际发布的变更条数。发布是异步的,命令会等到完成再返回结果。只发布 DDL;数据变更需自行同步。
147
+
148
+ > 预览与发布同一端点,故 `+db-env-diff` 也需写 scope(不是纯只读权限)。
149
+
150
+ ```bash
151
+ lark-cli apps +db-env-create --app-id "$app_id" --environment dev --dry-run
152
+ lark-cli apps +db-env-create --app-id "$app_id" --environment dev --sync-data --yes
153
+ lark-cli apps +db-env-diff --app-id "$app_id"
154
+ lark-cli apps +db-env-migrate --app-id "$app_id" --yes
155
+ ```
156
+
157
+ ## 时间点恢复(PITR)
158
+
159
+ **`+db-recovery-diff`**:预览把库恢复到 `--target` 时间点会带来哪些变更(受影响的表、行数、预计耗时),不落地。同样需写 scope。
160
+
161
+ **`+db-recovery-apply`(高危,需 `--yes`)**:把库恢复到某个时间点,**会覆盖当前数据**,不可逆。
162
+
163
+ - 可恢复窗口最长 **7 天**,且不早于**最近一次 `+db-env-migrate`**;超出窗口的目标会被拒。
164
+ - 目标时间点与当前库一致时返回 `no_changes`(空操作),不算失败。
165
+ - 动手前务必先 `+db-recovery-diff` 给用户确认。
166
+
167
+ ```bash
168
+ lark-cli apps +db-recovery-diff --app-id "$app_id" --target 2h
169
+ lark-cli apps +db-recovery-apply --app-id "$app_id" --target 2026-04-15T10:00:00Z --yes
170
+ ```
171
+
172
+ ## 配额
173
+
174
+ **`+db-quota-get`**:查数据库存储用量(已用量、表数、视图数;配额接入后还会给总配额与使用率)。
175
+
176
+ ```bash
177
+ lark-cli apps +db-quota-get --app-id "$app_id" --environment dev
178
+ ```
179
+
180
+ ## 时间格式(`--since` / `--until` / `--target`)
181
+
182
+ 按用户口语自然传入即可,支持:
183
+ - 相对时间 `7d` / `2h` / `30s`(从现在往前推)
184
+ - 日期 `2026-04-15`
185
+ - 日期时间 `2026-04-15T10:00:00`
186
+ - 带时区的 ISO 8601 `2026-04-15T10:00:00Z` / `2026-04-15T10:00:00+08:00`
187
+
188
+ > **时区**:不带时区的 `日期` / `日期时间` 按**运行机器的本地时区**解析(再归一化到 UTC)。CI(UTC)与本地(如 UTC+8)跑同一条命令,时间边界会差几小时;要精确锁定时区时显式写 ISO 8601 带偏移(如 `...+08:00` / `...Z`)。`--target`(PITR 恢复)尤其建议带时区,避免恢复到非预期时间点。
189
+
190
+ ## 授权细节
191
+
192
+ 以下操作前必须向用户展示影响范围并取得明确授权(exit-10 审批流程见 [`../SKILL.md`](../SKILL.md) 沙箱约定):
193
+
194
+ | 场景 | 触发条件 | 展示内容 |
195
+ |---|---|---|
196
+ | 表结构变更 | CREATE / ALTER / DROP TABLE / INDEX / COLUMN | 目标对象、变更内容;DROP 说明数据风险 |
197
+ | 数据删除 | DELETE / TRUNCATE | 目标表、WHERE 条件、`SELECT count(*)` 命中行数 |
198
+ | 多环境初始化 | `+db-env-create` | 不可逆、会创建 dev 分支,可选 `--sync-data` 复制数据 |
199
+ | dev -> online 发布 | `+db-env-migrate` | 先展示 `+db-env-diff` 输出,说明影响 online |
200
+ | PITR 恢复 | `+db-recovery-apply` | 先展示 `+db-recovery-diff`,说明恢复点之后变更会被覆盖丢失 |
201
+
202
+ `--yes` 只跳过 CLI 确认关卡,不代替授权。
203
+
204
+ ## Platform Forbidden SQL
205
+
206
+ 命中会被服务端拒绝并经 typed `error` 返回。
207
+
208
+ | 类别 | 禁止 SQL |
209
+ |---|---|
210
+ | 数据库级 | `CREATE / DROP / ALTER DATABASE` |
211
+ | Schema 级 | `CREATE / DROP SCHEMA` |
212
+ | 用户级 | `CREATE / DROP USER` |
213
+ | 角色级 | `CREATE / DROP / ALTER ROLE` |
214
+ | Owner 切换 | `REASSIGN OWNED` / `DROP OWNED` |
215
+ | Extension | 仅白名单内允许,如 `pg_trgm`、`pgcrypto` |
216
+
217
+ 业务红线:禁止操作平台保留表如 `auth`、`users`;禁止 DROP 平台审计列;业务创建人 / 负责人字段命名为 `creator` / `owner` / `author`,避免混淆审计列。
218
+
219
+ ## PostgreSQL Edge Cases
220
+
221
+ | 场景 | 规则 |
222
+ |---|---|
223
+ | 系统表白名单 | 只允许 `information_schema.tables/columns/table_constraints/key_column_usage/views/sequences/schemata`、`pg_indexes`、`pg_description` |
224
+ | 系统表禁用 | 禁止 `pg_tables`、`pg_policies`、`pg_type`、`pg_class`、`pg_attribute`、`pg_catalog.*` |
225
+ | DISTINCT + window functions | 分两层查询,先 DISTINCT 再窗口函数 |
226
+ | 日期相减 | 两个 DATE 相减直接返回天数整数 |
227
+ | 内联 COMMENT | 禁止 `column TEXT COMMENT 'xx'`,使用独立 `COMMENT ON` |
228
+ | CREATE TYPE | 不支持 `IF NOT EXISTS` |
229
+ | CREATE POLICY | 不支持 `IF NOT EXISTS` |
230
+ | ALTER TABLE ADD CONSTRAINT | 不支持 `IF NOT EXISTS` |
231
+
232
+ ### JSONB comments
233
+
234
+ JSONB 字段必须用 `COMMENT ON COLUMN ... IS '@type { ... }'` 声明 TypeScript 类型;CREATE TABLE 和 COMMENT 应放在同一次 DDL 调用中。
235
+
236
+ ```sql
237
+ COMMENT ON COLUMN orders.items IS '@type { items: Array<{ sku: string }> }';
238
+ COMMENT ON COLUMN orders.metadata IS '@type { source: string } @description 订单来源';
239
+ COMMENT ON COLUMN product.payload IS '@type { key: string }';
240
+ ```
241
+
242
+ 当 `@type` 里含图片语义字段(`image` / `cover_url` / `avatar` / `gallery` / `images` / `photos`)时,mock 写入规则同普通图片列:先找语义匹配图片,再调用 `generate_image`,不能直接写 Picsum。
243
+
244
+ ### `user_profile` compound type
245
+
246
+ 平台内置:`(user_id varchar, name varchar, email varchar, avatar text, status integer)`,无需创建。仅允许业务 SQL 访问 `(field).user_id`;不要依赖 name / email / avatar / status。
247
+
248
+ ```sql
249
+ INSERT INTO teacher (teacher_profile, class_id)
250
+ VALUES (ROW('1847292986161210')::user_profile, gen_random_uuid());
251
+
252
+ SELECT (teacher_profile).user_id AS teacher_profile, class_id
253
+ FROM teacher;
254
+
255
+ UPDATE teacher
256
+ SET teacher_profile = ROW('1847292357012580')::user_profile
257
+ WHERE (teacher_profile).user_id = '1847292986161210';
258
+
259
+ CREATE INDEX idx_teacher_user_id ON teacher (((teacher_profile).user_id));
260
+ CREATE UNIQUE INDEX uk_teacher_user_id ON teacher (((teacher_profile).user_id));
261
+ ```
262
+
263
+ 表达式唯一性必须用 `CREATE UNIQUE INDEX`;`ALTER TABLE ... ADD CONSTRAINT ... UNIQUE` 不支持 `(field).user_id` 这类表达式列。
264
+
265
+ ### pg function constraints
266
+
267
+ 创建函数时:函数体内禁止 DDL;`RETURNS trigger` 必须 `LANGUAGE plpgsql`。
268
+
269
+ ```sql
270
+ CREATE OR REPLACE FUNCTION fn_set_updated_at()
271
+ RETURNS trigger
272
+ LANGUAGE plpgsql
273
+ AS $$
274
+ BEGIN
275
+ NEW.title := trim(NEW.title);
276
+ RETURN NEW;
277
+ END;
278
+ $$;
279
+ ```
280
+
281
+ ## Mock Data Details
282
+
283
+ | 中文用户 user_id | name | 英文用户 user_id | name |
284
+ |---|---|---|---|
285
+ | 1847292357012580 | 张伟 | 1846114399229988 | John Smith |
286
+ | 1847292986161210 | 李明 | 1847298549409911 | Emma Johnson |
287
+ | 1838411738368010 | 刘洋 | 1847291727560708 | Michael Brown |
288
+ | 1847292458018820 | 赵丽 | 1848568929333380 | Robert Wilson |
289
+ | 1847286122258458 | 孙强 | 1847751107397639 | Maria Garcia |
290
+
291
+ 图片 URL 决策:优先用户上传的语义匹配图片;其次历史消息中语义匹配图片;否则调用 `generate_image`。prompt 必须与数据语义匹配;禁止使用品牌名、角色名、真实人物等版权内容。只有生成失败才用 Picsum,且必须带 seed:`https://picsum.photos/seed/${seed}/400/300`;不能先写 Picsum 再声称已经生成图片。
292
+
293
+ JSONB 图片字段同样适用:只要 `@type` 中包含 `image` / `cover_url` / `avatar` / `gallery` / `images` / `photos` 等图片地址语义,就不能跳过 `generate_image`。
294
+
295
+ ## `schema.ts` Codegen Split
296
+
297
+ `server/database/schema.ts` 是 DB 元数据生成产物,只能只读辅助确认结构,禁止手改。
298
+
299
+ | 现象 | 处理 |
300
+ |---|---|
301
+ | DB 结构、默认值、类型或约束不对 | 改 DDL 后重跑 codegen,让 `schema.ts` 跟随真源刷新 |
302
+ | DB 正确但 `schema.ts` 展示错误 | 视为 codegen 渲染 bug;不要手改产物,说明平台侧需修复 |