@teamix-evo/skills 0.12.1 → 0.13.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.
- package/README.md +1 -1
- package/manifest.json +11 -28
- package/package.json +2 -2
- package/src/teamix-evo-code-opentrek/SKILL.md +13 -13
- package/src/teamix-evo-code-opentrek/api-layering.md +53 -44
- package/src/teamix-evo-code-opentrek/checklist.md +24 -24
- package/src/teamix-evo-code-opentrek/file-structure.md +55 -36
- package/src/teamix-evo-code-opentrek/forms-and-validation.md +17 -16
- package/src/teamix-evo-code-opentrek/reuse-first.md +6 -9
- package/src/teamix-evo-code-opentrek/testing.md +14 -14
- package/src/teamix-evo-code-uni-manager/SKILL.md +15 -15
- package/src/teamix-evo-code-uni-manager/api-layering.md +74 -58
- package/src/teamix-evo-code-uni-manager/checklist.md +28 -28
- package/src/teamix-evo-code-uni-manager/error-and-loading.md +2 -2
- package/src/teamix-evo-code-uni-manager/file-structure.md +77 -62
- package/src/teamix-evo-code-uni-manager/forms-and-validation.md +17 -15
- package/src/teamix-evo-code-uni-manager/reuse-first.md +7 -10
- package/src/teamix-evo-code-uni-manager/routing-and-codesplit.md +1 -1
- package/src/teamix-evo-code-uni-manager/testing.md +37 -37
- package/src/teamix-evo-design-opentrek/SKILL.md +17 -20
- package/src/teamix-evo-design-opentrek/boundaries.md +1 -1
- package/src/teamix-evo-design-opentrek/checklist.md +5 -5
- package/src/teamix-evo-design-opentrek/components.md +19 -19
- package/src/teamix-evo-design-opentrek/examples/standard-card-list.html +1 -1
- package/src/teamix-evo-design-opentrek/examples/standard-table-list.html +1 -1
- package/src/teamix-evo-design-opentrek/foundations.md +6 -6
- package/src/teamix-evo-design-opentrek/pages/dashboard-page/SKILL.md +18 -19
- package/src/teamix-evo-design-opentrek/pages/dashboard-page/patterns/dashboard-opentrek.md +6 -6
- package/src/teamix-evo-design-opentrek/pages/detail-page/SKILL.md +24 -25
- package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/api-doc-detail.md +3 -7
- package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/comparison-detail.md +3 -7
- package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/monitor-detail.md +3 -7
- package/src/teamix-evo-design-opentrek/pages/detail-page/patterns/resource-detail.md +10 -10
- package/src/teamix-evo-design-opentrek/pages/form-page/SKILL.md +26 -27
- package/src/teamix-evo-design-opentrek/pages/list-page/SKILL.md +35 -36
- package/src/teamix-evo-design-opentrek/pages/list-page/_shared/item-card-spec.md +41 -32
- package/src/teamix-evo-design-opentrek/pages/list-page/patterns/card-list-opentrek.md +10 -10
- package/src/teamix-evo-design-opentrek/pages/list-page/patterns/card-list.md +23 -23
- package/src/teamix-evo-design-opentrek/pages/list-page/patterns/standard-list-opentrek.md +8 -8
- package/src/teamix-evo-design-opentrek/pages/list-page/patterns/standard-list.md +8 -8
- package/src/teamix-evo-design-opentrek/patterns/color-mapping.md +2 -2
- package/src/teamix-evo-design-opentrek/patterns/dashboard.md +1 -1
- package/src/teamix-evo-design-opentrek/patterns/detail-page.md +9 -9
- package/src/teamix-evo-design-opentrek/patterns/form-page.md +6 -6
- package/src/teamix-evo-design-opentrek/patterns/list-page.md +9 -9
- package/src/teamix-evo-design-opentrek/patterns/page-types.md +3 -3
- package/src/teamix-evo-design-opentrek/principles.md +541 -0
- package/src/teamix-evo-design-opentrek/rules/common-components.json +206 -76
- package/src/teamix-evo-design-opentrek/rules/component-specs.json +2 -2
- package/src/teamix-evo-design-opentrek/rules/page-frame.json +197 -193
- package/src/teamix-evo-design-opentrek/{generation-flow.md → workflow.md} +141 -22
- package/src/teamix-evo-design-uni-manager/SKILL.md +5 -5
- package/src/teamix-evo-design-uni-manager/boundaries.md +2 -2
- package/src/teamix-evo-design-uni-manager/brand.md +1 -1
- package/src/teamix-evo-design-uni-manager/checklist.md +2 -2
- package/src/teamix-evo-design-uni-manager/components.md +11 -11
- package/src/teamix-evo-design-uni-manager/foundations.md +7 -7
- package/src/teamix-evo-design-uni-manager/generation-flow.md +3 -3
- package/src/teamix-evo-manage/SKILL.md +111 -709
- package/src/teamix-evo-manage/init.md +98 -0
- package/src/teamix-evo-manage/migrate.md +100 -0
- package/src/teamix-evo-manage/rearchitect-capture-guide.md +174 -0
- package/src/teamix-evo-manage/rearchitect.md +373 -0
- package/src/teamix-evo-manage/update-component-staging.md +188 -0
- package/src/teamix-evo-manage/update-token-rename.md +126 -0
- package/src/teamix-evo-manage/update-token-treatment.md +116 -0
- package/src/teamix-evo-manage/update.md +213 -0
- package/src/teamix-evo-design-opentrek/brand.md +0 -154
- package/src/teamix-evo-design-opentrek/pages/list-page/_shared/search-combo-spec.md +0 -194
- package/src/teamix-evo-design-opentrek/philosophy.md +0 -98
- package/src/teamix-evo-design-opentrek/rules/README.md +0 -39
- package/src/teamix-evo-design-opentrek/rules/_assets/OP_AGENT RUNTIME.svg +0 -1
- package/src/teamix-evo-design-opentrek/rules/_assets/OP_AI GATEWAY.svg +0 -1
- package/src/teamix-evo-design-opentrek/rules/_assets/OP_AI STUDIO.svg +0 -1
- package/src/teamix-evo-design-opentrek/rules/_assets/OP_DEV-2.svg +0 -1
- package/src/teamix-evo-design-opentrek/rules/_assets/OP_LOGO.svg +0 -1
- package/src/teamix-evo-design-opentrek/rules/_assets/OP_OPS.svg +0 -1
- package/src/teamix-evo-design-opentrek/rules/layout-rules.json +0 -218
- package/src/teamix-evo-design-opentrek/rules/page-header-spec.md +0 -123
- package/src/teamix-evo-design-opentrek/rules/sidebar-spec.md +0 -217
- package/src/teamix-evo-upgrade/SKILL.md +0 -431
- /package/src/teamix-evo-design-opentrek/{rules/boundaries.rules.json → boundaries.json} +0 -0
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
src/
|
|
13
|
+
├── features/ # 业务领域(每个子目录聚合 api/hooks/types/mocks/schema)
|
|
13
14
|
├── pages/ # 路由页面(每个目录对应一条路由)
|
|
14
15
|
├── components/ # 跨页面复用的业务组件
|
|
15
|
-
├──
|
|
16
|
-
├── hooks/ # 自定义 Hook(包含数据 hook、UI hook)
|
|
16
|
+
├── hooks/ # 跨领域共享的通用 Hook(极少数,如 useDebounce)
|
|
17
17
|
├── contexts/ # React Context(跨子树共享、低频更新的全局态)
|
|
18
18
|
├── stores/ # 高频全局态(zustand / jotai / redux,首次需要时引入,只用一种)
|
|
19
|
-
├── types/ #
|
|
19
|
+
├── types/ # 跨领域通用类型(ApiResponse<T>、Pagination<T>)
|
|
20
20
|
├── utils/ # 纯函数工具(无 React、无副作用)
|
|
21
21
|
├── lib/ # 三方 SDK 包装、http 实例、环境配置、monitor
|
|
22
22
|
├── routes/ # 路由配置 + 守卫(若用 react-router 集中式声明)
|
|
@@ -29,7 +29,7 @@ src/
|
|
|
29
29
|
└── App.tsx # 根组件
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
> 没列出的目录按需补,但**不要**新增同义层(如同时有 `utils/` 和 `helpers/`、`
|
|
32
|
+
> 没列出的目录按需补,但**不要**新增同义层(如同时有 `utils/` 和 `helpers/`、`services/` 和 `features/`、`views/` 和 `pages/`)。`*.test.ts(x)` 文件**就近**放在被测文件同目录,**不要**集中堆到顶层 `tests/`(见 [`testing.md`](testing.md))。
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
@@ -56,7 +56,7 @@ src/pages/
|
|
|
56
56
|
|
|
57
57
|
- 页面组件**默认 default export**,与文件名一致
|
|
58
58
|
- `_components/` `_hooks/` 用下划线前缀标记**私有**,**禁止跨页面 import**
|
|
59
|
-
-
|
|
59
|
+
- 跨页面用得到的组件 → 升到 `src/components/`;领域 hook → 放 `src/features/<domain>/hooks.ts`
|
|
60
60
|
|
|
61
61
|
### `src/components/`
|
|
62
62
|
|
|
@@ -78,27 +78,46 @@ src/components/
|
|
|
78
78
|
- **不要**重复 `@teamix-evo/ui` 已经提供的能力(见 [reuse-first.md](reuse-first.md))
|
|
79
79
|
- **不要**写"小工具组件"如 `Wrapper`、`Container` —— 用 div + tailwind 即可
|
|
80
80
|
|
|
81
|
-
### `src/
|
|
81
|
+
### `src/features/`
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
**职责**:业务领域代码。每个子目录聚合一个领域的全部代码。详见 [`api-layering.md`](api-layering.md)。
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
src/features/
|
|
87
|
+
├── order/
|
|
88
|
+
│ ├── api.ts # 请求纯函数(listOrders, createOrder, ...)
|
|
89
|
+
│ ├── hooks.ts # react-query 封装(useOrderList, useCreateOrder, ...)
|
|
90
|
+
│ ├── types.ts # 领域类型(Order, OrderStatus, ...)
|
|
91
|
+
│ ├── mocks.ts # 本地 mock 数据(开发阶段)
|
|
92
|
+
│ └── schema.ts # zod schema(CreateOrderInputSchema, ...)
|
|
93
|
+
├── user/
|
|
94
|
+
│ └── ...
|
|
95
|
+
└── tenant/
|
|
96
|
+
└── ...
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
约束:
|
|
100
|
+
|
|
101
|
+
- 一个领域 = 一个子目录,**不按技术类型拆**
|
|
102
|
+
- api.ts 是纯函数层,**不依赖 React**
|
|
103
|
+
- hooks.ts 调同目录 api.ts,**禁止**直接 fetch
|
|
104
|
+
- types.ts 仅类型,无运行时代码
|
|
105
|
+
- 同领域内用相对路径 `./types`、`./api`
|
|
84
106
|
|
|
85
107
|
### `src/hooks/`
|
|
86
108
|
|
|
87
|
-
|
|
109
|
+
**职责**:跨领域共享的通用 Hook(极少数)。
|
|
88
110
|
|
|
89
111
|
```
|
|
90
112
|
src/hooks/
|
|
91
|
-
├──
|
|
92
|
-
├── useCreateOrder.ts
|
|
93
|
-
├── useDebounce.ts # UI hook
|
|
113
|
+
├── useDebounce.ts # 通用 UI hook
|
|
94
114
|
└── useMediaQuery.ts
|
|
95
115
|
```
|
|
96
116
|
|
|
97
117
|
约束:
|
|
98
118
|
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
- 数据 hook 调 `src/services/`,**禁止**直接 fetch
|
|
119
|
+
- 领域数据 hook **不放这里**,放 `src/features/<domain>/hooks.ts`
|
|
120
|
+
- 只放与业务领域无关的通用 hook
|
|
102
121
|
|
|
103
122
|
### 全局态选型决策
|
|
104
123
|
|
|
@@ -133,13 +152,13 @@ Context 文件位置:
|
|
|
133
152
|
|
|
134
153
|
### `src/types/`
|
|
135
154
|
|
|
136
|
-
|
|
155
|
+
**职责**:跨领域通用类型声明。
|
|
137
156
|
|
|
138
157
|
约束:
|
|
139
158
|
|
|
140
159
|
- 只放 `.ts` 类型文件,**不导出运行时代码**
|
|
141
|
-
-
|
|
142
|
-
-
|
|
160
|
+
- Domain 类型放 `src/features/<domain>/types.ts`,**不放这里**
|
|
161
|
+
- 仅放跨领域通用类型:`api.ts`(ApiResponse<T>、Pagination<T>)、`common.ts`
|
|
143
162
|
|
|
144
163
|
### `src/utils/`
|
|
145
164
|
|
|
@@ -147,7 +166,7 @@ Context 文件位置:
|
|
|
147
166
|
|
|
148
167
|
约束:
|
|
149
168
|
|
|
150
|
-
- **不依赖 React**(用了 React 应该是 hook,放 `src/hooks/`)
|
|
169
|
+
- **不依赖 React**(用了 React 应该是 hook,放 `src/features/<domain>/hooks.ts` 或 `src/hooks/`)
|
|
151
170
|
- **不依赖 DOM**(用了 DOM 应该是 lib 层包装)
|
|
152
171
|
- **不发请求**(发请求是 service)
|
|
153
172
|
- 一个文件一个主题:`format.ts`、`validate.ts`、`array.ts`
|
|
@@ -205,7 +224,7 @@ src/routes/
|
|
|
205
224
|
```ts
|
|
206
225
|
// ✅
|
|
207
226
|
import { Button } from '@teamix-evo/ui';
|
|
208
|
-
import { listOrders } from '@/
|
|
227
|
+
import { listOrders } from '@/features/order/api';
|
|
209
228
|
import { OrderStatusBadge } from '@/components/OrderStatusBadge';
|
|
210
229
|
|
|
211
230
|
// ❌
|
|
@@ -217,21 +236,21 @@ import { listOrders } from '../../../services/order';
|
|
|
217
236
|
## Import 边界(单向依赖)
|
|
218
237
|
|
|
219
238
|
```
|
|
220
|
-
pages
|
|
221
|
-
components ──▶
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
stores
|
|
225
|
-
types
|
|
226
|
-
utils
|
|
227
|
-
lib
|
|
239
|
+
pages ──▶ components, features, hooks, types, utils, lib, stores
|
|
240
|
+
components ──▶ features, hooks, types, utils, lib (NOT pages)
|
|
241
|
+
features/* ──▶ lib, types (内部 api→types, hooks→api+types; NOT components, NOT pages)
|
|
242
|
+
hooks ──▶ types, utils, lib (NOT features, NOT components, NOT pages)
|
|
243
|
+
stores ──▶ types, utils, lib (NOT features, NOT hooks)
|
|
244
|
+
types ──▶ (no runtime imports)
|
|
245
|
+
utils ──▶ types only
|
|
246
|
+
lib ──▶ types only
|
|
228
247
|
```
|
|
229
248
|
|
|
230
249
|
要点:
|
|
231
250
|
|
|
232
|
-
- **
|
|
251
|
+
- **features/*/api.ts 不依赖 React** —— 它是纯函数层
|
|
233
252
|
- **types / utils / lib 是叶子层** —— 不依赖业务层,谁都能引
|
|
234
|
-
- **反向依赖直接否决**(component 不能 import page,
|
|
253
|
+
- **反向依赖直接否决**(component 不能 import page,api 不能 import hook)
|
|
235
254
|
|
|
236
255
|
---
|
|
237
256
|
|
|
@@ -240,10 +259,10 @@ lib ──▶ types only
|
|
|
240
259
|
| 反模式 | 为什么禁 | 应该怎么做 |
|
|
241
260
|
| ------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
242
261
|
| `src/views/`、`src/screens/` 与 `src/pages/` 并存 | 同义层,认知爆炸 | 二选一,统一叫 `pages/` |
|
|
243
|
-
| `src/
|
|
262
|
+
| `src/services/` 与 `src/features/` 并存 | 同义层 | 统一用 `features/` |
|
|
244
263
|
| `src/utils/` 与 `src/helpers/` 并存 | 同义层 | 统一叫 `utils/` |
|
|
245
264
|
| 在 `src/components/` 里写 page-only 组件 | 抽象层级别错位 | 放 `src/pages/<id>/_components/` |
|
|
246
|
-
| 在 `src/utils/` 里写 React Hook | 边界错位 |
|
|
265
|
+
| 在 `src/utils/` 里写 React Hook | 边界错位 | 领域 hook → `features/<domain>/hooks.ts`;通用 hook → `src/hooks/` |
|
|
247
266
|
| 一个文件 export 5 个不相关的工具 | 命名失焦 | 拆成多文件,一个主题一个文件 |
|
|
248
267
|
| `index.ts` 大量 `export *` 当 barrel | 影响 tree-shaking、循环依赖 | 显式 named export 需要的几个 |
|
|
249
268
|
| 为消除一处 props drilling 直接引 zustand | 升级过度,徒增心智 | 用 React `Context` |
|
|
@@ -264,15 +283,15 @@ lib ──▶ types only
|
|
|
264
283
|
| 新增订单列表页 | `src/pages/orders/index.tsx` |
|
|
265
284
|
| 新增订单状态徽章(跨页面用) | `src/components/OrderStatusBadge.tsx` |
|
|
266
285
|
| 新增订单状态徽章(只在订单页用) | `src/pages/orders/_components/OrderStatusBadge.tsx` |
|
|
267
|
-
| 新增"取消订单"接口调用 | `src/
|
|
268
|
-
| 新增"取消订单"的 mutation hook | `src/hooks
|
|
286
|
+
| 新增"取消订单"接口调用 | `src/features/order/api.ts` 加 `cancelOrder` |
|
|
287
|
+
| 新增"取消订单"的 mutation hook | `src/features/order/hooks.ts` 加 `useCancelOrder` |
|
|
269
288
|
| 新增日期格式化函数 | `src/utils/format.ts`(先 grep 是否已存在) |
|
|
270
289
|
| 新增鉴权拦截器 | `src/lib/http.ts` 加 interceptor |
|
|
271
|
-
| 新增订单 domain 类型 | `src/
|
|
290
|
+
| 新增订单 domain 类型 | `src/features/order/types.ts` |
|
|
272
291
|
| 跨少量组件分享当前用户 / 主题 | `src/contexts/UserContext.tsx`(用 React Context) |
|
|
273
292
|
| 跨域高频全局态(首次需要) | `src/stores/useXxxStore.ts`(按需引 zustand,固定后只用一种) |
|
|
274
|
-
| 列表 / 详情等服务端数据 | `src/hooks
|
|
275
|
-
| 新增"下单表单"(react-hook-form + zod) | `src/pages/orders/new/_components/CreateOrderForm.tsx` + `src/
|
|
293
|
+
| 列表 / 详情等服务端数据 | `src/features/<domain>/hooks.ts` 包 `react-query`,**不进** store / Context |
|
|
294
|
+
| 新增"下单表单"(react-hook-form + zod) | `src/pages/orders/new/_components/CreateOrderForm.tsx` + `src/features/order/schema.ts` |
|
|
276
295
|
| 跨页面复用表单(地址 / 客户搜索) | `src/components/forms/<Name>Form.tsx` + 对应 schema |
|
|
277
296
|
| 新增路由 / 页面入口 | `src/routes/index.tsx` 注册 + `src/pages/<id>/index.tsx`(default export,被 `React.lazy` 引入) |
|
|
278
297
|
| 新增鉴权 / 角色守卫 | `src/routes/guards.tsx` |
|
|
@@ -22,22 +22,24 @@
|
|
|
22
22
|
## Schema 落点
|
|
23
23
|
|
|
24
24
|
```
|
|
25
|
-
src/
|
|
26
|
-
├──
|
|
27
|
-
|
|
25
|
+
src/features/order/
|
|
26
|
+
├── api.ts # 请求函数:listOrders、createOrder
|
|
27
|
+
├── schema.ts # zod schema:CreateOrderInput、UpdateOrderInput
|
|
28
|
+
├── hooks.ts # react-query 封装
|
|
29
|
+
└── types.ts # 领域类型
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
约定:
|
|
31
33
|
|
|
32
|
-
- **每个 domain 一个
|
|
34
|
+
- **每个 domain 一个 `schema.ts`**,与 api / hooks / types 同目录
|
|
33
35
|
- 从 schema 派生类型:`export type CreateOrderInput = z.infer<typeof CreateOrderInputSchema>`
|
|
34
|
-
-
|
|
36
|
+
- api 的入参 / 返回类型**优先用** schema 推导,而不是手写 interface
|
|
35
37
|
- **不要**把 schema 写在页面 / 组件文件里 —— schema 是 domain 资产,跨页面复用
|
|
36
38
|
|
|
37
39
|
### 示例
|
|
38
40
|
|
|
39
41
|
```ts
|
|
40
|
-
// src/
|
|
42
|
+
// src/features/order/schema.ts
|
|
41
43
|
import { z } from 'zod';
|
|
42
44
|
|
|
43
45
|
export const CreateOrderInputSchema = z.object({
|
|
@@ -57,13 +59,12 @@ export type CreateOrderInput = z.infer<typeof CreateOrderInputSchema>;
|
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
```ts
|
|
60
|
-
// src/
|
|
62
|
+
// src/features/order/api.ts
|
|
61
63
|
import { http } from '@/lib/http';
|
|
62
|
-
import type { CreateOrderInput } from './
|
|
63
|
-
import type { Order } from '
|
|
64
|
+
import type { CreateOrderInput } from './schema';
|
|
65
|
+
import type { Order } from './types';
|
|
64
66
|
|
|
65
67
|
export async function createOrder(input: CreateOrderInput): Promise<Order> {
|
|
66
|
-
// 服务端层也可在这里再 parse 一次防御
|
|
67
68
|
const { data } = await http.post('/api/orders', input);
|
|
68
69
|
return data;
|
|
69
70
|
}
|
|
@@ -100,11 +101,11 @@ src/components/forms/
|
|
|
100
101
|
// src/pages/orders/new/_components/CreateOrderForm.tsx
|
|
101
102
|
import { useForm } from 'react-hook-form';
|
|
102
103
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
103
|
-
import { useCreateOrder } from '@/hooks
|
|
104
|
+
import { useCreateOrder } from '@/features/order/hooks';
|
|
104
105
|
import {
|
|
105
106
|
CreateOrderInputSchema,
|
|
106
107
|
type CreateOrderInput,
|
|
107
|
-
} from '@/
|
|
108
|
+
} from '@/features/order/schema';
|
|
108
109
|
import { Button, Input, Form, FormField, FormItem } from '@/components/ui';
|
|
109
110
|
|
|
110
111
|
export function CreateOrderForm() {
|
|
@@ -155,7 +156,7 @@ export function CreateOrderForm() {
|
|
|
155
156
|
- ❌ 在 `onChange` 里手写 `if (value.length > 20) setError(...)`
|
|
156
157
|
- ❌ 校验报错信息硬编码在组件里("请输入正确的手机号") —— 写在 schema 里,UI 只读
|
|
157
158
|
- ❌ 表单状态用 `useState`,然后再加 `useEffect` 同步校验 —— 直接用 `useForm`
|
|
158
|
-
- ❌ schema 在组件文件里就地定义 —— 抽到
|
|
159
|
+
- ❌ schema 在组件文件里就地定义 —— 抽到 `features/<domain>/schema.ts`
|
|
159
160
|
- ❌ 提交逻辑写在 `<form onSubmit>` 里直接 fetch —— 走 mutation hook
|
|
160
161
|
|
|
161
162
|
---
|
|
@@ -215,8 +216,8 @@ pnpm add react-hook-form zod @hookform/resolvers
|
|
|
215
216
|
```
|
|
216
217
|
## 表单改动
|
|
217
218
|
|
|
218
|
-
- src/
|
|
219
|
-
- src/
|
|
219
|
+
- src/features/order/schema.ts: 新增 CreateOrderInputSchema(zod)、派生类型
|
|
220
|
+
- src/features/order/api.ts: createOrder 入参用派生类型
|
|
220
221
|
- src/pages/orders/new/_components/CreateOrderForm.tsx: useForm + zodResolver
|
|
221
|
-
- src/hooks
|
|
222
|
+
- src/features/order/hooks.ts: useCreateOrder — useMutation 包 createOrder,onError 区分字段级 / 通用
|
|
222
223
|
```
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
|
|
35
35
|
### 查询顺序(从快到慢)
|
|
36
36
|
|
|
37
|
-
1.
|
|
38
|
-
2.
|
|
37
|
+
1. **读 `.teamix-evo/meta/ui/manifest.json`** —— 一次列全部,扫描是否有同名 / 近义。
|
|
38
|
+
2. **`grep <关键词> .teamix-evo/meta/ui/manifest.json`** —— 子串匹配 id / name / description;需要详细 Props/示例时读 `.teamix-evo/meta/ui/<id>.md`。
|
|
39
39
|
3. **本项目 grep** —— `grep -r "from '@/components/ui'" src/` 看哪些已经装机。
|
|
40
40
|
4. **本项目 `.teamix-evo/ui/manifest.lock.json`** —— 已装机的 ui entry 清单。
|
|
41
41
|
|
|
@@ -64,11 +64,8 @@
|
|
|
64
64
|
|
|
65
65
|
### 页面骨架来源(列表 / 详情 / 表单 / 仪表盘)
|
|
66
66
|
|
|
67
|
-
> ⚠️ **AI 默认不调用 `@teamix-evo/templates` 包**(见 ADR 0031 skill-templates-decoupling)。页面骨架按下列优先级生成:
|
|
68
|
-
|
|
69
67
|
1. **首选** —— 读 `teamix-evo-design-opentrek` skill 的 [`patterns/{list|detail|form|dashboard}-page.md`](../teamix-evo-design-opentrek/patterns/),按 Zone Map 与决策树用 ui 原子件 + biz-ui 业务件**直接拼装**到 `src/pages/<id>/`
|
|
70
|
-
2. **patterns/ 未覆盖时** —— 按业界流行的中后台页面架构(antd Pro / shadcn Examples 等)
|
|
71
|
-
3. **`@teamix-evo/templates` 包与 CLI 命令仍保留**,但仅在用户**显式**要求(如"用 templates 包的 frozen 骨架")时才走 `teamix-evo templates add`
|
|
68
|
+
2. **patterns/ 未覆盖时** —— 按业界流行的中后台页面架构(antd Pro / shadcn Examples 等)与用户描述自由实现
|
|
72
69
|
|
|
73
70
|
### 决策表
|
|
74
71
|
|
|
@@ -77,7 +74,7 @@
|
|
|
77
74
|
| 列表页 / 详情页 / 表单页 / 仪表盘骨架 | 读 design skill `patterns/*.md` → ui + biz-ui 拼装 |
|
|
78
75
|
| "带筛选的用户表格"、"带审批流的卡片" | 优先 `biz-ui` |
|
|
79
76
|
| 一次性的、强领域绑定的组合 | 写在 `src/components/<domain>/` 里,**不要污染 biz-ui** |
|
|
80
|
-
| patterns/ 未覆盖的特殊页面 | 按业界流行架构 +
|
|
77
|
+
| patterns/ 未覆盖的特殊页面 | 按业界流行架构 + 用户描述自由实现 |
|
|
81
78
|
|
|
82
79
|
---
|
|
83
80
|
|
|
@@ -87,7 +84,7 @@
|
|
|
87
84
|
|
|
88
85
|
1. **本项目 grep**:
|
|
89
86
|
```bash
|
|
90
|
-
grep -rn "function <近义名>" src/utils/ src/lib/ src/
|
|
87
|
+
grep -rn "function <近义名>" src/utils/ src/lib/ src/features/
|
|
91
88
|
```
|
|
92
89
|
2. **`@teamix-evo/*` 是否提供**(少数情况,如格式化、token 工具)
|
|
93
90
|
3. **依赖里的成熟库** —— 例如:
|
|
@@ -112,7 +109,7 @@
|
|
|
112
109
|
1. **命名要能让下次复用查得到** —— 起 `OrderStatusBadge` 而不是 `MyBadge`;`useOrderList` 而不是 `useList`。
|
|
113
110
|
2. **抽象层级别低于一次性页面** —— 跨页面会用的才放 `src/components/`,只在一个页面用的写在 `src/pages/<id>/_components/`。
|
|
114
111
|
3. **暴露面尽量窄** —— 默认只 `export` 这次需要的 API,别一次性 `export *`。
|
|
115
|
-
4. **写完登记** —— 在 PR
|
|
112
|
+
4. **写完登记** —— 在 PR 描述里明确”新增 `<path>`,因为 ui / biz-ui / patterns / 本项目均未提供 X 能力”。
|
|
116
113
|
|
|
117
114
|
---
|
|
118
115
|
|
|
@@ -29,12 +29,12 @@ src/
|
|
|
29
29
|
├── utils/
|
|
30
30
|
│ ├── format.ts
|
|
31
31
|
│ └── format.test.ts # ← 紧邻
|
|
32
|
-
├──
|
|
33
|
-
│
|
|
34
|
-
│
|
|
35
|
-
├──
|
|
36
|
-
│
|
|
37
|
-
│
|
|
32
|
+
├── features/
|
|
33
|
+
│ └── order/
|
|
34
|
+
│ ├── api.ts
|
|
35
|
+
│ ├── api.test.ts # ← 紧邻
|
|
36
|
+
│ ├── hooks.ts
|
|
37
|
+
│ └── hooks.test.tsx
|
|
38
38
|
└── components/
|
|
39
39
|
├── OrderStatusBadge.tsx
|
|
40
40
|
└── OrderStatusBadge.test.tsx
|
|
@@ -61,7 +61,7 @@ src/test/
|
|
|
61
61
|
|
|
62
62
|
| 优先级 | 类型 | 例子 | 必测? |
|
|
63
63
|
| ------ | ------------------------------------- | ----------------------------------- | -------------- |
|
|
64
|
-
| P0 | 纯函数(`src/utils/`、`
|
|
64
|
+
| P0 | 纯函数(`src/utils/`、`features/*/api.ts`) | `formatMoney`、`isValidOrder` | ✅ **必测** |
|
|
65
65
|
| P0 | zod schema | `CreateOrderInputSchema.parse(...)` | ✅ **必测** |
|
|
66
66
|
| P0 | 关键业务路径(下单 / 支付 / 鉴权) | E2E-style 组件测 | ✅ **必测** |
|
|
67
67
|
| P1 | Hook(数据 hook + 自定义 UI hook) | `useOrderList`、`useDebounce` | 推荐 |
|
|
@@ -133,9 +133,9 @@ afterAll(() => server.close());
|
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
```ts
|
|
136
|
-
// src/
|
|
136
|
+
// src/features/order/api.test.ts
|
|
137
137
|
import { describe, it, expect } from 'vitest';
|
|
138
|
-
import { listOrders } from './
|
|
138
|
+
import { listOrders } from './api';
|
|
139
139
|
|
|
140
140
|
describe('listOrders', () => {
|
|
141
141
|
it('返回订单列表', async () => {
|
|
@@ -149,10 +149,10 @@ describe('listOrders', () => {
|
|
|
149
149
|
### Hook
|
|
150
150
|
|
|
151
151
|
```tsx
|
|
152
|
-
// src/hooks
|
|
152
|
+
// src/features/order/hooks.test.tsx
|
|
153
153
|
import { renderHook, waitFor } from '@testing-library/react';
|
|
154
154
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
155
|
-
import { useOrderList } from './
|
|
155
|
+
import { useOrderList } from './hooks';
|
|
156
156
|
|
|
157
157
|
function wrapper({ children }: { children: React.ReactNode }) {
|
|
158
158
|
const qc = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
|
@@ -247,7 +247,7 @@ renderWithProviders(<OrderListPage />, { route: '/orders?status=pending' });
|
|
|
247
247
|
| 测 `setState` 是否被调用 | 测了实现,重构即崩 | 测渲染结果 / 用户行为 |
|
|
248
248
|
| `getByTestId` 当默认查询 | data-testid 跟可访问性绑不上 | `getByRole` / `getByLabelText` 优先 |
|
|
249
249
|
| 一个 it 里 expect 10 次无关断言 | 失败定位难 | 拆多个 it |
|
|
250
|
-
| mock 整个 hook(`vi.mock('@/
|
|
250
|
+
| mock 整个 hook(`vi.mock('@/features/...')`) | 失去集成价值 | msw mock 后端,hook 真跑 |
|
|
251
251
|
| 自己 mock fetch / axios | 与生产代码路径不一致 | 用 msw |
|
|
252
252
|
| 测试里写 `setTimeout(..., 1000)` 等异步 | 慢且不稳定 | `await waitFor` / `findBy*` |
|
|
253
253
|
| 全局 mock console.error 静默 | 错过真实告警 | 让测试输出 console.error,但 setup 里 fail on it |
|
|
@@ -308,8 +308,8 @@ pnpm exec msw init public/ --save # 浏览器 worker
|
|
|
308
308
|
## 测试覆盖
|
|
309
309
|
|
|
310
310
|
- 新增 src/utils/calcDiscount.ts → 同目录 calcDiscount.test.ts(5 个 case)
|
|
311
|
-
- 新增 src/
|
|
312
|
-
- 新增 src/hooks
|
|
311
|
+
- 新增 src/features/order/api.ts:createOrder → api.test.ts(成功 / 422 字段错 / 500)
|
|
312
|
+
- 新增 src/features/order/hooks.ts:useCreateOrder → hooks.test.tsx(success / error)
|
|
313
313
|
- 复用 src/components/OrderStatusBadge.tsx → 已有 test 覆盖,无需补
|
|
314
314
|
- 跳过测: src/pages/orders/new/index.tsx(纯组合,关键逻辑已在 hook / form 层测)
|
|
315
315
|
```
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: teamix-evo-code-uni-manager
|
|
3
3
|
description: |
|
|
4
|
-
Enforce teamix-evo coding conventions in uni-manager
|
|
5
|
-
TRIGGER when: user asks to
|
|
6
|
-
SKIP: pure visual
|
|
7
|
-
Coordinates with: teamix-evo-design-uni-manager (
|
|
4
|
+
Enforce teamix-evo coding conventions in uni-manager apps — reuse-first, tenant/region context propagation, `src/` layering.
|
|
5
|
+
TRIGGER when: user asks to 新增/重构/写 组件/页面/接口/hook in a 云管/专有云/多租户 console; phrases like "create a CRUD page" / "add an API call" / "调接口"; file write under `src/pages/**`, `src/components/**`, `src/features/**`.
|
|
6
|
+
SKIP: pure visual/layout design with no code change (→ design-uni-manager); lifecycle commands (→ manage); token/style-only changes (→ ESLint).
|
|
7
|
+
Coordinates with: teamix-evo-design-uni-manager (design handles visual side, this skill handles file placement and reuse).
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# teamix-evo-code-uni-manager
|
|
@@ -23,7 +23,7 @@ Activate this skill whenever AI is about to **write or refactor code** inside a
|
|
|
23
23
|
- "把这段重构一下"
|
|
24
24
|
- "create a CRUD page for 多云实例"
|
|
25
25
|
- "add an API call to list instances across regions"
|
|
26
|
-
- Any time AI is about to create a new file under `src/pages/`、`src/components/`、`src/
|
|
26
|
+
- Any time AI is about to create a new file under `src/pages/`、`src/components/`、`src/features/` in a hybrid-cloud console
|
|
27
27
|
|
|
28
28
|
If the task is purely about _visual design_ of a screen, use [`teamix-evo-design-uni-manager`](../teamix-evo-design-uni-manager/SKILL.md) instead — or run both in tandem.
|
|
29
29
|
|
|
@@ -31,10 +31,10 @@ If the task is purely about _visual design_ of a screen, use [`teamix-evo-design
|
|
|
31
31
|
|
|
32
32
|
Before AI writes or commits code, it performs an **8-step gated flow**. Steps 1-4 are baseline (**必须执行,不得跳过**); steps 5-7 are topic gates (run when the task touches that topic); step 8 is the final self-review (**必须执行,不得跳过**).
|
|
33
33
|
|
|
34
|
-
1. **🚧 Reuse-first check** — **MUST READ** [`reuse-first.md`](reuse-first.md). Before creating any new component, query the `@teamix-evo/ui` registry (via
|
|
35
|
-
2. **🚧 Layering check** — **MUST READ** [`api-layering.md`](api-layering.md). Any code that talks to a backend goes under `src/
|
|
36
|
-
3. **🚧 Directory check** — **MUST READ** [`file-structure.md`](file-structure.md). Place the new file under the right top-level folder; uni-manager-specific shells (TenantContext / RegionContext / CloudBadge) have conventional locations.
|
|
37
|
-
4. **🚧 Forms gate** — if the task involves a form, **MUST READ** [`forms-and-validation.md`](forms-and-validation.md). `react-hook-form` + `zod`; schema lives at `src/
|
|
34
|
+
1. **🚧 Reuse-first check** — **MUST READ** [`reuse-first.md`](reuse-first.md). Before creating any new component, query the `@teamix-evo/ui` registry (via `.teamix-evo/meta/ui/manifest.json` + `<id>.md`), the **biz-ui/uni-manager** layer (um-topbar / CloudBadge / ContextSwitcher placeholders), and grep the local project. Only write new code when no reuse path exists. **组件兗底铁律**:找不到时优先 ui 原子件组合,**禁止**自撸基础件。
|
|
35
|
+
2. **🚧 Layering check** — **MUST READ** [`api-layering.md`](api-layering.md). Any code that talks to a backend goes under `src/features/<domain>/api.ts`; multi-tenant / multi-region / multi-cloud context (tenantId / regionId / cloudProvider) is **propagated through `lib/http.ts` interceptors**, not as ad-hoc params per call. Components never call `fetch` / `axios` directly. Data hooks live in `src/features/<domain>/hooks.ts` and consume api functions.
|
|
36
|
+
3. **🚧 Directory check** — **MUST READ** [`file-structure.md`](file-structure.md). Place the new file under the right top-level folder (pages / components / features / utils / lib / stores / contexts); uni-manager-specific shells (TenantContext / RegionContext / CloudBadge) have conventional locations.
|
|
37
|
+
4. **🚧 Forms gate** — if the task involves a form, **MUST READ** [`forms-and-validation.md`](forms-and-validation.md). `react-hook-form` + `zod`; schema lives at `src/features/<domain>/schema.ts`. Dangerous operations (delete / release / destroy) **must** route through `useDangerConfirm` (input resource name).
|
|
38
38
|
5. **Error/loading gate** — if the task adds a page or data hook, **MUST READ** [`error-and-loading.md`](error-and-loading.md). Ensure global ErrorBoundary, page-level fallback, and three-state handling (`isPending` / `isError` / data) are in place; mutations report success/error via `toast`. Cross-cloud resource-not-found has a dedicated fallback.
|
|
39
39
|
6. **Routing gate** — if the task adds a route or page-entry, **MUST READ** [`routing-and-codesplit.md`](routing-and-codesplit.md). Pages use `React.lazy`; auth/role guards live in `src/routes/guards.tsx`; **list-page filters MUST sync `tenantId` / `regionId` / `cloudProvider` into URL search params**; um-topbar context switch rewrites the current URL.
|
|
40
40
|
7. **Testing gate** — **MUST READ** [`testing.md`](testing.md). Pure functions and zod schemas are **mandatory** to test; tenant-context-aware http handlers must be covered by msw.
|
|
@@ -51,17 +51,17 @@ Before AI writes or commits code, it performs an **8-step gated flow**. Steps 1-
|
|
|
51
51
|
|
|
52
52
|
## Outputs
|
|
53
53
|
|
|
54
|
-
- Code placed under the conventional path
|
|
55
|
-
- Reuse decisions explicitly logged ("reused `Button` from `@teamix-evo/ui`" / "reused `um-topbar` from `biz-ui/uni-manager`" / "no match found, wrote a new `
|
|
54
|
+
- Code placed under the conventional path (`src/pages/<id>/`、`src/features/<domain>/api.ts`、…)
|
|
55
|
+
- Reuse decisions explicitly logged ("reused `Button` from `@teamix-evo/ui`" / "reused `um-topbar` from `biz-ui/uni-manager`" / "no match found, wrote a new `InstanceCard` under `src/components/`")
|
|
56
56
|
- Tenant / region / cloud context propagation logged
|
|
57
57
|
- Pass / fail status against [`checklist.md`](checklist.md)
|
|
58
58
|
|
|
59
59
|
## How to invoke (typical flow)
|
|
60
60
|
|
|
61
61
|
1. Parse user intent → identify which artifact is being created (page / component / service / hook / util / form / route)
|
|
62
|
-
2. Read [`reuse-first.md`](reuse-first.md) and run the reuse query (
|
|
62
|
+
2. Read [`reuse-first.md`](reuse-first.md) and run the reuse query (读 `.teamix-evo/meta/` 本地文件, then biz-ui/uni-manager, then local grep)
|
|
63
63
|
3. Read [`file-structure.md`](file-structure.md) to pick the destination directory
|
|
64
|
-
4. If the change touches network / backend, read [`api-layering.md`](api-layering.md) — confirm tenant / region / cloud headers are injected via interceptor
|
|
64
|
+
4. If the change touches network / backend, read [`api-layering.md`](api-layering.md) — confirm tenant / region / cloud headers are injected via interceptor; place api in `src/features/<domain>/api.ts`
|
|
65
65
|
5. If the change involves a form, read [`forms-and-validation.md`](forms-and-validation.md) — for dangerous operations, plug `useDangerConfirm`
|
|
66
66
|
6. If the change adds a page / data hook, read [`error-and-loading.md`](error-and-loading.md) for fallback / Skeleton / toast wiring
|
|
67
67
|
7. If the change adds a route or page entry, read [`routing-and-codesplit.md`](routing-and-codesplit.md) — confirm tenant / region URL sync
|
|
@@ -75,7 +75,7 @@ Before AI writes or commits code, it performs an **8-step gated flow**. Steps 1-
|
|
|
75
75
|
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- |
|
|
76
76
|
| [`reuse-first.md`](reuse-first.md) | 复用决策流(ui 原子件 + biz-ui/uni-manager + 本项目);组件兜底铁律 |
|
|
77
77
|
| [`file-structure.md`](file-structure.md) | 顶层 `src/` 目录骨架、归属、import 边界、命名、全局态分级(含 TenantContext / RegionContext) |
|
|
78
|
-
| [`api-layering.md`](api-layering.md) |
|
|
78
|
+
| [`api-layering.md`](api-layering.md) | Feature-based 三层结构(`features/<domain>/`)+ 多租户 / 多区域 / 跨云上下文注入 |
|
|
79
79
|
| [`forms-and-validation.md`](forms-and-validation.md) | `react-hook-form` + `zod`;危险操作走 `useDangerConfirm`(输入资源名称确认) |
|
|
80
80
|
| [`error-and-loading.md`](error-and-loading.md) | 全局 / 页面 ErrorBoundary、三态、Suspense、toast、跨云资源专属 fallback |
|
|
81
81
|
| [`routing-and-codesplit.md`](routing-and-codesplit.md) | `React.lazy`、guards、404/403/500、tenant/region/cloud 进 URL search params、um-topbar 切换 URL 改写 |
|
|
@@ -91,7 +91,7 @@ Before AI writes or commits code, it performs an **8-step gated flow**. Steps 1-
|
|
|
91
91
|
## Why these conventions(uni-manager 视角)
|
|
92
92
|
|
|
93
93
|
- **Single source for UI** — `@teamix-evo/ui` 89 原子件 + `biz-ui/uni-manager`(当前 1 实物 um-topbar,其余如 CloudBadge / ContextSwitcher 是概念占位)。Re-implementing 顶部 topbar / 基础件会破坏一致性三件套(UM1/UM2/UM3)。
|
|
94
|
-
- **Stable seams for change** — tenant / region / cloud 上下文集中在 `lib/http.ts` interceptor 与 `contexts/TenantContext.tsx`,新增云厂商或区域不需要改 89 处
|
|
94
|
+
- **Stable seams for change** — tenant / region / cloud 上下文集中在 `lib/http.ts` interceptor 与 `contexts/TenantContext.tsx`,新增云厂商或区域不需要改 89 处 api 调用。keeping API calls in `src/features/<domain>/api.ts` means a backend rename only edits one file; keeping components free of fetch logic means they stay easy to test and reuse.
|
|
95
95
|
- **Predictable file location** — 所有 uni-manager 项目目录形状一致;新接手的人 5 分钟内能找到「租户切换在哪管」「跨云列表怎么写」「危险操作怎么二次确认」。
|
|
96
96
|
|
|
97
97
|
<!-- teamix-evo:managed:end -->
|