create-dwy 0.5.0 → 0.6.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.
Files changed (156) hide show
  1. package/bin/index.js +1 -1
  2. package/package.json +2 -2
  3. package/src/create.js +61 -37
  4. package/src/sync.js +213 -53
  5. package/templates/claude-global/CLAUDE.md +92 -0
  6. package/templates/claude-global/rules/dwy-android-core.md +610 -0
  7. package/templates/claude-global/rules/dwy-api-design.md +110 -0
  8. package/templates/claude-global/rules/dwy-db-migration.md +46 -0
  9. package/templates/claude-global/rules/dwy-flutter-core.md +564 -0
  10. package/templates/claude-global/rules/dwy-flutter-network.md +222 -0
  11. package/templates/claude-global/rules/dwy-flutter-router.md +97 -0
  12. package/templates/claude-global/rules/dwy-flutter-testing.md +94 -0
  13. package/templates/claude-global/rules/dwy-git-commit-convention.md +82 -0
  14. package/templates/claude-global/rules/dwy-git-security.md +53 -0
  15. package/templates/claude-global/rules/dwy-payload-limits.md +178 -0
  16. package/templates/claude-global/rules/{prefer-open-source.md → dwy-prefer-open-source.md} +4 -0
  17. package/templates/claude-global/rules/dwy-project-structure.md +181 -0
  18. package/templates/claude-global/rules/{python-code-style.md → dwy-python-core.md} +314 -357
  19. package/templates/claude-global/rules/dwy-python-fastapi.md +272 -0
  20. package/templates/claude-global/rules/dwy-python-orm.md +61 -0
  21. package/templates/claude-global/rules/{backend-security.md → dwy-python-security.md} +116 -79
  22. package/templates/claude-global/rules/dwy-python-testing.md +53 -0
  23. package/templates/claude-global/rules/{server-security.md → dwy-server-security.md} +1 -2
  24. package/templates/claude-global/rules/dwy-tdd-development.md +70 -0
  25. package/templates/claude-global/rules/dwy-tech-stack.md +60 -0
  26. package/templates/claude-global/rules/dwy-vue-api.md +146 -0
  27. package/templates/claude-global/rules/{vue-code-style.md → dwy-vue-core.md} +361 -152
  28. package/templates/claude-global/rules/dwy-vue-pinia.md +75 -0
  29. package/templates/claude-global/rules/dwy-vue-testing.md +102 -0
  30. package/templates/claude-global/settings.json +20 -0
  31. package/templates/claude-global/skills/dwy-deploy-audit/SKILL.md +481 -0
  32. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-data.md +117 -0
  33. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-network.md +74 -0
  34. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-runtime.md +184 -0
  35. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_base.sh +39 -0
  36. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_capacity.sh +278 -0
  37. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_db.sh +122 -0
  38. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_docker.sh +249 -0
  39. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_env.sh +64 -0
  40. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_https.sh +60 -0
  41. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_logs.sh +209 -0
  42. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_nginx.sh +92 -0
  43. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_resilience.sh +157 -0
  44. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_secrets.sh +327 -0
  45. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_services.sh +77 -0
  46. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_ssh.sh +56 -0
  47. package/templates/claude-global/skills/dwy-deploy-audit/scripts/run_all.sh +105 -0
  48. package/templates/claude-global/skills/dwy-docker/SKILL.md +187 -0
  49. package/templates/claude-global/skills/dwy-docker/references/ask-templates.md +142 -0
  50. package/templates/claude-global/skills/dwy-docker/references/templates.md +479 -0
  51. package/templates/claude-global/skills/dwy-docker/references/version-rules.md +76 -0
  52. package/templates/claude-global/skills/dwy-docker/scripts/query_dockerhub.py +204 -0
  53. package/templates/claude-global/skills/dwy-docker/scripts/scan_images.sh +185 -0
  54. package/templates/claude-global/skills/dwy-eapi/SKILL.md +433 -0
  55. package/templates/claude-global/skills/dwy-eapi/references/tasks-integration-guide.md +387 -0
  56. package/templates/claude-global/skills/dwy-ekit/SKILL.md +85 -0
  57. package/templates/claude-global/skills/dwy-ekit/references/data.md +135 -0
  58. package/templates/claude-global/skills/dwy-ekit/references/form.md +68 -0
  59. package/templates/claude-global/skills/dwy-ekit/references/request.md +183 -0
  60. package/templates/claude-global/skills/dwy-ekit/references/ui.md +109 -0
  61. package/templates/claude-global/skills/{dwy-frontend-eui → dwy-eui}/SKILL.md +129 -15
  62. package/templates/claude-global/skills/dwy-eui/references/eui-design-guide.md +257 -0
  63. package/templates/claude-global/skills/dwy-eui/references/eui-integration-guide.md +302 -0
  64. package/templates/claude-global/skills/dwy-eui/references/eui-landing-design-guide.md +437 -0
  65. package/templates/claude-global/skills/dwy-fullstack-scaffold/SKILL.md +214 -0
  66. package/templates/claude-global/skills/dwy-mirror-source/SKILL.md +275 -0
  67. package/templates/claude-global/skills/dwy-mirror-source/references/dockerfile-snippets.md +228 -0
  68. package/templates/claude-global/skills/dwy-mirror-source/references/mirror-providers.md +150 -0
  69. package/templates/claude-global/skills/dwy-mirror-source/scripts/__pycache__/check_mirrors.cpython-313.pyc +0 -0
  70. package/templates/claude-global/skills/dwy-mirror-source/scripts/apply_mirrors.py +666 -0
  71. package/templates/claude-global/skills/dwy-mirror-source/scripts/check_mirrors.py +868 -0
  72. package/templates/claude-global/skills/dwy-pentest/SKILL.md +344 -0
  73. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__init__.py +1 -0
  74. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/__init__.cpython-311.pyc +0 -0
  75. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/config.cpython-311.pyc +0 -0
  76. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/executor.cpython-311.pyc +0 -0
  77. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/severity.cpython-311.pyc +0 -0
  78. package/templates/claude-global/skills/dwy-pentest/scripts/lib/__pycache__/validator.cpython-311.pyc +0 -0
  79. package/templates/claude-global/skills/dwy-pentest/scripts/lib/config.py +109 -0
  80. package/templates/claude-global/skills/dwy-pentest/scripts/lib/executor.py +157 -0
  81. package/templates/claude-global/skills/dwy-pentest/scripts/lib/severity.py +96 -0
  82. package/templates/claude-global/skills/dwy-pentest/scripts/lib/validator.py +113 -0
  83. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_auth.py +289 -0
  84. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_recon.py +217 -0
  85. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_report.py +343 -0
  86. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_scan.py +205 -0
  87. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_ssl.py +208 -0
  88. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_vuln.py +205 -0
  89. package/templates/claude-global/skills/dwy-pentest/scripts/pentest_web.py +330 -0
  90. package/templates/claude-global/skills/dwy-pentest/scripts/pyproject.toml +14 -0
  91. package/templates/claude-global/skills/dwy-pentest/scripts/setup_tools.sh +97 -0
  92. package/templates/claude-global/skills/dwy-pentest/scripts/uv.lock +415 -0
  93. package/templates/claude-global/skills/dwy-publish/SKILL.md +135 -0
  94. package/templates/claude-global/skills/dwy-vue-core/SKILL.md +890 -0
  95. package/templates/project/backend/.dwy.hbs +5 -0
  96. package/templates/project/backend/.python-version +1 -0
  97. package/templates/project/backend/CLAUDE.md.hbs +40 -0
  98. package/templates/project/{web/backend → backend}/alembic/script.py.mako +2 -0
  99. package/templates/project/{web/backend → backend}/alembic.ini.hbs +0 -1
  100. package/templates/project/backend/deploy.sh.hbs +18 -0
  101. package/templates/project/{web → backend}/docker-compose.prod.yml.hbs +1 -1
  102. package/templates/project/{web/backend → backend}/pyproject.toml.hbs +4 -5
  103. package/templates/project/{web/backend → backend}/src/app/config.py.hbs +1 -1
  104. package/templates/project/backend/src/app/database.py +10 -0
  105. package/templates/project/backend/src/app/dependencies.py +5 -0
  106. package/templates/project/{web/backend → backend}/src/app/main.py.hbs +3 -3
  107. package/templates/project/backend/src/app/models/base.py +5 -0
  108. package/templates/project/web/CLAUDE.md.hbs +29 -36
  109. package/templates/project/web/{frontend → apps/web}/index.html.hbs +1 -0
  110. package/templates/project/web/{frontend → apps/web}/package.json.hbs +4 -3
  111. package/templates/project/web/apps/web/src/App.vue +9 -0
  112. package/templates/project/web/apps/web/src/api/client.ts +5 -0
  113. package/templates/project/web/apps/web/src/composables/.gitkeep +0 -0
  114. package/templates/project/web/apps/web/src/layouts/DefaultLayout.vue +8 -0
  115. package/templates/project/web/{frontend → apps/web}/src/router/index.ts +1 -1
  116. package/templates/project/web/{frontend → apps/web}/src/stores/auth.ts +4 -2
  117. package/templates/project/web/apps/web/src/style.css +2 -0
  118. package/templates/project/web/apps/web/src/types/router.d.ts +8 -0
  119. package/templates/project/web/apps/web/src/views/HomeView.vue +8 -0
  120. package/templates/project/web/apps/web/tsconfig.app.json +18 -0
  121. package/templates/project/web/apps/web/tsconfig.json +6 -0
  122. package/templates/project/web/{frontend → apps/web}/vite.config.ts.hbs +7 -1
  123. package/templates/project/web/package.json.hbs +16 -0
  124. package/templates/project/web/packages/.gitkeep +0 -0
  125. package/templates/project/web/pnpm-workspace.yaml +3 -0
  126. package/templates/claude-global/rules/agent-team-execution.md +0 -138
  127. package/templates/claude-global/rules/agent-team-patterns.md +0 -157
  128. package/templates/claude-global/rules/git-security.md +0 -144
  129. package/templates/claude-global/skills/dwy-auto-sync/SKILL.md +0 -52
  130. package/templates/claude-global/skills/dwy-backend-base/SKILL.md +0 -279
  131. package/templates/claude-global/skills/dwy-frontend-core/SKILL.md +0 -181
  132. package/templates/project/web/.claude/commands/deploy.md +0 -4
  133. package/templates/project/web/backend/src/app/models/base.py +0 -5
  134. package/templates/project/web/deploy.sh.hbs +0 -113
  135. package/templates/project/web/frontend/src/App.vue +0 -3
  136. package/templates/project/web/frontend/src/api/client.ts +0 -13
  137. package/templates/project/web/frontend/src/style.css +0 -1
  138. package/templates/project/web/frontend/src/views/HomeView.vue +0 -5
  139. package/templates/project/web/frontend/tsconfig.app.json +0 -14
  140. package/templates/project/web/frontend/tsconfig.json +0 -4
  141. /package/templates/{project/web/backend → claude-global/skills/dwy-pentest/scripts}/.python-version +0 -0
  142. /package/templates/project/{web/backend → backend}/Dockerfile +0 -0
  143. /package/templates/project/{web/backend → backend}/alembic/env.py.hbs +0 -0
  144. /package/templates/{claude-global/skills → project/backend/alembic/versions}/.gitkeep +0 -0
  145. /package/templates/project/{web → backend}/docker-compose.dev.yml.hbs +0 -0
  146. /package/templates/project/{web/backend → backend}/src/app/__init__.py +0 -0
  147. /package/templates/project/{web/backend → backend}/src/app/models/__init__.py +0 -0
  148. /package/templates/project/{web/backend → backend}/src/app/routers/__init__.py +0 -0
  149. /package/templates/project/{web/backend → backend}/src/app/routers/health.py +0 -0
  150. /package/templates/project/{web/backend → backend}/src/app/schemas/__init__.py +0 -0
  151. /package/templates/project/{web/backend → backend}/src/app/services/__init__.py +0 -0
  152. /package/templates/project/{web/backend → backend}/tests/__init__.py +0 -0
  153. /package/templates/project/{web/backend → backend}/tests/conftest.py.hbs +0 -0
  154. /package/templates/project/{web/backend/alembic/versions → mobile}/.gitkeep +0 -0
  155. /package/templates/project/web/{frontend → apps/web}/src/components/.gitkeep +0 -0
  156. /package/templates/project/web/{frontend → apps/web}/src/main.ts +0 -0
@@ -0,0 +1,110 @@
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 同时用于请求和响应。
@@ -0,0 +1,46 @@
1
+ ---
2
+ description: Alembic 数据库迁移规范
3
+ paths:
4
+ - "**/alembic/**"
5
+ - "**/alembic.ini"
6
+ - "**/migrations/**"
7
+ ---
8
+
9
+ # Alembic 数据库迁移规范
10
+
11
+ ## 一、初始化
12
+
13
+ ```bash
14
+ cd backend
15
+ alembic init alembic
16
+ ```
17
+
18
+ ## 二、配置
19
+
20
+ ```python
21
+ # alembic/env.py — 必须配置项
22
+ from app.database import Base # 导入 ORM Base
23
+ from app.models import * # 导入所有模型(确保被扫描到)
24
+ target_metadata = Base.metadata
25
+ ```
26
+
27
+ ## 三、工作流
28
+
29
+ ```bash
30
+ # 模型变更后生成迁移
31
+ alembic revision --autogenerate -m "add user table"
32
+
33
+ # 执行迁移(dev 和 prod 相同)
34
+ alembic upgrade head
35
+
36
+ # 回滚一步
37
+ alembic downgrade -1
38
+ ```
39
+
40
+ ## 四、强制规则
41
+
42
+ - 每次 model 变更**必须**生成 migration 文件,禁止手动 `CREATE TABLE`
43
+ - 迁移文件**必须**提交到 git,dev 和 prod 共用同一套迁移
44
+ - 生产数据库只通过 `alembic upgrade head` 变更 schema
45
+ - 迁移文件命名:Alembic 自动生成 revision ID + 人类可读描述
46
+ - 禁止在迁移文件中写业务数据操作(seed data 放 scripts/ 目录)
@@ -0,0 +1,564 @@
1
+ ---
2
+ description: Flutter + Dart 基础风格(结构/Riverpod/命名/模型/Dart 语言/Lint)
3
+ paths:
4
+ - "**/*.dart"
5
+ - "**/pubspec.yaml"
6
+ - "**/analysis_options.yaml"
7
+ ---
8
+
9
+ # Flutter + Dart 基础风格规范
10
+
11
+ ## 一、项目结构
12
+
13
+ ### 1.1 标准目录
14
+
15
+ ```
16
+ project_name/
17
+ ├── lib/
18
+ │ ├── main.dart # runApp + ProviderScope
19
+ │ ├── app.dart # MaterialApp.router + GoRouter + Theme
20
+ │ │
21
+ │ ├── core/ # 全局基础设施(不含业务逻辑)
22
+ │ │ ├── config/
23
+ │ │ │ └── env.dart # 环境配置(API 地址、OSS 端点等)
24
+ │ │ ├── network/
25
+ │ │ │ ├── dio_client.dart # Dio 实例 + 全部拦截器
26
+ │ │ │ ├── api_response.dart # 统一响应模型(对齐 eapi 格式)
27
+ │ │ │ └── interceptors/
28
+ │ │ │ ├── token_interceptor.dart
29
+ │ │ │ ├── refresh_interceptor.dart
30
+ │ │ │ ├── unwrap_interceptor.dart
31
+ │ │ │ └── error_interceptor.dart
32
+ │ │ ├── storage/
33
+ │ │ │ └── token_storage.dart # FlutterSecureStorage 封装
34
+ │ │ ├── theme/
35
+ │ │ │ ├── app_theme.dart # ThemeData(亮色 + 暗色)
36
+ │ │ │ └── app_colors.dart # 设计 tokens
37
+ │ │ └── utils/ # 通用工具(格式化、校验等)
38
+ │ │
39
+ │ ├── features/ # 功能模块(feature-first 拆分)
40
+ │ │ ├── auth/
41
+ │ │ │ ├── data/
42
+ │ │ │ │ ├── auth_repository.dart
43
+ │ │ │ │ └── auth_dto.dart
44
+ │ │ │ ├── domain/
45
+ │ │ │ │ └── user_entity.dart
46
+ │ │ │ └── presentation/
47
+ │ │ │ ├── login_page.dart
48
+ │ │ │ ├── auth_provider.dart
49
+ │ │ │ └── widgets/
50
+ │ │ │ └── login_form.dart
51
+ │ │ ├── home/
52
+ │ │ │ └── ...
53
+ │ │ └── {feature_name}/
54
+ │ │ ├── data/ # 数据层:Repository 实现 + DTO
55
+ │ │ ├── domain/ # 领域层:Entity(可选,简单场景直接用 DTO)
56
+ │ │ └── presentation/ # 表现层:Page + Provider + Widget
57
+ │ │
58
+ │ └── shared/ # 跨功能共享
59
+ │ ├── providers/ # 全局 Provider(auth、theme、dio)
60
+ │ ├── widgets/ # 共享 Widget(AppBar、ErrorView 等)
61
+ │ └── models/ # 共享数据模型
62
+ │
63
+ ├── test/
64
+ │ ├── core/
65
+ │ ├── features/
66
+ │ │ └── {feature_name}/
67
+ │ └── shared/
68
+ │
69
+ ├── pubspec.yaml
70
+ ├── analysis_options.yaml # Lint 规则
71
+ ├── build.yaml # build_runner 配置
72
+ ├── .env.example
73
+ └── TEST_CASES.md
74
+ ```
75
+
76
+ ### 1.2 目录规则
77
+
78
+ | 规则 | 说明 |
79
+ |------|------|
80
+ | features/ 按功能拆分 | 每个功能自包含 data/domain/presentation,不跨功能引用 data/ |
81
+ | core/ 禁止业务逻辑 | 只放基础设施(网络、存储、主题、工具) |
82
+ | shared/ 放跨功能共享 | 两个以上 feature 共用的 provider/widget/model |
83
+ | domain/ 可选 | 简单 CRUD 场景可省略 domain/,直接 DTO 传递 |
84
+ | 一个文件一个公开类 | 文件名与主要类名对应(snake_case) |
85
+
86
+ ### 1.3 入口文件
87
+
88
+ ```dart
89
+ // main.dart
90
+ void main() {
91
+ runApp(const ProviderScope(child: App()));
92
+ }
93
+
94
+ // app.dart
95
+ class App extends ConsumerWidget {
96
+ const App({super.key});
97
+
98
+ @override
99
+ Widget build(BuildContext context, WidgetRef ref) {
100
+ final router = ref.watch(routerProvider);
101
+ return MaterialApp.router(
102
+ routerConfig: router,
103
+ theme: AppTheme.light,
104
+ darkTheme: AppTheme.dark,
105
+ );
106
+ }
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ## 二、Riverpod 状态管理
113
+
114
+ ### 2.1 Provider 类型选择
115
+
116
+ 使用 `riverpod_generator`(@riverpod 注解)自动生成 Provider,禁止手写 Provider 声明。
117
+
118
+ ```yaml
119
+ # pubspec.yaml
120
+ dependencies:
121
+ flutter_riverpod: ^2.6.0
122
+ riverpod_annotation: ^2.6.0
123
+
124
+ dev_dependencies:
125
+ riverpod_generator: ^2.6.0
126
+ build_runner: ^2.4.0
127
+ ```
128
+
129
+ **类型选择规则:**
130
+
131
+ | 场景 | 用法 | 示例 |
132
+ |------|------|------|
133
+ | 同步计算/常量 | `@riverpod` 函数 | 主题、配置、计算值 |
134
+ | 异步一次性获取 | `@riverpod` async 函数 | 获取用户详情 |
135
+ | 带参数的查询 | `@riverpod` 函数 + 参数 | 按 ID 获取数据 |
136
+ | 可变状态(同步) | `@riverpod` class extends _$Xxx | 表单状态、开关 |
137
+ | 可变状态(异步) | `@riverpod` class + AsyncValue | 列表 CRUD、分页 |
138
+ | 全局长驻 | `@Riverpod(keepAlive: true)` | 认证状态、Dio 实例 |
139
+
140
+ ### 2.2 代码生成模式
141
+
142
+ ```dart
143
+ // 推荐:使用 @riverpod 注解(自动生成 Provider)
144
+ import 'package:riverpod_annotation/riverpod_annotation.dart';
145
+ part 'user_provider.g.dart';
146
+
147
+ // 只读 Provider(函数式)
148
+ @riverpod
149
+ Future<User> userDetail(Ref ref, {required int userId}) async {
150
+ final dio = ref.watch(dioProvider);
151
+ final response = await dio.get('/api/users/$userId');
152
+ return User.fromJson(response.data);
153
+ }
154
+
155
+ // 可变状态 Provider(类式)
156
+ @riverpod
157
+ class UserList extends _$UserList {
158
+ @override
159
+ Future<List<User>> build() async {
160
+ final dio = ref.watch(dioProvider);
161
+ final response = await dio.get('/api/users');
162
+ return (response.data['items'] as List).map((e) => User.fromJson(e)).toList();
163
+ }
164
+
165
+ Future<void> refresh() async {
166
+ state = const AsyncLoading();
167
+ state = await AsyncValue.guard(() => build());
168
+ }
169
+
170
+ Future<void> deleteUser(int id) async {
171
+ final dio = ref.read(dioProvider);
172
+ await dio.delete('/api/users/$id');
173
+ ref.invalidateSelf(); // 重新获取列表
174
+ }
175
+ }
176
+
177
+ // 全局长驻 Provider
178
+ @Riverpod(keepAlive: true)
179
+ class Auth extends _$Auth {
180
+ @override
181
+ AuthState build() {
182
+ return const AuthState.unauthenticated();
183
+ }
184
+
185
+ Future<void> login(String username, String password) async { ... }
186
+ void logout() { ... }
187
+ }
188
+ ```
189
+
190
+ ### 2.3 ref 使用规则
191
+
192
+ | 方法 | 用途 | 使用场景 |
193
+ |------|------|---------|
194
+ | `ref.watch(provider)` | 响应式监听,值变化时重建 | build() 方法中 |
195
+ | `ref.read(provider)` | 一次性读取,不监听变化 | 事件处理(onPressed、onSubmit) |
196
+ | `ref.listen(provider, callback)` | 监听变化执行副作用 | 显示 SnackBar、导航 |
197
+ | `ref.invalidate(provider)` | 强制刷新 Provider | 数据变更后刷新列表 |
198
+
199
+ **禁止:**
200
+ - 禁止在 `build()` 中用 `ref.read()`(应该用 `ref.watch()`)
201
+ - 禁止在 `onPressed` 回调中用 `ref.watch()`(应该用 `ref.read()`)
202
+
203
+ ### 2.4 Widget 选择
204
+
205
+ ```dart
206
+ // ConsumerWidget — 无状态,优先使用
207
+ class UserListPage extends ConsumerWidget {
208
+ const UserListPage({super.key});
209
+
210
+ @override
211
+ Widget build(BuildContext context, WidgetRef ref) {
212
+ final users = ref.watch(userListProvider);
213
+ return users.when(
214
+ data: (list) => ListView(...),
215
+ loading: () => const CircularProgressIndicator(),
216
+ error: (err, stack) => ErrorView(error: err),
217
+ );
218
+ }
219
+ }
220
+
221
+ // ConsumerStatefulWidget — 需要 initState/dispose 或动画控制器时使用
222
+ class AnimatedPage extends ConsumerStatefulWidget { ... }
223
+ ```
224
+
225
+ **选择规则:** 优先 `ConsumerWidget`,只有需要 `StatefulWidget` 生命周期时才用 `ConsumerStatefulWidget`。
226
+
227
+ ### 2.5 禁止事项
228
+
229
+ | 禁止 | 说明 |
230
+ |------|------|
231
+ | `StateNotifier` / `StateNotifierProvider` | 已废弃,使用 `Notifier` / `AsyncNotifier` |
232
+ | `ChangeNotifier` / `ChangeNotifierProvider` | Riverpod 不推荐,使用 Notifier |
233
+ | 手写 Provider 声明 | 必须用 `@riverpod` 注解 + code generation |
234
+ | `ref.watch()` 在事件回调中 | 事件回调用 `ref.read()` |
235
+ | Provider 间循环依赖 | 重新设计数据流方向 |
236
+
237
+ ---
238
+
239
+ ## 三、命名规范
240
+
241
+ ### 3.1 文件命名
242
+
243
+ 全部 `snake_case`,文件名反映内容:
244
+
245
+ ```
246
+ user_profile_page.dart # 页面
247
+ user_list_provider.dart # Provider
248
+ auth_repository.dart # Repository
249
+ user_entity.dart # 实体
250
+ user_dto.dart # DTO
251
+ dio_client.dart # 工具类
252
+ login_form.dart # Widget
253
+ token_interceptor.dart # 拦截器
254
+ ```
255
+
256
+ ### 3.2 类命名
257
+
258
+ | 类型 | 命名规则 | 示例 |
259
+ |------|---------|------|
260
+ | Page | `{Feature}{Action}Page` | `UserListPage`, `LoginPage` |
261
+ | Widget | 描述性 PascalCase | `LoginForm`, `UserCard`, `ErrorView` |
262
+ | Provider (函数式) | `{entity}{action}Provider` (自动生成) | `userDetailProvider`, `userListProvider` |
263
+ | Provider (类式) | `{Entity}{Action}` + `Provider` (自动生成) | `UserList` → `userListProvider` |
264
+ | Notifier | `{Entity}{Action}` | `UserList`, `Auth`, `ThemeMode` |
265
+ | Repository | `{Feature}Repository` | `AuthRepository`, `UserRepository` |
266
+ | Entity | `{Name}` | `User`, `Order`, `Factor` |
267
+ | DTO | `{Name}Dto` 或 `{Name}Response` | `UserDto`, `LoginResponse` |
268
+ | Service | `{Feature}Service` | `OssService`, `NotificationService` |
269
+
270
+ ### 3.3 变量和函数命名
271
+
272
+ ```dart
273
+ // 变量:camelCase
274
+ final userName = 'John';
275
+ final isLoading = false;
276
+ final userList = <User>[];
277
+
278
+ // 函数:camelCase,动词开头
279
+ Future<User> fetchUser(int id) async { ... }
280
+ void deleteUser(int id) { ... }
281
+ bool isValidEmail(String email) { ... }
282
+
283
+ // 常量:lowerCamelCase(Dart 官方风格,不用 UPPER_SNAKE)
284
+ const defaultPageSize = 20;
285
+ const maxRetryCount = 3;
286
+
287
+ // 私有成员:_前缀
288
+ final _cache = <String, dynamic>{};
289
+ void _handleError(Object error) { ... }
290
+ ```
291
+
292
+ ### 3.4 禁止魔法字符串
293
+
294
+ 同一个字符串字面量在文件内出现 2 次及以上时,**必须**提取为常量。
295
+
296
+ ```dart
297
+ // ❌ 魔法字符串散落多处
298
+ await secureStorage.write(key: 'access_token', value: token);
299
+ final t = await secureStorage.read(key: 'access_token');
300
+
301
+ // ✅ 提取为常量
302
+ const _accessTokenKey = 'access_token';
303
+ await secureStorage.write(key: _accessTokenKey, value: token);
304
+ final t = await secureStorage.read(key: _accessTokenKey);
305
+
306
+ // ✅ 跨文件共享的 key 放到常量文件
307
+ // core/constants/storage_keys.dart
308
+ class StorageKeys {
309
+ StorageKeys._();
310
+ static const accessToken = 'access_token';
311
+ static const refreshToken = 'refresh_token';
312
+ static const theme = 'theme';
313
+ }
314
+ ```
315
+
316
+ ### 3.5 目录和包命名
317
+
318
+ ```
319
+ features/user_management/ # snake_case
320
+ core/network/ # snake_case
321
+ shared/widgets/ # snake_case
322
+ ```
323
+
324
+ ---
325
+
326
+ ## 四、数据模型与序列化
327
+
328
+ ### 4.1 freezed + json_serializable
329
+
330
+ ```yaml
331
+ # pubspec.yaml
332
+ dependencies:
333
+ freezed_annotation: ^2.4.0
334
+ json_annotation: ^4.9.0
335
+
336
+ dev_dependencies:
337
+ freezed: ^2.5.0
338
+ json_serializable: ^6.8.0
339
+ build_runner: ^2.4.0
340
+ ```
341
+
342
+ ```dart
343
+ // features/user/domain/user_entity.dart
344
+ import 'package:freezed_annotation/freezed_annotation.dart';
345
+ part 'user_entity.freezed.dart';
346
+ part 'user_entity.g.dart';
347
+
348
+ @freezed
349
+ class User with _$User {
350
+ const factory User({
351
+ required int id,
352
+ required String username,
353
+ required String role,
354
+ @JsonKey(name: 'is_active') required bool isActive,
355
+ @JsonKey(name: 'created_at') required DateTime createdAt,
356
+ }) = _User;
357
+
358
+ factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
359
+ }
360
+ ```
361
+
362
+ ### 4.2 规则
363
+
364
+ | 规则 | 说明 |
365
+ |------|------|
366
+ | 数据模型用 `@freezed` | 不手写 `fromJson/toJson/copyWith/==` |
367
+ | 后端字段 snake_case → 前端 camelCase | 用 `@JsonKey(name: 'snake_case')` 映射 |
368
+ | 禁止手写序列化 | 必须用 json_serializable 代码生成 |
369
+ | 运行代码生成 | `dart run build_runner build --delete-conflicting-outputs` |
370
+
371
+ ---
372
+
373
+ ## 五、Dart 语言规范
374
+
375
+ ### 5.1 类型标注
376
+
377
+ ```dart
378
+ // 显式标注公开 API 的返回类型
379
+ Future<List<User>> fetchUsers() async { ... }
380
+ String formatDate(DateTime date) { ... }
381
+
382
+ // 局部变量可用 final/var 推断
383
+ final users = await fetchUsers();
384
+ var count = 0;
385
+
386
+ // 禁止 dynamic(除非与原生 JSON 交互的边界点)
387
+ ```
388
+
389
+ ### 5.2 Null Safety
390
+
391
+ ```dart
392
+ // 优先用非空类型
393
+ String name = 'default'; // 非空
394
+
395
+ // 只在真正可能为 null 时用 ?
396
+ String? middleName;
397
+
398
+ // 禁止滥用 !(bang operator),先 null check
399
+ if (user != null) {
400
+ print(user.name); // 安全
401
+ }
402
+ // 或用 ?.
403
+ user?.name;
404
+
405
+ // 禁止
406
+ print(user!.name); // 可能运行时崩溃
407
+ ```
408
+
409
+ ### 5.3 异步
410
+
411
+ ```dart
412
+ // async/await 优先
413
+ final user = await fetchUser(id);
414
+
415
+ // 多个独立异步操作用 Future.wait 并行
416
+ final (users, orders) = await (
417
+ fetchUsers(),
418
+ fetchOrders(),
419
+ ).wait;
420
+
421
+ // 禁止 .then() 链式调用(可读性差)
422
+ // fetchUser(id).then((user) => fetchOrders(user.id)).then(...) // 禁止
423
+ ```
424
+
425
+ ### 5.4 集合操作
426
+
427
+ ```dart
428
+ // 推荐:collection-if / collection-for
429
+ final widgets = [
430
+ const Header(),
431
+ if (showBanner) const Banner(),
432
+ for (final item in items) ItemCard(item: item),
433
+ ];
434
+
435
+ // 推荐:级联操作符
436
+ final paint = Paint()
437
+ ..color = Colors.blue
438
+ ..strokeWidth = 2.0;
439
+ ```
440
+
441
+ ### 5.5 构造函数
442
+
443
+ ```dart
444
+ // 推荐:命名参数 + required
445
+ class UserCard extends StatelessWidget {
446
+ const UserCard({
447
+ super.key,
448
+ required this.user,
449
+ this.onTap,
450
+ });
451
+
452
+ final User user;
453
+ final VoidCallback? onTap;
454
+ }
455
+
456
+ // 禁止位置参数超过 2 个
457
+ ```
458
+
459
+ ---
460
+
461
+ ## 六、Lint 规则
462
+
463
+ ### 6.1 analysis_options.yaml
464
+
465
+ ```yaml
466
+ include: package:flutter_lints/flutter.yaml
467
+
468
+ linter:
469
+ rules:
470
+ - prefer_const_constructors
471
+ - prefer_const_declarations
472
+ - prefer_final_locals
473
+ - avoid_print # 禁止 print
474
+ - require_trailing_commas # 尾逗号(方便 diff)
475
+ - sort_constructors_first
476
+ - prefer_single_quotes # 统一单引号
477
+ - always_use_package_imports # 禁止相对导入
478
+
479
+ analyzer:
480
+ errors:
481
+ missing_return: error
482
+ dead_code: warning
483
+ exclude:
484
+ - "**/*.g.dart"
485
+ - "**/*.freezed.dart"
486
+ ```
487
+
488
+ ### 6.2 Import 规则
489
+
490
+ ```dart
491
+ // 使用 package import(禁止相对导入)
492
+ import 'package:my_app/features/auth/data/auth_repository.dart'; // 正确
493
+ // import '../data/auth_repository.dart'; // 禁止
494
+
495
+ // 导入顺序(dart > package > 项目 > 相对路径)
496
+ import 'dart:async';
497
+ import 'dart:convert';
498
+
499
+ import 'package:flutter/material.dart';
500
+ import 'package:flutter_riverpod/flutter_riverpod.dart';
501
+
502
+ import 'package:my_app/core/network/dio_client.dart';
503
+ import 'package:my_app/features/auth/data/auth_repository.dart';
504
+ ```
505
+
506
+ ---
507
+
508
+ ## 七、代码自检清单
509
+
510
+ 提交前逐条确认:
511
+
512
+ - [ ] 文件名全部 snake_case
513
+ - [ ] 公开类/函数有类型标注
514
+ - [ ] Provider 用 @riverpod 注解生成,不手写
515
+ - [ ] 无 StateNotifier / ChangeNotifier
516
+ - [ ] ref.watch 只在 build() 中,ref.read 只在事件回调中
517
+ - [ ] 路由全部用 GoRouter,无 Navigator.push
518
+ - [ ] 数据模型用 @freezed,无手写 fromJson
519
+ - [ ] HTTP 请求通过 DioClient,无裸 http.get / Dio()
520
+ - [ ] 无 print(),调试用 debugPrint 或 logger
521
+ - [ ] 无 dynamic 类型(JSON 边界除外)
522
+ - [ ] 无 ! bang operator(先 null check)
523
+ - [ ] 常量构造函数加 const
524
+ - [ ] 尾逗号(trailing comma)
525
+ - [ ] package import,无相对导入
526
+ - [ ] 代码生成文件已更新(`dart run build_runner build`)
527
+ - [ ] 新增功能有对应测试
528
+ - [ ] TEST_CASES.md 已同步
529
+
530
+ ---
531
+
532
+ ## 八、环境变量管理(Flutter)
533
+
534
+ 使用编译时注入或 `.env` + `flutter_dotenv`:
535
+
536
+ ```bash
537
+ # .env
538
+ API_BASE_URL=http://localhost:8000/api
539
+
540
+ # 或编译时注入
541
+ flutter run --dart-define=API_BASE_URL=http://localhost:8000/api
542
+ ```
543
+
544
+ **强制规则:**
545
+
546
+ | 规则 | 说明 |
547
+ |------|------|
548
+ | 每个项目必须有 `.env.example` | 列出所有变量名 + 注释说明,值用占位符 |
549
+ | `.env` 文件禁止提交 git | 已在 git-security.md 约束 |
550
+ | 禁止硬编码 | 数据库连接、密钥、API 地址等必须走环境变量 |
551
+
552
+ ---
553
+
554
+ ## 九、状态管理(跨端共识)
555
+
556
+ | 平台 | 方案 | 详细规范 |
557
+ |------|------|---------|
558
+ | Vue | Pinia Setup Store | 见 `vue-code-style.md` 状态管理章节 |
559
+ | Flutter | Riverpod | 见本文件第二章 |
560
+
561
+ **跨端共识:**
562
+ - 认证状态全局管理(Vue: `useAuthStore`,Flutter: `authProvider`)
563
+ - 页面级状态就近管理,不上提到全局
564
+ - 缓存策略:列表数据按需刷新,不做客户端持久化缓存(除离线场景)