create-dwy 0.7.1 → 0.9.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 (96) hide show
  1. package/package.json +1 -1
  2. package/src/create.js +50 -3
  3. package/src/sync.js +228 -130
  4. package/src/utils.js +4 -0
  5. package/templates/claude-global/CLAUDE.md +81 -6
  6. package/templates/claude-global/rules/dwy-postgres.md +89 -0
  7. package/templates/claude-global/rules/dwy-python-backend.md +492 -0
  8. package/templates/claude-global/rules/dwy-python-core.md +94 -634
  9. package/templates/claude-global/rules/dwy-python-testing.md +115 -13
  10. package/templates/claude-global/rules/dwy-redis.md +88 -0
  11. package/templates/claude-global/rules/dwy-vue-core.md +341 -645
  12. package/templates/claude-global/rules/dwy-vue-pinia.md +47 -34
  13. package/templates/claude-global/rules/dwy-vue-testing.md +120 -55
  14. package/templates/claude-global/skills/dwy-deploy-audit/references/checks-network.md +1 -1
  15. package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_nginx.sh +1 -1
  16. package/templates/claude-global/skills/dwy-dolphindb/SKILL.md +22 -15
  17. package/templates/claude-global/skills/dwy-dolphindb/evals/evals.json +23 -0
  18. package/templates/claude-global/skills/dwy-dolphindb/references/dolphindb-rules.md +100 -1
  19. package/templates/claude-global/skills/dwy-ekit/SKILL.md +142 -276
  20. package/templates/claude-global/skills/dwy-eui/SKILL.md +264 -182
  21. package/templates/claude-global/skills/dwy-fullstack-scaffold/SKILL.md +117 -129
  22. package/templates/claude-global/skills/dwy-git-commit/SKILL.md +125 -0
  23. package/templates/claude-global/skills/dwy-publish/SKILL.md +1 -1
  24. package/templates/claude-global/{rules/dwy-tech-stack.md → skills/dwy-tech-stack/SKILL.md} +4 -3
  25. package/templates/project/fullstack-monorepo/CLAUDE.md.hbs +81 -0
  26. package/templates/project/fullstack-monorepo/backend/.python-version +1 -0
  27. package/templates/project/fullstack-monorepo/backend/CLAUDE.md.hbs +68 -0
  28. package/templates/project/fullstack-monorepo/backend/Dockerfile.dev +23 -0
  29. package/templates/project/fullstack-monorepo/backend/alembic/env.py.hbs +68 -0
  30. package/templates/project/fullstack-monorepo/backend/alembic/script.py.mako +26 -0
  31. package/templates/project/fullstack-monorepo/backend/alembic.ini.hbs +43 -0
  32. package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/pyproject.toml +16 -0
  33. package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/src/dwy_shared/__init__.py +12 -0
  34. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/pyproject.toml.hbs +20 -0
  35. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/__init__.py.hbs +40 -0
  36. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/config.py +9 -0
  37. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/models.py.hbs +17 -0
  38. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/protocols.py +14 -0
  39. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/router.py.hbs +22 -0
  40. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/schemas.py +21 -0
  41. package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/service.py +11 -0
  42. package/templates/project/fullstack-monorepo/backend/pyproject.toml.hbs +84 -0
  43. package/templates/project/fullstack-monorepo/backend/src/app/__init__.py +3 -0
  44. package/templates/project/fullstack-monorepo/backend/src/app/config.py.hbs +21 -0
  45. package/templates/project/fullstack-monorepo/backend/src/app/exceptions.py +26 -0
  46. package/templates/project/fullstack-monorepo/backend/src/app/factories.py +16 -0
  47. package/templates/project/fullstack-monorepo/backend/src/app/infra/__init__.py +1 -0
  48. package/templates/project/fullstack-monorepo/backend/src/app/main.py.hbs +65 -0
  49. package/templates/project/fullstack-monorepo/backend/src/app/middleware/__init__.py +1 -0
  50. package/templates/project/fullstack-monorepo/backend/tests/__init__.py +0 -0
  51. package/templates/project/fullstack-monorepo/backend/tests/conftest.py.hbs +42 -0
  52. package/templates/project/fullstack-monorepo/dev.sh.hbs +83 -0
  53. package/templates/project/fullstack-monorepo/docker-compose.dev.yml.hbs +36 -0
  54. package/templates/project/fullstack-monorepo/frontend/CLAUDE.md.hbs +35 -0
  55. package/templates/project/fullstack-monorepo/frontend/Dockerfile +18 -0
  56. package/templates/project/fullstack-monorepo/frontend/apps/web/index.html.hbs +13 -0
  57. package/templates/project/fullstack-monorepo/frontend/apps/web/package.json.hbs +31 -0
  58. package/templates/project/fullstack-monorepo/frontend/apps/web/src/App.vue.hbs +10 -0
  59. package/templates/project/fullstack-monorepo/frontend/apps/web/src/api/client.ts.hbs +11 -0
  60. package/templates/project/fullstack-monorepo/frontend/apps/web/src/features/{{initialDomain}}/.gitkeep +0 -0
  61. package/templates/project/fullstack-monorepo/frontend/apps/web/src/index.css +12 -0
  62. package/templates/project/fullstack-monorepo/frontend/apps/web/src/main.ts +17 -0
  63. package/templates/project/fullstack-monorepo/frontend/apps/web/src/router/index.ts.hbs +24 -0
  64. package/templates/project/fullstack-monorepo/frontend/apps/web/src/stores/.gitkeep +0 -0
  65. package/templates/project/fullstack-monorepo/frontend/apps/web/src/types/.gitkeep +0 -0
  66. package/templates/project/fullstack-monorepo/frontend/apps/web/src/views/HomeView.vue.hbs +36 -0
  67. package/templates/project/fullstack-monorepo/frontend/apps/web/tsconfig.json +7 -0
  68. package/templates/project/fullstack-monorepo/frontend/apps/web/vite.config.ts.hbs +27 -0
  69. package/templates/project/fullstack-monorepo/frontend/nginx.conf +11 -0
  70. package/templates/project/fullstack-monorepo/frontend/package.json.hbs +13 -0
  71. package/templates/project/fullstack-monorepo/frontend/packages/core/package.json.hbs +15 -0
  72. package/templates/project/fullstack-monorepo/frontend/packages/core/src/index.ts +3 -0
  73. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/package.json.hbs +14 -0
  74. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/index.ts.hbs +16 -0
  75. package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/pages/IndexPage.vue.hbs +9 -0
  76. package/templates/project/fullstack-monorepo/frontend/packages/ui/package.json.hbs +15 -0
  77. package/templates/project/fullstack-monorepo/frontend/packages/ui/src/index.ts +3 -0
  78. package/templates/project/fullstack-monorepo/frontend/pnpm-workspace.yaml.hbs +23 -0
  79. package/templates/project/fullstack-monorepo/frontend/tsconfig.base.json.hbs +23 -0
  80. package/templates/claude-global/rules/dwy-api-design.md +0 -110
  81. package/templates/claude-global/rules/dwy-git-commit-convention.md +0 -82
  82. package/templates/claude-global/rules/dwy-git-security.md +0 -53
  83. package/templates/claude-global/rules/dwy-payload-limits.md +0 -186
  84. package/templates/claude-global/rules/dwy-prefer-open-source.md +0 -32
  85. package/templates/claude-global/rules/dwy-project-structure.md +0 -181
  86. package/templates/claude-global/rules/dwy-python-fastapi.md +0 -272
  87. package/templates/claude-global/rules/dwy-python-orm.md +0 -61
  88. package/templates/claude-global/rules/dwy-python-security.md +0 -636
  89. package/templates/claude-global/rules/dwy-server-security.md +0 -518
  90. package/templates/claude-global/rules/dwy-vue-api.md +0 -146
  91. package/templates/claude-global/skills/dwy-ekit/references/data.md +0 -135
  92. package/templates/claude-global/skills/dwy-ekit/references/form.md +0 -68
  93. package/templates/claude-global/skills/dwy-ekit/references/request.md +0 -183
  94. package/templates/claude-global/skills/dwy-ekit/references/ui.md +0 -109
  95. package/templates/claude-global/skills/dwy-vue-core/SKILL.md +0 -890
  96. /package/templates/{claude-global/commands → project/fullstack-monorepo/backend/alembic/versions}/.gitkeep +0 -0
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Python pytest 测试规范
2
+ description: Python pytest 测试规范(目录组织、fixture、异步、AAA 结构)
3
3
  paths:
4
4
  - "**/tests/**/*.py"
5
5
  - "**/test_*.py"
@@ -9,14 +9,81 @@ paths:
9
9
 
10
10
  # Python pytest 测试规范
11
11
 
12
- ## 十四、测试
12
+ ## 一、测试目录组织(强制)
13
+
14
+ ### 核心约束
15
+
16
+ **测试目录与业务源码并列、独立存放。** 测试文件**禁止**混入源码目录(`src/` 或 `app/` 等)。
13
17
 
14
18
  ### 强制规则
19
+
20
+ - 测试目录与源码目录平级、独立,常用名 `tests/`(也可按团队约定,但**必须**独立)
21
+ - **禁止**在源码目录中放任何 `test_*.py` / `*_test.py` 文件
22
+ - 测试目录内部结构应**镜像**对应源码结构,便于定位被测对象
23
+ - 测试文件命名:`test_{被测模块名}.py`(pytest 默认发现规则)
24
+ - 测试函数命名:`test_{被测行为}` —— 描述行为而非实现
25
+ - 全局 fixture 放测试根目录的 `conftest.py`,子目录 fixture 放对应子目录的 `conftest.py`
26
+ - pytest 配置在 `pyproject.toml` 显式声明:
27
+
28
+ ```toml
29
+ [tool.pytest.ini_options]
30
+ testpaths = ["tests"]
31
+ asyncio_mode = "auto"
32
+ python_files = ["test_*.py"]
33
+ python_functions = ["test_*"]
34
+ ```
35
+
36
+ - 测试依赖(`pytest` / `pytest-asyncio` / `httpx` / `pytest-mock` 等)放 `[dev]` 或 `[test]` extras,**禁止**进生产依赖
37
+ - 跨包发布的代码不得 import 测试目录下的内容
38
+
39
+ > 具体目录布局由项目结构决定(单包、monorepo 子包、扁平 `app/` 等),AI 自行判断;唯一不变的是"测试目录独立、与源码并列"。
40
+
41
+ ### 标准目录结构(仅供参考)
42
+
43
+ ```
44
+ project/
45
+ ├── src/
46
+ │ └── app/
47
+ │ ├── routers/
48
+ │ │ └── user.py
49
+ │ ├── services/
50
+ │ │ └── user.py
51
+ │ ├── models/
52
+ │ │ └── user.py
53
+ │ └── main.py
54
+ ├── tests/ # 测试根目录
55
+ │ ├── conftest.py # 全局 fixture(client / db_session 等)
56
+ │ ├── routers/
57
+ │ │ ├── __init__.py
58
+ │ │ └── test_user.py # 测 app/routers/user.py
59
+ │ ├── services/
60
+ │ │ ├── __init__.py
61
+ │ │ └── test_user.py # 测 app/services/user.py
62
+ │ └── models/
63
+ │ ├── __init__.py
64
+ │ └── test_user.py # 测 app/models/user.py
65
+ └── pyproject.toml
66
+ ```
67
+
68
+ ---
69
+
70
+ ## 二、技术栈
71
+
15
72
  - 使用 `pytest` + `pytest-asyncio` + `httpx`
16
- - 使用 `TestClient` 或 `AsyncClient` 测试 API
73
+ - API 测试使用 `httpx.AsyncClient` 配合 `ASGITransport`,**禁止**使用同步 `TestClient` 测异步路由
74
+
75
+ ---
76
+
77
+ ## 三、Fixture
78
+
79
+ ### 强制规则
80
+
81
+ - 测试数据使用 `pytest.fixture`,**禁止**在测试函数中硬编码业务数据
82
+ - 数据库相关 fixture 必须保证测试间隔离(每个测试事务回滚或重建表)
83
+ - 跨测试共享的 fixture 放 `conftest.py`,单文件用的 fixture 留在文件内
17
84
 
18
85
  ```python
19
- # conftest.py
86
+ # tests/conftest.py
20
87
  import pytest
21
88
  from httpx import ASGITransport, AsyncClient
22
89
  from app.main import app
@@ -28,26 +95,61 @@ async def client():
28
95
  base_url="http://test",
29
96
  ) as ac:
30
97
  yield ac
98
+ ```
99
+
100
+ ---
101
+
102
+ ## 四、测试编写规范
103
+
104
+ ### 强制规则
105
+
106
+ - 测试结构遵循 **Arrange-Act-Assert**(准备 → 调用 → 断言)
107
+ - 一个测试只验证一个行为,**禁止**在一个 test 函数中堆多个不相关断言
108
+ - 断言要具体(断言字段值),**禁止**只断言"不报错"
109
+ - 必须覆盖:成功路径、失败路径(404 / 422 / 401 / 403)、边界值
110
+ - 敏感字段(密码、token)**必须**显式断言**不在**响应中
111
+
112
+ ```python
113
+ # tests/routers/test_user.py
114
+ import pytest
115
+ from httpx import AsyncClient
31
116
 
32
- # test_user.py
33
117
  @pytest.mark.anyio
34
- async def test_create_user_returns_201(client: AsyncClient):
35
- response = await client.post("/users/", json={
118
+ async def test_create_user_returns_201_without_password(client: AsyncClient):
119
+ # Arrange
120
+ payload = {
36
121
  "name": "Alice",
37
122
  "email": "alice@example.com",
38
123
  "password": "securepass123",
39
- })
124
+ }
125
+
126
+ # Act
127
+ response = await client.post("/users/", json=payload)
128
+
129
+ # Assert
40
130
  assert response.status_code == 201
41
131
  data = response.json()
42
132
  assert data["name"] == "Alice"
43
- assert "password" not in data # 响应不包含密码
133
+ assert "password" not in data
134
+ assert "hashed_password" not in data
44
135
 
45
136
  @pytest.mark.anyio
46
137
  async def test_get_nonexistent_user_returns_404(client: AsyncClient):
47
- response = await client.get("/users/99999")
138
+ response = await client.get("/users/00000000-0000-0000-0000-000000000000")
48
139
  assert response.status_code == 404
49
140
  ```
50
141
 
51
- - 测试函数名描述行为而非实现
52
- - 测试数据使用 `pytest.fixture`,不要硬编码
53
- - 测试结构遵循 Arrange-Act-Assert
142
+ ---
143
+
144
+ ## 五、违规检测清单
145
+
146
+ | 检查项 | 违规模式 | 严重程度 |
147
+ |--------|---------|---------|
148
+ | 测试与源码混放 | 测试文件放在 `src/` 或 `app/` 内(如 `app/services/test_user.py`) | 高 |
149
+ | 测试目录不规范 | 项目无 `tests/` 目录或 `pyproject.toml` 未配 `testpaths` | 高 |
150
+ | 镜像结构断裂 | 测试目录结构与源码目录结构不对应,难以定位 | 中 |
151
+ | 同步 TestClient | 异步路由用同步 `TestClient` 测试 | 高 |
152
+ | 测试无断言 | 只调用接口不断言响应字段 | 高 |
153
+ | 敏感字段未校验 | 用户接口测试未断言密码字段不在响应中 | 高 |
154
+ | 测试数据硬编码 | 复用的测试数据不抽 fixture,散落在多个 test 函数中 | 中 |
155
+ | 测试依赖泄漏 | `pytest` 等测试依赖进入生产依赖列表 | 高 |
@@ -0,0 +1,88 @@
1
+ ---
2
+ description: Redis 安全与使用规范(必须用 dwyeapi 客户端、密码、绑定、危险命令禁用、key TTL 与前缀、敏感数据禁存)
3
+ ---
4
+
5
+ # Redis 安全与使用规范
6
+
7
+ 适用于使用 Redis 作为缓存 / 会话存储 / Token 黑名单 / 速率限制存储的 Python 后端项目。
8
+
9
+ ---
10
+
11
+ ## 一、客户端使用(强制)
12
+
13
+ - **必须**通过 dwyeapi 缓存模块获取共享异步 Redis 客户端(具体 API 查 `dwy-eapi` skill)
14
+ - **禁止**业务代码中 `aioredis.from_url(...)` 自建连接池
15
+ - **禁止**直接使用同步 `redis-py`(除非脚本类一次性任务)
16
+
17
+ ---
18
+
19
+ ## 二、服务端配置(强制)
20
+
21
+ | 规则 | 说明 |
22
+ |------|------|
23
+ | 认证 | **必须**设置 `requirepass`,无密码 Redis 一律拒绝接入生产 |
24
+ | 绑定地址 | `bind 127.0.0.1` 或内网地址,**禁止** `bind 0.0.0.0` |
25
+ | 危险命令 | **禁用**或重命名 `FLUSHALL` / `FLUSHDB` / `CONFIG` / `KEYS` / `DEBUG` |
26
+ | 内存上限 | 设 `maxmemory` 与 `maxmemory-policy`(推荐 `allkeys-lru`),防止 OOM |
27
+ | 持久化 | 根据用途选择:缓存可关 AOF;会话 / 黑名单需 AOF everysec |
28
+
29
+ ```conf
30
+ # redis.conf 关键项示例
31
+ requirepass <strong-password>
32
+ bind 127.0.0.1
33
+ rename-command FLUSHALL ""
34
+ rename-command FLUSHDB ""
35
+ rename-command CONFIG ""
36
+ rename-command KEYS ""
37
+ rename-command DEBUG ""
38
+ maxmemory 256mb
39
+ maxmemory-policy allkeys-lru
40
+ ```
41
+
42
+ ---
43
+
44
+ ## 三、Key 设计规范(强制)
45
+
46
+ | 规则 | 说明 |
47
+ |------|------|
48
+ | 必须 TTL | 所有 key **必须**显式设置过期时间(`ex` / `pexpire`),**禁止**遗留无 TTL 的 key |
49
+ | 必须项目前缀 | 所有 key 必须有项目前缀,格式 `{app}:{domain}:{detail}`(如 `myapp:token:blacklist:abc123`) |
50
+ | snake_case | key 段用 snake_case,**禁止**驼峰或中文 |
51
+ | 不存敏感原文 | **禁止**存储密码、身份证、银行卡、token 原文(token 存哈希) |
52
+
53
+ ### 正反例
54
+
55
+ ```python
56
+ # 反例
57
+ await redis.set("abc123", "1") # 无前缀
58
+ await redis.set("myapp:data:xxx", value) # 无 TTL
59
+ await redis.set("myapp:user:password", "123456") # 存敏感原文
60
+ await redis.set("myapp:userToken", "ey...") # 驼峰命名
61
+
62
+ # 正例
63
+ await redis.set("myapp:token:blacklist:abc123", "1", ex=3600)
64
+ await redis.set("myapp:cache:user:uuid:f7e2", json_data, ex=300)
65
+ ```
66
+
67
+ ---
68
+
69
+ ## 四、Pub/Sub 与 Stream 使用约束
70
+
71
+ - 业务消息**禁止**用 Pub/Sub 当持久队列(Pub/Sub 无 ACK 与持久化)
72
+ - 持久任务用 dwyeapi tasks 模块(基于 ARQ)或 Redis Stream
73
+ - Stream 必须设消费者组 ACK 与死信处理
74
+
75
+ ---
76
+
77
+ ## 五、违规检测清单
78
+
79
+ | 检查项 | 违规模式 | 严重程度 |
80
+ |--------|---------|---------|
81
+ | 绑定 0.0.0.0 | 服务对公网暴露 | **致命 → STOP** |
82
+ | 无密码 | 生产 Redis 未设 `requirepass` | **致命 → STOP** |
83
+ | 存敏感原文 | 密码 / 身份证 / token 明文存 Redis | **致命 → STOP** |
84
+ | 自建连接池 | 业务代码 `aioredis.from_url(...)`,未走 dwyeapi 缓存模块 | 高 |
85
+ | 危险命令未禁 | `FLUSHALL` / `KEYS` / `CONFIG` 等可在生产执行 | 高 |
86
+ | Key 无 TTL | `redis.set()` 没有 `ex` 参数(业务上明确永久存储除外) | 中 |
87
+ | Key 无前缀 | Key 无项目前缀,污染共享 Redis | 中 |
88
+ | Pub/Sub 当队列 | 业务关键消息走 Pub/Sub | 高 |