@robsun/create-keystone-app 0.2.15 → 0.4.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 (96) hide show
  1. package/README.md +46 -44
  2. package/dist/create-keystone-app.js +347 -10
  3. package/dist/create-module.js +1217 -1187
  4. package/package.json +1 -1
  5. package/template/.claude/skills/keystone-implement/SKILL.md +113 -0
  6. package/template/.claude/skills/keystone-implement/references/CHECKLIST.md +91 -0
  7. package/template/.claude/skills/keystone-implement/references/PATTERNS.md +1088 -0
  8. package/template/.claude/skills/keystone-implement/references/SCHEMA.md +135 -0
  9. package/template/.claude/skills/keystone-implement/references/TESTING.md +231 -0
  10. package/template/.claude/skills/keystone-requirements/SKILL.md +296 -0
  11. package/template/.claude/skills/keystone-requirements/references/CONFIRM_TEMPLATE.md +170 -0
  12. package/template/.claude/skills/keystone-requirements/references/SCHEMA.md +135 -0
  13. package/template/.eslintrc.js +3 -0
  14. package/template/.github/workflows/ci.yml +30 -0
  15. package/template/.github/workflows/release.yml +32 -0
  16. package/template/.golangci.yml +11 -0
  17. package/template/README.md +82 -81
  18. package/template/apps/server/README.md +8 -0
  19. package/template/apps/server/cmd/server/main.go +27 -185
  20. package/template/apps/server/config.example.yaml +31 -1
  21. package/template/apps/server/config.yaml +31 -1
  22. package/template/apps/server/go.mod +61 -19
  23. package/template/apps/server/go.sum +185 -32
  24. package/template/apps/server/internal/frontend/embed.go +3 -8
  25. package/template/apps/server/internal/modules/example/README.md +18 -0
  26. package/template/apps/server/internal/modules/example/api/handler/handler_test.go +9 -0
  27. package/template/apps/server/internal/modules/example/api/handler/item_handler.go +468 -165
  28. package/template/apps/server/internal/modules/example/bootstrap/seeds/item.go +217 -8
  29. package/template/apps/server/internal/modules/example/domain/models/item.go +40 -7
  30. package/template/apps/server/internal/modules/example/domain/service/approval_callback.go +68 -0
  31. package/template/apps/server/internal/modules/example/domain/service/approval_schema.go +41 -0
  32. package/template/apps/server/internal/modules/example/domain/service/errors.go +20 -22
  33. package/template/apps/server/internal/modules/example/domain/service/item_service.go +267 -7
  34. package/template/apps/server/internal/modules/example/domain/service/item_service_test.go +281 -0
  35. package/template/apps/server/internal/modules/example/i18n/keys.go +32 -20
  36. package/template/apps/server/internal/modules/example/i18n/locales/en-US.json +30 -18
  37. package/template/apps/server/internal/modules/example/i18n/locales/zh-CN.json +30 -18
  38. package/template/apps/server/internal/modules/example/infra/exporter/item_exporter.go +119 -0
  39. package/template/apps/server/internal/modules/example/infra/importer/item_importer.go +77 -0
  40. package/template/apps/server/internal/modules/example/infra/repository/item_repository.go +99 -49
  41. package/template/apps/server/internal/modules/example/module.go +171 -97
  42. package/template/apps/server/internal/modules/example/tests/integration_test.go +7 -0
  43. package/template/apps/server/internal/modules/manifest.go +7 -7
  44. package/template/apps/web/README.md +4 -2
  45. package/template/apps/web/package.json +1 -1
  46. package/template/apps/web/src/app.config.ts +8 -6
  47. package/template/apps/web/src/index.css +7 -3
  48. package/template/apps/web/src/main.tsx +2 -5
  49. package/template/apps/web/src/modules/example/help/en-US/faq.md +27 -0
  50. package/template/apps/web/src/modules/example/help/en-US/items.md +30 -0
  51. package/template/apps/web/src/modules/example/help/en-US/overview.md +31 -0
  52. package/template/apps/web/src/modules/example/help/zh-CN/faq.md +27 -0
  53. package/template/apps/web/src/modules/example/help/zh-CN/items.md +31 -0
  54. package/template/apps/web/src/modules/example/help/zh-CN/overview.md +32 -0
  55. package/template/apps/web/src/modules/example/locales/en-US/example.json +99 -32
  56. package/template/apps/web/src/modules/example/locales/zh-CN/example.json +85 -18
  57. package/template/apps/web/src/modules/example/pages/ExampleItemsPage.tsx +840 -237
  58. package/template/apps/web/src/modules/example/services/exampleItems.ts +79 -8
  59. package/template/apps/web/src/modules/example/types.ts +14 -1
  60. package/template/apps/web/src/modules/index.ts +1 -0
  61. package/template/apps/web/vite.config.ts +9 -3
  62. package/template/docs/CONVENTIONS.md +17 -17
  63. package/template/package.json +4 -5
  64. package/template/pnpm-lock.yaml +76 -5
  65. package/template/scripts/build.bat +15 -3
  66. package/template/scripts/build.sh +9 -3
  67. package/template/scripts/check-help.js +249 -0
  68. package/template/scripts/compress-assets.js +89 -0
  69. package/template/scripts/test.bat +23 -0
  70. package/template/scripts/test.sh +16 -0
  71. package/template/.claude/skills/keystone-dev/SKILL.md +0 -90
  72. package/template/.claude/skills/keystone-dev/references/ADVANCED_PATTERNS.md +0 -716
  73. package/template/.claude/skills/keystone-dev/references/APPROVAL.md +0 -121
  74. package/template/.claude/skills/keystone-dev/references/CAPABILITIES.md +0 -261
  75. package/template/.claude/skills/keystone-dev/references/CHECKLIST.md +0 -285
  76. package/template/.claude/skills/keystone-dev/references/GOTCHAS.md +0 -390
  77. package/template/.claude/skills/keystone-dev/references/PATTERNS.md +0 -605
  78. package/template/.claude/skills/keystone-dev/references/TEMPLATES.md +0 -2710
  79. package/template/.claude/skills/keystone-dev/references/TESTING.md +0 -44
  80. package/template/.codex/skills/keystone-dev/SKILL.md +0 -90
  81. package/template/.codex/skills/keystone-dev/references/ADVANCED_PATTERNS.md +0 -716
  82. package/template/.codex/skills/keystone-dev/references/APPROVAL.md +0 -121
  83. package/template/.codex/skills/keystone-dev/references/CAPABILITIES.md +0 -261
  84. package/template/.codex/skills/keystone-dev/references/CHECKLIST.md +0 -285
  85. package/template/.codex/skills/keystone-dev/references/GOTCHAS.md +0 -390
  86. package/template/.codex/skills/keystone-dev/references/PATTERNS.md +0 -605
  87. package/template/.codex/skills/keystone-dev/references/TEMPLATES.md +0 -2710
  88. package/template/.codex/skills/keystone-dev/references/TESTING.md +0 -44
  89. package/template/apps/server/internal/app/routes/module_routes.go +0 -16
  90. package/template/apps/server/internal/app/routes/routes.go +0 -226
  91. package/template/apps/server/internal/app/startup/startup.go +0 -74
  92. package/template/apps/server/internal/frontend/handler.go +0 -122
  93. package/template/apps/server/internal/modules/registry.go +0 -145
  94. package/template/apps/web/src/modules/example/help/faq.md +0 -23
  95. package/template/apps/web/src/modules/example/help/items.md +0 -26
  96. package/template/apps/web/src/modules/example/help/overview.md +0 -25
@@ -1,390 +0,0 @@
1
- # Keystone 开发常见陷阱
2
-
3
- > 开发中容易踩的坑和解决方案。
4
-
5
- ## 后端陷阱
6
-
7
- ### G1: 菜单/模块不显示
8
-
9
- **症状**:模块代码写完,但菜单不出现或 API 404
10
-
11
- **原因**:未在配置中启用模块
12
-
13
- **解决**:
14
- ```yaml
15
- # config.yaml
16
- modules:
17
- enabled:
18
- - example
19
- - your_new_module # 添加这行
20
- ```
21
-
22
- ```typescript
23
- // app.config.ts
24
- modules: {
25
- enabled: ['example', 'your_new_module'] // 添加这里
26
- }
27
- ```
28
-
29
- ---
30
-
31
- ### G2: Handler panic: nil pointer
32
-
33
- **症状**:调用 API 时服务 panic
34
-
35
- **原因**:Handler 或 Service 未初始化
36
-
37
- **错误代码**:
38
- ```go
39
- func (h *Handler) List(c *gin.Context) {
40
- items, _ := h.svc.List(c) // h.svc 可能为 nil
41
- }
42
- ```
43
-
44
- **正确代码**:
45
- ```go
46
- func (h *Handler) List(c *gin.Context) {
47
- if h == nil || h.svc == nil {
48
- response.ServiceUnavailableI18n(c, modulei18n.MsgServiceUnavailable)
49
- return
50
- }
51
- // ...
52
- }
53
- ```
54
-
55
- ---
56
-
57
- ### G3: 数据跨租户泄露
58
-
59
- **症状**:用户能看到其他租户的数据
60
-
61
- **原因**:Repository 查询缺少租户过滤
62
-
63
- **错误代码**:
64
- ```go
65
- func (r *Repository) List(ctx context.Context) ([]Entity, error) {
66
- var items []Entity
67
- r.db.Find(&items) // 未过滤租户
68
- return items, nil
69
- }
70
- ```
71
-
72
- **正确代码**:
73
- ```go
74
- func (r *Repository) List(ctx context.Context, tenantID uint) ([]Entity, error) {
75
- var items []Entity
76
- r.db.Where("tenant_id = ?", tenantID).Find(&items)
77
- return items, nil
78
- }
79
- ```
80
-
81
- ---
82
-
83
- ### G4: 翻译键显示为原始键
84
-
85
- **症状**:界面显示 `example.item.created` 而非翻译文本
86
-
87
- **原因**:
88
- 1. 未调用 `RegisterI18n()`
89
- 2. 翻译 JSON 文件路径错误
90
- 3. 键名不匹配
91
-
92
- **检查**:
93
- ```go
94
- // module.go 中必须有
95
- func (m *Module) RegisterI18n() error {
96
- return modulei18n.RegisterLocales() // 确保调用
97
- }
98
-
99
- // i18n/i18n.go
100
- //go:embed locales/*.json // 确保路径正确
101
- var translations embed.FS
102
- ```
103
-
104
- ---
105
-
106
- ### G5: GORM 自动更新 UpdatedAt 失效
107
-
108
- **症状**:更新记录后 `updated_at` 未变化
109
-
110
- **原因**:使用 `Updates()` 时只更新传入字段
111
-
112
- **解决**:使用 `Save()` 或显式设置
113
- ```go
114
- // 方式一:使用 Save
115
- r.db.Save(entity)
116
-
117
- // 方式二:显式更新
118
- r.db.Model(entity).Updates(map[string]interface{}{
119
- "name": entity.Name,
120
- "updated_at": time.Now(),
121
- })
122
- ```
123
-
124
- ---
125
-
126
- ### G6: 软删除查不到数据
127
-
128
- **症状**:数据库有记录但查询返回空
129
-
130
- **原因**:GORM 自动添加 `deleted_at IS NULL` 条件
131
-
132
- **解决**:
133
- ```go
134
- // 查询包含已删除记录
135
- r.db.Unscoped().Where("id = ?", id).First(&entity)
136
-
137
- // 恢复已删除记录
138
- r.db.Unscoped().Model(&Entity{}).
139
- Where("id = ?", id).
140
- Update("deleted_at", nil)
141
- ```
142
-
143
- ---
144
-
145
- ### G7: 循环依赖导致编译失败
146
-
147
- **症状**:`import cycle not allowed`
148
-
149
- **原因**:service 和 repository 互相导入
150
-
151
- **错误结构**:
152
- ```
153
- service/ → imports → repository/
154
- repository/ → imports → service/ // 循环!
155
- ```
156
-
157
- **解决**:在 service 定义接口,repository 实现
158
- ```go
159
- // service/service.go
160
- type EntityRepository interface {
161
- FindByID(id uint) (*models.Entity, error)
162
- }
163
-
164
- // repository/repository.go
165
- // 实现 service.EntityRepository 接口,但不导入 service 包
166
- ```
167
-
168
- ---
169
-
170
- ## 前端陷阱
171
-
172
- ### G8: Modal destroyOnClose 无效
173
-
174
- **症状**:Modal 关闭后再打开,表单数据残留
175
-
176
- **原因**:Ant Design v6 API 变更
177
-
178
- **错误代码**:
179
- ```tsx
180
- <Modal destroyOnClose> // v6 已废弃
181
- ```
182
-
183
- **正确代码**:
184
- ```tsx
185
- <Modal destroyOnHidden> // v6 使用这个
186
- ```
187
-
188
- ---
189
-
190
- ### G9: 翻译不生效
191
-
192
- **症状**:`t('key')` 返回 key 本身
193
-
194
- **原因**:
195
- 1. 未注册翻译文件
196
- 2. 命名空间错误
197
-
198
- **检查**:
199
- ```typescript
200
- // index.ts 中确保导入翻译文件
201
- import './locales/zh-CN/module.json'
202
- import './locales/en-US/module.json'
203
-
204
- // 使用时指定正确命名空间
205
- const { t } = useTranslation('module') // 不是 'common'
206
- ```
207
-
208
- ---
209
-
210
- ### G10: API 响应解构错误
211
-
212
- **症状**:`TypeError: Cannot read property 'xxx' of undefined`
213
-
214
- **原因**:响应结构是 `{ data: { data: {...} } }`
215
-
216
- **错误代码**:
217
- ```typescript
218
- const response = await api.get<ApiResponse<Entity>>('/entity/1')
219
- return response.data // 这是外层 data
220
- ```
221
-
222
- **正确代码**:
223
- ```typescript
224
- const { data } = await api.get<ApiResponse<Entity>>('/entity/1')
225
- return data.data // 这是内层 data
226
- ```
227
-
228
- ---
229
-
230
- ### G11: Table columns 类型错误
231
-
232
- **症状**:TypeScript 报类型不兼容
233
-
234
- **原因**:未使用 `ColumnsType<T>`
235
-
236
- **错误代码**:
237
- ```tsx
238
- const columns = [
239
- { title: 'Name', dataIndex: 'name' }
240
- ]
241
- ```
242
-
243
- **正确代码**:
244
- ```tsx
245
- import type { ColumnsType } from 'antd/es/table'
246
-
247
- const columns: ColumnsType<Entity> = [
248
- { title: 'Name', dataIndex: 'name', key: 'name' }
249
- ]
250
- ```
251
-
252
- ---
253
-
254
- ### G12: Form 验证不触发
255
-
256
- **症状**:点击提交按钮无反应
257
-
258
- **原因**:未正确使用 `Form.useForm()` 或 `validateFields()`
259
-
260
- **错误代码**:
261
- ```tsx
262
- const handleSubmit = () => {
263
- const values = form.getFieldsValue() // 不会触发验证
264
- }
265
- ```
266
-
267
- **正确代码**:
268
- ```tsx
269
- const handleSubmit = async () => {
270
- try {
271
- const values = await form.validateFields() // 会触发验证
272
- // 处理提交
273
- } catch {
274
- return // 验证失败,不提交
275
- }
276
- }
277
- ```
278
-
279
- ---
280
-
281
- ### G13: useCallback 依赖缺失
282
-
283
- **症状**:函数行为不符合预期,使用旧闭包值
284
-
285
- **原因**:useCallback 依赖数组不完整
286
-
287
- **错误代码**:
288
- ```tsx
289
- const fetchData = useCallback(async () => {
290
- const data = await listItems({ status: filter }) // filter 可能是旧值
291
- }, []) // 缺少 filter 依赖
292
- ```
293
-
294
- **正确代码**:
295
- ```tsx
296
- const fetchData = useCallback(async () => {
297
- const data = await listItems({ status: filter })
298
- }, [filter]) // 添加 filter 依赖
299
- ```
300
-
301
- ---
302
-
303
- ### G14: 权限菜单不显示
304
-
305
- **症状**:有权限但菜单不出现
306
-
307
- **原因**:
308
- 1. `app.config.ts` 未启用模块
309
- 2. 权限码不匹配
310
-
311
- **检查**:
312
- ```typescript
313
- // routes.tsx
314
- handle: {
315
- menu: {
316
- permission: 'module:entity:view', // 确保格式正确
317
- }
318
- }
319
-
320
- // 后端权限注册
321
- reg.CreateActionI18n(
322
- "module:entity:view", // 必须与前端一致
323
- ...
324
- )
325
- ```
326
-
327
- ---
328
-
329
- ## 性能陷阱
330
-
331
- ### G15: N+1 查询
332
-
333
- **症状**:列表页加载慢,日志显示大量 SQL
334
-
335
- **原因**:循环中查询关联数据
336
-
337
- **错误代码**:
338
- ```go
339
- entities, _ := repo.List(ctx, tenantID)
340
- for i := range entities {
341
- entities[i].Category, _ = repo.GetCategory(entities[i].CategoryID) // N次查询
342
- }
343
- ```
344
-
345
- **正确代码**:
346
- ```go
347
- // 使用 Preload
348
- r.db.Preload("Category").Find(&entities)
349
-
350
- // 或批量查询
351
- categoryIDs := extractIDs(entities)
352
- categories, _ := repo.GetCategoriesByIDs(categoryIDs)
353
- ```
354
-
355
- ---
356
-
357
- ### G16: 无限重渲染
358
-
359
- **症状**:页面卡死,控制台显示大量渲染日志
360
-
361
- **原因**:useEffect 依赖数组包含每次渲染都变化的值
362
-
363
- **错误代码**:
364
- ```tsx
365
- useEffect(() => {
366
- fetchData()
367
- }, [{ page, pageSize }]) // 对象每次都是新引用
368
- ```
369
-
370
- **正确代码**:
371
- ```tsx
372
- useEffect(() => {
373
- fetchData()
374
- }, [page, pageSize]) // 使用原始值
375
- ```
376
-
377
- ---
378
-
379
- ## 快速排查表
380
-
381
- | 现象 | 首先检查 |
382
- |------|----------|
383
- | 404 Not Found | config.yaml + manifest.go 注册 |
384
- | 菜单不显示 | app.config.ts 启用 |
385
- | 翻译键原样显示 | RegisterI18n() + JSON 文件路径 |
386
- | nil pointer panic | Handler nil 检查 |
387
- | 数据泄露 | 租户 ID 过滤 |
388
- | TypeScript 报错 | 类型定义 + ColumnsType |
389
- | 表单验证无效 | validateFields() 使用 |
390
- | Modal 数据残留 | destroyOnHidden |