@teamix-evo/skills 0.3.0 → 0.4.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/manifest.json +61 -45
- package/package.json +2 -2
- package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/SKILL.md +18 -18
- package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/checklist.md +2 -2
- package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/reuse-first.md +25 -17
- package/src/teamix-evo-code-uni-manager/SKILL.md +95 -0
- package/src/teamix-evo-code-uni-manager/api-layering.md +370 -0
- package/src/teamix-evo-code-uni-manager/checklist.md +193 -0
- package/src/teamix-evo-code-uni-manager/error-and-loading.md +389 -0
- package/src/teamix-evo-code-uni-manager/file-structure.md +339 -0
- package/src/teamix-evo-code-uni-manager/forms-and-validation.md +459 -0
- package/src/teamix-evo-code-uni-manager/reuse-first.md +188 -0
- package/src/teamix-evo-code-uni-manager/routing-and-codesplit.md +450 -0
- package/src/teamix-evo-code-uni-manager/testing.md +396 -0
- package/src/teamix-evo-design-opentrek/SKILL.md +71 -0
- package/src/teamix-evo-design-opentrek/boundaries.md +513 -0
- package/src/teamix-evo-design-opentrek/brand.md +154 -0
- package/src/teamix-evo-design-opentrek/checklist.md +83 -0
- package/src/teamix-evo-design-opentrek/components.md +245 -0
- package/src/teamix-evo-design-opentrek/flows.md +51 -0
- package/src/teamix-evo-design-opentrek/foundations.md +271 -0
- package/src/teamix-evo-design-opentrek/generation-flow.md +185 -0
- package/src/teamix-evo-design-opentrek/patterns/dashboard.md +31 -0
- package/src/teamix-evo-design-opentrek/patterns/detail-page.md +202 -0
- package/src/teamix-evo-design-opentrek/patterns/form-page.md +289 -0
- package/src/teamix-evo-design-opentrek/patterns/list-page.md +334 -0
- package/src/teamix-evo-design-opentrek/patterns/page-types.md +154 -0
- package/src/teamix-evo-design-opentrek/philosophy.md +96 -0
- package/src/teamix-evo-design-opentrek/rules/README.md +39 -0
- package/src/teamix-evo-design-opentrek/rules/boundaries.rules.json +391 -0
- package/src/teamix-evo-design-uni-manager/SKILL.md +73 -0
- package/src/teamix-evo-design-uni-manager/boundaries.md +564 -0
- package/src/teamix-evo-design-uni-manager/brand.md +202 -0
- package/src/teamix-evo-design-uni-manager/checklist.md +115 -0
- package/src/teamix-evo-design-uni-manager/components.md +254 -0
- package/src/teamix-evo-design-uni-manager/flows.md +63 -0
- package/src/teamix-evo-design-uni-manager/foundations.md +258 -0
- package/src/teamix-evo-design-uni-manager/generation-flow.md +194 -0
- package/src/teamix-evo-design-uni-manager/patterns/dashboard.md +95 -0
- package/src/teamix-evo-design-uni-manager/patterns/detail-page.md +224 -0
- package/src/teamix-evo-design-uni-manager/patterns/form-page.md +329 -0
- package/src/teamix-evo-design-uni-manager/patterns/list-page.md +356 -0
- package/src/teamix-evo-design-uni-manager/patterns/page-types.md +165 -0
- package/src/teamix-evo-design-uni-manager/philosophy.md +106 -0
- package/src/teamix-evo-design-uni-manager/rules/README.md +49 -0
- package/src/teamix-evo-design-uni-manager/rules/boundaries.rules.json +418 -0
- package/src/teamix-evo-manage/SKILL.md +281 -0
- package/skills/teamix-evo-design-rules/SKILL.md +0 -86
- package/skills/teamix-evo-design-rules/boundaries.md +0 -89
- package/skills/teamix-evo-design-rules/checklist.md +0 -108
- package/skills/teamix-evo-design-rules/generation-flow.md +0 -142
- package/skills/teamix-evo-design-rules/prompts/page-design.md +0 -148
- package/skills/teamix-evo-design-rules-opentrek/SKILL.md +0 -48
- package/skills/teamix-evo-design-rules-opentrek/brand-rules.md +0 -74
- package/skills/teamix-evo-design-rules-uni-manager/SKILL.md +0 -51
- package/skills/teamix-evo-design-rules-uni-manager/ai-scenarios.md +0 -51
- package/skills/teamix-evo-design-rules-uni-manager/command-center.md +0 -108
- package/skills/teamix-evo-design-rules-uni-manager/danger-ops.md +0 -87
- package/skills/teamix-evo-manage/SKILL.md +0 -178
- package/skills/teamix-evo-ui-upgrade/SKILL.md +0 -75
- /package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/api-layering.md +0 -0
- /package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/error-and-loading.md +0 -0
- /package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/file-structure.md +0 -0
- /package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/forms-and-validation.md +0 -0
- /package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/routing-and-codesplit.md +0 -0
- /package/{skills/teamix-evo-coding-conventions → src/teamix-evo-code-opentrek}/testing.md +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# 业务工程目录约定(uni-manager)
|
|
2
|
+
|
|
3
|
+
> 业内主流 React/Vite 业务工程的标准目录骨架。本文件是 AI 决定"新建文件应该放在哪"的唯一参考。**uni-manager 在通用结构基础上,额外约定多租户/多区域/跨云上下文相关目录。**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 顶层 `src/` 骨架
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/
|
|
11
|
+
├── pages/ # 路由页面(每个目录对应一条路由)
|
|
12
|
+
├── components/ # 跨页面复用的业务组件
|
|
13
|
+
├── services/ # 后端通信(纯函数,见 api-layering.md)
|
|
14
|
+
├── hooks/ # 自定义 Hook(包含数据 hook、UI hook)
|
|
15
|
+
├── contexts/ # React Context(跨子树共享、低频更新的全局态;含 TenantContext / RegionContext)
|
|
16
|
+
├── stores/ # 高频全局态(zustand / jotai / redux,首次需要时引入,只用一种)
|
|
17
|
+
├── types/ # Domain / API 类型声明(.ts 仅类型,无运行时)
|
|
18
|
+
├── utils/ # 纯函数工具(无 React、无副作用)
|
|
19
|
+
├── lib/ # 三方 SDK 包装、http 实例、active-context、monitor
|
|
20
|
+
├── routes/ # 路由配置 + 守卫(若用 react-router 集中式声明)
|
|
21
|
+
├── layouts/ # 应用级 / 区域级布局(ConsoleLayout、AuthLayout)
|
|
22
|
+
├── test/ # 测试基础设施(setup.ts、handlers.ts、render.tsx、fixtures/)
|
|
23
|
+
├── styles/ # 全局样式 / token 覆盖(尽量少)
|
|
24
|
+
├── assets/ # 图片 / 字体 / 静态文件
|
|
25
|
+
├── locales/ # i18n 资源(可选)
|
|
26
|
+
├── main.tsx # 应用入口
|
|
27
|
+
└── App.tsx # 根组件
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
> 没列出的目录按需补,但**不要**新增同义层(如同时有 `utils/` 和 `helpers/`、`api/` 和 `services/`、`views/` 和 `pages/`)。`*.test.ts(x)` 文件**就近**放在被测文件同目录,**不要**集中堆到顶层 `tests/`(见 [`testing.md`](testing.md))。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## uni-manager 增量目录约定
|
|
35
|
+
|
|
36
|
+
| 路径 | 用途 |
|
|
37
|
+
| -------------------------------- | ------------------------------------------------------------------------------- |
|
|
38
|
+
| `src/contexts/TenantContext.tsx` | 租户上下文 Provider + `useTenant()` |
|
|
39
|
+
| `src/contexts/RegionContext.tsx` | 区域上下文 Provider + `useRegion()` |
|
|
40
|
+
| `src/lib/active-context.ts` | vanilla TS 实现的 active tenant/region/cloud 单例(供 interceptor 与 React 共享) |
|
|
41
|
+
| `src/lib/http.ts` | 集中注入 `X-Tenant-Id` / `X-Region-Id` / `X-Cloud-Provider` 请求头 |
|
|
42
|
+
| `src/components/cloud/` | 跨云通用组件占位:`CloudBadge`、`RegionBadge`、`ProviderIcon` |
|
|
43
|
+
| `src/components/danger/` | 危险操作组件占位:`DangerConfirmDialog`、`useDangerConfirm` |
|
|
44
|
+
| `src/components/context/` | 上下文切换组件占位:`ContextSwitcher`(切租户/区域时弹 AlertDialog) |
|
|
45
|
+
| `src/services/<domain>.cloud.ts` | 跨云查询服务(显式覆盖 interceptor,并发多 cloud) |
|
|
46
|
+
|
|
47
|
+
> 这些目录是"概念占位拼装"的标准落点(详见 [reuse-first.md](reuse-first.md))。biz-ui/uni-manager 已实装 `um-topbar`,其余先以本工程内组件兜底,后续逐步抽包。
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 各目录职责与边界
|
|
52
|
+
|
|
53
|
+
### `src/pages/`
|
|
54
|
+
|
|
55
|
+
**职责**:路由页面。一个目录 = 一条路由。
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
src/pages/
|
|
59
|
+
├── instances/
|
|
60
|
+
│ ├── index.tsx # 列表页(/instances)
|
|
61
|
+
│ ├── [id].tsx # 详情页(/instances/:id)
|
|
62
|
+
│ ├── _components/ # 仅本页面用的子组件(下划线前缀,不导出给外部)
|
|
63
|
+
│ │ └── InstanceFilterBar.tsx
|
|
64
|
+
│ └── _hooks/ # 仅本页面用的 hook
|
|
65
|
+
│ └── useInstanceFilter.ts
|
|
66
|
+
└── tenants/
|
|
67
|
+
└── ...
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
约束:
|
|
71
|
+
|
|
72
|
+
- 页面组件**默认 default export**,与文件名一致
|
|
73
|
+
- `_components/` `_hooks/` 用下划线前缀标记**私有**,**禁止跨页面 import**
|
|
74
|
+
- 跨页面用得到的组件/hook → 升到 `src/components/` `src/hooks/`
|
|
75
|
+
|
|
76
|
+
### `src/components/`
|
|
77
|
+
|
|
78
|
+
**职责**:跨页面复用的业务组件。
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
src/components/
|
|
82
|
+
├── InstanceStatusBadge.tsx
|
|
83
|
+
├── TenantAvatar.tsx
|
|
84
|
+
├── cloud/
|
|
85
|
+
│ ├── CloudBadge.tsx
|
|
86
|
+
│ ├── RegionBadge.tsx
|
|
87
|
+
│ └── ProviderIcon.tsx
|
|
88
|
+
├── danger/
|
|
89
|
+
│ └── DangerConfirmDialog.tsx
|
|
90
|
+
├── context/
|
|
91
|
+
│ └── ContextSwitcher.tsx
|
|
92
|
+
└── filters/
|
|
93
|
+
├── DateRangeFilter.tsx
|
|
94
|
+
└── StatusFilter.tsx
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
约束:
|
|
98
|
+
|
|
99
|
+
- 命名 PascalCase,文件名 = 组件名
|
|
100
|
+
- 单组件 = 单文件;复杂组件可建子目录 `<Name>/{index.tsx, types.ts, hooks.ts}`
|
|
101
|
+
- **不要**重复 `@teamix-evo/ui` / `biz-ui/uni-manager` 已经提供的能力(见 [reuse-first.md](reuse-first.md))
|
|
102
|
+
- **不要**写"小工具组件"如 `Wrapper`、`Container` —— 用 div + tailwind 即可
|
|
103
|
+
- 跨云/危险/上下文相关组件统一放 `cloud/` `danger/` `context/` 子目录,便于后续抽到 biz-ui/uni-manager
|
|
104
|
+
|
|
105
|
+
### `src/services/`
|
|
106
|
+
|
|
107
|
+
**职责**:后端通信纯函数。详见 [`api-layering.md`](api-layering.md)。
|
|
108
|
+
|
|
109
|
+
uni-manager 强约定:
|
|
110
|
+
|
|
111
|
+
- service **不显式拼 tenantId / regionId**(走 `lib/http.ts` interceptor 自动注入)
|
|
112
|
+
- 例外:跨云/跨租户查询接口 `*.cloud.ts`,可显式 `headers: { 'X-Tenant-Id': tenantId }` 覆盖
|
|
113
|
+
|
|
114
|
+
### `src/hooks/`
|
|
115
|
+
|
|
116
|
+
**职责**:跨页面复用的自定义 Hook。
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
src/hooks/
|
|
120
|
+
├── useInstanceList.ts # 数据 hook(queryKey 必须含 tenantId/regionId)
|
|
121
|
+
├── useCreateInstance.ts
|
|
122
|
+
├── useTenant.ts # 读取 TenantContext + 切换 active tenant
|
|
123
|
+
├── useRegion.ts
|
|
124
|
+
├── useCloudProvider.ts
|
|
125
|
+
├── useDangerConfirm.ts # 危险操作(输入资源名才执行)
|
|
126
|
+
└── useDebounce.ts
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
约束:
|
|
130
|
+
|
|
131
|
+
- 命名必须 `use` 开头
|
|
132
|
+
- 单 hook = 单文件
|
|
133
|
+
- 数据 hook 调 `src/services/`,**禁止**直接 fetch
|
|
134
|
+
- queryKey **必须**包含 `tenantId` / `regionId`(见 [`api-layering.md`](api-layering.md) §3)
|
|
135
|
+
|
|
136
|
+
### `src/contexts/`
|
|
137
|
+
|
|
138
|
+
**职责**:跨子树共享、低频更新的全局态。uni-manager 默认存在:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
src/contexts/
|
|
142
|
+
├── TenantContext.tsx # 当前租户(切换会触发 react-query invalidate)
|
|
143
|
+
├── RegionContext.tsx # 当前区域
|
|
144
|
+
└── UserContext.tsx # 当前用户
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
约束:
|
|
148
|
+
|
|
149
|
+
- Context Provider 内部**必须**双向同步 `lib/active-context.ts`(让 interceptor 能拿到最新值)
|
|
150
|
+
- Context value **必须**含 setter,切换时同时:
|
|
151
|
+
1. 写 active-context
|
|
152
|
+
2. URL 同步(`useSearchParams`)
|
|
153
|
+
3. `queryClient.invalidateQueries()`(详见 [`routing-and-codesplit.md`](routing-and-codesplit.md))
|
|
154
|
+
|
|
155
|
+
### 全局态选型决策
|
|
156
|
+
|
|
157
|
+
**装机时默认不预装任何状态库**。按"最小够用"逐级升级,不要直接跳到 zustand:
|
|
158
|
+
|
|
159
|
+
| 场景 | 用什么 |
|
|
160
|
+
| ------------------------------------------------ | -------------------------------------------------------- |
|
|
161
|
+
| 组件内状态 | `useState` / `useReducer` |
|
|
162
|
+
| 跨少量组件、低频更新(当前用户、主题、租户、区域) | React `Context` |
|
|
163
|
+
| 跨域、多页面、**高频**更新的客户端态 | `src/stores/`(zustand / jotai / redux 选一) |
|
|
164
|
+
| 服务端数据(列表、详情、表单提交) | `react-query` / `swr`,**永远不进 Context、也不进 store** |
|
|
165
|
+
|
|
166
|
+
> 如果项目自始至终只用 Context + react-query 就能解决,**不需要**建 `src/stores/`,也不需要引 zustand。等真出现跨域高频全局态再装。
|
|
167
|
+
|
|
168
|
+
### `src/stores/`
|
|
169
|
+
|
|
170
|
+
**职责**:跨域、高频更新的客户端全局态。**不是**全局态的默认入口,先看上方「全局态选型决策」。
|
|
171
|
+
|
|
172
|
+
约束:
|
|
173
|
+
|
|
174
|
+
- 一个项目**只用一种**状态库(zustand / jotai / redux 选一,首次需要时引入并固定)
|
|
175
|
+
- 按 domain 拆 store:`useInstanceStore.ts`、`useTenantStore.ts`
|
|
176
|
+
- **不要**把服务端数据放 store —— 用 `react-query` / `swr` 缓存(它们就是异步 store)
|
|
177
|
+
- **不要**为了消除一处 props drilling 就建 store —— 那是 Context 的场景
|
|
178
|
+
|
|
179
|
+
### `src/types/`
|
|
180
|
+
|
|
181
|
+
**职责**:类型声明。
|
|
182
|
+
|
|
183
|
+
约束:
|
|
184
|
+
|
|
185
|
+
- 只放 `.ts` 类型文件,**不导出运行时代码**
|
|
186
|
+
- 按 domain 拆:`instance.ts`、`tenant.ts`、`region.ts`、`cloud.ts`
|
|
187
|
+
- 通用类型放 `api.ts`、`common.ts`
|
|
188
|
+
|
|
189
|
+
### `src/utils/`
|
|
190
|
+
|
|
191
|
+
**职责**:纯函数工具。
|
|
192
|
+
|
|
193
|
+
约束:
|
|
194
|
+
|
|
195
|
+
- **不依赖 React**(用了 React 应该是 hook,放 `src/hooks/`)
|
|
196
|
+
- **不依赖 DOM**(用了 DOM 应该是 lib 层包装)
|
|
197
|
+
- **不发请求**(发请求是 service)
|
|
198
|
+
- 一个文件一个主题:`format.ts`、`validate.ts`、`array.ts`、`cloud.ts`(云厂商显示名映射)
|
|
199
|
+
|
|
200
|
+
### `src/lib/`
|
|
201
|
+
|
|
202
|
+
**职责**:三方 SDK 包装、http 实例、env 读取、active-context 单例。
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
src/lib/
|
|
206
|
+
├── http.ts # axios / fetch 实例(全局唯一,interceptor 注入 tenant/region/cloud)
|
|
207
|
+
├── active-context.ts # vanilla TS 单例:getActiveTenant / setActiveTenant ...
|
|
208
|
+
├── env.ts # import.meta.env 的类型化封装
|
|
209
|
+
├── analytics.ts # 埋点 SDK 包装
|
|
210
|
+
└── monitor.ts # Sentry / 错误上报
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
约束:
|
|
214
|
+
|
|
215
|
+
- 这一层**与 React 解耦**,可以在 Node / 测试中跑
|
|
216
|
+
- **不放业务逻辑** —— 业务逻辑去 service / hook
|
|
217
|
+
- `active-context.ts` 是 Context 与 interceptor 的桥梁:Context Provider 内 setter 双向同步它
|
|
218
|
+
|
|
219
|
+
### `src/routes/`
|
|
220
|
+
|
|
221
|
+
仅当使用集中式路由声明(react-router data router)时才有:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
src/routes/
|
|
225
|
+
├── index.tsx # createBrowserRouter 声明
|
|
226
|
+
├── guards.tsx # 鉴权守卫 + 租户/区域参数守卫
|
|
227
|
+
└── paths.ts # 路径常量集中
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
文件路由(file-based routing)项目不需要这个目录。
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 命名约定
|
|
235
|
+
|
|
236
|
+
| 类型 | 风格 | 例 |
|
|
237
|
+
| -------------- | ------------------------------------ | ----------------------------------- |
|
|
238
|
+
| 目录 | kebab-case | `src/pages/instance-detail/` |
|
|
239
|
+
| React 组件文件 | PascalCase.tsx | `InstanceStatusBadge.tsx` |
|
|
240
|
+
| Hook 文件 | camelCase.ts,`use` 前缀 | `useInstanceList.ts` |
|
|
241
|
+
| Service 文件 | camelCase.ts,domain 名 | `instance.ts` / `instance.cloud.ts` |
|
|
242
|
+
| 工具文件 | camelCase.ts | `formatDate.ts` |
|
|
243
|
+
| 类型文件 | camelCase.ts,domain 名 | `instance.ts` |
|
|
244
|
+
| 常量文件 | camelCase.ts 或 SCREAMING_SNAKE 导出 | `constants.ts` |
|
|
245
|
+
| 测试文件 | `*.test.ts(x)` 紧邻被测文件 | `formatDate.test.ts` |
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 路径别名
|
|
250
|
+
|
|
251
|
+
业务工程默认配 `@/*` 指向 `src/*`,所有跨目录 import 走别名:
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
// ✅
|
|
255
|
+
import { Button } from '@teamix-evo/ui';
|
|
256
|
+
import { Topbar } from 'biz-ui/uni-manager/um-topbar';
|
|
257
|
+
import { listInstances } from '@/services/instance';
|
|
258
|
+
import { CloudBadge } from '@/components/cloud/CloudBadge';
|
|
259
|
+
|
|
260
|
+
// ❌
|
|
261
|
+
import { listInstances } from '../../../services/instance';
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Import 边界(单向依赖)
|
|
267
|
+
|
|
268
|
+
```
|
|
269
|
+
pages ──▶ components, hooks, services, types, utils, lib, stores, contexts
|
|
270
|
+
components ──▶ hooks, services, types, utils, lib, contexts (NOT pages)
|
|
271
|
+
hooks ──▶ services, types, utils, lib, stores, contexts (NOT components, NOT pages)
|
|
272
|
+
services ──▶ types, lib (NOT hooks, NOT components, NOT pages, NOT contexts)
|
|
273
|
+
contexts ──▶ types, utils, lib (NOT services, NOT hooks)
|
|
274
|
+
stores ──▶ types, utils, lib (NOT services, NOT hooks)
|
|
275
|
+
types ──▶ (no runtime imports)
|
|
276
|
+
utils ──▶ types only
|
|
277
|
+
lib ──▶ types only
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
要点:
|
|
281
|
+
|
|
282
|
+
- **services 不依赖 React** —— 它是纯函数层(tenant/region 走 interceptor,不在 service 显式读 Context)
|
|
283
|
+
- **types / utils / lib 是叶子层** —— 不依赖业务层,谁都能引
|
|
284
|
+
- **反向依赖直接否决**(component 不能 import page,service 不能 import hook)
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 反模式速查
|
|
289
|
+
|
|
290
|
+
| 反模式 | 为什么禁 | 应该怎么做 |
|
|
291
|
+
| ----------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
292
|
+
| `src/views/`、`src/screens/` 与 `src/pages/` 并存 | 同义层,认知爆炸 | 二选一,统一叫 `pages/` |
|
|
293
|
+
| `src/api/` 与 `src/services/` 并存 | 同义层 | 统一叫 `services/` |
|
|
294
|
+
| `src/utils/` 与 `src/helpers/` 并存 | 同义层 | 统一叫 `utils/` |
|
|
295
|
+
| 在 `src/components/` 里写 page-only 组件 | 抽象层级别错位 | 放 `src/pages/<id>/_components/` |
|
|
296
|
+
| 在 `src/utils/` 里写 React Hook | 边界错位 | 放 `src/hooks/` |
|
|
297
|
+
| 一个文件 export 5 个不相关的工具 | 命名失焦 | 拆成多文件,一个主题一个文件 |
|
|
298
|
+
| `index.ts` 大量 `export *` 当 barrel | 影响 tree-shaking、循环依赖 | 显式 named export 需要的几个 |
|
|
299
|
+
| 为消除一处 props drilling 直接引 zustand | 升级过度,徒增心智 | 用 React `Context` |
|
|
300
|
+
| 服务端数据塞进 Context / store | 与 query 缓存形成双源,易漂移 | 一律走 `react-query` / `swr` |
|
|
301
|
+
| 表单字段用一堆 `useState` 拼 | 字段越多越糟,校验散落 | `useForm` + `zodResolver`(见 [`forms-and-validation.md`](forms-and-validation.md)) |
|
|
302
|
+
| 页面顶部 `import` 不 lazy + 无 Suspense | 首屏 bundle 爆炸 / 进入即崩 | `React.lazy` + Layout 挂 Suspense(见 [`routing-and-codesplit.md`](routing-and-codesplit.md)) |
|
|
303
|
+
| 鉴权写在每个 page 顶部 | 散乱、易漏、UI 与 URL 两层不一致 | `src/routes/guards.tsx` 集中,URL 与 sidebar 两层都判 |
|
|
304
|
+
| 全局没有 ErrorBoundary | 任何未捕获异常直接白屏 | App 根挂 `ErrorBoundary` + `reportError` |
|
|
305
|
+
| 测试堆在顶层 `tests/` 目录 | 改文件忘记移动测试,易漂移 | `*.test.ts(x)` 就近紧邻被测文件 |
|
|
306
|
+
| `alert()` / `window.location.href = ...` | 阻断、丑、丢状态 | `toast.error()` / `useNavigate()` |
|
|
307
|
+
| 自建 `Topbar.tsx` 替代 `biz-ui/uni-manager/um-topbar` | 一致性三件套 UM1 红线 | 直接用 `um-topbar`(见 [reuse-first.md](reuse-first.md)) |
|
|
308
|
+
| service 函数手动拼接 `tenantId` | 上下文与传输层耦合,散点漂移 | `lib/http.ts` interceptor 集中注入(见 [`api-layering.md`](api-layering.md)) |
|
|
309
|
+
| 危险删除接口只用 `confirm("确定?")` | UM 红线,误操作概率高 | `useDangerConfirm`(见 [`forms-and-validation.md`](forms-and-validation.md) §10) |
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 决策速查表
|
|
314
|
+
|
|
315
|
+
| AI 收到的请求 | 文件应该放在 |
|
|
316
|
+
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
317
|
+
| 新增实例列表页 | `src/pages/instances/index.tsx` |
|
|
318
|
+
| 新增实例状态徽章(跨页面用) | `src/components/InstanceStatusBadge.tsx` |
|
|
319
|
+
| 新增实例状态徽章(只在实例页用) | `src/pages/instances/_components/InstanceStatusBadge.tsx` |
|
|
320
|
+
| 新增"释放实例"接口调用 | `src/services/instance.ts` 加 `releaseInstance` |
|
|
321
|
+
| 新增"释放实例"的 mutation hook | `src/hooks/useReleaseInstance.ts`(用 useDangerConfirm 包装) |
|
|
322
|
+
| 新增日期格式化函数 | `src/utils/format.ts`(先 grep 是否已存在) |
|
|
323
|
+
| 新增鉴权 + 租户 header 拦截器 | `src/lib/http.ts` 加 interceptor;active 值放 `src/lib/active-context.ts` |
|
|
324
|
+
| 新增实例 domain 类型 | `src/types/instance.ts` |
|
|
325
|
+
| 跨少量组件分享当前用户 / 主题 / 租户 / 区域 | `src/contexts/<Name>Context.tsx`(同时同步 `lib/active-context.ts`) |
|
|
326
|
+
| 跨域高频全局态(首次需要) | `src/stores/useXxxStore.ts`(按需引 zustand,固定后只用一种) |
|
|
327
|
+
| 列表 / 详情等服务端数据 | `src/hooks/useXxx.ts` 包 `react-query`,queryKey 含 tenantId/regionId,**不进** store / Context |
|
|
328
|
+
| 新增"创建实例表单" | `src/pages/instances/new/_components/CreateInstanceForm.tsx` + `src/services/instance.schema.ts` |
|
|
329
|
+
| 跨页面复用表单(地址 / 标签编辑) | `src/components/forms/<Name>Form.tsx` + 对应 schema |
|
|
330
|
+
| 新增路由 / 页面入口 | `src/routes/index.tsx` 注册 + `src/pages/<id>/index.tsx`(default export,被 `React.lazy` 引入) |
|
|
331
|
+
| 新增鉴权 / 角色守卫 | `src/routes/guards.tsx` |
|
|
332
|
+
| 全局 ErrorBoundary fallback 组件 | `src/components/GlobalErrorFallback.tsx` |
|
|
333
|
+
| 跨云资源 404 兜底(资源被删除/迁移) | `src/components/cloud/CloudResourceNotFound.tsx`(见 [`error-and-loading.md`](error-and-loading.md) §7) |
|
|
334
|
+
| Sentry / 日志上报包装 | `src/lib/monitor.ts`(`reportError(err, extra?)`) |
|
|
335
|
+
| 测试基础设施(msw handler / 自定义 render) | `src/test/handlers.ts` / `src/test/render.tsx` |
|
|
336
|
+
| 纯函数 / service / hook 的测试 | 同目录 `<name>.test.ts(x)`(就近,不集中) |
|
|
337
|
+
| 跨云查询(并发多 cloud / 显式 tenantId 覆盖) | `src/services/<domain>.cloud.ts`(显式传 header,**不**走 active-context) |
|
|
338
|
+
| 危险确认对话框(输入资源名才执行) | `src/components/danger/DangerConfirmDialog.tsx` + `src/hooks/useDangerConfirm.ts` |
|
|
339
|
+
| 全局 topbar(品牌 / 租户切换 / 区域切换 / 用户菜单) | **直接用** `biz-ui/uni-manager/um-topbar`,**不要**自建 |
|