@h-ai/cli 0.1.0-alpha.54 → 0.1.0-alpha.55
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/README.md +4 -0
- package/package.json +7 -7
- package/templates/base/package.json.hbs +1 -1
- package/templates/skills/AGENTS.md +8 -22
- package/templates/skills/CLAUDE.md +3 -16
- package/templates/skills/bridges/admin/AGENTS.md +3 -16
- package/templates/skills/bridges/admin/CLAUDE.md +3 -11
- package/templates/skills/bridges/admin/copilot-instructions.md +2 -39
- package/templates/skills/bridges/api/AGENTS.md +5 -18
- package/templates/skills/bridges/api/CLAUDE.md +3 -11
- package/templates/skills/bridges/api/copilot-instructions.md +3 -38
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +24 -59
- package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +1 -15
- package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +5 -45
- package/templates/skills/bridges/h5/AGENTS.md +4 -17
- package/templates/skills/bridges/h5/CLAUDE.md +3 -11
- package/templates/skills/bridges/h5/copilot-instructions.md +2 -37
- package/templates/skills/bridges/mobile-app/AGENTS.md +5 -18
- package/templates/skills/bridges/mobile-app/CLAUDE.md +3 -11
- package/templates/skills/bridges/mobile-app/copilot-instructions.md +2 -38
- package/templates/skills/bridges/website/AGENTS.md +4 -17
- package/templates/skills/bridges/website/CLAUDE.md +3 -11
- package/templates/skills/bridges/website/copilot-instructions.md +2 -37
- package/templates/skills/copilot-instructions.md +2 -36
- package/templates/skills/hai-ai/SKILL.md +35 -389
- package/templates/skills/hai-ai/guide.md +383 -0
- package/templates/skills/hai-ai/reference.md +1 -1
- package/templates/skills/hai-api-client/SKILL.md +6 -6
- package/templates/skills/hai-api-contract/SKILL.md +10 -25
- package/templates/skills/hai-app-create/SKILL.md +29 -388
- package/templates/skills/hai-app-create/reference.md +350 -0
- package/templates/skills/hai-app-review/SKILL.md +9 -23
- package/templates/skills/hai-app-tests/SKILL.md +29 -494
- package/templates/skills/hai-app-tests/reference.md +442 -0
- package/templates/skills/hai-audit/SKILL.md +6 -6
- package/templates/skills/hai-build/SKILL.md +19 -338
- package/templates/skills/hai-build/reference.md +326 -0
- package/templates/skills/hai-cache/SKILL.md +27 -32
- package/templates/skills/hai-capacitor/SKILL.md +19 -366
- package/templates/skills/hai-capacitor/reference.md +352 -0
- package/templates/skills/hai-ci/SKILL.md +6 -21
- package/templates/skills/hai-core/SKILL.md +25 -566
- package/templates/skills/hai-core/reference.md +533 -0
- package/templates/skills/hai-crypto/SKILL.md +6 -20
- package/templates/skills/hai-datapipe/SKILL.md +9 -23
- package/templates/skills/hai-deploy/SKILL.md +6 -24
- package/templates/skills/hai-framework-sync/SKILL.md +8 -20
- package/templates/skills/hai-iam/SKILL.md +27 -371
- package/templates/skills/hai-iam/reference.md +343 -0
- package/templates/skills/hai-kit/SKILL.md +6 -6
- package/templates/skills/hai-payment/SKILL.md +6 -26
- package/templates/skills/hai-pr-review/SKILL.md +6 -22
- package/templates/skills/hai-reach/SKILL.md +19 -317
- package/templates/skills/hai-reach/reference.md +303 -0
- package/templates/skills/hai-reldb/SKILL.md +19 -472
- package/templates/skills/hai-reldb/reference.md +452 -0
- package/templates/skills/hai-scheduler/SKILL.md +6 -6
- package/templates/skills/hai-serv/SKILL.md +27 -759
- package/templates/skills/hai-serv/reference.md +736 -0
- package/templates/skills/hai-storage/SKILL.md +7 -25
- package/templates/skills/hai-ui/SKILL.md +29 -625
- package/templates/skills/hai-ui/reference.md +598 -0
- package/templates/skills/hai-vecdb/SKILL.md +18 -303
- package/templates/skills/hai-vecdb/reference.md +291 -0
|
@@ -1,397 +1,38 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hai-app-create
|
|
3
|
-
description:
|
|
3
|
+
description: "在 hai 应用中新增页面、路由、API、服务、模型或组件。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# hai-app-create
|
|
6
|
+
# hai-app-create
|
|
7
7
|
|
|
8
8
|
## 能力契约
|
|
9
9
|
|
|
10
10
|
| 项目 | 契约 |
|
|
11
11
|
| --- | --- |
|
|
12
|
-
| 能力 |
|
|
13
|
-
| 适用场景 |
|
|
14
|
-
| 输入 |
|
|
15
|
-
| 输出 |
|
|
16
|
-
| 限制 |
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
1. 明确功能的输入、输出、边界条件、错误场景
|
|
40
|
-
2. 确定需要创建的文件(服务、路由、Schema、组件等)
|
|
41
|
-
3. 设计测试用例清单(参照 `hai-app-tests` 技能的覆盖范围要求)
|
|
42
|
-
|
|
43
|
-
### Step 2:编写测试(Red 阶段)
|
|
44
|
-
|
|
45
|
-
1. **创建单元测试**:在 `tests/` 下为服务层、Schema 编写 Vitest 测试
|
|
46
|
-
2. **创建 E2E 测试**:在 `e2e/` 下为 API 端点、页面交互编写 Playwright 测试
|
|
47
|
-
3. **创建空的实现文件**:仅包含函数签名和类型定义,不写实际逻辑(确保 import 不报错)
|
|
48
|
-
4. **运行测试确认全部失败**:
|
|
49
|
-
```bash
|
|
50
|
-
pnpm --filter <app-name> test # 应全部 FAIL
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### Step 3:编写实现(Green 阶段)
|
|
54
|
-
|
|
55
|
-
按照下文的「创建指南」编写实际功能代码,每完成一个功能点立即运行测试确认通过。
|
|
56
|
-
|
|
57
|
-
### Step 4:重构与验证(Refactor 阶段)
|
|
58
|
-
|
|
59
|
-
1. 参照 `hai-app-review` 审查代码规范
|
|
60
|
-
2. 运行质量门禁:`pnpm typecheck && pnpm lint && pnpm test`
|
|
61
|
-
3. 运行 E2E:`pnpm --filter <app-name> test:e2e`
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## 目录结构约定
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
src/
|
|
69
|
-
hooks.server.ts # `handle` hook 入口
|
|
70
|
-
app.css # 全局样式(TailwindCSS 4)
|
|
71
|
-
lib/
|
|
72
|
-
server/
|
|
73
|
-
init.ts # 应用初始化(模块 init 顺序)
|
|
74
|
-
services/ # 业务服务层(Server-only)
|
|
75
|
-
index.ts # 服务聚合导出
|
|
76
|
-
user.ts # 示例:用户服务
|
|
77
|
-
schemas/ # 请求校验 Schema(Zod)
|
|
78
|
-
components/ # 业务组件(非 @h-ai/ui 通用组件)
|
|
79
|
-
stores/ # 客户端 Store(Svelte 5 Runes)
|
|
80
|
-
paraglide/ # i18n 生成文件(禁止手动修改)
|
|
81
|
-
routes/
|
|
82
|
-
+layout.svelte # 根布局
|
|
83
|
-
+page.svelte # 首页
|
|
84
|
-
(auth)/ # 认证分组路由
|
|
85
|
-
login/+page.svelte
|
|
86
|
-
admin/ # 管理区域
|
|
87
|
-
users/
|
|
88
|
-
+page.svelte # 列表页
|
|
89
|
-
+page.server.ts # 列表数据加载
|
|
90
|
-
[id]/
|
|
91
|
-
+page.svelte # 详情页
|
|
92
|
-
+page.server.ts
|
|
93
|
-
api/ # API 端点
|
|
94
|
-
auth/+server.ts
|
|
95
|
-
health/+server.ts
|
|
96
|
-
iam/
|
|
97
|
-
users/+server.ts
|
|
98
|
-
messages/ # i18n 消息文件
|
|
99
|
-
en-US.json
|
|
100
|
-
zh-CN.json
|
|
101
|
-
config/ # 模块配置文件
|
|
102
|
-
_core.yml
|
|
103
|
-
_db.yml
|
|
104
|
-
_cache.yml
|
|
105
|
-
_iam.yml
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## 创建页面
|
|
111
|
-
|
|
112
|
-
### 页面路由规则
|
|
113
|
-
|
|
114
|
-
使用 SvelteKit 文件路由,参考 `src/routes/` 约定:
|
|
115
|
-
|
|
116
|
-
| 类型 | 路径示例 | 说明 |
|
|
117
|
-
| -------- | ---------------------------------- | -------------------- |
|
|
118
|
-
| 静态页面 | `routes/about/+page.svelte` | 常规页面 |
|
|
119
|
-
| 动态路由 | `routes/users/[id]/+page.svelte` | URL 参数 |
|
|
120
|
-
| 分组路由 | `routes/(auth)/login/+page.svelte` | 共享布局,不影响 URL |
|
|
121
|
-
| API 端点 | `routes/api/users/+server.ts` | RESTful API |
|
|
122
|
-
|
|
123
|
-
### 页面文件模板
|
|
124
|
-
|
|
125
|
-
```svelte
|
|
126
|
-
<!-- +page.svelte -->
|
|
127
|
-
<script lang="ts">
|
|
128
|
-
// Svelte 5 Runes 语法
|
|
129
|
-
let { data } = $props()
|
|
130
|
-
let loading = $state(false)
|
|
131
|
-
|
|
132
|
-
async function handleAction() {
|
|
133
|
-
loading = true
|
|
134
|
-
try {
|
|
135
|
-
// 业务逻辑
|
|
136
|
-
} finally {
|
|
137
|
-
loading = false
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
</script>
|
|
141
|
-
|
|
142
|
-
<div class="container mx-auto p-4">
|
|
143
|
-
<!-- 使用 @h-ai/ui 组件 -->
|
|
144
|
-
</div>
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### 数据加载(+page.server.ts)
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
import type { PageServerLoad } from './$types'
|
|
151
|
-
import { kit } from '@h-ai/kit'
|
|
152
|
-
|
|
153
|
-
export const load: PageServerLoad = async (event) => {
|
|
154
|
-
// 权限守卫
|
|
155
|
-
const guard = kit.guard.requireAuth(event)
|
|
156
|
-
if (!guard.success)
|
|
157
|
-
return kit.response.redirect('/login')
|
|
158
|
-
|
|
159
|
-
// 加载数据
|
|
160
|
-
const result = await someService.list()
|
|
161
|
-
if (!result.success)
|
|
162
|
-
return kit.response.error(500, result.error.message)
|
|
163
|
-
|
|
164
|
-
return { items: result.data }
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
---
|
|
169
|
-
|
|
170
|
-
## 创建 API 端点
|
|
171
|
-
|
|
172
|
-
### RESTful 端点模板
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
// src/routes/api/[resource]/+server.ts
|
|
176
|
-
import type { RequestHandler } from './$types'
|
|
177
|
-
import { kit } from '@h-ai/kit'
|
|
178
|
-
import { z } from 'zod'
|
|
179
|
-
|
|
180
|
-
const CreateSchema = z.object({
|
|
181
|
-
name: z.string().min(1).max(100),
|
|
182
|
-
description: z.string().optional(),
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
// GET - 列表
|
|
186
|
-
export const GET = kit.handler(async ({ locals }) => {
|
|
187
|
-
kit.guard.requirePermission(locals.session, 'resource:read')
|
|
188
|
-
|
|
189
|
-
const result = await service.list()
|
|
190
|
-
if (!result.success)
|
|
191
|
-
return kit.response.error(500, result.error.message)
|
|
192
|
-
return kit.response.ok(result.data)
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
// POST - 创建
|
|
196
|
-
export const POST = kit.handler(async ({ request, locals }) => {
|
|
197
|
-
kit.guard.requirePermission(locals.session, 'resource:create')
|
|
198
|
-
|
|
199
|
-
const data = await kit.validate.formOrFail(request, CreateSchema)
|
|
200
|
-
|
|
201
|
-
const result = await service.create(data)
|
|
202
|
-
if (!result.success)
|
|
203
|
-
return kit.response.error(500, result.error.message)
|
|
204
|
-
return kit.response.created(result.data)
|
|
205
|
-
})
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### 要点
|
|
209
|
-
|
|
210
|
-
- 所有端点**必须**用 `kit.handler(async ({ locals, request, ... }) => { ... })` 包裹,由 handler 统一处理 throw 的 Response
|
|
211
|
-
- 权限守卫使用 `kit.guard.requirePermission(locals.session, 'xxx:yyy')`,它本身就是 throw 模式(未通过时 throw 403 Response),**无需**检查返回值
|
|
212
|
-
- 输入校验使用 `await kit.validate.formOrFail(request, Schema)`,校验失败时 throw 400 Response,**无需**手动判断 valid
|
|
213
|
-
- 返回统一使用 `kit.response.*`
|
|
214
|
-
- HaiResult 错误直接透传,不重新包装
|
|
215
|
-
- 框架模块 API 不抛异常,不要用 `try/catch` 处理模块返回的错误,直接检查 `result.success`
|
|
216
|
-
|
|
217
|
-
---
|
|
218
|
-
|
|
219
|
-
## 创建服务层
|
|
220
|
-
|
|
221
|
-
服务层位于 `$lib/server/services/`,处理业务逻辑。
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
import type { HaiResult } from '@h-ai/core'
|
|
225
|
-
// src/lib/server/services/article.ts
|
|
226
|
-
import { core } from '@h-ai/core'
|
|
227
|
-
import { reldb } from '@h-ai/reldb'
|
|
228
|
-
|
|
229
|
-
const logger = core.logger
|
|
230
|
-
|
|
231
|
-
/** 创建文章 */
|
|
232
|
-
export async function createArticle(input: CreateArticleInput): Promise<HaiResult<Article>> {
|
|
233
|
-
logger.debug('Creating article', { title: input.title })
|
|
234
|
-
|
|
235
|
-
const result = await reldb.crud.create('articles', {
|
|
236
|
-
id: core.id.uuid(),
|
|
237
|
-
...input,
|
|
238
|
-
created_at: new Date().toISOString(),
|
|
239
|
-
})
|
|
240
|
-
if (!result.success)
|
|
241
|
-
return result
|
|
242
|
-
|
|
243
|
-
logger.info('Article created', { id: result.data.id })
|
|
244
|
-
return result
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/** 获取文章列表 */
|
|
248
|
-
export async function listArticles(params: ListParams): Promise<HaiResult<PaginatedResult<Article>>> {
|
|
249
|
-
logger.debug('Listing articles', { page: params.page })
|
|
250
|
-
return reldb.crud.paginate('articles', params)
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### 服务层规则
|
|
255
|
-
|
|
256
|
-
- 统一返回 `HaiResult<T>`
|
|
257
|
-
- 写操作需 `debug`(进入)+ `info`(成功)日志
|
|
258
|
-
- 读操作仅 `debug` 日志
|
|
259
|
-
- 禁止 `console.log`,使用 `core.logger`
|
|
260
|
-
- 服务层不处理 HTTP 响应格式,只返回 HaiResult
|
|
261
|
-
|
|
262
|
-
---
|
|
263
|
-
|
|
264
|
-
## 创建数据模型
|
|
265
|
-
|
|
266
|
-
### Schema 定义(SQL DDL)
|
|
267
|
-
|
|
268
|
-
数据库表 Schema 定义在 `$lib/server/init.ts` 中:
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
const BUSINESS_SCHEMA = `
|
|
272
|
-
CREATE TABLE IF NOT EXISTS articles (
|
|
273
|
-
id TEXT PRIMARY KEY,
|
|
274
|
-
title TEXT NOT NULL,
|
|
275
|
-
content TEXT,
|
|
276
|
-
author_id TEXT NOT NULL,
|
|
277
|
-
status TEXT DEFAULT 'draft',
|
|
278
|
-
created_at TEXT DEFAULT (datetime('now')),
|
|
279
|
-
updated_at TEXT DEFAULT (datetime('now'))
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
CREATE INDEX IF NOT EXISTS idx_articles_author_id ON articles(author_id);
|
|
283
|
-
CREATE INDEX IF NOT EXISTS idx_articles_status ON articles(status);
|
|
284
|
-
`
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### 类型定义
|
|
288
|
-
|
|
289
|
-
```typescript
|
|
290
|
-
// 在服务文件或独立类型文件中定义
|
|
291
|
-
interface Article {
|
|
292
|
-
id: string
|
|
293
|
-
title: string
|
|
294
|
-
content: string | null
|
|
295
|
-
authorId: string
|
|
296
|
-
status: 'draft' | 'published' | 'archived'
|
|
297
|
-
createdAt: string
|
|
298
|
-
updatedAt: string
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
interface CreateArticleInput {
|
|
302
|
-
title: string
|
|
303
|
-
content?: string
|
|
304
|
-
authorId: string
|
|
305
|
-
}
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
## 创建业务组件
|
|
311
|
-
|
|
312
|
-
业务组件放在 `$lib/components/`,通用 UI 使用 `@h-ai/ui`。
|
|
313
|
-
|
|
314
|
-
```svelte
|
|
315
|
-
<!-- src/lib/components/ArticleCard.svelte -->
|
|
316
|
-
<script lang="ts">
|
|
317
|
-
import type { Article } from '$lib/server/services/article'
|
|
318
|
-
|
|
319
|
-
let { article, onEdit }: { article: Article, onEdit?: () => void } = $props()
|
|
320
|
-
</script>
|
|
321
|
-
|
|
322
|
-
<div class="card bg-base-100 shadow">
|
|
323
|
-
<div class="card-body">
|
|
324
|
-
<h2 class="card-title">{article.title}</h2>
|
|
325
|
-
<p>{article.content ?? ''}</p>
|
|
326
|
-
{#if onEdit}
|
|
327
|
-
<div class="card-actions justify-end">
|
|
328
|
-
<button class="btn btn-primary" onclick={onEdit}>编辑</button>
|
|
329
|
-
</div>
|
|
330
|
-
{/if}
|
|
331
|
-
</div>
|
|
332
|
-
</div>
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### 组件规则
|
|
336
|
-
|
|
337
|
-
- 使用 Svelte 5 Runes 语法(`$props()`、`$state()`、`$derived()`、`$effect()`)
|
|
338
|
-
- 事件回调通过 props 传入(非 `createEventDispatcher`)
|
|
339
|
-
- 样式使用 TailwindCSS 4 + DaisyUI 5 class
|
|
340
|
-
- 通用 UI 组件优先使用 `@h-ai/ui`,不重复实现
|
|
341
|
-
- i18n 文本使用 `$lib/paraglide/messages.js` 中的 key
|
|
342
|
-
|
|
343
|
-
---
|
|
344
|
-
|
|
345
|
-
## 初始化顺序
|
|
346
|
-
|
|
347
|
-
在 `$lib/server/init.ts` 中管理模块初始化顺序:
|
|
348
|
-
|
|
349
|
-
```
|
|
350
|
-
core.init() → reldb.init() → cache.init() → iam.init() → createBusinessTables()
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
新增模块时需在此文件中按依赖顺序添加初始化调用。
|
|
354
|
-
|
|
355
|
-
---
|
|
356
|
-
|
|
357
|
-
## 容器交付
|
|
358
|
-
|
|
359
|
-
- 保持脚手架根目录 `Dockerfile`、`.dockerignore` 与 `package.json` 中 `docker:build*` / `podman:build*` 命令同步。
|
|
360
|
-
- Podman 多阶段构建保持 `--format docker --jobs=1`;前者保留 `HEALTHCHECK`,后者避免部分 Podman 5.8/Buildah 组合在并行 stage 构建时触发内部 semaphore panic。
|
|
361
|
-
- 先复制 lockfile 与 workspace 配置执行 `pnpm fetch`,再复制源码并离线安装、构建;避免源码变化重复下载依赖,同时兼容新增 workspace。
|
|
362
|
-
- SvelteKit 服务使用 Node adapter;纯 Vite 前端使用带 SPA fallback 的静态镜像;fullstack 的 Service 与 Web 分别交付,Service 直接监听且不增加转发进程。
|
|
363
|
-
- Web 的 `PUBLIC_*` 部署配置在容器启动时生成静态运行时配置,不作为 build arg 烘焙,确保同一镜像可跨环境部署。
|
|
364
|
-
- 配置文件随镜像提供,并允许只读挂载覆盖;密钥只通过环境变量或 `--env-file` 注入。
|
|
365
|
-
- 普通构建不携带 `data/`;只有用户明确运行 `docker:build:data` / `podman:build:data` 时才通过 named build context 嵌入 SQLite/本地存储初始快照。
|
|
366
|
-
- 数据库和本地存储的持续写入必须落到 volume,不能依赖镜像可写层。
|
|
367
|
-
- 完成前实际启动镜像,验证健康端点、非 root 用户、环境变量覆盖、配置挂载和预置数据读取。
|
|
368
|
-
|
|
369
|
-
---
|
|
370
|
-
|
|
371
|
-
## 检查清单
|
|
372
|
-
|
|
373
|
-
- [ ] **TDD 流程已执行**:先写测试 → 确认失败 → 再实现 → 确认通过
|
|
374
|
-
- [ ] 单元测试已编写(服务层、Schema)
|
|
375
|
-
- [ ] E2E 测试已编写(API 端点、页面交互)
|
|
376
|
-
- [ ] 页面使用 Svelte 5 Runes 语法
|
|
377
|
-
- [ ] API 端点有权限守卫与输入校验
|
|
378
|
-
- [ ] 服务层统一返回 `HaiResult<T>`
|
|
379
|
-
- [ ] 日志级别正确(读 debug / 写 debug+info / 失败 warn|error)
|
|
380
|
-
- [ ] 禁止 `console.log`、`any`、硬编码密钥
|
|
381
|
-
- [ ] 用户可见文本走 i18n
|
|
382
|
-
- [ ] Docker / Podman 镜像可启动,配置/环境变量/数据目录行为已验证
|
|
383
|
-
- [ ] 新增表有索引定义
|
|
384
|
-
- [ ] 组件优先使用 `@h-ai/ui`
|
|
385
|
-
- [ ] `pnpm typecheck && pnpm lint && pnpm test` 通过
|
|
386
|
-
|
|
387
|
-
---
|
|
388
|
-
|
|
389
|
-
## 相关 Skills
|
|
390
|
-
|
|
391
|
-
- `hai-build`:项目架构与模块初始化顺序
|
|
392
|
-
- `hai-app-tests`:TDD 测试规范(Red 阶段详细指引)
|
|
393
|
-
- `hai-app-review`:代码审查规范(Refactor 阶段参照)
|
|
394
|
-
- `hai-kit`:SvelteKit 集成的完整 API
|
|
395
|
-
- `hai-ui`:UI 组件库使用
|
|
396
|
-
- `hai-reldb`:数据库操作详细 API
|
|
397
|
-
- `hai-iam`:认证与权限管理
|
|
12
|
+
| 能力 | 在 hai 应用中新增页面、路由、API、服务、模型或组件 |
|
|
13
|
+
| 适用场景 | 已确定需求的应用功能实现 |
|
|
14
|
+
| 输入 | 功能需求、现有路由/contract、数据模型和验收场景 |
|
|
15
|
+
| 输出 | 最小实现、必要测试、i18n 与同步文档 |
|
|
16
|
+
| 限制 | 优先复用;TDD 仅让新增目标用例先失败,已有回归保持通过。API workspace 不生成 SvelteKit 路由。 |
|
|
17
|
+
|
|
18
|
+
## 使用路径
|
|
19
|
+
|
|
20
|
+
- 从真实路由/contract、UI 组件和服务层扩展;API workspace、SvelteKit 和 SPA 的文件结构不能混用。
|
|
21
|
+
- 对新增行为先写有意义的目标用例,已有回归保持通过;同步 i18n、README 和调用方。
|
|
22
|
+
|
|
23
|
+
## 按需参考
|
|
24
|
+
|
|
25
|
+
详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
|
|
26
|
+
|
|
27
|
+
- 适用场景
|
|
28
|
+
- TDD 开发流程(强制)
|
|
29
|
+
- 目录结构约定
|
|
30
|
+
- 创建页面
|
|
31
|
+
- 创建 API 端点
|
|
32
|
+
- 创建服务层
|
|
33
|
+
- 创建数据模型
|
|
34
|
+
- 创建业务组件
|
|
35
|
+
- 初始化顺序
|
|
36
|
+
- 容器交付
|
|
37
|
+
- 检查清单
|
|
38
|
+
- 相关 Skills
|