@lark-apaas/coding-miaoda-sandbox-skills 0.1.26 → 0.1.27

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.
@@ -64,7 +64,7 @@ gate-tools:
64
64
  | 规则 | 要求 |
65
65
  |---|---|
66
66
  | SQL 执行通道 | 只用 `+db-execute`,不要裸连数据库或调用其它 SQL 工具 |
67
- | 查结构只认 DB | 表结构 / 字段 / 索引 / 约束一律 `+db-table-list` / `+db-table-get --table <table>`。`server/database/schema.ts` 只在写 TS 代码对齐类型时读,**不能用来回答结构问题**——它是生成产物,可能滞后于 DB |
67
+ | 查结构只认 DB | 表结构 / 字段 / 索引 / 约束一律 `+db-table-list` / `+db-table-get --table <table>`。`server/database/schema.ts` 只在写 TS 代码对齐类型时读,**不能用来回答结构问题**——它是生成产物,除了可能滞后于 DB,还会静默丢掉条件索引的 `WHERE` 和 CHECK 约束(丢掉 WHERE 后,部分唯一索引在 `schema.ts` 里读起来是全表唯一) |
68
68
  | `schema.ts` 禁止手改 | `schema.ts` 是 `npm run gen:db-schema` 的生成产物。DB 结构不对就改 DDL 后重跑 `npm run gen:db-schema`;DB 正确但 `schema.ts` 渲染错误时同样不手改,向用户说明是 schema 生成器 bug |
69
69
  | DDL 后刷新 `schema.ts` | `+db-execute` **不会**自动刷新 `schema.ts`。每次 DDL 成功后立即在应用工程根目录执行 `npm run gen:db-schema`,再写引用新表 / 新列的 TS 代码 |
70
70
  | 变更历史只认 DB | 结构变更历史用 `+db-changelog-list`。`git log -- server/database/schema.ts` 只是代码侧痕迹,**不等价**,不能用来回答"做过哪些 DDL 改动" |
@@ -59,11 +59,11 @@ const userMap = new Map(users.map(u => [u.id, u]));
59
59
  - N+1 queries: per-item DB calls inside loops — use batch or JOIN
60
60
  - List endpoints without pagination — will break as data grows
61
61
  - OFFSET pagination on large datasets — use cursor pagination (WHERE id > cursor)
62
- - Multiple independent DB queries running serially — use Promise.all
62
+ - Multiple independent DB queries running serially — use Promise.all. The platform connection pool caps real concurrency at **7**; beyond that queries queue. It only pays off for IO-bound queries — CPU-heavy ones (large aggregations, big `generate_series`) still take the same total time, so for those the only fix is fewer/cheaper queries
63
63
  - External API calls without timeout
64
- - WHERE/ORDER BY columns missing indexes — **cross-check with schema definition: for every ORDER BY or WHERE column in service queries, verify a matching index exists in schema.ts**
64
+ - WHERE/ORDER BY columns missing indexes — **cross-check against the live DDL: for every ORDER BY or WHERE column in service queries, verify a matching index exists via `npx -y @lark-apaas/miaoda-data-cli db schema <table>`. Do NOT use `schema.ts` for this — it is a generated mirror that silently drops partial-index `WHERE` clauses and CHECK constraints, so an existing partial index reads as missing (and a partial unique index reads as full-table unique)**
65
65
  - Aggregation done in JS instead of SQL layer — fetch all rows then compute in app is a common anti-pattern
66
- - **Sorting fields used in list/ranking endpoints must have database indexes — read schema.ts and verify**
66
+ - **Sorting fields used in list/ranking endpoints must have database indexes — verify with `db schema <table>` (the live DDL), not `schema.ts`**
67
67
  - **Date-range loop expansion in JS (CRITICAL)**: code shaped like `for (let d = new Date(start); d <= end; d.setDate(d.getDate()+1)) for (item of items) ...` is O(N×days). For 1000 records over 90 days = 90,000 ops per request. Must be pushed to SQL using `generate_series(start, end, '1 day') + unnest(array_field) + GROUP BY ... HAVING COUNT(*) > N` — let the database do the date×row cross product
68
68
  - **Multiple endpoints sharing the same base data should be merged**: e.g. Dashboard frontend calling 4 separate stats endpoints, each internally re-querying the full teacher table to build a lookup map. Merge into a single overview endpoint that runs the 4 stats in parallel internally and shares one base-data query.
69
69
  - **Stats / Dashboard endpoints must have a default time window**: any query that scans the entire fact table for aggregation (`select ... from coursePlan` with no `where`) will degrade as data grows. Add a default `where startDate >= now() - interval '90 day'` (or business-appropriate window) so it can hit `idx_*_start_date`. Without a time window, even with indexes the planner may still seq-scan. If "all history" is required, use a materialized view or pre-aggregated table refreshed on schedule, never a live full-table scan.
@@ -59,11 +59,11 @@ const userMap = new Map(users.map(u => [u.id, u]));
59
59
  - N+1 queries: per-item DB calls inside loops — use batch or JOIN
60
60
  - List endpoints without pagination — will break as data grows
61
61
  - OFFSET pagination on large datasets — use cursor pagination (WHERE id > cursor)
62
- - Multiple independent DB queries running serially — use Promise.all
62
+ - Multiple independent DB queries running serially — use Promise.all. The platform connection pool caps real concurrency at **7**; beyond that queries queue. It only pays off for IO-bound queries — CPU-heavy ones (large aggregations, big `generate_series`) still take the same total time, so for those the only fix is fewer/cheaper queries
63
63
  - External API calls without timeout
64
- - WHERE/ORDER BY columns missing indexes — **cross-check with schema definition: for every ORDER BY or WHERE column in service queries, verify a matching index exists in schema.ts**
64
+ - WHERE/ORDER BY columns missing indexes — **cross-check against the live DDL: for every ORDER BY or WHERE column in service queries, verify a matching index exists via `npx -y @lark-apaas/miaoda-data-cli db schema <table>`. Do NOT use `schema.ts` for this — it is a generated mirror that silently drops partial-index `WHERE` clauses and CHECK constraints, so an existing partial index reads as missing (and a partial unique index reads as full-table unique)**
65
65
  - Aggregation done in JS instead of SQL layer — fetch all rows then compute in app is a common anti-pattern
66
- - **Sorting fields used in list/ranking endpoints must have database indexes — read schema.ts and verify**
66
+ - **Sorting fields used in list/ranking endpoints must have database indexes — verify with `db schema <table>` (the live DDL), not `schema.ts`**
67
67
  - **Date-range loop expansion in JS (CRITICAL)**: code shaped like `for (let d = new Date(start); d <= end; d.setDate(d.getDate()+1)) for (item of items) ...` is O(N×days). For 1000 records over 90 days = 90,000 ops per request. Must be pushed to SQL using `generate_series(start, end, '1 day') + unnest(array_field) + GROUP BY ... HAVING COUNT(*) > N` — let the database do the date×row cross product
68
68
  - **Multiple endpoints sharing the same base data should be merged**: e.g. Dashboard frontend calling 4 separate stats endpoints, each internally re-querying the full teacher table to build a lookup map. Merge into a single overview endpoint that runs the 4 stats in parallel internally and shares one base-data query.
69
69
  - **Stats / Dashboard endpoints must have a default time window**: any query that scans the entire fact table for aggregation (`select ... from coursePlan` with no `where`) will degrade as data grows. Add a default `where startDate >= now() - interval '90 day'` (or business-appropriate window) so it can hit `idx_*_start_date`. Without a time window, even with indexes the planner may still seq-scan. If "all history" is required, use a materialized view or pre-aggregated table refreshed on schedule, never a live full-table scan.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-miaoda-sandbox-skills",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "description": "Miaoda 合并沙箱 skills 包(包含原 miaoda-skills 的 miaoda / miaoda-modern / miaoda-design / shared 四条业务线);发布公网 npm,随沙箱运行时经 update-skills 同步到 .agent/skills/",
5
5
  "type": "module",
6
6
  "files": [