@lark-apaas/coding-steering 0.1.53-alpha.20260916160524 → 0.1.53

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 (36) hide show
  1. package/package.json +6 -6
  2. package/steering/nestjs-react-fullstack/skills/app-init-feasibility-guide/SKILL.md +2 -1
  3. package/steering/nestjs-react-fullstack/skills/client-builtins-file-storage-service/SKILL.md +1 -0
  4. package/steering/nestjs-react-fullstack/skills/client-builtins-user-service/SKILL.md +2 -0
  5. package/steering/nestjs-react-fullstack/skills/coding-guide/SKILL.md +70 -15
  6. package/steering/nestjs-react-fullstack/skills/design-guide/SKILL.md +188 -0
  7. package/steering/nestjs-react-fullstack/skills/design-guide/references/broadsheet.md +311 -0
  8. package/steering/nestjs-react-fullstack/skills/design-guide/references/claude-editorial-research.md +375 -0
  9. package/steering/nestjs-react-fullstack/skills/design-guide/references/corporate-blueprint.md +252 -0
  10. package/steering/nestjs-react-fullstack/skills/design-guide/references/crimson-frosted-glass.md +221 -0
  11. package/steering/nestjs-react-fullstack/skills/design-guide/references/cybernetic-vault-terminal.md +74 -0
  12. package/steering/nestjs-react-fullstack/skills/design-guide/references/dashboard.md +233 -0
  13. package/steering/nestjs-react-fullstack/skills/design-guide/references/digital-e-guide.md +349 -0
  14. package/steering/nestjs-react-fullstack/skills/design-guide/references/flowbite.md +179 -0
  15. package/steering/nestjs-react-fullstack/skills/design-guide/references/frontend-design.md +66 -0
  16. package/steering/nestjs-react-fullstack/skills/design-guide/references/handwritten-sketch.md +211 -0
  17. package/steering/nestjs-react-fullstack/skills/design-guide/references/industry.md +346 -0
  18. package/steering/nestjs-react-fullstack/skills/design-guide/references/metabase.md +220 -0
  19. package/steering/nestjs-react-fullstack/skills/design-guide/references/minimal-jade.md +205 -0
  20. package/steering/nestjs-react-fullstack/skills/design-guide/references/nebula-crimson.md +306 -0
  21. package/steering/nestjs-react-fullstack/skills/design-guide/references/nexuscore-analytics.md +74 -0
  22. package/steering/nestjs-react-fullstack/skills/design-guide/references/organic-minimalism.md +251 -0
  23. package/steering/nestjs-react-fullstack/skills/design-guide/references/phosphor-hud.md +214 -0
  24. package/steering/nestjs-react-fullstack/skills/design-guide/references/pm-spec.md +233 -0
  25. package/steering/nestjs-react-fullstack/skills/design-guide/references/pop-art.md +264 -0
  26. package/steering/nestjs-react-fullstack/skills/design-guide/references/token-mapping.md +68 -0
  27. package/steering/nestjs-react-fullstack/skills/design-guide/references/warm-elegance.md +215 -0
  28. package/steering/nestjs-react-fullstack/skills/design-guide/references/wild-orange.md +203 -0
  29. package/steering/nestjs-react-fullstack/skills/plugin-guide/SKILL.md +4 -1
  30. package/steering/nestjs-react-fullstack/skills/plugin-guide/references/plugin-coding-guide.md +37 -5
  31. package/steering/nestjs-react-fullstack/skills_local/client-builtins-user-service/SKILL.md +2 -0
  32. package/steering/nestjs-react-fullstack/skills_local/coding-guide/SKILL.md +53 -14
  33. package/steering/nestjs-react-fullstack/skills_local/plugin-guide/SKILL.md +1 -1
  34. package/steering/nestjs-react-fullstack/skills_local/plugin-guide/references/plugin-coding-guide.md +37 -5
  35. package/steering/vite-react/skills/plugin-guide/SKILL.md +2 -5
  36. package/steering/nestjs-react-fullstack/skills_common/mcp-guide/SKILL.md +0 -376
package/package.json CHANGED
@@ -1,14 +1,11 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-steering",
3
- "version": "0.1.53-alpha.20260916160524",
3
+ "version": "0.1.53",
4
4
  "description": "Stack-specific steering content for miaoda-coding templates",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "steering"
8
8
  ],
9
- "scripts": {
10
- "lint:md": "markdownlint 'steering/**/*.md' --ignore 'steering/**/skills/**' --ignore 'steering/**/skills_common/**' --ignore 'steering/**/skills_local/**'"
11
- },
12
9
  "devDependencies": {
13
10
  "markdownlint-cli": "^0.47.0"
14
11
  },
@@ -20,5 +17,8 @@
20
17
  "miaoda",
21
18
  "coding-steering"
22
19
  ],
23
- "license": "MIT"
24
- }
20
+ "license": "MIT",
21
+ "scripts": {
22
+ "lint:md": "markdownlint 'steering/**/*.md' --ignore 'steering/**/skills/**' --ignore 'steering/**/skills_common/**' --ignore 'steering/**/skills_local/**'"
23
+ }
24
+ }
@@ -71,7 +71,7 @@ available-agents:
71
71
  | 实时多人编辑、毫秒级协同 | 弱实时刷新、提交后同步 |
72
72
  | 原生 App、桌面端、浏览器插件 | Web 应用、响应式页面 |
73
73
  | 服务端持久写本地文件 | 平台文件服务、数据库、临时 `/tmp` |
74
- | 服务启动时下载大文件、全量同步或批量迁移 | 采用异步处理,避免阻塞服务启动 |
74
+ | `constructor`、`onModuleInit`、`onApplicationBootstrap` 中执行或直接发起下载大文件、全量同步或批量迁移 | 使用平台支持的独立异步任务或外部触发机制;不得在钩子内用 `void Promise`、异步 IIFE、定时器等方式后台发起 |
75
75
  | 无凭证调用受限第三方系统 | 要求用户提供 API、凭证或授权方式 |
76
76
  | 自建账号体系绕过平台登录 | 使用平台内置身份与权限 |
77
77
  | 多语言 i18n、深浅色主题切换(非平台内置) | 需自行实现并计入工作量;规格中先确认是否必要 |
@@ -113,6 +113,7 @@ available-agents:
113
113
  - 角色权限:查看、创建、编辑、删除、导出、配置等操作的分配。
114
114
  - 集成点:飞书、多维表格、AI、内网接口、OpenAPI、自动化触发。
115
115
  - 边界与限制:不支持的能力、外部依赖、数据权限边界。
116
+ - 启动约束:若有下载大文件、全量同步或批量迁移,规格中明确由平台支持的独立异步任务或外部触发机制执行;不得在 `constructor`、`onModuleInit` 或 `onApplicationBootstrap` 中执行或直接发起,声明为 `async`、使用 `void Promise`、异步 IIFE 或定时器均不符合要求。
116
117
  - 交给 Code agent 时标明需要加载的专项 skill(表格、表单、图表、插件、权限、文件、自动化)。
117
118
  - 需要 native addon 时:确认它提供覆盖 linux-x64 / glibc 的预编译二进制并记录包名与版本;没有预编译二进制、装的时候要现场编译的不能用。
118
119
 
@@ -21,6 +21,7 @@ match-template-name: nestjs-react-fullstack
21
21
  ## 使用注意
22
22
  - **入口边界**:本 SDK 是**应用前端代码**读写应用存储的唯一入口。Agent 自己在对话 / 开发中上传、灌数据或调试文件,先加载应用文件存储操作 skill(按「应用文件存储 / 文件上传 / 文件下载」召回),用其 CLI 命令操作,具体命令一律以该 skill 为准——二者操作同一个应用存储桶,但**该 CLI 命令只供 Agent 在沙箱终端使用,禁止写进页面代码**,页面里一律用本 SDK。
23
23
  - @lark-apaas/client-toolkit/dataloom 这个SDK只适用于前端调用,禁止在服务端调用
24
+ - **沙箱 dev 限制**:`uploadFile` 打的 `/app/<appId>/__runtime__/api/v1/storage/object/<bucket>/pre_upload` **在沙箱 dev 下恒 404**,只有发布态可用。这是环境限制不是代码缺陷,按本 skill 写法即为正确,不要为它改代码;开发期要验证上传链路改走接口测试直接打后端接口,或复用库里已有的文件 URL。详见 coding-guide「沙箱 dev 不提供平台 runtime 接口」。
24
25
  - 上传成功后,最重要的返回值是 `data.download_url`。需要将此URL保存到你的业务数据库中
25
26
  - **⚠️ 场景区分(重要)**:`dataloom.storage` 仅适用于需要持久化存储文件或获取 `download_url` 保存到数据库的场景。如果文件仅作为插件输入(传给 `capabilityClient`),**必须直接传 File/Blob 对象,禁止先走 dataloom 上传再传 URL**;插件调用(capability)不属于 dataloom,详见 plugin-guide
26
27
  - **download_url 格式说明**:`download_url` 返回的可能是相对路径(如 `/spark/app/.../storage/object/...`),这是正常行为。**禁止**在前面拼接 `window.location.origin` 或其他域名前缀,平台会自动解析相对路径。直接使用原始值即可。
@@ -14,6 +14,8 @@ match-template-name: nestjs-react-fullstack
14
14
 
15
15
  > **边界说明**:`authClient.session` 仅用于用户登录/登出/获取用户信息等鉴权操作。**插件调用(capability)不属于账户 SDK**,须使用独立的 `capabilityClient`(参见 plugin-guide)。
16
16
  >
17
+ > **沙箱 dev 限制**:本 skill 的能力底层打 `/app/<appId>/__runtime__/api/v1/account/*`,这类端点**在沙箱 dev 下打不通**(POST 404;GET 落 SPA fallback 返回 200 + index.html),只有发布态可用。`useCurrentUserProfile()` 打的是 `account/login/user`;UserSelect / DepartmentSelect / UserDisplay 打 `search_user` / `list_users` / `user_profile` / `search_department`。看到 404 或选人列表为空时,禁止改 `business-ui` 组件、禁止加兜底请求或换自研控件绕过;开发期要验证「按当前用户过滤 / 展示姓名」改由服务端出数据(`req.userContext` / `AuthNPaasService`)。详见 coding-guide「沙箱 dev 不提供平台 runtime 接口」。
18
+ >
17
19
  > **运行时边界**:本 skill 所有能力(`authClient`、`useCurrentUserProfile`、UserSelect/UserDisplay 等)仅限前端代码使用,**严禁在 `server/**` 中 import**。服务端获取用户身份用 `req.userContext` / `AuthNPaasService`(见 `user-identity` skill),完整边界规则见 coding-guide。
18
20
 
19
21
  ## 怎么选(决策指引)
@@ -139,6 +139,11 @@ shared/ # 前后端共享的目录
139
139
  - **import 类型前必须确认实际导出**:先读取文件确认类型名称存在且拼写一致,禁止臆造类型名
140
140
  - 属性统一 camelCase(禁止 snake_case),server 端 schema 的 snake_case 不应泄漏到接口类型
141
141
  - shared 目录是前后端共享文件,**禁止反向引用** `@server/*`、`@client/*` 等路径别名
142
+ - **请求 DTO 中的 shared 字符串联合别名**:`shared/api.interface.ts` 是前后端契约权威。带 `class-validator` 的 NestJS 请求 DTO 字段若对应 shared 字符串字面量联合 `type` alias,不把 imported alias 直接写在 DTO 属性上;改用等价 inline literal union + `@IsString()` + `@IsIn([...])`,DTO class 仍 `implements` shared 请求接口。
143
+ - ❌ `type!: ExpressionElementType`
144
+ - ✅ `@IsString()` + `@IsIn(['tile', 'operator'])` + `type!: 'tile' | 'operator'`
145
+ - **机械核对**:先数 shared alias 字面量个数 N,inline union 和 `@IsIn` 数组都必须恰好 N 个,且每个字面量完全一致;数量或名称不等就是错,不能只写“不得窄于”。
146
+ - 边界:shared 真实 `enum` 用 `@IsEnum(EnumName)`;嵌套 DTO 用 `@ValidateNested()` + `@Type(() => XxxDto)`;普通对象字段用 `@IsObject()`;Date 转换按 `@Type(() => Date)` 处理。禁止用 `@Type(() => String)` 只为绕过 lint。
142
147
 
143
148
  ## 代码质量约束
144
149
 
@@ -155,7 +160,7 @@ shared/ # 前后端共享的目录
155
160
 
156
161
  ## 依赖使用规范
157
162
 
158
- 1. **子包完整性检查**:部分库有多个子包(如 `@dnd-kit/core` + `@dnd-kit/sortable` + `@dnd-kit/utilities`),添加 import 后必须确认 package.json 中包含所有需要的子包
163
+ 1. **子包完整性检查**:部分库有多个子包(如 `@radix-ui/react-*` 系列每个组件都是独立子包),添加 import 后必须确认 package.json 中包含所有需要的子包
159
164
  2. **禁止安装时需现场编译的 native addon**(`node-gyp rebuild`、`binding.gyp`、需要系统头文件或编译器)。依赖按平台内置能力 / 浏览器能力 → 纯 JS 或 WASM → 有预编译二进制的 native addon 的顺序选型
160
165
  3. 用法不清时查看 readme,可进一步搜索或网页访问获取信息
161
166
 
@@ -180,6 +185,46 @@ shared/ # 前后端共享的目录
180
185
  - `.eslintrc.js`、`.prettierrc`
181
186
  - `node_modules/`、`.git/`、`dist/`、`build/`
182
187
 
188
+ ### 沙箱 dev 不提供平台 runtime 接口(`__runtime__`)
189
+
190
+ dev server 只代理 `/api`、`/openapi`、`/__innerapi__`(外加 legacy 的 `/af/p/:appId/api`、`/af/p/:appId/__innerapi__`)。`/app/<appId>/__runtime__/*` 这一整类**平台 runtime 接口在沙箱 dev 下打不通**,只有发布态才由网关接管。
191
+
192
+ **症状分两种,按请求方法区分**:POST 直接 404;**GET 会落到 Vite 的 SPA fallback,拿回 200 + `index.html`**,业务侧表现为「返回了一坨 HTML,JSON 解析失败」——见下方「问题排查指引」里「API 测试返回 HTML 内容时」那条,两者是同一回事。
193
+
194
+ 已知受影响端点:
195
+
196
+ | 端点 | 方法 | 谁会打到它 |
197
+ |------|------|-----------|
198
+ | `api/v1/permissions/roles` | GET | `AppContainer` **每次加载应用自动打**,不需要你写任何代码 |
199
+ | `api/v1/observability/{logs,traces,metrics}/collect`、`current_server_timestamp` | POST/GET | 平台埋点上报,**自动打** |
200
+ | `api/v1/account/login/user` | POST | `useCurrentUserProfile()` → `authClient.session.getUserInfo()` |
201
+ | `api/v1/account/search_user`、`list_users`、`user_profile`、`search_department`、`convert_lark_user` | POST / `user_profile` 是 GET | `business-ui` 的 UserSelect / DepartmentSelect / UserDisplay |
202
+ | `api/v1/account/search`、`api/v1/account/chat/list_chats` | POST | ChatSelect 选群组件 |
203
+ | `api/v1/studio/user/profile` | GET | `getUserProfile()` |
204
+ | `api/v1/storage/object/<bucket>/pre_upload` | POST | `dataloom.storage.uploadFile()` 前端上传 |
205
+ | `api/v1/studio/plugins/tmp_files/acquire_upload_url`、`acquire_download_url` | POST | `capabilityClient` 的文件类入参 |
206
+
207
+ > `useCurrentUserProfile()` 打的是 `account/login/user`,**不是** `user_profile`/`search_user` 那一排;它另外还打一个 `GET /api/authnpaas/lark-user-id`,那条走 `/api`、被代理、正常。
208
+
209
+ **这是环境限制,不是应用缺陷,也不是组件坏了。** 看到这些 404 / HTML 响应时:
210
+
211
+ - **禁止**改 `client/src/components/business-ui/**`(平台保护文件)、**禁止**给组件加兜底请求或改用自研选人控件绕过——发布后这些端点是正常的,绕过写法反而是错的
212
+ - 需要在开发期验证「按当前用户过滤」「展示用户姓名」这类逻辑:改由服务端出数据。服务端的 `req.userContext` 和 `AuthNPaasService` 由网关注入,**不受此限制**,始终可用(见 `user-identity` / `contacts-service` skill)。`useCurrentUserProfile()` 在这里长期停在加载态就是这个原因
213
+ - 需要在开发期验证上传链路:改用接口测试直接打后端接口,或复用库里已有的文件 URL,不要在浏览器里点上传
214
+ - 依赖上述端点的 E2E 用例不要写成浏览器交互 Case,改走接口层往返验证
215
+
216
+ 另外,`UserSelect` 弹层是**搜索驱动**的:不输关键词时列表为空属预期行为,不是接口挂了。
217
+
218
+ ## 应用访问入口(404 / 白屏先看这里)
219
+
220
+ 沙箱内页面入口、API 入口、NestJS 端口不是一回事,禁止用 `5173/3000/8001/8080` 枚举猜测。
221
+
222
+ - **看页面 / 白屏 / 交互**:优先用截图、视觉检查或 E2E 工具,并只传相对路径;工具会打开沙箱真实预览入口(E2E 走 8080 nginx/openresty 鉴权代理)。不要用 `curl` 拿 HTML 判断页面是否渲染。
223
+ - **测后端接口**:优先用接口测试工具,只传以 `/api` 或 `/openapi` 开头的业务路径;工具会自动拼 `CLIENT_BASE_PATH`、选择正确 dev 端口,并补 CSRF 与用户身份。
224
+ - **必须手写 curl 调 `/api/*` 时**:打 client dev server,不要打 NestJS `SERVER_PORT`;URL 必须带 `$CLIENT_BASE_PATH`,并同时带 `Cookie: suda-csrf-token=<X>` 与 `X-Suda-Csrf-Token: <X>`(两值字面相等)。漏 basePath 是 404,漏 CSRF 是 403,都不是业务代码 bug,不要为此改 csrf 中间件或给接口加白名单。
225
+ - **不要直连 NestJS 端口**:会绕过 dev server / 网关注入,`x-larkgw-suda-webuser` 缺失后 `userContext.userId` 为空,依赖身份的接口会误判。
226
+ - **判断服务是否启动**:看 `client-devserver` / `server-devserver` 日志的 ready / 编译成功。裸端口访问返回 404 或连不上(只监听 IPv6 等)都不能当服务故障的依据;同一 URL 连续两次同状态码就换排查方向,不要 `sleep` + curl 重试。
227
+
183
228
  ## 质量保障流程
184
229
 
185
230
  通用提交前检查(代码检查 / 接口测试 / 读日志确认无错误)见系统任务流程约束;本栈具体落点:
@@ -233,10 +278,9 @@ shared/ # 前后端共享的目录
233
278
  - **三方集成**:调用第三方 API 需在后端实现,使用 @nestjs/axios
234
279
  - **能力边界**:服务端不支持文件上传(FaaS 限制),前端用 dataloom SDK 上传,服务端仅保存元信息
235
280
  - **环境判断**:`process.env.NODE_ENV === "production"` 表示生产环境
236
- - **文件系统**:临时文件、下载内容和处理中间产物统一写入 `/tmp` 下的独立目录,用完后清理
237
- - **启动关键路径**:`bootstrap`、`onModuleInit` 和 `OnApplicationBootstrap` 只做必须的同步装配,不得执行 DDL、全量数据同步、长轮询或无界外部请求。应用应尽早 `listen()`;非关键预热放到后台任务,外部调用必须有超时、错误日志和降级路径
281
+ - **运行时文件系统(CRITICAL)**:生产 FaaS 中 `process.cwd()` 指向只读部署目录 `/opt/bytefaas`;禁止在该目录或项目目录下创建或写入 `uploads`、`logs`、缓存等,也禁止“先写工作目录,失败再回退 `/tmp`”。临时文件、下载内容和处理中间产物必须直接写入 `/tmp` 下的独立目录
238
282
  - **服务端运行时资源文件**(字体 / 证书 / 模板 / wasm 等需在运行时读取的非代码文件,CRITICAL — 发布后静默失效根因):① 必须在 `nest-cli.json` 的 `assets` 中声明(如 `{"include": "assets/<dir>/**/*", "outDir": "dist/server"}`),否则不会进 `dist/` 构建产物;② 路径用 `__dirname` 相对**编译产物**定位(如 `path.join(__dirname, "../assets/...")`),**禁止 `process.cwd()` 相对源码路径**——dev 跑源码能命中、发布跑 `dist/` 会落空;③ 资源缺失或加载失败必须 **fail-loud**(抛错或明确错误日志),禁止 `catch` 后静默返回残缺产物
239
- - **启动生命周期**:`constructor`、`onModuleInit` 和 `onApplicationBootstrap` 应快速完成,避免在其中下载大文件、全量同步或批量迁移;仅将钩子声明为 `async` 仍会被等待,无法缩短启动时间
283
+ - **启动生命周期**:`bootstrap`、`constructor`、`onModuleInit` 和 `onApplicationBootstrap` 都位于服务启动或就绪关键路径,应快速完成,只做必要且确定的装配、内存初始化和配置校验;不得在其中执行或直接发起 DDL、下载大文件、全量同步、批量迁移、长轮询或无界外部请求。仅将钩子声明为 `async`,或在钩子内用 `void Promise`、异步 IIFE、定时器等 fire-and-forget 写法启动任务,都不算移出启动流程;耗时工作必须由平台支持的独立异步任务或外部触发机制执行
240
284
 
241
285
  ## 日志约定
242
286
 
@@ -315,7 +359,15 @@ await db.select().from(users).where(eq(users.adminUser, userId));
315
359
  | 按月 / 按天筛 date、timestamptz | 半开区间 `and(gte(col, "2026-08-01"), lt(col, "2026-09-01"))`;日期列不能用 `like(col, "2026-08%")` |
316
360
  | 数字列过滤(`@Query` 取到的是 string) | 先 `Number(q)` 再进 `eq` |
317
361
 
318
- - **`count()` 返回 string**(PostgreSQL bigint)。
362
+ - **区分 Drizzle helper 与原生 SQL `COUNT()`**:当前模板的 `drizzle-orm@0.44.6` 中,`count()` helper 返回 `number`;原生 SQL `COUNT()` 返回 PostgreSQL `bigint`,驱动结果可能是 `string`。需要保留超过 `Number.MAX_SAFE_INTEGER` 的精确值时,使用 `BigInt` 或保留字符串,不要转成 `Number`。
363
+
364
+ ```typescript
365
+ const [{ total }] = await db.select({ total: count() }).from(users); // total: number
366
+
367
+ const rawTotal = '9007199254740993';
368
+ const exactTotal = BigInt(rawTotal); // ✅ 9007199254740993n
369
+ const unsafeTotal = Number(rawTotal); // ❌ 9007199254740992,精度丢失
370
+ ```
319
371
 
320
372
  - **UUID 多值过滤不要直接插值数组到 `ANY(...::uuid[])`**:在 sql 模板中直接插入 ids 这类 JS 数组,可能被展开成 `($1, $2, ...)::uuid[]`,运行时报 `42846: cannot cast type record to uuid[]`。
321
373
 
@@ -338,7 +390,11 @@ await db.select().from(users).where(eq(users.adminUser, userId));
338
390
  - **Drizzle raw `sql` 参数不走列 encoder**:绑定 schema 列的 helper 会编码;raw `sql` 的 `${...}` 只是 driver 参数。Date / custom type 进 raw SQL 前先转 driver-safe 标量(时间用 ISO string)或改回 helper;`user_profile` 仍按上一小节专表处理。
339
391
  - raw SQL 聚合、`filter (...)`、`CASE WHEN`、窗口函数或复杂 where 涉及 Date / custom type 时,按 `raw-sql-boundary-audit` 审计,并实际调用对应 API 验证 HTTP 200,避免隐藏 500。
340
392
 
341
- - **时间列跨网络后都是 string**:`date` `$inferSelect` 就是 `string`(原样透传,禁止 `new Date()` 包装);`timestamp` / `timestamptz` `Date`,**必须在 service 出口 `.toISOString()`**。两类在 `shared/api.interface.ts` 中统一声明为 `string`,前端需要 Date 时手动 `new Date(value)`。
393
+ - **时间字段:写库前查 `schema.ts`,别按 SQL 列名猜**(drizzle-date-boundary-v1)。用 `typeof table.$inferInsert` / `$inferSelect` 看这列在 TS 里是 `Date` 还是 `string`——custom type 会改掉默认映射。
394
+ - 列是 `Date`、DTO 给字符串 → 转成 `Date` 再写,非法值抛 `BadRequestException`,update 保留 `null`。
395
+ - 列是 `string` → 原样写,别转 `Date`。
396
+ - 读出 `Date` → 出口 `.toISOString()`;读出 `string` → 原样返回。`shared/api.interface.ts` 里两类都声明为 `string`。
397
+ - `toDriver` 收得比应用类型宽,但 `.values()` / `.set()` 只认 `$inferInsert`;别靠放宽 custom type 消错。
342
398
 
343
399
  - **禁止删类型注解消除报错**(`as unknown as T` 同禁):典型症状是「改完 service,错误跑到 controller 了」——错误没有转移,是校验点被往外推了一层;推到最外层删完,报错归零而契约失守。
344
400
 
@@ -560,7 +616,9 @@ async createArticle(@Req() req: Request, @Body() dto: CreateArticleDto) {
560
616
 
561
617
  1. 使用 API 测试工具测试不依赖用户信息的接口
562
618
  2. 积极使用 `read_logs` 工具,如无有效日志可增加 logger 打印
563
- 3. API 测试返回 HTML 内容时:检查模块注册顺序、路由顺序、请求路径。禁止修改内置 ViewController
619
+ 3. API 测试返回 HTML 内容时:检查模块注册顺序、路由顺序、请求路径。禁止修改内置 ViewController。若路径含 `__runtime__`,那就是下一条——GET 未被代理时会落 SPA fallback 返回 index.html
620
+ 4. 请求路径含 `__runtime__` 的 404(POST)或 200 + HTML(GET):属沙箱 dev 环境限制,不是应用缺陷,见「沙箱 dev 不提供平台 runtime 接口」
621
+ 5. 服务端启动即崩、`/api` 全部 502 且报 `UnknownDependenciesException ... argument Function at index [0]`:查构造函数有没有空参 `@Inject()`(见 plugin-guide),不要先去改 Module 的 imports / providers
564
622
 
565
623
  ---
566
624
 
@@ -581,6 +639,8 @@ async createArticle(@Req() req: Request, @Body() dto: CreateArticleDto) {
581
639
  {% if projectMeta['flags']['supportTiptapAndStreamdown'] %}
582
640
  - **富文本**: `business-ui/tiptap-editor`(阅读 README.md)
583
641
  - **Markdown 渲染**: `components/ui/streamdown`(内置 prose 排版)
642
+ {% else %}
643
+ - **Markdown 渲染**: `components/ui/markdown`(react-markdown + remark-gfm,内置 prose 排版)
584
644
  {% endif %}
585
645
 
586
646
  ## API 请求
@@ -618,6 +678,8 @@ import { axiosForBackend } from '@lark-apaas/client-toolkit/utils/getAxiosForBac
618
678
  {% if projectMeta['flags']['supportTiptapAndStreamdown'] %}
619
679
  | TiptapEditorComplete | `business-ui/tiptap-editor` | 富文本编辑器 |
620
680
  | Streamdown | `components/ui/streamdown` | Markdown/流式渲染 |
681
+ {% else %}
682
+ | Markdown | `components/ui/markdown` | Markdown 渲染(react-markdown + remark-gfm) |
621
683
  {% endif %}
622
684
 
623
685
  ### 组件 Skill 召回规则(强制执行)
@@ -781,15 +843,8 @@ return <h1>{data?.title || '未知标题'}</h1>;
781
843
  | 验证 | zod |
782
844
  | 工具函数 | lodash |
783
845
  | 样式 | clsx |
784
- | Excel | xlsx(**仅前端实现,禁止服务端实现**。解析后将结构化数据传到服务端保存) |
785
- | PDF 导出 | jspdf + html2canvas(**仅前端实现,禁止服务端实现**) |
786
- | 文件上传 | react-dropzone |
787
- | 二维码 | qrcode.react |
788
846
  | 用户反馈 | sonner |
789
- | 拖拽 | @dnd-kit/core |
790
- | 数字动画 | react-countup |
791
- | Base64 | js-base64 — `import { encode, decode } from 'js-base64'` |
792
- | 3D 场景 | cobe |
847
+
793
848
 
794
849
  ## 滚动分页最佳实践
795
850
 
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: design-guide
3
+ description: 写第一个页面、组件或样式文件之前确定并记录视觉方向:沿用已有设计、遵循用户指定、匹配预置风格,或交给 frontend-design 自行设计。
4
+ steering: true
5
+ steering-topic: frontend_design
6
+ match-template-name: nestjs-react-fullstack
7
+ control-by-feature-ab: true
8
+ hook: SessionStart
9
+ available-agents:
10
+ - Code
11
+ metadata:
12
+ display-names:
13
+ zh-CN: 设计指南
14
+ en-US: Design Guide
15
+ ---
16
+
17
+ # 设计指南
18
+
19
+ 写第一个页面、组件或样式文件之前,先确定应用要呈现什么样子。设计要有明确特点,并适合当前产品。
20
+
21
+ 仅修改现有应用的数据、功能或局部内容,且用户没有要求调整整体视觉时,沿用已有设计,不重新匹配风格,也不改写已有设计方向。新增页面或组件本身不代表需要换风格。
22
+
23
+ 需要确定新的视觉方向时,先理解产品做什么、给谁使用、最重要的任务是什么,以及用户期望的氛围和使用感受。设计元素可以来自产品相关的材料、工具、物品和常用说法。推断必须有用户需求或已知上下文作为依据,不补写用户没有表达的审美偏好。
24
+
25
+ ## 选择设计方向
26
+
27
+ 按以下顺序判断:
28
+
29
+ ### 1. 遵循用户明确指定的方向
30
+
31
+ 用户点名某个预置风格时,直接采用该风格。用户要求还原或沿用某个参考设计,或已经给出足以确定整体视觉方向的配色、排版与组件形态时,按用户指定执行。
32
+
33
+ “高级一点”“有科技感”“活泼一些”“偏深色”等属于偏好线索,不是完整方案;“深色背景”“绿色主色”等局部要求需要保留,但仍应在这些要求内继续匹配预置风格或自行设计。截图、附件或产品链接只有在用户明确要求参考其视觉时,才作为视觉方向;只用于提供功能或内容时,不据此判断用户指定了风格。
34
+
35
+ ### 2. 匹配预置风格
36
+
37
+ 用户没有给出完整方案时,不要看到某类应用就固定选择一种风格。先从下面四方面找出 2–4 个都可能合适的预置风格:
38
+
39
+ 1. 页面主要用途:操作、分析数据、阅读内容、填写表单或展示产品。
40
+ 2. 用户想要的感觉:冷静或亲和、克制或张扬、明亮或深色、现代或杂志感。
41
+ 3. 实际使用情况:频繁操作或沉浸浏览、内容紧凑或留白较多、主要在电脑使用或经常在窄屏使用。
42
+ 4. 产品自身特点:所属行业、常见物品、材料、目标用户和常用说法能否自然融入该风格。
43
+
44
+ 索引只帮助初步选择,不表示某类应用只能使用某个风格。同一种应用通常有多个合理候选。比较候选时,先按主要界面机制缩小范围,而不是按行业名称决定:
45
+
46
+ - 高频操作、表格和表单为主:区分标准组件化软件、温和紧凑的指标工作台、开阔的数据分析画布、绿色轻影的任务与指标面板。
47
+ - 报告、知识和连续阅读为主:区分冷静的纸面规格文档、人文研究编辑界面、杂志式纸张层次、新闻印刷结构。
48
+ - 强视觉展示或沉浸浏览为主:区分深色技术面板、毛玻璃舞台、明暗叙事区块、粗边硬影或漫画拼贴。
49
+ - 轻量查询、填写或个人工具:只有大留白、超大圆角、自然色和稀疏结构确实适合主要操作时,才使用对应的有机方向;需要密集表格或连续高频操作时,回到操作型候选。
50
+
51
+ 在相邻候选之间,按下面的视觉机制完成最后比较;这些差异只解释已有索引,不改变各风格含义:
52
+
53
+ - 明亮操作与数据界面:区分标准化中圆角组件与完整明暗模式、暖米白细边无影的紧凑指标台、绿色轻影指标卡、开阔浅蓝分析区域、直角蓝线编号结构和工程图纸标记。
54
+ - 深色技术与分析界面:区分绿色终端语法、蓝黑圆角嵌套面板、紫色紧凑直角面板、红色毛玻璃舞台和明暗交替的深红叙事区块。
55
+ - 文档与编辑界面:区分冷灰蓝单栏规格纸、人文奶油研究界面、旋转纸卡杂志层次和黑白新闻印刷结构。
56
+ - 轻量与表达型界面:区分白底超大圆角自然留白、暖黄渐变与深浅卡片、手写纸张、黑白橙粗边硬影和高饱和漫画拼贴。
57
+
58
+ 采用一个风格,需要能说明需求中的哪些特征与该风格的布局密度、组件几何、主要配色关系、排版、材质、交互方式或标志性细节相呼应。清晰层级、熟悉控件、现代、专业、简洁、易用和响应式属于所有合格界面的基础质量,只用于检查可用性,不能单独作为区分预置风格的证据。一个颜色、一个形容词,或登录、保存、增删改查、统计等单个普通功能也不能单独决定风格。
59
+
60
+ 如果多项操作共同决定了主界面的长期结构,例如持续使用的表格与表单、筛选和批量操作、多角色工作区、审批与状态流转、排期与资源分配、看板拖拽,那么由此形成的布局密度、组件形态和交互节奏属于呈现约束,可以作为候选的正向证据;仍需比较相邻候选,不能只按企业应用类别决定。
61
+
62
+ 同一组中的候选如果仍只能用共同的业务用途或基础质量解释,无法用上述视觉或结构证据区分,就使用 frontend-design。否则选择差异证据最具体、同时不影响使用效率的一项;如果最初只找到一个候选,再找一个用途相近和一个感觉相近的候选进行比较,不要随机选择。
63
+
64
+ 选定后,完整读取对应的 `references/<风格英文名>.md` 和 `references/token-mapping.md`。允许根据实际内容调整信息密度、间距、尺寸和局部布局;决定风格辨识度的主要配色关系、核心材质和标志形态应保持一致。需要替换这些主要元素才能适配时,不采用该风格。
65
+
66
+ ### 3. 使用 frontend-design
67
+
68
+ 没有明确贴合的预置风格,或核实完整规格后发现需要替换主要视觉元素才能满足需求时,直接读取 `references/frontend-design.md`,按其中的方法确定产品主题、质感、配色和最有辨识度的设计元素。保留用户已经表达的局部要求和偏好。
69
+
70
+ frontend-design 只需定下基础设计要素(主题、质感、配色、签名元素),不要在 `design.md` 里展开成预置风格那样的完整规格文档;具体色值、字体、组件样式变量落进主题样式文件,`design.md` 与 `AGENTS.md` 只保留精简概述。
71
+
72
+ 不需要为了召回而选出一个风格,也不需要逐一排除全部预置风格。
73
+
74
+ ## 保存设计方向
75
+
76
+ 命中预置风格时,用 `bash` 工具把你刚完整读取的那个风格文件**复制**成应用根目录的 `design.md`,并在首行加入受管标识 `<!-- miaoda-design-guide: managed preset=<风格英文名> -->`。不要用 `write` 逐字重写整份规格——既浪费上下文,也容易和源文件产生偏差。复制命令示例(`<刚读取的风格文件路径>` 用你实际读取的那个 references 路径替换):
77
+
78
+ ```bash
79
+ { printf '<!-- miaoda-design-guide: managed preset=<风格英文名> -->\n'; cat "<刚读取的风格文件路径>"; } > design.md
80
+ ```
81
+
82
+ 覆盖前先检查现有 `design.md`:
83
+
84
+ - 文件不存在时直接生成。
85
+ - 首行是受管标识时,可以用上面的命令重新生成;切换风格时同样用新风格文件完整覆盖。
86
+ - 首行没有受管标识时,将它视为用户文件,不覆盖;停止写入并说明冲突。
87
+
88
+ frontend-design 自定义方向没有可复制的源文件,只把基础设计要素写进 `design.md`,不要展开成预置风格那样的完整规格。
89
+
90
+ 后续只引用项目中的 `design.md`。先确认 `design.md` 写入成功,再更新 `AGENTS.md`。
91
+
92
+ 需要确定新视觉方向时,在 `AGENTS.md` 中保留唯一一个简短的 `## 设计方向` 章节。已有章节时更新,不重复追加;已有多个同名章节时停止并说明冲突。根据实际情况选择一种格式:
93
+
94
+ ```markdown
95
+ ## 设计方向
96
+
97
+ - 预置风格:`design.md`(<风格中文名>)
98
+ ```
99
+
100
+ ```markdown
101
+ ## 设计方向
102
+
103
+ - 用户指定:<一句话说清用户给的方向与来源,如“用户附件设计稿:深蓝主色 + 卡片式布局”>
104
+ ```
105
+
106
+ ```markdown
107
+ ## 设计方向
108
+
109
+ - 自定义:产品主题 <一句话> / 质感 <一句话> / 配色 <主色与基础色,给色值> / 辨识度设计 <一句话>
110
+ ```
111
+
112
+ 用户点名预置风格时使用“预置风格”格式。完整的自定义视觉方案使用“用户指定”格式。frontend-design 生成的方向使用“自定义”格式。具体颜色和样式变量写入主题样式文件,不写入 `AGENTS.md`。
113
+
114
+ ## 页面适配底线
115
+
116
+ - 先让桌面宽屏拥有完整的信息层级和合理密度,再设计窄屏重排;不要把桌面端做成放大的手机单列页。
117
+ - 页面宽度要跟随窗口变化并设置最大宽度;网格要能自动增减列数;在内容排不下时切换布局。主要布局不要写死宽高。
118
+ - 窄屏优先改变排列、折叠次要信息和收纳导航,不缩小到不可读;除数据表格等必要区域外,不产生整页横向滚动。
119
+ - 生成持续可见的桌面左侧菜单时,最好增加收起和展开操作,并优先复用模板已有的侧栏组件;用户明确要求固定菜单时除外。
120
+ - 按钮和其他可点击区域要足够大。固定侧栏、悬浮装饰、超大标题和多栏内容在窄屏都要有明确的调整方式。
121
+
122
+ 界面图形和状态标识不使用 emoji,使用项目现有图标或文字。
123
+
124
+ ## 风格索引
125
+
126
+ 索引只概括视觉特征,不限定业务场景。具体规格与例外以对应风格文件为准。
127
+
128
+ - `phosphor-hud` **赛博光幕**
129
+ 视觉:近黑背景与深灰表面,霓虹绿通过透明度变化建立层级 / 等宽正文、超粗标题、全大写标签与方括号语法 / 主体组件零圆角,细线边框、L 型转角与发光效果 / CRT 扫描线、胶片噪点、终端式标记 / 机械、冷峻、工业化
130
+
131
+ - `industry` **工业图纸**
132
+ 视觉:冷灰白图纸底与单一钢蓝构成技术色调,深钢蓝仅作分节强调 / Barlow Condensed 压缩标题搭配 Barlow 正文和等宽标记 / 直角发丝线框,卡片与图框可带四角套准十字 / 内容照片双色化、工程编号和制图标记增强识别 / 冷静、工程化、精确
133
+
134
+ - `cybernetic-vault-terminal` **赛博机库**
135
+ 视觉:深蓝黑画布、藏蓝表面、白色主文字与灰色辅助文字,天蓝和亮蓝用于主要行动 / Inter 中等字重大标题与常规正文,JetBrains Mono 承载小型技术标签 / 24px 圆角卡片与细边框,控件采用约 23px 圆角或胶囊形态 / 紧凑的嵌套面板与突出数值 / 冷峻、理性
136
+
137
+ - `nexuscore-analytics` **核心分析**
138
+ 视觉:近黑画布与深灰表面,白色主文字、灰色辅助文字,紫色集中于主要行动 / Inter 中等字重大标题与常规正文,JetBrains Mono 承载小型标签 / 8px 圆角卡片与控件,细边框区分嵌套表面 / 紧凑的模块化面板、清晰的信息层级与数值强调 / 冷静、紧凑
139
+
140
+ - `crimson-frosted-glass` **暗黑毛玻璃**
141
+ 视觉:黑底叠加模糊背景图与渐变遮罩,白色文字、亮红强调 / 超大粗体无衬线标题,紧字距,大数值突出 / 半透明白色毛玻璃卡片,24px 大圆角与细边框,卡片不依赖投影分层 / 透景层次、大幅图卡与数据块组合 / 沉浸、鲜明、具有空间深度
142
+
143
+ - `nebula-crimson` **深红星云**
144
+ 视觉:白色、浅灰与近黑大面积交替,暗酒红用于品牌区块和重点信息 / 超粗巨型标题与紧字距,全大写宽字距小标签 / 中到大圆角面板,暗区半透明玻璃容器,局部柔和或品牌色投影 / 全幅明暗交替、网格线、局部碳纤维纹理与深红模糊光斑 / 庄重、浓烈、富有叙事节奏
145
+
146
+ - `dashboard` **陶土净台**
147
+ 视觉:暖米白底、纯白卡片与暖黑文字,陶土橙集中于主按钮和主图表,次级图表采用中性色 / 系统无衬线字体,常规正文与中等字重小标题,大数字收紧字距,小标签全大写宽字距 / 10px 圆角卡片、6px 圆角控件,1px 暖灰边框,无投影 / 疏朗的指标面板与细线表格,以灰度、大小写和字距建立层级 / 温润、干净、克制
148
+
149
+ - `minimal-jade` **简约翡翠**
150
+ 视觉:浅灰蓝底、纯白卡片、草绿主强调,次级图表系列用灰阶,深绿和红色用于限定的趋势与状态表达 / 无衬线粗体大标题,JetBrains Mono 等宽数字与表格数字对齐 / 12px 圆角白卡、浅阴影,边框悬停时由透明转浅灰 / 卡片轻微上浮,首要图表系列草绿、其余按黑色透明度递减,局部草绿装饰条 / 简洁、清晰、理性
151
+
152
+ - `metabase` **湖光蓝调**
153
+ 视觉:纯白与极浅蓝平面,深蓝墨字,明亮蓝色用于主按钮和交互焦点 / Lato 人文无衬线字体,粗体标题与常规正文形成清晰层级 / 小到中圆角,1px 半透明中性边框,平铺卡片轻投影,浮层采用更深漫射阴影 / 浅蓝静区、实底蓝主按钮与描边次按钮 / 通透、清爽、平和
154
+
155
+ - `corporate-blueprint` **蓝图**
156
+ 视觉:冷浅灰画布、白色卡片、深蓝主强调,图表以蓝色深浅层级为主,状态标签保留语义色 / 无衬线大标题与小号全大写宽字距标签,数值列等宽对齐 / 主卡片零圆角、顶部 3px 深蓝边线,配轻阴影与细分隔线 / 深蓝渐变头部、斜切几何装饰与编号章节 / 秩序、严谨、精确
157
+
158
+ - `pm-spec` **规格蓝本**
159
+ 视觉:冷灰蓝底、白色纸面与深墨文字,靛紫用于小面积结构性强调 / Charter 衬线标题与引用,无衬线正文,等宽体承载全大写微标签 / 10px 圆角卡片、1px 细边框,无投影,引用块配强调色左边线 / 单栏纸面文档流、紧凑正文、元信息条与局部分栏信息块 / 严肃、克制、秩序感
160
+
161
+ - `claude-editorial-research` **陶色书卷**
162
+ 视觉:暖奶油画布、米色卡片与暖近黑产品面,陶土珊瑚用于主按钮和强调色块 / 常规字重衬线展示标题配负字距,人文无衬线正文,代码采用等宽体 / 中等圆角、发丝边框,层次主要来自表面色差,投影稀疏 / 奶油与深色表面交替,整块珊瑚强调卡与深色代码窗 / 温和、沉思、社论感
163
+
164
+ - `digital-e-guide` **暖陶刊物**
165
+ 视觉:暖陶粉径向渐变背景,奶油纸卡与暖黑文字,马克红主强调、暖橙少量辅助 / Cormorant 大衬线标题与斜体强调,DM Serif Text 衬线正文,等宽体承载元信息 / 4px 微圆角纸卡、长柔阴影与发丝分隔线 / 纸卡交替微旋,双栏正文、外缘引文卡与圆贴纸形成摊开杂志的层次 / 温暖、文艺、印刷感
166
+
167
+ - `broadsheet` **新闻大报**
168
+ 视觉:纸白与近黑墨色为主,青、洋红和工艺黄只作克制点色 / Source Serif 4 衬线字体贯穿标题、正文和控件,主要靠字阶与留白建立层级 / 1–4px 微圆角、细线分隔,卡片仅用于真正离散的条目 / CMYK 套印偏移、网点图像和印版标记形成新闻印刷签名 / 理性、编辑感、公共信息气质
169
+
170
+ - `organic-minimalism` **有机极简**
171
+ 视觉:纯白画布与浅暖灰绿表面,柔和石灰绿强调激活态、按钮和结果 / 简洁无衬线排版,标题与数值通过字重和字号区分 / 40–48px 超大圆角主卡片,极淡边框与浅阴影 / 大留白、极简线性图标、稀疏装饰 / 自然、轻盈、松弛
172
+
173
+ - `warm-elegance` **暖调精致**
174
+ 视觉:暖米、暖灰与暖黄渐变背景,白色卡片与深灰黑反转区,黄色点缀主行动和活跃信息 / 无衬线标题与正文,轻字重大数值、等宽辅助数据,局部斜体小标签 / 32px 主卡片与 24px 深色嵌入卡片,浅区轻投影,深区更强投影与局部光晕 / 深浅卡片对比,纤细胶囊柱图、环形进度与磨砂玻璃标签 / 温暖、柔和、安心
175
+
176
+ - `flowbite` **Flowbite**
177
+ 视觉:白色与浅灰表面、深灰标题,蓝色主按钮和链接,支持对应暗色配色 / Inter 无衬线排版,超粗大标题配紧字距,正文常规字重 / 规整中圆角,以 8px 为主,1px 浅边框与轻投影 / 实底蓝按钮、浅蓝徽章、浅灰输入框,组件形态统一 / 清晰、规整、务实
178
+
179
+ - `handwritten-sketch` **手绘草稿**
180
+ 视觉:米黄纸底、白色卡片与墨黑文字,标记笔红、钢笔蓝和便利贴黄点缀 / Kalam 手写标题与 Patrick Hand 手写正文,中文使用系统字体兜底 / 不规则弯曲圆角、3px 墨黑粗边与零模糊偏移硬阴影 / 圆点纸纹、微旋卡片、透明胶带、图钉和波浪下划线,局部黑板反色 / 亲和、轻松、手工感
181
+
182
+ - `wild-orange` **橙色野性**
183
+ 视觉:纯白画布、黑色文字与粗边,橙色主强调搭配少量浅橙和灰阶 / 粗体大写无衬线标题,Playfair 斜体衬线点缀装饰文字与小数值 / 直角卡片、2–4px 黑色粗边、4–8px 零模糊硬阴影 / 几何装饰圆、橙色横幅、圆形编号,卡片按压式位移与阴影收缩 / 自信、大胆、图形感
184
+
185
+ - `pop-art` **波普艺术**
186
+ 视觉:明亮黄色主背景,白色卡片,红、绿、蓝高饱和色块搭配纯黑 / 漫画展示字体、超粗标题与醒目标签,中文使用无衬线兜底 / 粗黑描边、零模糊偏移硬阴影,大圆角卡片与胶囊按钮搭配直角色块 / 半色调网点、轻微倾斜的拼贴标题、按压位移交互 / 热烈、直接、漫画感
187
+
188
+ 这份列表只用于初步选择。选定后,颜色、圆角、字号、组件样式和例外情况一律以对应风格文件为准。