create-dwy 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/package.json +1 -1
  2. package/src/create.js +50 -3
  3. package/src/utils.js +8 -0
  4. package/templates/claude-global/CLAUDE.md +81 -6
  5. package/templates/claude-global/rules/dwy-postgres.md +89 -0
  6. package/templates/claude-global/rules/dwy-python-backend.md +492 -0
  7. package/templates/claude-global/rules/dwy-python-core.md +94 -634
  8. package/templates/claude-global/rules/dwy-python-testing.md +115 -13
  9. package/templates/claude-global/rules/dwy-redis.md +88 -0
  10. package/templates/claude-global/rules/dwy-vue-core.md +341 -645
  11. package/templates/claude-global/rules/dwy-vue-pinia.md +47 -34
  12. package/templates/claude-global/rules/dwy-vue-testing.md +120 -55
  13. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-network.md +1 -1
  14. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_nginx.sh +1 -1
  15. package/templates/claude-global/skills/dwy-dolphindb/SKILL.md +22 -15
  16. package/templates/claude-global/skills/dwy-dolphindb/evals/evals.json +23 -0
  17. package/templates/claude-global/skills/dwy-dolphindb/references/dolphindb-rules.md +100 -1
  18. package/templates/claude-global/skills/dwy-ekit/SKILL.md +142 -276
  19. package/templates/claude-global/skills/dwy-eui/SKILL.md +264 -182
  20. package/templates/claude-global/skills/dwy-fullstack-scaffold/SKILL.md +117 -129
  21. package/templates/claude-global/skills/dwy-git-commit/SKILL.md +125 -0
  22. package/templates/claude-global/skills/dwy-publish/SKILL.md +1 -1
  23. package/templates/claude-global/{rules/dwy-tech-stack.md → skills/dwy-tech-stack/SKILL.md} +4 -3
  24. package/templates/project/fullstack-monorepo/CLAUDE.md.hbs +81 -0
  25. package/templates/project/fullstack-monorepo/_env.example.hbs +24 -0
  26. package/templates/project/fullstack-monorepo/_gitignore +37 -0
  27. package/templates/project/fullstack-monorepo/backend/.python-version +1 -0
  28. package/templates/project/fullstack-monorepo/backend/CLAUDE.md.hbs +68 -0
  29. package/templates/project/fullstack-monorepo/backend/Dockerfile.dev +23 -0
  30. package/templates/project/fullstack-monorepo/backend/alembic/env.py.hbs +68 -0
  31. package/templates/project/fullstack-monorepo/backend/alembic/script.py.mako +26 -0
  32. package/templates/project/fullstack-monorepo/backend/alembic.ini.hbs +43 -0
  33. package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/pyproject.toml +16 -0
  34. package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/src/dwy_shared/__init__.py +12 -0
  35. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/pyproject.toml.hbs +20 -0
  36. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/__init__.py.hbs +40 -0
  37. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/config.py +9 -0
  38. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/models.py.hbs +17 -0
  39. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/protocols.py +14 -0
  40. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/router.py.hbs +22 -0
  41. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/schemas.py +21 -0
  42. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/service.py +11 -0
  43. package/templates/project/fullstack-monorepo/backend/pyproject.toml.hbs +84 -0
  44. package/templates/project/fullstack-monorepo/backend/src/app/__init__.py +3 -0
  45. package/templates/project/fullstack-monorepo/backend/src/app/config.py.hbs +21 -0
  46. package/templates/project/fullstack-monorepo/backend/src/app/exceptions.py +26 -0
  47. package/templates/project/fullstack-monorepo/backend/src/app/factories.py +16 -0
  48. package/templates/project/fullstack-monorepo/backend/src/app/infra/__init__.py +1 -0
  49. package/templates/project/fullstack-monorepo/backend/src/app/main.py.hbs +65 -0
  50. package/templates/project/fullstack-monorepo/backend/src/app/middleware/__init__.py +1 -0
  51. package/templates/project/fullstack-monorepo/backend/tests/__init__.py +0 -0
  52. package/templates/project/fullstack-monorepo/backend/tests/conftest.py.hbs +42 -0
  53. package/templates/project/fullstack-monorepo/dev.sh.hbs +83 -0
  54. package/templates/project/fullstack-monorepo/docker-compose.dev.yml.hbs +36 -0
  55. package/templates/project/fullstack-monorepo/frontend/CLAUDE.md.hbs +35 -0
  56. package/templates/project/fullstack-monorepo/frontend/Dockerfile +18 -0
  57. package/templates/project/fullstack-monorepo/frontend/_npmrc +3 -0
  58. package/templates/project/fullstack-monorepo/frontend/apps/web/index.html.hbs +13 -0
  59. package/templates/project/fullstack-monorepo/frontend/apps/web/package.json.hbs +31 -0
  60. package/templates/project/fullstack-monorepo/frontend/apps/web/src/App.vue.hbs +10 -0
  61. package/templates/project/fullstack-monorepo/frontend/apps/web/src/api/client.ts.hbs +11 -0
  62. package/templates/project/fullstack-monorepo/frontend/apps/web/src/features/{{initialDomain}}/.gitkeep +0 -0
  63. package/templates/project/fullstack-monorepo/frontend/apps/web/src/index.css +12 -0
  64. package/templates/project/fullstack-monorepo/frontend/apps/web/src/main.ts +17 -0
  65. package/templates/project/fullstack-monorepo/frontend/apps/web/src/router/index.ts.hbs +24 -0
  66. package/templates/project/fullstack-monorepo/frontend/apps/web/src/stores/.gitkeep +0 -0
  67. package/templates/project/fullstack-monorepo/frontend/apps/web/src/types/.gitkeep +0 -0
  68. package/templates/project/fullstack-monorepo/frontend/apps/web/src/views/HomeView.vue.hbs +36 -0
  69. package/templates/project/fullstack-monorepo/frontend/apps/web/tsconfig.json +7 -0
  70. package/templates/project/fullstack-monorepo/frontend/apps/web/vite.config.ts.hbs +27 -0
  71. package/templates/project/fullstack-monorepo/frontend/nginx.conf +11 -0
  72. package/templates/project/fullstack-monorepo/frontend/package.json.hbs +13 -0
  73. package/templates/project/fullstack-monorepo/frontend/packages/core/package.json.hbs +15 -0
  74. package/templates/project/fullstack-monorepo/frontend/packages/core/src/index.ts +3 -0
  75. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/package.json.hbs +14 -0
  76. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/index.ts.hbs +16 -0
  77. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/pages/IndexPage.vue.hbs +9 -0
  78. package/templates/project/fullstack-monorepo/frontend/packages/ui/package.json.hbs +15 -0
  79. package/templates/project/fullstack-monorepo/frontend/packages/ui/src/index.ts +3 -0
  80. package/templates/project/fullstack-monorepo/frontend/pnpm-workspace.yaml.hbs +23 -0
  81. package/templates/project/fullstack-monorepo/frontend/tsconfig.base.json.hbs +23 -0
  82. package/templates/claude-global/rules/dwy-api-design.md +0 -110
  83. package/templates/claude-global/rules/dwy-git-commit-convention.md +0 -82
  84. package/templates/claude-global/rules/dwy-git-security.md +0 -53
  85. package/templates/claude-global/rules/dwy-payload-limits.md +0 -186
  86. package/templates/claude-global/rules/dwy-prefer-open-source.md +0 -32
  87. package/templates/claude-global/rules/dwy-project-structure.md +0 -181
  88. package/templates/claude-global/rules/dwy-python-fastapi.md +0 -272
  89. package/templates/claude-global/rules/dwy-python-orm.md +0 -61
  90. package/templates/claude-global/rules/dwy-python-security.md +0 -636
  91. package/templates/claude-global/rules/dwy-server-security.md +0 -518
  92. package/templates/claude-global/rules/dwy-vue-api.md +0 -146
  93. package/templates/claude-global/skills/dwy-ekit/references/data.md +0 -135
  94. package/templates/claude-global/skills/dwy-ekit/references/form.md +0 -68
  95. package/templates/claude-global/skills/dwy-ekit/references/request.md +0 -183
  96. package/templates/claude-global/skills/dwy-ekit/references/ui.md +0 -109
  97. package/templates/claude-global/skills/dwy-vue-core/SKILL.md +0 -890
  98. /package/templates/{claude-global/commands → project/fullstack-monorepo/backend/alembic/versions}/.gitkeep +0 -0
@@ -1,110 +0,0 @@
1
- ---
2
- description: 后端 API URL/响应格式/状态码/Schema 命名规范
3
- paths:
4
- - "**/routers/**/*.py"
5
- - "**/schemas/**/*.py"
6
- - "**/services/**/*.py"
7
- - "**/dependencies.py"
8
- - "**/main.py"
9
- ---
10
-
11
- # API 设计规范
12
-
13
- ---
14
-
15
- ## 一、URL 命名
16
-
17
- ```
18
- 基础格式: /api/{resource}
19
-
20
- GET /api/users # 列表(支持分页)
21
- POST /api/users # 创建
22
- GET /api/users/{id} # 详情
23
- PATCH /api/users/{id} # 部分更新
24
- DELETE /api/users/{id} # 删除
25
-
26
- # 子资源
27
- GET /api/users/{id}/orders # 用户的订单列表
28
-
29
- # 动作(非 CRUD,用 POST + 动词)
30
- POST /api/users/{id}/activate
31
- POST /api/tasks/{id}/cancel
32
- POST /api/tasks/{id}/retry
33
- ```
34
-
35
- **规则:**
36
- - 资源名用复数、kebab-case:`/api/upload-tasks`(不是 `uploadTasks` 或 `upload_task`)
37
- - 路径参数用 `{id}` 不用 `{user_id}`(除非有歧义)
38
- - 查询参数用 snake_case:`?page_size=20&task_type=export`
39
- - 所有路由加 `/api` 前缀
40
- - 禁止在 URL 中包含动词(用 HTTP 方法区分),但非 CRUD 操作例外
41
-
42
- ## 二、统一响应格式
43
-
44
- 所有 API 使用 eapi response 模块的标准格式:
45
-
46
- **成功响应(`response.success()`):**
47
- ```json
48
- {
49
- "code": 200,
50
- "message": "success",
51
- "data": { ... },
52
- "timestamp": 1712467200
53
- }
54
- ```
55
-
56
- **分页响应(`response.paginated()`):**
57
- ```json
58
- {
59
- "code": 200,
60
- "message": "success",
61
- "data": {
62
- "items": [ ... ],
63
- "total": 100,
64
- "page": 1,
65
- "page_size": 20
66
- },
67
- "timestamp": 1712467200
68
- }
69
- ```
70
-
71
- **错误响应(eapi 异常处理器自动生成):**
72
- ```json
73
- {
74
- "code": "NOT_FOUND",
75
- "message": "用户不存在"
76
- }
77
- ```
78
-
79
- **禁止:** 自造响应格式、在 router 中手动构造 `{"success": true, ...}` 等非标准格式。
80
-
81
- ## 三、HTTP 状态码
82
-
83
- | 场景 | 状态码 | 说明 |
84
- |------|--------|------|
85
- | 查询/更新成功 | 200 | GET / PATCH 默认 |
86
- | 创建成功 | 201 | POST 创建资源 |
87
- | 删除成功 | 204 | DELETE,无响应体 |
88
- | 参数错误 | 400 | 请求格式错误 |
89
- | 未认证 | 401 | Token 缺失或过期 |
90
- | 无权限 | 403 | 认证通过但权限不足 |
91
- | 资源不存在 | 404 | — |
92
- | 业务错误 | 422 | 参数合法但业务规则不允许 |
93
-
94
- ## 四、Pydantic Schema 命名约定
95
-
96
- ```python
97
- # 创建请求
98
- class UserCreate(BaseModel): ...
99
-
100
- # 更新请求(所有字段可选)
101
- class UserUpdate(BaseModel): ...
102
-
103
- # 响应
104
- class UserResponse(BaseModel): ...
105
-
106
- # 列表项(精简字段)
107
- class UserBrief(BaseModel): ...
108
- ```
109
-
110
- 请求和响应**必须分离**,禁止同一个 Schema 同时用于请求和响应。
@@ -1,82 +0,0 @@
1
- ---
2
- description: Git commit message 规范(type 枚举、scope、中文 subject、提交前检查)
3
- ---
4
-
5
- # Git Commit 强制规范
6
-
7
- 每次 `git commit` 前按顺序执行以下检查,任一步未通过则 **STOP,不得提交**。
8
-
9
- ## Step 1: 分析变更
10
-
11
- `git diff --cached` 回答:这次改做了几件事?涉及哪些模块?
12
-
13
- **做了多件事(无法用 ≤72 字符 subject 清晰描述)→ 必须拆成多个 commit。**
14
-
15
- ## Step 2: 确定 scope
16
-
17
- 读当前项目 CLAUDE.md 的 `## Git Commit Scope` 段落:
18
-
19
- - **找到** → scope 从其中枚举值选,不得自造
20
- - **没找到** → 提醒用户:「当前项目 CLAUDE.md 未定义 Git Commit Scope,建议添加」,scope 可省略
21
-
22
- 单模块变更 → **必须**带 scope;跨模块变更 → 省略 scope。
23
-
24
- ## Step 3: 生成 message
25
-
26
- 格式:`<type>(<scope>): <subject>` 或(无 scope)`<type>: <subject>`
27
-
28
- **type 枚举(只能从中选)**:
29
-
30
- | type | 用途 |
31
- |------|------|
32
- | feat | 新功能 |
33
- | fix | 修复 bug |
34
- | refactor | 重构(不改外部行为) |
35
- | chore | 构建/依赖/配置/发版等杂务 |
36
- | docs | 文档 |
37
- | test | 测试 |
38
- | perf | 性能优化 |
39
- | style | 代码格式(不影响逻辑) |
40
- | ci | CI/CD 配置 |
41
-
42
- **subject**:中文、无句号、≤72 字符、动宾短语(添加/修复/移除/重构/升级)。
43
-
44
- **body(可选)**:空一行后写;中文;只写 why 不复述 what;破坏性变更加 `BREAKING CHANGE:` 前缀(subject 用 `feat!:` / `fix!:` 标记)。
45
-
46
- ## Step 4: 禁止大模型署名
47
-
48
- commit message(subject、body、footer、trailer)**禁止出现任何大模型/AI 工具相关内容**,覆盖系统默认的 `Co-Authored-By` 追加行为。
49
-
50
- **禁止出现的内容(不完全列举)**:
51
-
52
- - `Co-Authored-By: Claude ...` / `Co-Authored-By: GPT ...` / `Co-Authored-By: Copilot ...` 等 AI 署名 trailer
53
- - `Generated with Claude Code` / `🤖 Generated with ...` 等生成声明
54
- - `noreply@anthropic.com` / `noreply@openai.com` 等 AI 厂商邮箱
55
- - 任何提到 Claude / ChatGPT / GPT / Copilot / Cursor / AI / 大模型 / LLM 的字样
56
-
57
- **执行要点**:
58
-
59
- - `git commit -m "..."` 只写规范内容,**绝不**附加 `Co-Authored-By` trailer
60
- - 使用 HEREDOC 传 commit message 时,HEREDOC 内容也不得包含上述字样
61
- - 若发现暂存的 message 含大模型信息,**立即删除**后再提交
62
-
63
- ## 常见错误 vs 正确
64
-
65
- | 错误 | 正确 |
66
- |------|------|
67
- | `feat: add user login`(英文) | `feat: 添加用户登录功能` |
68
- | `fix(eui): 修复了按钮样式。` | `fix(eui): 修复按钮样式`(无句号、不用"了") |
69
- | `feat: 添加登录并修复登出 bug` | 拆成两个 commit |
70
- | `update: 修改配置` | `update` 不在枚举,应为 `chore` |
71
- | `feat(auth): ...`(项目无 auth scope) | 用项目已定义的 scope 值 |
72
- | message 末尾加 `Co-Authored-By: Claude ...` | 不加任何 AI 署名 trailer |
73
- | `🤖 Generated with Claude Code` | 不加任何生成声明 |
74
-
75
- ## 正确示例
76
-
77
- - `feat(eui): 添加 Image 组件,支持懒加载`
78
- - `fix: 修复 token 刷新竞态条件`
79
- - `refactor(backend): 提取分页逻辑为共享工具`
80
- - `chore: 升级 Vite 至 8.x`
81
- - `feat(eui)!: 重命名 EDialog open 属性为 v-model:open`
82
- - body:`BREAKING CHANGE: EDialog 不再接受 visible 属性,请改用 v-model:open`
@@ -1,53 +0,0 @@
1
- ---
2
- description: Git 提交前文件与敏感内容扫描规则(全局,每次 add/commit 都应检查)
3
- ---
4
-
5
- # Git 提交安全规则
6
-
7
- 每次 `git add` 或 `git commit` 前按本规则扫描暂存区。发现违规**立即停止并提示用户确认**。
8
-
9
- ## 一、禁止提交的文件
10
-
11
- | 类型 | 示例 |
12
- |---|---|
13
- | 环境变量 | `.env`, `.env.*`, `*.env` |
14
- | SSH 密钥 | `id_rsa`, `id_ed25519`, `*.pem`, `*.key` |
15
- | 证书 | `*.p12`, `*.pfx`, `*.jks`, `*.keystore` |
16
- | 数据库 | `*.sql`(含真实数据)、`*.dump`, `*.sqlite` |
17
- | 原始数据 | `*.xlsx`, `*.csv`(含用户/学生等敏感数据) |
18
- | 日志 | `*.log` |
19
- | Docker 卷 | `pgdata/`, `cache/*.json` |
20
-
21
- ## 二、禁止提交的内容(敏感模式)
22
-
23
- **总则**:代码、文档、规则文件、注释里禁止出现真实的 API Key / Token / 密码 / IP / 凭证,即使作为"示例"也不行。GitHub Secret Scanning 不区分上下文,真实格式的 key 写在文档里也会触发泄露告警。示例必须用明显的假值(`sk-xxxxxxxxxxxx`、`your-key-here`、`192.168.x.x`)。
24
-
25
- | 类型 | 匹配模式 |
26
- |---|---|
27
- | API Key | `sk-[a-zA-Z0-9]{20,}` |
28
- | AWS Key | `AKIA[0-9A-Z]{16}` |
29
- | 密码赋值 | `password\s*[:=]\s*["'][^"']{4,}` |
30
- | 数据库连接串 | `://\w+:[^@\s]+@` |
31
- | 私钥内容 | `-----BEGIN (RSA \|EC )?PRIVATE KEY-----` |
32
- | Token | `token\s*[:=]\s*["'][a-zA-Z0-9_\-]{20,}` |
33
- | Secret | `secret\s*[:=]\s*["'][^"']{8,}` |
34
- | 服务器 IP+端口 | `\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+` |
35
- | SSH 连接 | `ssh\s+.*@\d{1,3}\.\d{1,3}` |
36
-
37
- **例外(不算违规)**:`.env.example` 里的占位符;从环境变量读取(`os.getenv("API_KEY")`);`localhost`/`127.0.0.1` 的连接串;文档里的假数据;配置文件的空字符串默认值。
38
-
39
- ## 三、违规处理
40
-
41
- 检测到违规时:
42
-
43
- 1. **立即停止** `git add` / `git commit`
44
- 2. **列出违规项**:文件 + 行号 + 匹配的敏感模式 + 脱敏摘要(如 `sk-5522****dc3`)
45
- 3. **建议**:加入 `.gitignore` / 移到 `.env` / 用环境变量
46
- 4. **等用户明确确认**后才能继续;确认提交时,commit body 附注释 `GIT-SECURITY: 用户已确认提交此内容`
47
-
48
- ## 四、已提交敏感数据
49
-
50
- 若发现已在 git 历史中:立即通知用户,**建议先轮换凭证**,然后提供清理命令(不自动执行,待确认):
51
-
52
- - `git filter-repo --path <file> --invert-paths --force`
53
- - 或 `bfg --delete-files <filename>`
@@ -1,186 +0,0 @@
1
- ---
2
- description: 用户输入 / HTTP 请求体 / 文件上传的长度与大小限制。涉及表单字段 maxlength、Nginx client_max_body_size、Pydantic max_length、分页 page_size 上限、批量操作 items 限制、文件上传大小与像素校验时触发。
3
- paths:
4
- - "**/*.vue"
5
- - "**/*.py"
6
- - "**/nginx*.conf"
7
- ---
8
-
9
- # 数据载荷三层长度限制规则
10
-
11
- 防止大文本 DoS、内存耗尽、带宽滥用。所有涉及用户输入 / HTTP 请求体 / 文件上传的场景必须遵循三层限制,单层失守即高风险。
12
-
13
- 本文件是"长度 / 大小 / 数量"规则的**唯一权威源**。其他规则文件(`dwy-server-security.md`、`dwy-python-security.md`)的对应章节只做引用,不重复定义。
14
-
15
- ## 为什么需要三层
16
-
17
- - **前端 = UX 边界**:给用户即时反馈,避免无效输入浪费带宽和后端算力
18
- - **网关 = 流量边界**:Nginx / CDN / 负载均衡层拦截异常大请求,保护后端不被打满
19
- - **后端 = 业务边界**:字段级严格校验,阻断绕过前端的恶意请求
20
- - 三层职责不可互相替代。只靠前端易被绕过;只靠后端流量先耗在 TCP/TLS 握手和解析上;只靠网关无法挡住"多个小字段组合起来刚好达到 body 上限"的攻击
21
-
22
- 三层数字必须对齐:**前端 maxlength ≤ 后端 max_length**,**后端字段累加加冗余 ≤ 网关 client_max_body_size**。
23
-
24
- ## 第一层:前端输入限制
25
-
26
- ### 强制规则
27
-
28
- - 所有 `<input type="text">` / `<input type="search">` / `<textarea>` 必须设 `maxlength` 属性
29
- - `@dwydev/eui` 的 `EInput` / `ETextarea` / 可搜索 `ESelect` / 可输入 `ETag` 必须传 `maxlength` prop
30
- - 富文本编辑器(tiptap / quill 等)必须配置字符数上限,超出禁止输入
31
- - 文件选择控件必须在前端预校验大小和 MIME 类型(`accept` 属性 + JS 二次校验)
32
- - 批量操作前端必须做分页 / 分批,不允许一次性超过 items 上限
33
- - 表单校验层必须用 zod `.max()` 再补一道,防粘贴 / 脚本绕过 HTML `maxlength`
34
-
35
- ### 禁止事项
36
-
37
- - 禁止 `EInput` / `ETextarea` 不带 `maxlength` 上线
38
- - 禁止富文本编辑器无字符上限
39
- - 禁止"前端不限制,全部让后端兜底"
40
- - 禁止大文件(>10MB)走普通 API 中转
41
-
42
- ### 示例
43
-
44
- ```vue
45
- <!-- ✅ 正确 -->
46
- <EInput v-model="form.title" :maxlength="100" show-word-limit />
47
- <ETextarea v-model="form.desc" :maxlength="500" show-word-limit />
48
-
49
- <!-- ❌ 违规 -->
50
- <EInput v-model="form.title" />
51
- <ETextarea v-model="form.desc" />
52
- ```
53
-
54
- 配套 zod schema(vee-validate):
55
-
56
- ```ts
57
- import { z } from 'zod'
58
-
59
- const schema = z.object({
60
- title: z.string().max(100),
61
- desc: z.string().max(500),
62
- })
63
- ```
64
-
65
- ## 第二层:网关 / 部署限制
66
-
67
- ### 强制规则
68
-
69
- - Nginx `client_max_body_size` 必须显式配置,不允许使用默认值
70
- - 无文件上传业务时:全局 `client_max_body_size 1m`,**禁止** > `10m`
71
- - 有上传业务时:针对上传路径单独放宽(如 `location /api/upload` 设 `20m`),**禁止**全局放宽
72
- - 上传大文件(>10MB)必须走对象存储直传(MinIO / S3 预签名 URL),**禁止**走 API 中转
73
- - CDN / 负载均衡层的 body 限制和超时必须与 Nginx 数字对齐
74
-
75
- ### 示例
76
-
77
- ```nginx
78
- # server 块 — 全局默认
79
- client_max_body_size 1m;
80
- client_body_timeout 10s;
81
- client_header_timeout 10s;
82
-
83
- # 仅上传路径放宽
84
- location /api/upload {
85
- client_max_body_size 20m;
86
- proxy_pass http://127.0.0.1:8000;
87
- }
88
- ```
89
-
90
- ### 违规检测
91
-
92
- - Nginx 配置缺少 `client_max_body_size` 或值 > `10m` 但业务不是文件上传
93
- - 大文件上传路由走 API 中转而非对象存储直传
94
- - CDN 和 Nginx 的 body 上限不一致
95
-
96
- ## 第三层:后端数据校验
97
-
98
- ### 强制规则
99
-
100
- - Pydantic 每个 `str` 字段必须 `max_length`
101
- - Pydantic 每个 `list` 字段必须 `max_length`(限制数组元素数量)
102
- - `Query()` / `Path()` / `Header()` 参数同样必须 `max_length`
103
- - FastAPI 路由必须显式声明 Pydantic schema,**禁止** `data: dict` / `data: Any`
104
- - 分页 `page_size` 必须有 `le`(默认 `le=100`)
105
- - 后端不信任网关,必须在中间件做 request body 大小二次兜底(超出直接 413)
106
- - 图片上传除文件大小外,**必须**校验实际像素尺寸(Pillow `image.size`),防 decompression bomb
107
- - 文件大小后端二次校验,不信任前端声明的 `Content-Length`
108
-
109
- ### 示例
110
-
111
- ```python
112
- from pydantic import BaseModel, Field
113
-
114
- # ✅ 正确
115
- class UserCreate(BaseModel):
116
- name: str = Field(max_length=32)
117
- title: str = Field(max_length=100)
118
- desc: str = Field(max_length=500)
119
- tags: list[str] = Field(max_length=20)
120
-
121
- class ListParams(BaseModel):
122
- page: int = Field(default=1, ge=1)
123
- page_size: int = Field(default=20, ge=1, le=100)
124
-
125
- # ❌ 违规
126
- @router.post("/users")
127
- async def create_user(data: dict): ...
128
-
129
- class BadParams(BaseModel):
130
- page_size: int = 20 # 无 le,攻击者可传 999999
131
- name: str # 无 max_length
132
- tags: list[str] # 无 max_length
133
- ```
134
-
135
- > 说明:格式校验(`EmailStr` / 手机号 `pattern` / `HttpUrl` / 数字 `ge` / `le` 的数值范围)不是长度议题,仍归属 `dwy-python-security.md` §四,本文件不重复。
136
-
137
- ## 统一尺寸参考表
138
-
139
- 三层数字必须对齐。下表为全局默认,项目 CLAUDE.md 可为特殊业务覆盖个别字段(须显式说明原因)。
140
-
141
- | 场景 | 前端 maxlength | 后端 max_length | 网关 / 上传 |
142
- |------|---------------|----------------|-------------|
143
- | 用户名 | 32 | 32 | — |
144
- | 邮箱 | 254 | 254(RFC 5321) | — |
145
- | 密码(输入框) | 128 | 128 | — |
146
- | 手机号 | 20 | 20 | — |
147
- | 标题 / 短名称 | 100 | 100 | — |
148
- | 描述 / 摘要 | 500 | 500 | — |
149
- | 正文 / 评论 | 2000 | 2000 | — |
150
- | 富文本(HTML 串) | 100 KB | 100 KB | 走 body_size |
151
- | 搜索关键词 | 100 | 100 | — |
152
- | URL 字段 | 2048 | 2048 | — |
153
- | JSON body(默认) | — | 中间件兜底 1 MB | `client_max_body_size 1m` |
154
- | 图片上传(直发 API) | 前端预检 5 MB | 5 MB + 像素 `<= 8000×8000` | 上传路径 `10m` |
155
- | 通用小文件上传 | 前端预检 10 MB | 10 MB | 上传路径 `20m` |
156
- | 大文件(>10 MB) | — | — | 走对象存储直传,不过 API |
157
- | 批量接口 items | UI 分批 | `max_length=100` | — |
158
- | 查询分页 page_size | — | `le=100` | — |
159
-
160
- ### 边界原则
161
-
162
- - 前端 `maxlength` ≤ 后端 `max_length`(前端更严,UX 明确)
163
- - 后端所有字段 `max_length` 总和加冗余 ≤ 网关 `client_max_body_size`
164
- - 超出表中范围的业务必须在项目 CLAUDE.md 中显式记录并说明原因
165
-
166
- ## 全局禁止事项
167
-
168
- - 禁止任一层以"无限制"上线
169
- - 禁止三层数字互相冲突(例如前端 1000 但后端 100)
170
- - 禁止只靠前端 `maxlength` 而后端不校验
171
- - 禁止只靠后端 `max_length` 而前端不限
172
- - 禁止只靠网关 `client_max_body_size` 而无字段级 `max_length`
173
-
174
- ## 违规检测
175
-
176
- 发现以下任一情况,立即停止并提示用户:
177
-
178
- 1. `.vue` 文件中 `EInput` / `ETextarea` 没有 `maxlength`
179
- 2. 富文本组件(tiptap / quill)未配置字符上限
180
- 3. Pydantic `BaseModel` 有 `str` 字段但未设 `max_length`
181
- 4. Pydantic `BaseModel` 有 `list` 字段但未设 `max_length`
182
- 5. FastAPI 路由以 `dict` / `Any` 作为 body 参数
183
- 6. 分页参数无 `le` 上限
184
- 7. Nginx 配置缺失 `client_max_body_size`,或值 > `10m` 但业务不是文件上传
185
- 8. 上传 > 10MB 文件走 API 中转而非对象存储直传
186
- 9. 图片上传仅校验文件大小而不校验像素尺寸
@@ -1,32 +0,0 @@
1
- ---
2
- description: 优先使用成熟开源库,避免重复造轮子
3
- ---
4
-
5
- # 优先使用成熟开源方案
6
-
7
- 开发新功能时,优先选用成熟的开源项目/库,而不是手写实现。只有在确认没有合适的开源方案时,才自行实现。
8
-
9
- ## 决策流程
10
-
11
- ```
12
- 需要某项功能
13
- → 1. 搜索是否有成熟的开源库(npm/PyPI/GitHub stars > 1k、近期有维护)
14
- → 有:评估是否适配当前技术栈(Vue 3 / FastAPI / Node.js)
15
- → 适配:直接使用,不重复造轮子
16
- → 不适配:寻找替代方案
17
- → 没有合适的:自行实现,但在代码注释中说明为什么没用现成方案
18
- ```
19
-
20
- ## 强制规则
21
-
22
- - **禁止**手写已有成熟方案的功能:日期处理(dayjs/date-fns)、HTTP 请求(axios)、表单校验(zod/vee-validate)、状态管理(pinia)、图表(echarts/chart.js)、富文本(tiptap/quill)、拖拽(vuedraggable/dnd-kit)、虚拟滚动(@tanstack/virtual)、Markdown 渲染(markdown-it)、模糊搜索(fuse.js)
23
- - **禁止**手写加密/哈希/JWT 算法,必须使用 bcrypt/jose/crypto 等标准库
24
- - 选用开源库时,优先选择:项目已在用的依赖 > 社区主流方案 > 小众但适合的方案
25
-
26
- ## 例外情况
27
-
28
- 以下情况允许自行实现:
29
- - 功能极其简单(< 20 行),引入一个库反而增加复杂度
30
- - 开源库有严重的安全漏洞或已停止维护
31
- - 开源库的依赖体积过大,与需求不成比例
32
- - 项目有特殊定制需求,开源库无法满足且改造成本高于自建
@@ -1,181 +0,0 @@
1
- ---
2
- description: 后端/前端/Flutter/Monorepo 项目目录结构模板(按项目入口文件触发)
3
- paths:
4
- - "**/package.json"
5
- - "**/pyproject.toml"
6
- - "**/pubspec.yaml"
7
- - "**/pnpm-workspace.yaml"
8
- ---
9
-
10
- # 项目目录结构模板
11
-
12
- AI 创建文件时**必须**遵循以下目录结构,不得自造目录名或层级。
13
-
14
- ---
15
-
16
- ## 一、后端项目(FastAPI)
17
-
18
- ```
19
- backend/
20
- ├── src/app/
21
- │ ├── __init__.py
22
- │ ├── main.py # FastAPI 应用入口 + lifespan
23
- │ ├── config.py # 继承 eapi BaseSettings
24
- │ ├── database.py # create_async_engine_factory + create_session_factory
25
- │ ├── dependencies.py # FastAPI Depends(get_db, get_current_user)
26
- │ ├── exceptions.py # 项目级异常(继承 eapi AppError)
27
- │ ├── validators.py # 输入校验工具(防注入等)
28
- │ ├── models/ # SQLAlchemy ORM 模型
29
- │ │ ├── __init__.py
30
- │ │ ├── user.py # 每个实体一个文件
31
- │ │ └── ...
32
- │ ├── schemas/ # Pydantic v2 请求/响应模型
33
- │ │ ├── __init__.py
34
- │ │ ├── user.py # UserCreate, UserUpdate, UserResponse
35
- │ │ └── ...
36
- │ ├── routers/ # FastAPI 路由(按业务域拆分)
37
- │ │ ├── __init__.py
38
- │ │ ├── auth.py # 认证端点
39
- │ │ ├── user.py # 每个业务域一个文件
40
- │ │ └── ...
41
- │ ├── services/ # 业务逻辑层
42
- │ │ ├── __init__.py
43
- │ │ ├── auth.py
44
- │ │ ├── user.py # 与 router 同名,一一对应
45
- │ │ └── ...
46
- │ ├── tasks.py # ARQ 任务注册(@register 装饰器)
47
- │ └── worker.py # ARQ Worker 入口
48
- ├── alembic/ # 数据库迁移
49
- │ ├── versions/ # 迁移文件
50
- │ ├── env.py
51
- │ └── alembic.ini
52
- ├── scripts/ # 初始化/运维脚本
53
- │ ├── init_db.py # 初始化数据库表结构
54
- │ └── seed_admin.py # 创建初始管理员
55
- ├── tests/
56
- │ ├── conftest.py # pytest fixtures(SQLite 内存库、mock)
57
- │ ├── test_auth.py # 与 routers/ 同名
58
- │ └── ...
59
- ├── pyproject.toml # UV 依赖配置
60
- ├── Dockerfile.dev # 开发容器(--reload)
61
- ├── Dockerfile.prod # 生产容器(只读、non-root)
62
- ├── .env.example # 环境变量模板
63
- └── TEST_CASES.md # 测试用例清单
64
- ```
65
-
66
- **强制规则:**
67
- - 分层:`routers → schemas → services → models → database`,不可跨层调用
68
- - services 层抛 eapi 异常(AppError 子类),**不抛 HTTPException**
69
- - routers 层只做参数接收和 response 包装,**不写业务逻辑**
70
- - models/ schemas/ routers/ services/ 四个目录内文件按业务域一一对应
71
-
72
- ---
73
-
74
- ## 二、前端项目(Vue 3)
75
-
76
- ```
77
- frontend/
78
- ├── src/
79
- │ ├── main.ts # createApp + 插件注册
80
- │ ├── App.vue # 根组件
81
- │ ├── router/
82
- │ │ └── index.ts # Vue Router 配置 + 守卫
83
- │ ├── stores/ # Pinia Setup Store
84
- │ │ ├── auth.ts # 认证状态
85
- │ │ └── ...
86
- │ ├── api/ # HTTP 客户端(按业务域拆分)
87
- │ │ ├── client.ts # ekit createRequest() 实例
88
- │ │ ├── auth.ts # 登录/注册接口
89
- │ │ ├── user.ts # 用户接口
90
- │ │ └── ...
91
- │ ├── views/ # 页面级组件(路由对应)
92
- │ │ ├── LoginView.vue
93
- │ │ ├── DashboardView.vue
94
- │ │ └── ...
95
- │ ├── components/ # 共享 UI 组件(非页面级)
96
- │ ├── composables/ # Vue 3 组合式函数(use* 前缀)
97
- │ ├── utils/ # 纯工具函数
98
- │ └── index.css # Tailwind CSS 入口
99
- ├── tests/
100
- │ ├── api/
101
- │ ├── stores/
102
- │ ├── router/
103
- │ └── utils/
104
- ├── package.json
105
- ├── vite.config.ts
106
- ├── tsconfig.json
107
- ├── Dockerfile # 生产构建(多阶段)
108
- └── TEST_CASES.md
109
- ```
110
-
111
- **强制规则:**
112
- - views/ 放页面组件(路由直接引用),components/ 放复用组件
113
- - api/ 每个文件对应后端一个 router 模块,保持命名一致
114
- - stores/ 统一 Setup Store 写法(`export const useXxxStore = defineStore('xxx', () => {...})`)
115
-
116
- ---
117
-
118
- ## 三、Flutter 项目
119
-
120
- ```
121
- lib/
122
- ├── main.dart # runApp + ProviderScope
123
- ├── app.dart # MaterialApp.router + GoRouter
124
- ├── core/
125
- │ ├── config/
126
- │ │ └── env.dart # 环境配置
127
- │ ├── network/
128
- │ │ ├── dio_client.dart # Dio 实例 + 拦截器
129
- │ │ └── api_response.dart # 统一响应模型(对齐 eapi 格式)
130
- │ ├── storage/
131
- │ │ └── secure_storage.dart
132
- │ ├── theme/
133
- │ │ └── app_theme.dart # ThemeData + 设计 tokens
134
- │ └── utils/
135
- ├── features/ # 按功能模块拆分(feature-first)
136
- │ └── {feature_name}/
137
- │ ├── data/
138
- │ │ ├── {feature}_repository.dart # Repository 实现
139
- │ │ └── {feature}_dto.dart # 数据传输对象
140
- │ ├── domain/
141
- │ │ └── {feature}_entity.dart # 领域实体
142
- │ └── presentation/
143
- │ ├── {feature}_page.dart # 页面
144
- │ ├── {feature}_provider.dart # Riverpod Provider
145
- │ └── widgets/ # 功能内专属 Widget
146
- ├── shared/
147
- │ ├── providers/ # 全局 Provider(auth, theme)
148
- │ ├── widgets/ # 跨功能共享 Widget
149
- │ └── models/ # 共享数据模型
150
- test/
151
- ├── features/
152
- │ └── {feature_name}/
153
- └── core/
154
- ```
155
-
156
- **强制规则:**
157
- - features/ 按功能模块拆分,每个模块自包含 data/domain/presentation
158
- - core/ 放全局基础设施(网络、存储、主题),不放业务代码
159
- - shared/ 放跨功能共享的 provider/widget/model
160
-
161
- ---
162
-
163
- ## 四、Monorepo 项目结构(pnpm workspace)
164
-
165
- 当项目包含前端 + 后端时,使用 monorepo:
166
-
167
- ```
168
- project-root/
169
- ├── backend/ # FastAPI 后端(上述第一节结构)
170
- ├── frontend/ # Vue 前端(上述第二节结构)
171
- ├── mobile/ # Flutter 移动端(上述第三节结构,独立管理)
172
- ├── docker-compose.dev.yml # 开发环境
173
- ├── docker-compose.prod.yml # 生产环境
174
- ├── dev.sh # 一键启动脚本
175
- ├── pnpm-workspace.yaml # pnpm monorepo 配置
176
- ├── package.json # 根 package.json(scripts)
177
- ├── CLAUDE.md # 项目规范
178
- └── .env.example # 全局环境变量模板
179
- ```
180
-
181
- **注意:** Flutter 项目(mobile/)不纳入 pnpm workspace,独立用 `flutter pub get` 管理依赖。