@lark-apaas/coding-steering 0.1.6-alpha.9 → 0.1.6-beta.0

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 (30) hide show
  1. package/package.json +1 -1
  2. package/steering/nestjs-react-fullstack/skills/authz-guide/SKILL.md +1 -1
  3. package/steering/nestjs-react-fullstack/skills/authz-guide/references/dynamic-permission-guide.md +6 -0
  4. package/steering/nestjs-react-fullstack/skills/authz-guide/references/management-page-spec.md +4 -1
  5. package/steering/nestjs-react-fullstack/skills/client-add-aily-web-chat/SKILL.md +1 -1
  6. package/steering/nestjs-react-fullstack/skills/client-builtins-file-storage-service/SKILL.md +30 -4
  7. package/steering/nestjs-react-fullstack/skills/client-builtins-user-service/SKILL.md +39 -127
  8. package/steering/nestjs-react-fullstack/skills/feishu/SKILL.md +0 -1
  9. package/steering/nestjs-react-fullstack/skills/feishu/references/approval.md +1 -1
  10. package/steering/nestjs-react-fullstack/skills/feishu/references/attendance.md +1 -1
  11. package/steering/nestjs-react-fullstack/skills/feishu/references/bitable.md +3 -1
  12. package/steering/nestjs-react-fullstack/skills/feishu/references/calendar.md +1 -1
  13. package/steering/nestjs-react-fullstack/skills/feishu/references/contacts.md +1 -1
  14. package/steering/nestjs-react-fullstack/skills/feishu/references/doc.md +2 -1
  15. package/steering/nestjs-react-fullstack/skills/feishu/references/drive.md +2 -1
  16. package/steering/nestjs-react-fullstack/skills/feishu/references/events.md +2 -1
  17. package/steering/nestjs-react-fullstack/skills/feishu/references/id-convert.md +2 -2
  18. package/steering/nestjs-react-fullstack/skills/feishu/references/messaging.md +1 -1
  19. package/steering/nestjs-react-fullstack/skills/feishu/references/oauth.md +2 -1
  20. package/steering/nestjs-react-fullstack/skills/feishu/references/perm.md +2 -1
  21. package/steering/nestjs-react-fullstack/skills/feishu/references/wiki.md +3 -2
  22. package/steering/nestjs-react-fullstack/skills/openapi-guide/SKILL.md +1 -0
  23. package/steering/nestjs-react-fullstack/skills/plugin-guide/SKILL.md +36 -17
  24. package/steering/nestjs-react-fullstack/skills/plugin-guide/references/plugin-coding-guide.md +4 -1
  25. package/steering/nestjs-react-fullstack/skills/plugin-guide/references/table.md +4 -2
  26. package/steering/nestjs-react-fullstack/skills/react-hook-best-practices/SKILL.md +4 -4
  27. package/steering/nestjs-react-fullstack/skills/trigger-guide/SKILL.md +1 -0
  28. package/steering/nestjs-react-fullstack/skills/user-identity/SKILL.md +1 -0
  29. package/steering/nestjs-react-fullstack/skills_local/code-fix/SKILL.md +42 -28
  30. package/steering/nestjs-react-fullstack/skills_local/coding-guide/SKILL.md +37 -149
@@ -1,11 +1,6 @@
1
1
  ---
2
2
  name: coding-guide
3
- description: "项目全局编码规范,必须在任何代码编写、阅读、修改、排查前加载。覆盖:项目结构、目录组织、文件命名、NestJS 后端(MVCS/Drizzle ORM/API 规范/异常处理/用户上下文)、React 19 前端(shadcn/ui/Tailwind/路由/样式/组件规范)、前后端联调(shared 类型/axiosForBackend)、数据库操作、插件能力、质量保障流程、日志规范。Use when: 编写任意前端或后端代码、新建页面或模块、修改接口或数据库操作、排查编译错误或运行时问题、代码审查、理解项目架构。"
4
- steering: true
5
- steering-inclusion: always
6
- steering-topic: coding_guide
7
- match-template-name: nestjs-react-fullstack
8
- control-by-feature-ab: true
3
+ description: "项目全局编码规范,必须在任何代码编写、阅读、修改、排查前加载。覆盖:项目结构、目录组织、文件命名、NestJS 后端(MVCS/Drizzle ORM/API 规范/异常处理/用户上下文)、React 19 前端(shadcn/ui/Tailwind/路由/样式/组件规范)、前后端联调(shared 类型/axiosForBackend)、数据库操作、质量保障流程、日志规范。Use when: 编写任意前端或后端代码、新建页面或模块、修改接口或数据库操作、排查编译错误或运行时问题、代码审查、理解项目架构。"
9
4
  ---
10
5
  # 项目结构
11
6
 
@@ -22,7 +17,7 @@ control-by-feature-ab: true
22
17
 
23
18
  ## 后端结构 (`server/`)
24
19
 
25
- 基于 MVCS 架构,**禁止新增一级目录**。
20
+ 基于 MVCS 架构,**禁止新增一级目录**。
26
21
 
27
22
  ```
28
23
  server/ # 符合 NestJS 项目基本规范
@@ -36,8 +31,8 @@ server/ # 符合 NestJS 项目基本规范
36
31
  │ ├── hello.controller.ts # controller 示例
37
32
  │ ├── hello.module.ts # module 示例
38
33
  │ └── hello.service.ts # service 示例(可选)
39
- ├── database/ # Drizzle ORM 数据库相关。应用仅能进行 DML 操作。若用户需求设计表结构变更,DDL 相关操作需要使用 `ddl_sql` 工具进行。
40
- │ ├── schema.ts # Drizzle ORM 数据库 Schema 定义。会在执行完 DDL 操作后自动生成,必须从该文件导入数据库类型,禁止自行编写 schema 文件。如有需要可调用 CodeGen 工具手动生成。
34
+ ├── database/ # Drizzle ORM 数据库相关。表结构变更需走 npm run gen:db-schema 流程,不要手写 SQL DDL。
35
+ │ ├── schema.ts # Drizzle ORM 数据库 Schema 定义。必须从该文件导入数据库类型,禁止自行编写或修改 schema 文件 应通过 drizzle migration 生成。
41
36
  └── common/ # 共享工具和接口
42
37
  │ ├── filters/ # 通用错误处理。
43
38
  │ ├── constants/ # 通用常量。
@@ -68,10 +63,8 @@ client/
68
63
  │ ├── components/ # 可复用的 UI 组件
69
64
  │ │ ├── ui/ # shadcn/ui 组件[Use the components for functionality, but heavily style them.]
70
65
  │ │ │ ├── README.md # shadcn/ui 组件库使用说明 [请务必参考该文档进行组件使用]
71
- {% if projectMeta['flags']['supportBusinessUser'] %}
72
66
  │ │ ├── business-ui/ # 封装好的用户,部门选择组件以及展示组件
73
67
  │ │ │ ├── README.md # 用户展示,用户头像展示,部门选择展示逻辑必须使用 [请务必参考该文档进行组件使用],禁止直接使用avatar组件等方式自行实现
74
- {% endif %}
75
68
  │ │ ├── Layout.tsx # 布局包装器
76
69
  │ ├── hooks/ # 自定义 React hooks
77
70
  │ └── utils/ # 工具函数
@@ -128,7 +121,7 @@ shared/ # 前后端共享的目录
128
121
  - **将风格问题视为编码错误**:项目使用 `@eslint/js` + `typescript-eslint` 推荐配置
129
122
  - **ESLint 规范**(`@eslint/js` + `typescript-eslint`):
130
123
  - 正则控制字符用 unicode 标志:`/\x1b\[/u`
131
- - 避免无意义转义:字符串 `"'"` 非 `"\'"`, 正则 `[.]` 非 `[\.] `
124
+ - 避免无意义转义:字符串 `"'"` 非 `"\'"`, 正则 `[.]` 非 `[\.]`
132
125
  - switch-case 中声明变量用 `{}` 包裹作用域
133
126
 
134
127
  ## 依赖使用规范
@@ -156,14 +149,16 @@ shared/ # 前后端共享的目录
156
149
  ## 质量保障流程
157
150
 
158
151
  修改代码后:
152
+
159
153
  1. 运行代码检查工具检查语法错误
160
154
  2. 改动服务端代码 → 进行接口测试,确保新增接口测试通过
161
155
  3. 提交前 **必须** 读取相关日志确认无错误(服务端: server/server-devserver 日志;客户端: client-devserver 日志)
162
156
 
163
- 如果用户反馈编译失败、服务无法启动:
164
- 1. 调用代码检查工具
165
- 2. 读取 server-devserver client-devserver 日志
166
- 3. dev 服务无响应时可 `pkill -f "dev:server"` / `pkill -f "dev:client"` 触发重启
157
+ 如果用户反馈编译失败、服务无法启动:
158
+
159
+ 1. `tsc --noEmit` / `eslint` 等代码检查
160
+ 2. 查看 `logs/server.log` / `logs/server.std.log` / `logs/dev.log` 找具体错误
161
+ 3. dev 服务无响应:在跑 `npm run dev` 的终端 Ctrl+C 后重新启动即可
167
162
 
168
163
  ---
169
164
 
@@ -209,9 +204,8 @@ shared/ # 前后端共享的目录
209
204
 
210
205
  - **@Injectable() Service 注册**:创建 `@Injectable()` Service → 在对应 Module 的 `providers` 中注册(这条在模块目录内部完成,与聚合文件无关)
211
206
  - **三方集成**:调用第三方 API 需在后端实现,使用 @nestjs/axios
212
- - **能力边界**:服务端不支持文件上传(FaaS 限制),前端用 dataloom SDK 上传,服务端仅保存元信息
207
+ - **文件上传**:前端用 dataloom SDK 上传,服务端仅保存元信息(不要在服务端处理 multipart/form-data)
213
208
  - **环境判断**:`process.env.NODE_ENV === "production"` 表示生产环境
214
- - **文件系统**:**严禁使用 `fs` 写入非 `/tmp` 路径**(无状态 FaaS 容器)
215
209
 
216
210
  ## 日志约定
217
211
 
@@ -246,6 +240,7 @@ const query = conditions.length > 0
246
240
  ```
247
241
 
248
242
  - Count 查询:
243
+
249
244
  ```typescript
250
245
  // 简单 count
251
246
  const result = await this.db.select({ count: count() }).from(users).where(eq(users.status, "active"));
@@ -286,8 +281,8 @@ await db.select().from(users).where(eq(users.adminUser, userId));
286
281
  ### 数据库使用强约束
287
282
 
288
283
  - 仅通过 schema.ts 暴露的客户端和类型读写,禁止手写 SQL/临时类型
289
- - **变更流程(CRITICAL)**:`execute_sql` 执行 DDL 系统自动 codegen → **立即重新读取 schema.ts** → 再编写业务代码。跳过重新读取直接编码是 TS2339 批量错误的主要根因
290
- - 连接失败/SSL 错误:立即停机并提示用户联系技术支持
284
+ - **schema变更流程(CRITICAL)**:变更数据表结构后,运行 npm run gen:db-schema 重新生成 schema.ts → **立即重新读取 schema.ts** → 再编写业务代码。跳过重新读取直接编码是 TS2339 批量错误的主要根因
285
+ - 连接失败/SSL 错误:先检查 `.env.local` 里 `SUDA_DATABASE_URL` 是否正确(走过 `lark-cli apps +env-pull`),再排查网络/代理
291
286
 
292
287
  ## API 规范
293
288
 
@@ -305,12 +300,14 @@ await db.select().from(users).where(eq(users.adminUser, userId));
305
300
  5. **路由注册验证**:创建新 Controller 后必须用接口测试工具验证路由是否生效。**遇到 404 排查路径**:① 检查 `@Controller(...)` 是否以 `api/` 或 `openapi/` 开头 ② 检查 Module 是否在 `app.module.ts` 注册 ③ 检查静态路由是否在动态路由 `/:id` 之前
306
301
  6. **@Query/@Param 类型转换**:默认 string,必须在 controller 层手动转换(如 `parseInt(limit, 10)`)
307
302
  7. **写操作加 @NeedLogin**:POST/PUT/PATCH/DELETE 接口显式加 `@NeedLogin()` 装饰器:
303
+
308
304
  ```typescript
309
305
  import { NeedLogin } from "@lark-apaas/fullstack-nestjs-core";
310
306
  @NeedLogin()
311
307
  @Post()
312
308
  async createItem(@Req() req, @Body() dto) { ... }
313
309
  ```
310
+
314
311
  8. **OpenAPI 文档同步**:改动 `*.openapi.controller.ts` 或其引用的 interface / service 返回值 / schema 字段时,加载 `openapi-guide` skill,同步更新 `docs/openapi.json`
315
312
 
316
313
  ## 异常处理
@@ -341,115 +338,12 @@ async createArticle(@Req() req: Request, @Body() dto: CreateArticleDto) {
341
338
 
342
339
  ## 插件能力(Plugin)
343
340
 
344
- ### 召回规则(强制执行)
345
-
346
- 当用户需求涉及以下关键词时,**必须查询相应 Skill 获取开发指南**:
347
-
348
- | 关键词 | 对应能力 |
349
- |-------|---------|
350
- | 多维表格、飞书表格、Base、bitable | 飞书多维表格增删改查 |
351
- | 飞书消息、发送通知、消息推送 | 发送飞书消息 |
352
- | 飞书群、创建群组、群聊 | 创建飞书群组 |
353
- | AI生文、AI写作、文本生成 | AI智能生文 |
354
- | AI总结、文本摘要、内容提炼 | AI文本总结 |
355
- | AI翻译、多语言翻译、语言互译 | AI智能翻译 |
356
- | AI分类、文本分类、自动归类 | AI智能分类 |
357
- | 文本转JSON、结构化提取、文本解析 | AI文本转JSON |
358
- | AI生图、图片生成、智能配图 | AI智能生图 |
359
- | 图生图、图片编辑、图片修改 | AI图片编辑 |
360
- | 图片理解、图片识别、图片分析 | AI图片理解 |
361
- | 图片转JSON、图片提取、图片结构化 | AI图片转JSON |
362
- | 图片对比、图片比较、图片差异 | AI图片对比 |
363
- | 抠图、去背景、去水印、去文字 | AI智能抠图 |
364
- | 背景替换、换背景、背景合成 | AI背景替换 |
365
- | 文档解析、PDF解析、文件提取 | AI文档解析 |
366
- | 搜索总结、网页搜索、搜索摘要 | AI搜索总结 |
367
- | 语音合成、文本转语音、TTS | AI语音合成 |
368
- | 语音识别、音频转文字、STT | AI语音转文字 |
369
- | 插件实例、PluginInstance、Capability | 通用插件调用 |
370
-
371
- ### 插件配置完整性(CRITICAL)
372
-
373
- 调用 `capabilityClient.load(pluginInstanceId)` 前**必须确认**:
374
- 1. `server/capabilities/` 下存在对应 `.json` 配置文件
375
- 2. 配置 `id` 与代码中 `pluginInstanceId` 完全匹配
376
- 3. 不存在则**必须先用 `plugin_instance` 工具创建配置**
377
-
378
- ```typescript
379
- // ❌ 调用不存在的插件(CapabilityNotFoundError — 开发态 Top 错误)
380
- capabilityClient.load('feishu_monthly_demand'); // server/capabilities/ 下无此配置
381
-
382
- // ✅ load 失败时停止后续请求
383
- try {
384
- const result = await plugin.call('read_records', input);
385
- } catch (err) {
386
- if (err.name === 'CapabilityNotFoundError') { setConfigError(true); return; }
387
- throw err;
388
- }
389
- ```
390
- **缓存 load 结果**,避免重复 load 放大错误请求(单应用可达每页 4-6 次失败)。
391
-
392
- ### 关键区分:多维表格 vs 数据库表
393
-
394
- | 场景 | 判断 | 操作 |
395
- |-----|------|-----|
396
- | 明确提到"多维表格/飞书/Base/bitable" | 飞书平台外部服务 | 召回 `plugin_guide` |
397
- | "建表/DDL/schema变更" | 应用内数据库结构 | 使用 `ddl_sql` 工具 |
398
- | "往XX表插入数据"(无明确来源) | 检查 `schema.ts` | 有定义→Drizzle ORM;无定义→询问用户确认 |
399
-
400
- ### 多维表格应用的数据架构选择
401
-
402
- 当应用需要读取飞书多维表格数据时,根据**查询模式**选择架构:
403
-
404
- | 查询模式 | 架构选择 | 实现方式 |
405
- |---------|---------|---------|
406
- | 展示/编辑单条记录 | 纯插件 | `getRecord` / `batchUpdateRecords` |
407
- | 列表分页浏览 | 纯插件 | `searchRecords` + `pageToken` 游标分页 |
408
- | 统计聚合(计数/求和/平均) | **纯插件 + aggregateQuery** | 禁止 searchRecords 全量拉取后内存计算 |
409
- | 统计 + 明细下钻 | 纯插件 | 聚合用 `aggregateQuery`,下钻用 `searchRecords` + filter |
410
- | 排行榜 / TOP N | 纯插件 | `searchRecords` + sort + pageSize=N |
411
- | 复杂排序/多表关联/全文搜索 | 插件同步 + 本地数据库 | 定时/Webhook 同步到 postgres,复杂查询走数据库 |
412
- | 高频写入 + 读取 | 本地数据库为主 | 多维表格仅作展示/备份 |
413
-
414
- **快捷判断:**
415
- - 用户说"仪表盘/dashboard/驾驶舱/看板/统计" → **必须用 `aggregateQuery`**
416
- - 用户说"列表/明细/详情" → `searchRecords` 分页
417
- - 用户说"排行榜/TOP N" → `searchRecords` + sort + pageSize=N
418
- - 需要跨表关联或复杂计算 → 建本地数据库表 + 同步
341
+ 本地开发态**暂不支持** PluginInstance / capability 类插件能力的创建与调用 — 这套链路依赖云端 agent 工具(`plugin_instance` / `get_plugin_ai_json`)与平台下发的 `server/capabilities/` 配置,本地没有等价物。
419
342
 
420
- ### 使用方式
421
- 1. **复用优先**:先查询插件的 Skills,查看已有的候选插件实例 `available_plugin_instances`。
422
- 2. **查 Runtime Spec**:对候选插件实例调用 `get_plugin_ai_json(pluginInstanceId)`,以返回的 `actions[].key / inputSchema / outputSchema / outputMode` 作为**唯一权威**。
423
- 3. **不能复用才创建/更新**:通过 `plugin_instance` 工具 CREATE/UPDATE 生成或调整单文件 PluginInstance 配置。**绝对禁止**使用 `multi_edit` 工具和 `write` 工具来直接修改 `server/capabilities/` 目录下的内容。
424
- 4. **生成调用代码**:必须先调用 `get_plugin_ai_json(pluginInstanceId)` 获取输入输出要求,严格按 schema 与 outputMode 生成调用逻辑。
425
- > 详细用法、配置格式、代码示例请参阅 `plugin_guide` 文档。
343
+ 如果业务用到飞书多维表格、AI 生文/翻译/分类、消息推送等"插件能力"覆盖的场景:
426
344
 
427
- ### 插件调用 API 签名
428
-
429
- ```typescript
430
- // Client 侧
431
- capabilityClient.load(pluginInstanceId).call(actionKey, input) // 非流式
432
- capabilityClient.load(pluginInstanceId).callStream(actionKey, input) // 流式
433
- // Server 侧
434
- capabilityService.load(pluginInstanceId).call(actionKey, input)
435
- ```
436
-
437
- | 参数 | 说明 |
438
- |------|------|
439
- | `pluginInstanceId` | 插件实例 ID,如 `'booking_notification_feishu'` |
440
- | `actionKey` | 来自 `get_plugin_ai_json` 返回的 `actions[].key` |
441
- | `input` | 结构必须符合 `actions[].inputSchema` |
442
-
443
- ```typescript
444
- // ❌ 错误:把参数对象作为 actionKey 传入
445
- plugin.call(JSON.stringify({ meeting_title: '...' }));
446
- // ❌ 错误:漏掉 actionKey,直接传参数对象
447
- plugin.call({ meeting_title: '...' });
448
- // ✅ 正确:actionKey + input 分开传
449
- plugin.call('send_feishu_message', { meeting_title: '...' });
450
- ```
451
-
452
- 使用方式:复用优先 → 查 Runtime Spec(`get_plugin_ai_json`)→ 不能复用才创建 → 严格按 schema 生成调用代码。**绝对禁止**用 `multi_edit`/`write` 工具直接修改 `server/capabilities/` 目录下的内容。
345
+ - **数据存储/查询类**(多维表格 CRUD、列表分页、聚合统计):优先用本应用自带的 Postgres + Drizzle,数据可在云端运行时再同步飞书 Base
346
+ - **AI / 飞书消息类**:在云端发布后由平台插件链路承接;本地开发时可先用接口 mock 桩占位
453
347
 
454
348
  ## 自动化任务
455
349
 
@@ -458,11 +352,13 @@ plugin.call('send_feishu_message', { meeting_title: '...' });
458
352
  ## 分页最佳实践
459
353
 
460
354
  ### 传统分页(后台管理表格、跳页场景)
355
+
461
356
  - 1-indexed page,`@Max()` 限制 pageSize
462
357
  - 响应含 items/total/page/pageSize,page 超出返回空数组
463
358
  - 深分页性能差,大数据集考虑游标分页
464
359
 
465
360
  ### 游标分页(移动端/无限滚动,优先推荐)
361
+
466
362
  - 使用「唯一 + 可排序」字段作为游标排序依据,默认 创建时间+id 降序
467
363
  - cursor(首次空) + limit(默认12, @Max(50))
468
364
  - 响应仅 items/nextCursor/hasMore,不返回 total
@@ -471,10 +367,10 @@ plugin.call('send_feishu_message', { meeting_title: '...' });
471
367
 
472
368
  ## 问题排查指引
473
369
 
474
- 1. 使用 API 测试工具测试不依赖用户信息的接口
475
- 2. 积极使用 `read_logs` 工具,如无有效日志可增加 logger 打印
476
- 3. DevServer 停止响应时 `pkill` 对应进程触发重启
477
- 4. API 测试返回 HTML 内容时:检查模块注册顺序、路由顺序、请求路径。禁止修改内置 ViewController
370
+ 1. `curl` / 浏览器 DevTools / 第三方 HTTP 客户端测试不依赖用户信息的接口
371
+ 2. 查看 `logs/server.log` / `logs/server.std.log` 找后端报错;无有效日志时主动补 logger 打印
372
+ 3. dev 服务无响应:在跑 `npm run dev` 的终端 Ctrl+C 后重新启动
373
+ 4. API 测试返回 HTML 内容时:检查模块注册顺序、路由顺序、请求路径。禁止修改内置 ViewController
478
374
 
479
375
  ---
480
376
 
@@ -489,13 +385,9 @@ plugin.call('send_feishu_message', { meeting_title: '...' });
489
385
  - **图表**: ReactECharts,**开发前必须调用 `/charts-skill`**
490
386
  - **图标**: Lucide React(唯一图标库,禁止 Emoji 和其他图标库)
491
387
  - **表格/表单/图表**: 见下方"组件 Skill 召回规则",开发前必须先调用对应 Skill
492
- {% if projectMeta['flags']['supportBusinessUser'] %}
493
388
  - **用户**: 用户信息展示/选择必须用 `business-ui` 组件(阅读 README.md),禁止直接展示 userId
494
- {% endif %}
495
- {% if projectMeta['flags']['supportTiptapAndStreamdown'] %}
496
389
  - **富文本**: `business-ui/tiptap-editor`(阅读 README.md)
497
390
  - **Markdown 渲染**: `components/ui/streamdown`(内置 prose 排版)
498
- {% endif %}
499
391
 
500
392
  ## API 请求
501
393
 
@@ -527,13 +419,9 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
527
419
  | 组件 | 来源 | 用途 |
528
420
  |------|------|------|
529
421
  | Table | `@lark-apaas/client-toolkit/antd-table` | 数据表格,**先调 `/table-skill`** |
530
- {% if projectMeta['flags']['supportBusinessUser'] %}
531
422
  | UserSelect/UserDisplay/UserProfile/DepartmentSelect | `business-ui/*` | 用户/部门选择展示 |
532
- {% endif %}
533
- {% if projectMeta['flags']['supportTiptapAndStreamdown'] %}
534
423
  | TiptapEditorComplete | `business-ui/tiptap-editor` | 富文本编辑器 |
535
424
  | Streamdown | `components/ui/streamdown` | Markdown/流式渲染 |
536
- {% endif %}
537
425
 
538
426
  ### 组件 Skill 召回规则(强制执行)
539
427
 
@@ -557,7 +445,7 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
557
445
 
558
446
  ## @lark-apaas/client-toolkit
559
447
 
560
- **零假设原则**:绝不基于假设使用任何子模块。使用任何 `@lark-apaas/client-toolkit` 子模块前**必须**:① 查询 Skills `steering_doc_search` → ② 等待响应获取文档 → ③ 严格按文档编码。**禁止直接调用 `@lark-apaas/client-toolkit` 任何函数/方法**(不基于查询到的文档)。该库**仅可在前端代码中使用,禁止在后端代码中引用**。
448
+ **零假设原则**:绝不基于假设使用任何子模块。使用任何 `@lark-apaas/client-toolkit` 子模块前**必须**:① 先查询本地已加载的 Skills 或对应包文档 → ② 严格按文档编码。**禁止直接调用 `@lark-apaas/client-toolkit` 任何函数/方法**(不基于查询到的文档)。该库**仅可在前端代码中使用,禁止在后端代码中引用**。
561
449
 
562
450
  | 功能 | 导入路径 |
563
451
  |------|----------|
@@ -571,7 +459,7 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
571
459
 
572
460
  **useCurrentUserProfile** 返回 `Partial<IUserProfile>`,初始为空对象:访问字段用 `?.`,判断加载完成用 `if (!userInfo?.user_id)`。
573
461
 
574
- **UserService.listUsersByIds**: 根据用户 ID 获取用户详细信息(姓名/头像/邮箱/部门)时**必须使用**,**禁止自行实现用户信息查询逻辑**。非组件上下文需要批量获取用户信息时使用。返回 `result.data.userInfoMap: Record<string, UserInfo>`,UserInfo 含 `userID: string`, `name: I18nText { zh_cn, en_us?, ja_jp? }`, `avatar: string`, `email?: string`, `userType: "_employee"|"_externalUser"|"_anonymousUser"`, `department: { departmentID, name: I18nText }`。{% if projectMeta['flags']['supportBusinessUser'] %}展示场景仍优先用 UserDisplay/UserProfile 组件。{% endif %}
462
+ **UserService.listUsersByIds**: 根据用户 ID 获取用户详细信息(姓名/头像/邮箱/部门)时**必须使用**,**禁止自行实现用户信息查询逻辑**。非组件上下文需要批量获取用户信息时使用。返回 `result.data.userInfoMap: Record<string, UserInfo>`,UserInfo 含 `userID: string`, `name: I18nText { zh_cn, en_us?, ja_jp? }`, `avatar: string`, `email?: string`, `userType: "_employee"|"_externalUser"|"_anonymousUser"`, `department: { departmentID, name: I18nText }`。展示场景仍优先用 UserDisplay/UserProfile 组件。
575
463
 
576
464
  > ⚠️ `UserInfo` 不含任何飞书 ID 字段(`lark_user_id` / `open_id` / `union_id` 都没有)。需要飞书 ID 一律见 `user-identity` skill(当前用户、任意用户 user_id、open_id、union_id 各种场景都在那里)。
577
465
 
@@ -614,6 +502,7 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
614
502
  - **禁止 React.lazy**:严禁异步加载路由组件
615
503
  - **页面跳转**:必须用 `NavLink`/`Link`/`useNavigate`,**严禁 `window.location.href`**
616
504
  - **分享链接/二维码**(CRITICAL):应用部署后 URL 与本地路由不同,**必须**用 `resolveAppUrl` 转换:
505
+
617
506
  ```typescript
618
507
  import { resolveAppUrl } from '@lark-apaas/client-toolkit/utils/resolveAppUrl';
619
508
  const shareUrl = resolveAppUrl(`/detail/${id}`); // ✅ 路由路径→完整 URL
@@ -621,6 +510,7 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
621
510
  resolveAppUrl('https://other-site.com/page'); // ✅ 外部链接原样返回
622
511
  // ❌ 严禁自行拼接:`${window.location.origin}/detail/${id}`
623
512
  ```
513
+
624
514
  - **首页路由**:必须含指向 `/` 的 index 路由
625
515
  - **路由唯一性**:每页一个唯一路由
626
516
  - **导航**:NavLink + active 高亮,路径必须与 `app.tsx` 路由精确对应。全局 Layout 中使用 `useAppInfo`/`useCurrentUserProfile` 获取站点和用户信息
@@ -661,18 +551,16 @@ return <h1>{data?.title || '未知标题'}</h1>;
661
551
  ## 图片规范
662
552
 
663
553
  - **展示**:必须用 `@client/src/components/ui/image` 组件(非原生 `<img>`),响应式设 `sizes`,固定宽设 `width`
664
- {% if projectMeta['flags']['supportBusinessUser'] %}
665
554
  - 用户头像用 business-ui 组件
666
- {% endif %}
667
555
 
668
556
  ### 图片资源优先级
669
557
 
670
- 1. 用户上传图片(最高)
671
- 2. `generate_image`(主要方案)— 每个位置独立图片,禁止重复。提示词格式:`[主体] + [环境] + [风格] + [色彩] + [无文字说明]`
672
- - **必须包含**:「无文字、无字母、无符号」明确说明
673
- - **禁止出现**:① 使用场景("适合移动端")② 功能描述("适合/用于/作为")③ 目标用途("品牌展示/课程封面")④ 观众定位("吸引年轻人")⑤ 预期效果("视觉冲击力/引人注目")⑥ 媒介格式("移动端/印刷品")
674
- 3. 内置 Avatar(仅头像)— `@client/src/utils/img-resources/avatar-placeholders.ts`
675
- 4. Picsum(临时)— `https://picsum.photos/seed/${seed}/${w}/${h}`(必须带 seed)
558
+ 1. 用户上传图片(最高)
559
+ 2. 用户自带的素材库 / 设计资源 放到 `client/public/` CDN
560
+ 3. 内置 Avatar(仅头像)— `@client/src/utils/img-resources/avatar-placeholders.ts`
561
+ 4. Picsum(临时)— `https://picsum.photos/seed/${seed}/${w}/${h}`(必须带 seed)
562
+
563
+ > 本地开发态不接 AI 图片生成,需要 AI 生图请走云端发布后由平台插件链路承接
676
564
 
677
565
  ## 核心功能依赖
678
566