create-dwy 0.15.0 → 0.16.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/CHANGELOG.md +8 -0
- package/bin/index.js +5 -3
- package/package.json +1 -1
- package/src/skills-install.js +48 -7
- package/src/sync-all.js +6 -18
- package/templates/ai-tools/CLAUDE.md +27 -0
- package/templates/ai-tools/rules/Android/dwy-android-pitfalls.md +52 -0
- package/templates/ai-tools/rules/Python/dwy-python-backend.md +16 -63
- package/templates/ai-tools/rules/Python/dwy-python-base-lib.md +89 -0
- package/templates/ai-tools/rules/Python/dwy-python-pitfalls.md +49 -0
- package/templates/ai-tools/rules/Vue/dwy-vue-base-lib.md +127 -0
- package/templates/ai-tools/rules/Vue/dwy-vue-core.md +22 -86
- package/templates/ai-tools/rules/Vue/dwy-vue-pitfalls.md +66 -0
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dependency-freshness.md +59 -0
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-development.md +47 -2
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-acceptance/SKILL.md +3 -2
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md +51 -9
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-commercial/SKILL.md +58 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-competitor/SKILL.md +2 -1
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-explore/SKILL.md +83 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-mvp/SKILL.md +2 -1
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prd/SKILL.md +1 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/SKILL.md +14 -9
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/references/state-and-contract.md +65 -13
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prototype/SKILL.md +30 -11
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-release/SKILL.md +3 -2
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-design/SKILL.md +17 -10
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-dev/SKILL.md +42 -10
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-launch/SKILL.md +22 -10
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-prd/SKILL.md +13 -4
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-ship/SKILL.md +13 -4
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tasks/SKILL.md +12 -2
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tdd-dev/SKILL.md +15 -6
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-validate/SKILL.md +2 -1
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-version/SKILL.md +1 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-ideate/SKILL.md +0 -21
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/SKILL.md +0 -113
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/templates/STATE.md +0 -56
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dev-qa/SKILL.md +0 -117
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-market-analysis/SKILL.md +0 -92
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-coarse/SKILL.md +0 -72
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-coarse/templates/prd-coarse.md +0 -61
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-detailed/SKILL.md +0 -76
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-detailed/templates/prd-detailed.md +0 -119
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prototype/SKILL.md +0 -104
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-spike/SKILL.md +0 -81
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-dev/SKILL.md +0 -212
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-dev/templates/impl-plan.md +0 -115
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tech-feasibility/SKILL.md +0 -105
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-version-plan/SKILL.md +0 -64
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-version-plan/templates/version-plan.md +0 -72
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 团队内部基础库强制复用规范(eui UI 组件 + ekit 工具:禁重复造轮子、HTTP/存储/日期/校验/脱敏走 ekit、UI 走 eui)
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*.vue"
|
|
5
|
+
- "**/*.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Vue 团队基础库强制复用规范
|
|
9
|
+
|
|
10
|
+
`dwy-vue-core` rule 的团队内补充。通用 Vue 工程规范见 `dwy-vue-core`;本文件只管「凡 eui / ekit 已提供的能力,禁止自行实现,也禁止引入其他库重复造轮子」。
|
|
11
|
+
|
|
12
|
+
`@dwydev/eui` 与 `@dwydev/ekit` 是团队内部 npm 基础库,分别覆盖 UI 组件层与通用工具层。
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 一、必须复用的能力域
|
|
17
|
+
|
|
18
|
+
| 能力域 | 归属 |
|
|
19
|
+
|--------|------|
|
|
20
|
+
| 通用 UI 组件(Button / Input / Select / Dialog / Drawer / Form / Table 等) | eui |
|
|
21
|
+
| 主题 / 设计 tokens / 暗色模式 | eui |
|
|
22
|
+
| 表单校验(vee-validate + zod 集成) | eui + ekit |
|
|
23
|
+
| 中后台 / 落地页设计规范 | eui(references) |
|
|
24
|
+
| HTTP 客户端(拦截器 / token / 刷新 / 解包) | ekit |
|
|
25
|
+
| 本地存储 / Cookie | ekit(storage / cookie) |
|
|
26
|
+
| 日期 / 时间格式化 | ekit(date) |
|
|
27
|
+
| 数据校验 schema | ekit(validators) |
|
|
28
|
+
| PII 数据脱敏 | ekit(masking) |
|
|
29
|
+
| 剪贴板 / 文件下载 / qs 序列化 | ekit |
|
|
30
|
+
| VueUse 再导出(debounce / throttle / clickOutside / mediaQuery 等) | ekit(hooks) |
|
|
31
|
+
|
|
32
|
+
### 查阅方式(关键)
|
|
33
|
+
|
|
34
|
+
**在编写任何 Vue 代码前,以及调用任何 eui / ekit 提供的 API 之前,必须先用 `Skill` 工具加载对应 skill 查阅当前最新接口。** 本文件只规定约束与边界,**不固化**组件 props、函数签名 —— 这些会随版本演进,固化在 rule 里会与实际包不同步。
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Skill 工具调用:
|
|
38
|
+
- skill="dwy-eui" 组件库 API 与设计规范
|
|
39
|
+
- skill="dwy-ekit" 工具库 API 与契约
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 二、强制规则
|
|
45
|
+
|
|
46
|
+
- **禁止**业务代码出现 `axios` / `fetch` / `new XMLHttpRequest`,HTTP 走 ekit `createRequest`
|
|
47
|
+
- **禁止**直接 `localStorage.getItem` / `setItem` / `removeItem`,走 ekit storage / `useStorage`
|
|
48
|
+
- **禁止**直接 `document.cookie` 或单独引入 `js-cookie`,走 ekit cookie
|
|
49
|
+
- **禁止**业务代码 `new Date()` / `toLocaleString` / 直接 `import dayjs`,走 ekit date
|
|
50
|
+
- **禁止**手写 `navigator.clipboard` / `document.addEventListener('click', ...)` 监听,走 ekit copy / hooks
|
|
51
|
+
- **禁止**自定义已有 UI 组件(Button / Input / Select / Dialog / Form / Table 等),走 eui
|
|
52
|
+
- **禁止**自定义已有日期 / 时间 / 验证 / 脱敏 / 下载 工具函数,走 ekit
|
|
53
|
+
- 涉及任一能力域,**先查 skill 拿到当前 API,再写代码**
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 三、API 请求
|
|
58
|
+
|
|
59
|
+
### 强制规则
|
|
60
|
+
|
|
61
|
+
- HTTP 客户端**必须**用 ekit `createRequest` 创建,全局唯一实例放 `core/http.ts`(具体参数与插件查 `dwy-ekit` skill)
|
|
62
|
+
- **禁止**业务代码 `axios.create()` / `fetch()` / `new XMLHttpRequest()`
|
|
63
|
+
- 响应解包契约与 dwyeapi 对齐(`{ code, message, data }`),具体类型与守卫查 `dwy-ekit` skill
|
|
64
|
+
- 401 / 422 / 业务错误的统一处理由 ekit request 插件完成(具体 API 查 `dwy-ekit` skill)
|
|
65
|
+
- 业务侧 catch 用 ekit 提供的 `isApiBusinessError` 类型守卫做分支(`NOT_FOUND` / `VALIDATION_ERROR` / `PERMISSION_DENIED` 等)
|
|
66
|
+
|
|
67
|
+
> API 函数的目录归属、独立导出、类型标注等结构约定见 `dwy-vue-core` 第六节。
|
|
68
|
+
|
|
69
|
+
### 示例
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// core/http.ts —— 全局唯一 HTTP 客户端(具体 plugins 查 dwy-ekit skill)
|
|
73
|
+
import { createRequest } from '@dwydev/ekit'
|
|
74
|
+
|
|
75
|
+
export const request = createRequest({
|
|
76
|
+
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|
77
|
+
plugins: [
|
|
78
|
+
/* tokenPlugin / refreshTokenPlugin / unwrapPlugin —— 具体用法查 dwy-ekit skill */
|
|
79
|
+
],
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// modules/users/api.ts —— 该业务的 API
|
|
83
|
+
import { request } from '@/core/http'
|
|
84
|
+
import type { UserInfo, UserCreate } from './types'
|
|
85
|
+
|
|
86
|
+
export function getUsers(params: { page: number; page_size: number }) {
|
|
87
|
+
return request.get<{ items: UserInfo[]; total: number }>('/users', { params })
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function createUser(data: UserCreate) {
|
|
91
|
+
return request.post<UserInfo>('/users', data)
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 四、通用 hooks 走 ekit
|
|
98
|
+
|
|
99
|
+
通用 hooks(debounce / throttle / clickOutside / mediaQuery 等)**禁止**自己造,走 ekit hooks(具体 API 查 `dwy-ekit` skill)。
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 五、样式覆盖 eui
|
|
104
|
+
|
|
105
|
+
覆盖 eui 内部样式用 scoped CSS + `:deep(...)`(其余样式规范见 `dwy-vue-core` 第八节,优先 Tailwind)。
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 六、错误拦截走 ekit
|
|
110
|
+
|
|
111
|
+
401 / 422 / 业务错误的拦截走 ekit request 插件(查 `dwy-ekit` skill),**禁止**每个 API 都包 try-catch。业务侧统一在页面级或 store 级处理,用 `isApiBusinessError` 守卫分支。
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 七、违规检测清单(基础库相关)
|
|
116
|
+
|
|
117
|
+
AI 编写或审查 Vue 代码时,涉及 eui / ekit 必须检查以下违规模式(通用框架违规清单见 `dwy-vue-core` 第十四节):
|
|
118
|
+
|
|
119
|
+
| 检查项 | 违规模式 | 严重程度 |
|
|
120
|
+
|--------|---------|---------|
|
|
121
|
+
| 未查 skill | 使用 eui / ekit API 前未先查 `dwy-eui` / `dwy-ekit` skill | 高 |
|
|
122
|
+
| ekit 重复造轮子 | 自造 HTTP / storage / cookie / date / 校验 / 脱敏 等 ekit 已提供能力 | 高 |
|
|
123
|
+
| eui 重复造轮子 | 自造已有 UI 组件(Button / Input / Dialog 等) | 高 |
|
|
124
|
+
| 组件直调 axios | 组件内 `axios.get` / `fetch` / `new XMLHttpRequest` | **致命 → STOP** |
|
|
125
|
+
| 直接 localStorage | `localStorage.getItem` / `setItem` 出现在业务代码 | 高 |
|
|
126
|
+
| 直接 new Date | `new Date()` / `toLocaleString` / 直接 `import dayjs` | 高 |
|
|
127
|
+
| 旧 axios 例子 | 业务里出现 `axios.create()` / `interceptors.request.use(...)` | **致命 → STOP** |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Vue 3 + TS + Vite + Tailwind
|
|
2
|
+
description: Vue 3 + TS + Vite + Tailwind 应用层通用规范(业务聚合结构、组件 / TS / 路由 / API / 模板 / 样式 / 错误处理 / 注释)
|
|
3
3
|
paths:
|
|
4
4
|
- "**/*.vue"
|
|
5
5
|
- "**/*.ts"
|
|
@@ -8,50 +8,7 @@ paths:
|
|
|
8
8
|
|
|
9
9
|
# Vue 3 应用层开发规范
|
|
10
10
|
|
|
11
|
-
适用于基于 Vue 3 + TypeScript + Vite + Tailwind CSS
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 零、优先使用 eui / ekit 基础库(强制)
|
|
16
|
-
|
|
17
|
-
`@dwydev/eui` 与 `@dwydev/ekit` 是团队内部 npm 基础库,分别覆盖 UI 组件层与通用工具层。**凡是 eui / ekit 已提供的能力,禁止自行实现,也禁止引入其他库重复造轮子。**
|
|
18
|
-
|
|
19
|
-
### 必须复用的能力域
|
|
20
|
-
|
|
21
|
-
| 能力域 | 归属 |
|
|
22
|
-
|--------|------|
|
|
23
|
-
| 通用 UI 组件(Button / Input / Select / Dialog / Drawer / Form / Table 等) | eui |
|
|
24
|
-
| 主题 / 设计 tokens / 暗色模式 | eui |
|
|
25
|
-
| 表单校验(vee-validate + zod 集成) | eui + ekit |
|
|
26
|
-
| 中后台 / 落地页设计规范 | eui(references) |
|
|
27
|
-
| HTTP 客户端(拦截器 / token / 刷新 / 解包) | ekit |
|
|
28
|
-
| 本地存储 / Cookie | ekit(storage / cookie) |
|
|
29
|
-
| 日期 / 时间格式化 | ekit(date) |
|
|
30
|
-
| 数据校验 schema | ekit(validators) |
|
|
31
|
-
| PII 数据脱敏 | ekit(masking) |
|
|
32
|
-
| 剪贴板 / 文件下载 / qs 序列化 | ekit |
|
|
33
|
-
| VueUse 再导出(debounce / throttle / clickOutside / mediaQuery 等) | ekit(hooks) |
|
|
34
|
-
|
|
35
|
-
### 查阅方式(关键)
|
|
36
|
-
|
|
37
|
-
**在编写任何 Vue 代码前,以及调用任何 eui / ekit 提供的 API 之前,必须先用 `Skill` 工具加载对应 skill 查阅当前最新接口。** 本文件只规定约束与边界,**不固化**组件 props、函数签名 —— 这些会随版本演进,固化在 rule 里会与实际包不同步。
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
Skill 工具调用:
|
|
41
|
-
- skill="dwy-eui" 组件库 API 与设计规范
|
|
42
|
-
- skill="dwy-ekit" 工具库 API 与契约
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 强制规则
|
|
46
|
-
|
|
47
|
-
- **禁止**业务代码出现 `axios` / `fetch` / `new XMLHttpRequest`,HTTP 走 ekit `createRequest`
|
|
48
|
-
- **禁止**直接 `localStorage.getItem` / `setItem` / `removeItem`,走 ekit storage / `useStorage`
|
|
49
|
-
- **禁止**直接 `document.cookie` 或单独引入 `js-cookie`,走 ekit cookie
|
|
50
|
-
- **禁止**业务代码 `new Date()` / `toLocaleString` / 直接 `import dayjs`,走 ekit date
|
|
51
|
-
- **禁止**手写 `navigator.clipboard` / `document.addEventListener('click', ...)` 监听,走 ekit copy / hooks
|
|
52
|
-
- **禁止**自定义已有 UI 组件(Button / Input / Select / Dialog / Form / Table 等),走 eui
|
|
53
|
-
- **禁止**自定义已有日期 / 时间 / 验证 / 脱敏 / 下载 工具函数,走 ekit
|
|
54
|
-
- 涉及任一能力域,**先查 skill 拿到当前 API,再写代码**
|
|
11
|
+
适用于基于 Vue 3 + TypeScript + Vite + Tailwind CSS 的前端项目。团队内部 eui / ekit 基础库强制复用见 `dwy-vue-base-lib` rule;状态管理见 `dwy-vue-pinia` rule;测试见 `dwy-vue-testing` rule。
|
|
55
12
|
|
|
56
13
|
---
|
|
57
14
|
|
|
@@ -72,9 +29,9 @@ Skill 工具调用:
|
|
|
72
29
|
|
|
73
30
|
```
|
|
74
31
|
src/
|
|
75
|
-
├──
|
|
32
|
+
├── features/ # 业务功能根目录
|
|
76
33
|
│ ├── users/ # 用户功能
|
|
77
|
-
│ │ ├── api.ts # 该业务的 API
|
|
34
|
+
│ │ ├── api.ts # 该业务的 API(用全局 HTTP 客户端)
|
|
78
35
|
│ │ ├── store.ts # 该业务的 Pinia store
|
|
79
36
|
│ │ ├── types.ts # 该业务的类型
|
|
80
37
|
│ │ ├── views/ # 该业务的页面组件
|
|
@@ -92,7 +49,7 @@ src/
|
|
|
92
49
|
│ ├── composables/
|
|
93
50
|
│ └── constants/
|
|
94
51
|
├── core/ # 全局基础设施:HTTP client / 路由根 / 主题 / 启动
|
|
95
|
-
│ ├── http.ts #
|
|
52
|
+
│ ├── http.ts # 全局唯一 HTTP 客户端实例
|
|
96
53
|
│ ├── router.ts
|
|
97
54
|
│ └── main.ts
|
|
98
55
|
├── App.vue
|
|
@@ -135,12 +92,11 @@ export default {
|
|
|
135
92
|
```vue
|
|
136
93
|
<script setup lang="ts">
|
|
137
94
|
// 1. 类型导入
|
|
138
|
-
import type { UserInfo } from '@/
|
|
95
|
+
import type { UserInfo } from '@/features/users/types'
|
|
139
96
|
|
|
140
97
|
// 2. 组件 / 工具导入
|
|
141
98
|
import { ref, computed, onMounted } from 'vue'
|
|
142
99
|
import { useRouter } from 'vue-router'
|
|
143
|
-
import { EButton, EInput } from '@dwydev/eui'
|
|
144
100
|
|
|
145
101
|
// 3. Props / Emits
|
|
146
102
|
const props = defineProps<{ userId: number; title?: string }>()
|
|
@@ -250,7 +206,7 @@ const router = createRouter({
|
|
|
250
206
|
{
|
|
251
207
|
path: '/dashboard',
|
|
252
208
|
name: 'Dashboard',
|
|
253
|
-
component: () => import('@/
|
|
209
|
+
component: () => import('@/features/dashboard/views/DashboardView.vue'),
|
|
254
210
|
meta: { requiresAuth: true },
|
|
255
211
|
},
|
|
256
212
|
],
|
|
@@ -297,7 +253,7 @@ export function useList<T>(fetchFn: () => Promise<T[]>) {
|
|
|
297
253
|
}
|
|
298
254
|
```
|
|
299
255
|
|
|
300
|
-
通用 hooks(debounce / throttle / clickOutside / mediaQuery
|
|
256
|
+
通用 hooks(debounce / throttle / clickOutside / mediaQuery 等)**禁止**自己造,优先复用成熟现成方案。
|
|
301
257
|
|
|
302
258
|
---
|
|
303
259
|
|
|
@@ -305,27 +261,17 @@ export function useList<T>(fetchFn: () => Promise<T[]>) {
|
|
|
305
261
|
|
|
306
262
|
### 强制规则
|
|
307
263
|
|
|
308
|
-
- HTTP
|
|
309
|
-
- **禁止**业务代码 `axios.create()` / `fetch()` / `new XMLHttpRequest()`
|
|
264
|
+
- HTTP 客户端全局唯一实例放 `core/http.ts`,业务代码从该实例导入,**禁止**每个模块各自创建客户端
|
|
310
265
|
- 每个业务模块的 API 函数集中在该业务目录的 `api.ts`,按业务域隔离
|
|
311
266
|
- 每个 API 函数**独立导出**,**禁止** `default export`
|
|
312
267
|
- 请求参数 / 响应**必须**类型标注
|
|
313
|
-
|
|
268
|
+
|
|
269
|
+
> 团队项目 HTTP 客户端的创建(createRequest)、响应解包契约、错误处理守卫见 `dwy-vue-base-lib` rule。
|
|
314
270
|
|
|
315
271
|
### 示例
|
|
316
272
|
|
|
317
273
|
```typescript
|
|
318
|
-
//
|
|
319
|
-
import { createRequest } from '@dwydev/ekit'
|
|
320
|
-
|
|
321
|
-
export const request = createRequest({
|
|
322
|
-
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|
323
|
-
plugins: [
|
|
324
|
-
/* tokenPlugin / refreshTokenPlugin / unwrapPlugin —— 具体用法查 dwy-ekit skill */
|
|
325
|
-
],
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
// modules/users/api.ts —— 该业务的 API
|
|
274
|
+
// features/users/api.ts —— 该业务的 API
|
|
329
275
|
import { request } from '@/core/http'
|
|
330
276
|
import type { UserInfo, UserCreate } from './types'
|
|
331
277
|
|
|
@@ -340,8 +286,7 @@ export function createUser(data: UserCreate) {
|
|
|
340
286
|
|
|
341
287
|
### 错误处理契约
|
|
342
288
|
|
|
343
|
-
- 401 / 422 /
|
|
344
|
-
- 业务侧 catch 用 ekit 提供的 `isApiBusinessError` 类型守卫做分支(`NOT_FOUND` / `VALIDATION_ERROR` / `PERMISSION_DENIED` 等)
|
|
289
|
+
- 401 / 422 / 业务错误的统一处理放在 HTTP 客户端拦截层,不散落到每个调用点
|
|
345
290
|
- **禁止**每个 API 调用都包 `try/catch`,只在页面级或 store 级统一处理
|
|
346
291
|
|
|
347
292
|
---
|
|
@@ -360,7 +305,7 @@ export function createUser(data: UserCreate) {
|
|
|
360
305
|
<UserCard :user="user" @click="handleSelect" />
|
|
361
306
|
|
|
362
307
|
<!-- 双向绑定优先 v-model -->
|
|
363
|
-
<
|
|
308
|
+
<MyInput v-model="form.name" placeholder="请输入" />
|
|
364
309
|
```
|
|
365
310
|
|
|
366
311
|
**禁止**:
|
|
@@ -384,7 +329,7 @@ export function createUser(data: UserCreate) {
|
|
|
384
329
|
|
|
385
330
|
### 允许 scoped CSS 的场景
|
|
386
331
|
|
|
387
|
-
-
|
|
332
|
+
- 第三方组件库内部样式覆盖(`:deep(...)`)
|
|
388
333
|
- 复杂动画定义
|
|
389
334
|
- 无法用 Tailwind 表达的样式
|
|
390
335
|
|
|
@@ -448,7 +393,7 @@ async function handleSubmit() {
|
|
|
448
393
|
}
|
|
449
394
|
```
|
|
450
395
|
|
|
451
|
-
- 401 / 422 /
|
|
396
|
+
- 401 / 422 / 业务错误的拦截放在 HTTP 客户端拦截层统一处理,**禁止**每个 API 都包 try-catch
|
|
452
397
|
- **禁止**空 catch(`try { ... } catch {}` 吞异常)
|
|
453
398
|
- 异步操作**必须**有 loading 状态
|
|
454
399
|
|
|
@@ -482,16 +427,12 @@ VITE_API_BASE_URL=/api
|
|
|
482
427
|
import { ref, computed } from 'vue'
|
|
483
428
|
import { useRouter } from 'vue-router'
|
|
484
429
|
|
|
485
|
-
// 2. 第三方
|
|
430
|
+
// 2. 第三方 / 内部包
|
|
486
431
|
import { storeToRefs } from 'pinia'
|
|
487
432
|
|
|
488
|
-
// 3.
|
|
489
|
-
import {
|
|
490
|
-
import {
|
|
491
|
-
|
|
492
|
-
// 4. 项目内(@ 别名)
|
|
493
|
-
import { useAuthStore } from '@/modules/users/store'
|
|
494
|
-
import type { UserInfo } from '@/modules/users/types'
|
|
433
|
+
// 3. 项目内(@ 别名)
|
|
434
|
+
import { useAuthStore } from '@/features/users/store'
|
|
435
|
+
import type { UserInfo } from '@/features/users/types'
|
|
495
436
|
```
|
|
496
437
|
|
|
497
438
|
### 强制规则
|
|
@@ -555,19 +496,14 @@ AI 编写或审查 Vue 代码时,**必须**检查以下违规模式:
|
|
|
555
496
|
| **高** | 必须修正后才能继续,向用户说明 |
|
|
556
497
|
| **中** | 提示风险,建议修正 |
|
|
557
498
|
|
|
499
|
+
> 团队内部 eui / ekit 基础库相关的违规项(未查 skill、重复造轮子、组件直调 axios、直接 localStorage / new Date 等)见 `dwy-vue-base-lib` rule 第七节。
|
|
500
|
+
|
|
558
501
|
| 检查项 | 违规模式 | 严重程度 |
|
|
559
502
|
|--------|---------|---------|
|
|
560
|
-
| 未查 skill | 使用 eui / ekit API 前未先查 `dwy-eui` / `dwy-ekit` skill | 高 |
|
|
561
|
-
| ekit 重复造轮子 | 自造 HTTP / storage / cookie / date / 校验 / 脱敏 等 ekit 已提供能力 | 高 |
|
|
562
|
-
| eui 重复造轮子 | 自造已有 UI 组件(Button / Input / Dialog 等) | 高 |
|
|
563
|
-
| 组件直调 axios | 组件内 `axios.get` / `fetch` / `new XMLHttpRequest` | **致命 → STOP** |
|
|
564
|
-
| 直接 localStorage | `localStorage.getItem` / `setItem` 出现在业务代码 | 高 |
|
|
565
|
-
| 直接 new Date | `new Date()` / `toLocaleString` / 直接 `import dayjs` | 高 |
|
|
566
503
|
| 技术层散落 | 顶级 `views/` / `components/` / `stores/` / `api/` 把不同业务混放 | 高 |
|
|
567
504
|
| Options API | `<script>` 中 `export default { data, methods, ... }` | **致命 → STOP** |
|
|
568
505
|
| Options Store | `defineStore(id, { state, actions })` | **致命 → STOP** |
|
|
569
506
|
| any 无注释 | 使用 `any` 但未注释说明原因 | 高 |
|
|
570
|
-
| 旧 axios 例子 | 业务里出现 `axios.create()` / `interceptors.request.use(...)` | **致命 → STOP** |
|
|
571
507
|
| `v-if` + `v-for` 同元素 | 同一元素既 `v-if` 又 `v-for` | 高 |
|
|
572
508
|
| 模板复杂表达式 | 模板中 `.filter(...).length > 0` 等多语句 | 中 |
|
|
573
509
|
| 解构 store 丢响应性 | `const { x } = store`(应用 `storeToRefs`) | 高 |
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Vue 3 前端开发避坑清单(CSS 动画 / 响应式 / 路由 / 构建 / SSR 踩坑),按分类持续追加
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*.vue"
|
|
5
|
+
- "**/*.ts"
|
|
6
|
+
- "**/*.css"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Vue 3 前端开发坑清单
|
|
10
|
+
|
|
11
|
+
> 动手前先对照本清单避开已知坑;踩到新坑随手按四栏格式(现象 / 根因 / 正确做法 / 适用)追加到对应分类,没有合适分类就新建一个。
|
|
12
|
+
>
|
|
13
|
+
> 通用开发规范见 `dwy-vue-core` rule,本文件只记**非显而易见的实战坑**。
|
|
14
|
+
|
|
15
|
+
## 分类索引
|
|
16
|
+
|
|
17
|
+
- CSS 动画 / 过渡
|
|
18
|
+
- 响应式 / 组件(ref / reactive / 生命周期 / props)
|
|
19
|
+
- 路由(vue-router / 守卫 / 懒加载)
|
|
20
|
+
- 构建 / SSR(Vite / vite-ssg / 预渲染)
|
|
21
|
+
- i18n / 内容
|
|
22
|
+
- 排查方法论
|
|
23
|
+
- 其他分类遇到再加
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## CSS 动画 / 过渡
|
|
28
|
+
|
|
29
|
+
### View Transitions 圆形过渡:收回方向(clip-path 缩到 0)收尾闪一帧
|
|
30
|
+
|
|
31
|
+
- **现象**:用 View Transitions API + `clip-path: circle()` 做主题切换的圆形润开过渡。散开方向(圆 0→大)正常;收回方向(圆 大→0,旧层缩回圆心露出底下新主题)动画走完后页面闪一下。
|
|
32
|
+
- **根因**:CSS keyframes 默认 `animation-fill-mode: none`——**动画结束瞬间元素恢复到原始属性值,再等浏览器销毁 VT 伪元素树**。收回方向动画挂在 `::view-transition-old(root)`(旧主题层),从 `circle(175vmax)` 缩到 `circle(0)`;动画一结束,`clip-path` 因 `fill-mode:none` **回弹到无裁切(全屏可见)**,旧主题瞬间全屏重现一帧 → 这就是「闪」。散开方向不闪是因为它的动画挂在 new 层,回弹后的终态(全屏新主题)恰好 == 真实 DOM 态,肉眼看不出。不对称的本质:正在动画的上层,其回弹终态是否等于真实页面态。
|
|
33
|
+
- **正确做法**(纯 CSS,不动 JS):① 给做圆形动画的层加 **`forwards`**,动画结束后保持终态(缩到 `circle(0)` 的层保持不可见),杜绝回弹全屏闪现——这是关键修复;② 给静止的对侧层补一段**恒等铺满动画 + `both`**(`from`/`to` 都是 `circle(175vmax)`),让它整个过渡期间也作为活动合成层,与对侧合成待遇对称,收尾两层合成组同步解散,消除高对比(纯黑↔纯白)下的交接重绘。
|
|
34
|
+
```css
|
|
35
|
+
@keyframes vt-hold-full {
|
|
36
|
+
from { clip-path: circle(175vmax at var(--vt-x, 50%) var(--vt-y, 50%)); }
|
|
37
|
+
to { clip-path: circle(175vmax at var(--vt-x, 50%) var(--vt-y, 50%)); }
|
|
38
|
+
}
|
|
39
|
+
html[data-vt-direction='conceal']::view-transition-new(root) {
|
|
40
|
+
z-index: 1; animation: vt-hold-full var(--vt-dur) var(--vt-ease) both;
|
|
41
|
+
}
|
|
42
|
+
html[data-vt-direction='conceal']::view-transition-old(root) {
|
|
43
|
+
z-index: 2; animation: vt-circle-conceal var(--vt-dur) var(--vt-ease) forwards;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
- **适用**:通用。推广教训:① 凡 keyframes 动画**结束态偏离元素静止态**(clip-path / transform / opacity 终值非默认),必须显式 `animation-fill-mode: forwards`(或 `both`),否则结束瞬间回弹一帧;不限 View Transitions。② 高对比色块下任何一帧亮度跳变都肉眼可见,动画收尾要让「正在动画的上层终态 == 真实 DOM 态」。③ 逐帧闪烁靠截图基本抓不到(只在单帧出现),定位靠根因推理 + CSSOM 确认规则生效,别依赖视觉快照验证。
|
|
47
|
+
|
|
48
|
+
## 响应式 / 组件
|
|
49
|
+
|
|
50
|
+
<!-- 待填:踩到坑按四栏格式追加 -->
|
|
51
|
+
|
|
52
|
+
## 路由
|
|
53
|
+
|
|
54
|
+
<!-- 待填 -->
|
|
55
|
+
|
|
56
|
+
## 构建 / SSR
|
|
57
|
+
|
|
58
|
+
<!-- 待填 -->
|
|
59
|
+
|
|
60
|
+
## i18n / 内容
|
|
61
|
+
|
|
62
|
+
<!-- 待填 -->
|
|
63
|
+
|
|
64
|
+
## 排查方法论
|
|
65
|
+
|
|
66
|
+
<!-- 待填 -->
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 依赖版本新鲜度通用规则(首次技术选型下载依赖时,发布 <7 天的版本不采用;跨 npm/uv/Docker/Android/iOS/鸿蒙/Flutter 等所有栈)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# 依赖版本新鲜度规则
|
|
6
|
+
|
|
7
|
+
> 首次技术选型下载依赖(引新包、选 base 镜像 / SDK 版本)时,刚发布的新版本常带回归 bug:构建失败、Docker 镜像缺层、API breaking change。本规则约束 AI 在装新依赖前主动查「版本发布时间」,避开 <7 天的版本。
|
|
8
|
+
>
|
|
9
|
+
> 适用**所有技术栈**:npm/pnpm、uv/pip、Docker、Android(Gradle/Maven)、iOS(CocoaPods/SPM)、鸿蒙(ohpm)、Flutter(pub) 以及未来出现的任何包管理器。下面给出总约束 + 各栈示例,未列出的栈按「查官方 registry 发布时间」通用流程自行判断。
|
|
10
|
+
|
|
11
|
+
## 一、适用边界
|
|
12
|
+
|
|
13
|
+
- **仅约束首次技术选型下载依赖**:新项目引入新包、新搭脚手架选 base 镜像 / SDK 版本、原项目引入此前没用过的依赖。
|
|
14
|
+
- **已安装的旧版本无需为此升级**。本规则只管「新装 / 新选」,不管「存量升级」。
|
|
15
|
+
- 7 天是**下限排除条件**,不是「必须选最近一个 ≥7 天的版本」。最终选哪个稳定版由 AI 综合判断(成熟度、维护活跃度、依赖体积、与项目栈兼容性)。
|
|
16
|
+
|
|
17
|
+
## 二、核心约束
|
|
18
|
+
|
|
19
|
+
- **必须**在首次安装 / 选定版本前,查候选版本的「首次发布时间」
|
|
20
|
+
- 用官方 registry 的发布时间,**不是**上传时间、**不是** `latest` / `stable` tag 时间
|
|
21
|
+
- **禁止**采用发布时间距今 **<7 天**的版本
|
|
22
|
+
- **禁止**无脑用 `@latest` / `latest` / `stable` / 浮动 tag / 不带版本号安装——这些随时可能落到刚发布的新版本上
|
|
23
|
+
- 已安装版本**无需**为此规则升级
|
|
24
|
+
|
|
25
|
+
## 三、各栈查发布时间示例
|
|
26
|
+
|
|
27
|
+
未列出的栈,按「查官方 registry 元数据 → 取发布时间」自行处理。
|
|
28
|
+
|
|
29
|
+
| 栈 | 查发布时间方法 |
|
|
30
|
+
|---|---|
|
|
31
|
+
| npm / pnpm | `npm view <pkg> time --json`(取目标版本对应的时间字段) |
|
|
32
|
+
| uv / pip | PyPI JSON API:`https://pypi.org/pypi/<pkg>/json` 的 `releases[<version>][0].upload_time` |
|
|
33
|
+
| Docker | Docker Hub 镜像页 / API 的 `last_updated`;优先看具体 tag 的 push 时间 |
|
|
34
|
+
| Android (Gradle/Maven) | Maven Central `maven-metadata.xml` 的 `<lastUpdated>`(格式 yyyyMMddHHmmss) |
|
|
35
|
+
| iOS (CocoaPods) | `https://github.com/CocoaPods/Specs` 或仓库 release / tag 时间 |
|
|
36
|
+
| iOS (SPM) | 源仓库 release / tag 时间 |
|
|
37
|
+
| 鸿蒙 (ohpm) | ohpm registry 包元数据 publishTime |
|
|
38
|
+
| Flutter (pub) | `https://pub.dev/packages/<pkg>/versions` 页 published 时间 |
|
|
39
|
+
|
|
40
|
+
## 四、正反例
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# 反例:直接装 latest,可能落到昨天才发的版本
|
|
44
|
+
pnpm add some-pkg@latest
|
|
45
|
+
uv add some-pkg # 不锁版本
|
|
46
|
+
FROM node:latest # 随时被新镜像覆盖
|
|
47
|
+
implementation 'com.example:lib:latest'
|
|
48
|
+
|
|
49
|
+
# 正例:先查发布时间,选发布 ≥7 天的稳定版
|
|
50
|
+
npm view some-pkg time --json # 看候选版本发布时间
|
|
51
|
+
pnpm add some-pkg@1.2.3 # 1.2.3 发布已满 7 天
|
|
52
|
+
FROM node:20.18.1-slim # 该 tag push 已满 7 天
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 五、AI 自判提示
|
|
56
|
+
|
|
57
|
+
- 栈未列全时,先找该栈的**官方 registry**(包管理器背后的中央仓库),查目标版本的发布时间字段。
|
|
58
|
+
- 拿不到精确发布时间时,保守处理:选发布更早、更稳定的版本,不要选「最新」。
|
|
59
|
+
- 7 天窗口内的新版本,**等待**而非采用,**无任何例外**(含安全补丁)。等满 7 天再用。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: TDD 开发流程(新功能/bug 修复/重构的测试先行与回归策略)
|
|
2
|
+
description: TDD 开发流程(新功能/bug 修复/重构的测试先行与回归策略)与测试-源码分隔(测试工程独立 tests/ 目录、镜像源码结构、各栈目录约定)
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# TDD 开发规则
|
|
@@ -26,6 +26,42 @@ description: TDD 开发流程(新功能/bug 修复/重构的测试先行与回
|
|
|
26
26
|
2. 再重构 — 修改代码
|
|
27
27
|
3. 再跑测试 — 确认行为没变
|
|
28
28
|
|
|
29
|
+
## 测试与源码分隔(硬约束)
|
|
30
|
+
|
|
31
|
+
测试工程必须与源码分隔,不混在一起。
|
|
32
|
+
|
|
33
|
+
### 核心规则
|
|
34
|
+
|
|
35
|
+
- 测试代码**禁止**与源码同目录混放;测试集中在项目根 / 包根的独立 `tests/` 目录。
|
|
36
|
+
- `tests/` **镜像源码结构**,测试文件与被测源码一一对应、可反查:
|
|
37
|
+
- `src/foo/bar.ts` → `tests/foo/bar.test.ts`
|
|
38
|
+
- `src/services/user.py` → `tests/test_user.py`
|
|
39
|
+
- 源码目录(`src/`)保持纯净,**只放产品代码**;打包 / 发布产物天然不含测试,CI 用一个目录通配即可圈定全部测试。
|
|
40
|
+
- 测试用的 fixture / mock 数据 / 测试工具,放 `tests/` 内(如 `tests/fixtures/`、`tests/conftest.py`),不散落进源码目录。
|
|
41
|
+
|
|
42
|
+
### 为什么(约束的根因)
|
|
43
|
+
|
|
44
|
+
测试混入源码目录会引发一连串问题,分隔后一次性收口:
|
|
45
|
+
|
|
46
|
+
- **被打包进发布产物**:测试随源码一起发到 npm / PyPI,污染产物、撑大体积。
|
|
47
|
+
- **source map / 内部细节泄露**:测试常含内部实现假设、mock 的真实数据,泄露到产物有安全风险。
|
|
48
|
+
- **覆盖率 / 构建统计污染**:测试文件被计入源码统计,覆盖率、行数失真。
|
|
49
|
+
- **CI 难圈定范围**:源码与测试交织,CI 无法用一条目录规则排除测试。
|
|
50
|
+
- **AI / 工具难定位**:找不到「源码↔测试」对应关系,反复把测试误写进 `src/`。
|
|
51
|
+
|
|
52
|
+
### 各栈目录与命令速查表
|
|
53
|
+
|
|
54
|
+
| 栈 | 测试目录 | 命名约定 | 运行命令 |
|
|
55
|
+
|----|---------|---------|---------|
|
|
56
|
+
| Vue / Vitest | `tests/` 镜像 `src/` | `*.test.ts` | `pnpm vitest run [路径]` |
|
|
57
|
+
| Python / pytest | `tests/` | `test_*.py` | `pytest tests/ -v` / `uv run pytest` |
|
|
58
|
+
| Android | `src/test/`(单元)+ `src/androidTest/`(仪器) | `*Test.kt` | `./gradlew test` / `./gradlew connectedAndroidTest` |
|
|
59
|
+
| Node / CLI | `tests/` 镜像 `src/` | `*.test.ts` | 对应 runner(vitest / jest) |
|
|
60
|
+
|
|
61
|
+
注:Android 的 `src/test` / `src/androidTest` 是 Gradle 生态**强约定**的独立测试源集(test source set),与 `src/main` 源码完全分隔,符合本规范"测试与源码分隔"理念,按其生态默认即可,**属合规分隔**,不视为"测试写进 src"。
|
|
62
|
+
|
|
63
|
+
**通用准则(表中未列的栈)**:遵循「独立测试目录 + 镜像源码结构 + 该生态主流 runner 约定」三条原则自行判断,不硬套上表布局。
|
|
64
|
+
|
|
29
65
|
## 回归测试
|
|
30
66
|
|
|
31
67
|
### 开发中:只跑受影响的测试
|
|
@@ -55,7 +91,13 @@ pnpm vitest run tests/utils/format.test.ts # 改了单个工具函数
|
|
|
55
91
|
|
|
56
92
|
## TEST_CASES.md
|
|
57
93
|
|
|
58
|
-
每个包/项目维护一份 `TEST_CASES.md
|
|
94
|
+
每个包/项目维护一份 `TEST_CASES.md`,记录所有测试用例的清单。**`TEST_CASES.md` 跟测试目录走,不放项目根**:
|
|
95
|
+
|
|
96
|
+
- 有 `tests/` → 放 `tests/TEST_CASES.md`
|
|
97
|
+
- 测试源集分散(如 Android `src/test/`)→ 放对应测试根(`src/test/TEST_CASES.md`),与该模块测试同处
|
|
98
|
+
- 理念:测试清单是测试工程的一部分,归测试目录,与「测试与源码分隔」一致
|
|
99
|
+
|
|
100
|
+
内容要求:
|
|
59
101
|
|
|
60
102
|
- 人类可读,方便审查和手动编辑
|
|
61
103
|
- 新增/修改/删除功能时必须同步更新
|
|
@@ -68,3 +110,6 @@ pnpm vitest run tests/utils/format.test.ts # 改了单个工具函数
|
|
|
68
110
|
- **禁止**写完代码再补测试(先测试后代码)
|
|
69
111
|
- **禁止**测试不通过就提交
|
|
70
112
|
- **禁止** TEST_CASES.md 与实际测试不同步
|
|
113
|
+
- **禁止**测试文件写进 `src/` 源码目录(Android `src/test`、`src/androidTest` 例外,是 Gradle 标准测试源集)
|
|
114
|
+
- **禁止**测试目录结构与源码脱节(找不到「源码↔测试」对应关系)
|
|
115
|
+
- **禁止**把测试 fixture / mock 数据散落进源码目录
|
package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-acceptance/SKILL.md
CHANGED
|
@@ -9,15 +9,16 @@ description: "【dwy·验收测试】产品 0 到 1 上架迭代阶段。触发
|
|
|
9
9
|
## 输入(从哪读)
|
|
10
10
|
- state.json 的 `confirmed.dev_progress`、`confirmed.prd`、`confirmed.architecture`
|
|
11
11
|
- 项目源码 + `.dwy/prod/[项目]/02-需求规划/PRD.md`
|
|
12
|
-
- `.dwy/prod/[项目]/
|
|
12
|
+
- `.dwy/prod/[项目]/04-架构设计/接口契约.md`
|
|
13
13
|
|
|
14
14
|
## 实现
|
|
15
15
|
[包装型] 用全局本地 skill(位于 `~/.dwy/skills/<外部skill名>/`):
|
|
16
16
|
读其 `SKILL.md`(及同目录 scripts/、配套 .md),按它的方式与用户交互/提问,产出按下方「产出契约」落地。
|
|
17
|
+
- **提问形式(Claude Code 下强制)**:借用外部 skill 的「问什么、怎么一步步收敛」方法论,但**每个要用户选择/拍板的问题用 `AskUserQuestion` 工具弹点选卡片**,不在正文列 A/B/C/D 让用户打字;保留「一次一问、答完再问下一个」的节奏,开放式补充靠卡片的「Other」兜底。其他工具(Codex 等无此组件)退回外部 skill 原生的正文问答。
|
|
17
18
|
- 本 skill 依赖的外部 skill:`test-scenarios`、`intended-vs-implemented`(各对应 `~/.dwy/skills/<名>/`)
|
|
18
19
|
- 若 `~/.dwy/skills/<名>/` 不存在:提示用户先跑 `dwy skills install`(或 `dwy claude sync` 会自动装),不要自己用内置能力顶替。
|
|
19
20
|
|
|
20
21
|
## 产出契约(硬约束)
|
|
21
|
-
- 落到:`.dwy/prod/[项目]/
|
|
22
|
+
- 落到:`.dwy/prod/[项目]/05-上线交付/验收报告.md`
|
|
22
23
|
- 固定章节:集成/E2E 场景结果 / 兼容性 / 合规与沙盒 / 文档vs代码差距 / 验收结论
|
|
23
24
|
- 回写 state.json:`confirmed.acceptance`(验收结论 / 是否达上线标准)
|
package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md
CHANGED
|
@@ -1,28 +1,70 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dwy-architecture
|
|
3
|
-
description: "【dwy·技术架构】产品 0 到 1 设计与架构阶段。触发场景:用户说『设计架构 / 出技术方案 / 设计库表 / 定接口契约 / 技术架构 / architecture
|
|
3
|
+
description: "【dwy·技术架构】产品 0 到 1 设计与架构阶段。触发场景:用户说『设计架构 / 出技术方案 / 设计库表 / 定接口契约 / 技术架构 / architecture』,要在开发前定下技术架构、数据库设计和接口契约时。按四层架构(Assembly/Features/BizFoundation/Foundation)+ 统一选型(Python+FastAPI、Vue+Vite)产出。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
## 职责(单一)
|
|
7
|
-
按项目 rules
|
|
7
|
+
按项目 rules + 下方架构约束,产出技术架构 + 数据库库表设计 + 接口契约。
|
|
8
8
|
|
|
9
9
|
## 输入(从哪读)
|
|
10
10
|
- state.json 的 `confirmed.prd`、`confirmed.tasks`、`confirmed.prototype`
|
|
11
11
|
- `.dwy/prod/[项目]/02-需求规划/PRD.md`、`开发任务拆解.md`
|
|
12
12
|
- 项目 `.claude/rules/` 下的技术栈与编码规则
|
|
13
13
|
|
|
14
|
+
## 架构约束(硬)
|
|
15
|
+
|
|
16
|
+
项目已有 `.claude/rules/` 时**以项目 rules 为准**;项目无明确规定时按本节统一缺省。
|
|
17
|
+
|
|
18
|
+
### 技术选型(缺省基线,写在架构选项之上)
|
|
19
|
+
|
|
20
|
+
以下为默认选型基线,**先按此基线落地**;结合上下文(PRD / 选型 / 项目 rules)判断**基线不合适时,必须用 `AskUserQuestion` 跟用户确认后才换**,禁止默默偏离基线、也禁止默默换栈。
|
|
21
|
+
|
|
22
|
+
- **后端统一 Python + FastAPI**(异步、Pydantic v2、SQLAlchemy 2.0 风格,与 `dwyeapi` 生态对齐)
|
|
23
|
+
- **Python 虚拟环境用 `uv` 管理**(venv + 依赖 + 运行)
|
|
24
|
+
- **DB 迁移用 Alembic**(与 SQLAlchemy 2.0 配套)
|
|
25
|
+
- **配置 / settings 用 pydantic-settings**(与 `dwyeapi` config 对齐)
|
|
26
|
+
- **认证用 JWT**(与 `dwyeapi` security 的 create_token/decode_token + bcrypt 对齐)
|
|
27
|
+
- **后端有数据库时**:
|
|
28
|
+
- **关系型数据库用 PostgreSQL**(连接串如 `postgresql+asyncpg://user:pass@localhost:5432/mydb`)
|
|
29
|
+
- **内存数据库 / 缓存用 Redis**(`redis://localhost:6379/0`)
|
|
30
|
+
- **用 Docker 部署**(后端 + Postgres + Redis 编排到 `docker-compose.yml`)
|
|
31
|
+
- **反向代理 / 入口网关用 Nginx**
|
|
32
|
+
- **前端 Vue 用 Vite + TailwindCSS + TypeScript**(`@dwydev/eui` + `@dwydev/ekit` 可选用,不强制)
|
|
33
|
+
- **包管理器用 pnpm**(与本 monorepo 一致)
|
|
34
|
+
- **状态管理用 Pinia**
|
|
35
|
+
- **HTTP 客户端用 axios**(或 `@dwydev/ekit` 的 request)
|
|
36
|
+
- **E2E 测试用 Playwright**(单测 Vitest 为项目默认)
|
|
37
|
+
- **CI/CD 走 GitHub Actions + OIDC**(发布鉴权用 OIDC,禁长期静态凭据)
|
|
38
|
+
- **基线不适用就先确认**:任一项基线与上下文冲突(如纯前端无需 Docker/DB、要换其他 DB/MQ/中间件、不能用某项)→ 先 `AskUserQuestion` 跟用户确认,确认后在架构文档写明偏离基线的理由
|
|
39
|
+
|
|
40
|
+
### 四层架构(依赖严格单向向下:Assembly → Features → BizFoundation → Foundation)
|
|
41
|
+
|
|
42
|
+
| 层 | 职责 | 后端示例 | 前端示例 |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| **装配层 (Assembly)** | 实例化 / 依赖注入 / 路由挂载 / 生命周期,**零业务逻辑** | `src/app/`(main.py 装 Provider/Hook、factories) | `apps/web`(路由、stores、main.ts) |
|
|
45
|
+
| **Features (业务功能层)** | 各业务域领域逻辑,域内 router+service+schema+model **聚在同一目录** | `<域>/`(如 `factor/`、`plan/`、`quota/`) | `features/*`(如 auth、settings) |
|
|
46
|
+
| **业务基础层 (BizFoundation)** | 业务相关但跨业务域复用:鉴权、领域协议/Provider、领域设施 | `auth`、各包 `protocols.py`/`providers` | 跨域复用的业务 composable/store |
|
|
47
|
+
| **业务无关层 (Foundation)** | 与业务完全无关的 kernel | `shared`(DB/Redis/签名/中间件) | `core`(httpClient/格式化/常量) |
|
|
48
|
+
|
|
49
|
+
### 三条铁律
|
|
50
|
+
- **依赖单向向下,绝不反向**:下层禁止 import 上层;Foundation 禁止 import 任何业务包;跨业务域**不直接互 import**,靠装配层用 Protocol/Hook 桥接。
|
|
51
|
+
- **业务内聚**:一个业务域 = 一个目录,域内 router/service/schema/model 聚在一起。✅ `factor/`(含 router+service+validators);❌ 顶层 `routers/`+`services/`+`models/` 三个大锅各塞所有域。
|
|
52
|
+
- **装配层是唯一能 import 具体实现的地方**:业务代码只通过 `get_xxx_provider()` 取实例,换实现不改业务代码。
|
|
53
|
+
|
|
14
54
|
## 实现
|
|
15
55
|
[自写型]
|
|
16
|
-
1. 读项目 `.claude/rules
|
|
17
|
-
2.
|
|
18
|
-
3.
|
|
56
|
+
1. 读项目 `.claude/rules/`,结合上方架构约束产出架构(项目 rules 优先,本约束兜底)
|
|
57
|
+
2. 技术架构:**先按四层归位模块、按业务域聚目录**,再写分层/模块边界/选型理由;选型不确定处走 `AskUserQuestion`
|
|
58
|
+
3. **判有无后端**(读选型/PRD:有 API / 持久化 / 账户体系 → 有后端):
|
|
59
|
+
- **有后端** → 必出数据库设计,且**建模到位**:库表清单 / 字段(类型·约束·默认·可空) / 主外键关系 / 索引 / 必要的范式或反范式说明,与接口契约 schema 对齐
|
|
60
|
+
- **纯前端**(无后端)→ 跳过数据库设计,在 `技术架构.md` 注明「无后端,不涉及库表」
|
|
19
61
|
4. 接口契约:路由、请求/响应 schema(遵循项目响应格式约定)
|
|
20
|
-
5. **走 rules
|
|
62
|
+
5. **走 rules + 约束土建**,不引入约束外的技术栈
|
|
21
63
|
|
|
22
64
|
## 产出契约(硬约束)
|
|
23
|
-
- 落到:`.dwy/prod/[项目]/
|
|
65
|
+
- 落到:`.dwy/prod/[项目]/04-架构设计/技术架构.md`、`接口契约.md`,**有后端时**加 `数据库设计.md`
|
|
24
66
|
- 固定章节:
|
|
25
|
-
- 技术架构.md
|
|
26
|
-
- 数据库设计.md
|
|
67
|
+
- 技术架构.md:**四层划分 + 各业务域目录结构** / 模块边界 / 技术选型(按缺省基线写明 Python+FastAPI+uv+Alembic+pydantic-settings+JWT、前端 Vue+Vite+TS+Tailwind+pnpm+Pinia+axios+Playwright、CI/CD GitHub Actions OIDC;有 DB 写明 PostgreSQL+Redis+Docker+Nginx;偏离基线处写明原因)/ 选型不明或偏离基线处的 AskUserQuestion 确认记录 / 有无后端结论
|
|
68
|
+
- 数据库设计.md(**有后端必出**):库表清单 / 字段定义(类型·约束·默认·可空) / 主外键关系与索引 / 与接口契约对齐
|
|
27
69
|
- 接口契约.md:接口清单 / 请求响应 schema / 错误码
|
|
28
70
|
- 回写 state.json:`confirmed.architecture`
|