@jahanxu/trellis 0.4.2 → 0.5.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 (67) hide show
  1. package/dist/configurators/workflow.d.ts.map +1 -1
  2. package/dist/configurators/workflow.js +58 -1
  3. package/dist/configurators/workflow.js.map +1 -1
  4. package/dist/constants/paths.d.ts +17 -0
  5. package/dist/constants/paths.d.ts.map +1 -1
  6. package/dist/constants/paths.js +19 -0
  7. package/dist/constants/paths.js.map +1 -1
  8. package/dist/templates/claude/commands/trellis/handoff.md +90 -387
  9. package/dist/templates/claude/commands/trellis/pick-task.md +74 -444
  10. package/dist/templates/claude/commands/trellis/update-spec.md +19 -3
  11. package/dist/templates/claude/hooks/inject-subagent-context.py +17 -101
  12. package/dist/templates/claude/hooks/ralph-loop.py +1 -0
  13. package/dist/templates/claude/hooks/session-start.py +170 -54
  14. package/dist/templates/iflow/commands/trellis/handoff.md +148 -0
  15. package/dist/templates/iflow/commands/trellis/pick-task.md +145 -0
  16. package/dist/templates/iflow/commands/trellis/update-spec.md +19 -3
  17. package/dist/templates/iflow/hooks/inject-subagent-context.py +1 -0
  18. package/dist/templates/iflow/hooks/ralph-loop.py +1 -0
  19. package/dist/templates/iflow/hooks/session-start.py +171 -0
  20. package/dist/templates/markdown/index.d.ts +9 -0
  21. package/dist/templates/markdown/index.d.ts.map +1 -1
  22. package/dist/templates/markdown/index.js +10 -0
  23. package/dist/templates/markdown/index.js.map +1 -1
  24. package/dist/templates/markdown/spec/roles/designer/index.md.txt +57 -0
  25. package/dist/templates/markdown/spec/roles/designer/mock-data-standards.md.txt +63 -0
  26. package/dist/templates/markdown/spec/roles/designer/prototype-guidelines.md.txt +49 -0
  27. package/dist/templates/markdown/spec/roles/frontend-impl/api-integration.md.txt +63 -0
  28. package/dist/templates/markdown/spec/roles/frontend-impl/index.md.txt +57 -0
  29. package/dist/templates/markdown/spec/roles/frontend-impl/prototype-to-production.md.txt +57 -0
  30. package/dist/templates/markdown/spec/roles/pm/index.md.txt +45 -0
  31. package/dist/templates/markdown/spec/roles/pm/prd-template.md.txt +64 -0
  32. package/dist/templates/markdown/spec/roles/pm/requirement-checklist.md.txt +43 -0
  33. package/dist/templates/trellis/index.d.ts +1 -0
  34. package/dist/templates/trellis/index.d.ts.map +1 -1
  35. package/dist/templates/trellis/index.js +2 -0
  36. package/dist/templates/trellis/index.js.map +1 -1
  37. package/dist/templates/trellis/scripts/add_session.py +3 -2
  38. package/dist/templates/trellis/scripts/common/cli_adapter.py +4 -4
  39. package/dist/templates/trellis/scripts/common/developer.py +4 -4
  40. package/dist/templates/trellis/scripts/common/git_context.py +7 -7
  41. package/dist/templates/trellis/scripts/common/paths.py +64 -14
  42. package/dist/templates/trellis/scripts/common/phase.py +2 -2
  43. package/dist/templates/trellis/scripts/common/registry.py +16 -16
  44. package/dist/templates/trellis/scripts/common/task_queue.py +10 -10
  45. package/dist/templates/trellis/scripts/common/task_utils.py +5 -5
  46. package/dist/templates/trellis/scripts/common/worktree.py +8 -8
  47. package/dist/templates/trellis/scripts/pool.py +214 -266
  48. package/dist/templates/trellis/scripts/task.py +3 -116
  49. package/package.json +3 -3
  50. package/dist/templates/claude/commands/trellis/before-role-work.md +0 -364
  51. package/dist/templates/trellis/VERSION +0 -1
  52. package/dist/templates/trellis/deliverables/README.md +0 -51
  53. package/dist/templates/trellis/paths.README.md +0 -277
  54. package/dist/templates/trellis/paths.yaml +0 -41
  55. package/dist/templates/trellis/pool/implementations.json +0 -5
  56. package/dist/templates/trellis/pool/prototypes.json +0 -5
  57. package/dist/templates/trellis/pool/requirements.json +0 -5
  58. package/dist/templates/trellis/scripts/common/project_paths.py +0 -189
  59. package/dist/templates/trellis/scripts/handoff_generator.py +0 -380
  60. package/dist/templates/trellis/spec/roles/designer/index.md +0 -243
  61. package/dist/templates/trellis/spec/roles/designer/mock-data-standards.md +0 -481
  62. package/dist/templates/trellis/spec/roles/designer/prototype-guidelines.md +0 -429
  63. package/dist/templates/trellis/spec/roles/frontend-impl/api-integration.md +0 -565
  64. package/dist/templates/trellis/spec/roles/frontend-impl/index.md +0 -321
  65. package/dist/templates/trellis/spec/roles/frontend-impl/state-management.md +0 -599
  66. package/dist/templates/trellis/spec/roles/pm/index.md +0 -112
  67. package/dist/templates/trellis/spec/roles/pm/prd-template.md +0 -124
@@ -1,599 +0,0 @@
1
- # 状态管理规范
2
-
3
- > Frontend 角色选择和实现状态管理方案的指南
4
-
5
- ---
6
-
7
- ## 核心原则
8
-
9
- 状态管理应该:
10
- 1. **按需选择** - 根据复杂度选择合适的方案
11
- 2. **类型安全** - 使用 TypeScript 确保状态类型正确
12
- 3. **可预测性** - 状态变化清晰可追踪
13
- 4. **性能优化** - 避免不必要的重渲染
14
-
15
- ---
16
-
17
- ## 状态分类
18
-
19
- ### 1. 组件本地状态(Local State)
20
-
21
- **定义**:仅在单个组件内使用的状态
22
-
23
- **适用场景**:
24
- - 表单输入值
25
- - UI 切换状态(展开/折叠)
26
- - 临时加载状态
27
-
28
- **技术选择**:React `useState`
29
-
30
- **示例**:
31
- ```typescript
32
- const LoginForm = () => {
33
- const [email, setEmail] = useState('');
34
- const [password, setPassword] = useState('');
35
- const [showPassword, setShowPassword] = useState(false);
36
-
37
- return (
38
- <form>
39
- <input
40
- type="email"
41
- value={email}
42
- onChange={(e) => setEmail(e.target.value)}
43
- />
44
- <input
45
- type={showPassword ? 'text' : 'password'}
46
- value={password}
47
- onChange={(e) => setPassword(e.target.value)}
48
- />
49
- <button onClick={() => setShowPassword(!showPassword)}>
50
- {showPassword ? '隐藏' : '显示'}密码
51
- </button>
52
- </form>
53
- );
54
- };
55
- ```
56
-
57
- ---
58
-
59
- ### 2. 跨组件状态(Shared State)
60
-
61
- **定义**:多个组件共享的状态
62
-
63
- **适用场景**:
64
- - 用户认证状态
65
- - 主题设置(暗色/亮色模式)
66
- - 语言设置
67
-
68
- **技术选择**:React Context + `useContext`
69
-
70
- **示例**:
71
- ```typescript
72
- // src/contexts/AuthContext.tsx
73
- import { createContext, useContext, useState, ReactNode } from 'react';
74
- import type { User } from '@/types/user';
75
-
76
- interface AuthContextType {
77
- user: User | null;
78
- login: (user: User, token: string) => void;
79
- logout: () => void;
80
- }
81
-
82
- const AuthContext = createContext<AuthContextType | undefined>(undefined);
83
-
84
- export const AuthProvider = ({ children }: { children: ReactNode }) => {
85
- const [user, setUser] = useState<User | null>(null);
86
-
87
- const login = (user: User, token: string) => {
88
- setUser(user);
89
- localStorage.setItem('auth_token', token);
90
- };
91
-
92
- const logout = () => {
93
- setUser(null);
94
- localStorage.removeItem('auth_token');
95
- };
96
-
97
- return (
98
- <AuthContext.Provider value={{ user, login, logout }}>
99
- {children}
100
- </AuthContext.Provider>
101
- );
102
- };
103
-
104
- export const useAuth = () => {
105
- const context = useContext(AuthContext);
106
- if (!context) {
107
- throw new Error('useAuth must be used within AuthProvider');
108
- }
109
- return context;
110
- };
111
- ```
112
-
113
- **使用方式**:
114
- ```typescript
115
- // App.tsx
116
- <AuthProvider>
117
- <App />
118
- </AuthProvider>
119
-
120
- // LoginPage.tsx
121
- import { useAuth } from '@/contexts/AuthContext';
122
-
123
- const LoginPage = () => {
124
- const { login } = useAuth();
125
-
126
- const handleSubmit = async (email: string, password: string) => {
127
- const { user, token } = await loginAPI(email, password);
128
- login(user, token);
129
- };
130
-
131
- // ...
132
- };
133
-
134
- // Header.tsx
135
- import { useAuth } from '@/contexts/AuthContext';
136
-
137
- const Header = () => {
138
- const { user, logout } = useAuth();
139
-
140
- return (
141
- <div>
142
- {user && (
143
- <>
144
- <span>{user.name}</span>
145
- <button onClick={logout}>登出</button>
146
- </>
147
- )}
148
- </div>
149
- );
150
- };
151
- ```
152
-
153
- ---
154
-
155
- ### 3. 全局复杂状态(Global Complex State)
156
-
157
- **定义**:跨多个页面、需要复杂操作的状态
158
-
159
- **适用场景**:
160
- - 购物车状态
161
- - 消息通知队列
162
- - 应用配置
163
-
164
- **技术选择**:Zustand(推荐)或 Redux Toolkit
165
-
166
- ---
167
-
168
- ## Zustand 使用指南
169
-
170
- ### 1. 安装
171
-
172
- ```bash
173
- npm install zustand
174
- ```
175
-
176
- ### 2. 创建 Store
177
-
178
- ```typescript
179
- // src/stores/cartStore.ts
180
- import { create } from 'zustand';
181
- import type { Product } from '@/types/product';
182
-
183
- interface CartItem {
184
- product: Product;
185
- quantity: number;
186
- }
187
-
188
- interface CartStore {
189
- items: CartItem[];
190
- addItem: (product: Product, quantity: number) => void;
191
- removeItem: (productId: string) => void;
192
- updateQuantity: (productId: string, quantity: number) => void;
193
- clearCart: () => void;
194
- total: () => number;
195
- }
196
-
197
- export const useCartStore = create<CartStore>((set, get) => ({
198
- items: [],
199
-
200
- addItem: (product, quantity) => {
201
- set((state) => {
202
- const existingItem = state.items.find(
203
- (item) => item.product.id === product.id
204
- );
205
-
206
- if (existingItem) {
207
- return {
208
- items: state.items.map((item) =>
209
- item.product.id === product.id
210
- ? { ...item, quantity: item.quantity + quantity }
211
- : item
212
- ),
213
- };
214
- }
215
-
216
- return {
217
- items: [...state.items, { product, quantity }],
218
- };
219
- });
220
- },
221
-
222
- removeItem: (productId) => {
223
- set((state) => ({
224
- items: state.items.filter((item) => item.product.id !== productId),
225
- }));
226
- },
227
-
228
- updateQuantity: (productId, quantity) => {
229
- set((state) => ({
230
- items: state.items.map((item) =>
231
- item.product.id === productId ? { ...item, quantity } : item
232
- ),
233
- }));
234
- },
235
-
236
- clearCart: () => {
237
- set({ items: [] });
238
- },
239
-
240
- total: () => {
241
- const { items } = get();
242
- return items.reduce(
243
- (sum, item) => sum + item.product.price * item.quantity,
244
- 0
245
- );
246
- },
247
- }));
248
- ```
249
-
250
- ### 3. 使用 Store
251
-
252
- ```typescript
253
- // 组件中使用
254
- import { useCartStore } from '@/stores/cartStore';
255
-
256
- const CartPage = () => {
257
- const items = useCartStore((state) => state.items);
258
- const total = useCartStore((state) => state.total());
259
- const removeItem = useCartStore((state) => state.removeItem);
260
-
261
- return (
262
- <div>
263
- <h1>购物车</h1>
264
- {items.map((item) => (
265
- <div key={item.product.id}>
266
- <span>{item.product.name}</span>
267
- <span>数量: {item.quantity}</span>
268
- <button onClick={() => removeItem(item.product.id)}>删除</button>
269
- </div>
270
- ))}
271
- <p>总计: ¥{total}</p>
272
- </div>
273
- );
274
- };
275
- ```
276
-
277
- ### 4. Zustand 持久化
278
-
279
- ```typescript
280
- import { create } from 'zustand';
281
- import { persist } from 'zustand/middleware';
282
-
283
- export const useCartStore = create<CartStore>()(
284
- persist(
285
- (set, get) => ({
286
- items: [],
287
- addItem: (product, quantity) => {
288
- // ...
289
- },
290
- // ...
291
- }),
292
- {
293
- name: 'cart-storage', // localStorage key
294
- getStorage: () => localStorage,
295
- }
296
- )
297
- );
298
- ```
299
-
300
- ---
301
-
302
- ## Redux Toolkit 使用指南
303
-
304
- ### 1. 安装
305
-
306
- ```bash
307
- npm install @reduxjs/toolkit react-redux
308
- ```
309
-
310
- ### 2. 创建 Slice
311
-
312
- ```typescript
313
- // src/store/slices/cartSlice.ts
314
- import { createSlice, PayloadAction } from '@reduxjs/toolkit';
315
- import type { Product } from '@/types/product';
316
-
317
- interface CartItem {
318
- product: Product;
319
- quantity: number;
320
- }
321
-
322
- interface CartState {
323
- items: CartItem[];
324
- }
325
-
326
- const initialState: CartState = {
327
- items: [],
328
- };
329
-
330
- const cartSlice = createSlice({
331
- name: 'cart',
332
- initialState,
333
- reducers: {
334
- addItem: (state, action: PayloadAction<{ product: Product; quantity: number }>) => {
335
- const { product, quantity } = action.payload;
336
- const existingItem = state.items.find(
337
- (item) => item.product.id === product.id
338
- );
339
-
340
- if (existingItem) {
341
- existingItem.quantity += quantity;
342
- } else {
343
- state.items.push({ product, quantity });
344
- }
345
- },
346
- removeItem: (state, action: PayloadAction<string>) => {
347
- state.items = state.items.filter(
348
- (item) => item.product.id !== action.payload
349
- );
350
- },
351
- updateQuantity: (
352
- state,
353
- action: PayloadAction<{ productId: string; quantity: number }>
354
- ) => {
355
- const item = state.items.find(
356
- (item) => item.product.id === action.payload.productId
357
- );
358
- if (item) {
359
- item.quantity = action.payload.quantity;
360
- }
361
- },
362
- clearCart: (state) => {
363
- state.items = [];
364
- },
365
- },
366
- });
367
-
368
- export const { addItem, removeItem, updateQuantity, clearCart } = cartSlice.actions;
369
- export default cartSlice.reducer;
370
- ```
371
-
372
- ### 3. 配置 Store
373
-
374
- ```typescript
375
- // src/store/index.ts
376
- import { configureStore } from '@reduxjs/toolkit';
377
- import cartReducer from './slices/cartSlice';
378
-
379
- export const store = configureStore({
380
- reducer: {
381
- cart: cartReducer,
382
- },
383
- });
384
-
385
- export type RootState = ReturnType<typeof store.getState>;
386
- export type AppDispatch = typeof store.dispatch;
387
- ```
388
-
389
- ### 4. 使用 Store
390
-
391
- ```typescript
392
- // App.tsx
393
- import { Provider } from 'react-redux';
394
- import { store } from './store';
395
-
396
- <Provider store={store}>
397
- <App />
398
- </Provider>
399
-
400
- // 组件中使用
401
- import { useSelector, useDispatch } from 'react-redux';
402
- import { addItem, removeItem } from '@/store/slices/cartSlice';
403
- import type { RootState } from '@/store';
404
-
405
- const CartPage = () => {
406
- const items = useSelector((state: RootState) => state.cart.items);
407
- const dispatch = useDispatch();
408
-
409
- const handleRemove = (productId: string) => {
410
- dispatch(removeItem(productId));
411
- };
412
-
413
- return (
414
- // ...
415
- );
416
- };
417
- ```
418
-
419
- ---
420
-
421
- ## 服务器状态管理
422
-
423
- ### 使用 React Query(推荐)
424
-
425
- **定义**:从服务器获取的数据(用户列表、产品详情等)
426
-
427
- **技术选择**:React Query(TanStack Query)
428
-
429
- **安装**:
430
- ```bash
431
- npm install @tanstack/react-query
432
- ```
433
-
434
- **配置**:
435
- ```typescript
436
- // src/App.tsx
437
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
438
-
439
- const queryClient = new QueryClient({
440
- defaultOptions: {
441
- queries: {
442
- staleTime: 60000, // 1分钟内数据不过期
443
- refetchOnWindowFocus: false,
444
- },
445
- },
446
- });
447
-
448
- <QueryClientProvider client={queryClient}>
449
- <App />
450
- </QueryClientProvider>
451
- ```
452
-
453
- **使用示例**:
454
- ```typescript
455
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
456
- import { getUsers, deleteUser } from '@/lib/api/user';
457
-
458
- const UserList = () => {
459
- const queryClient = useQueryClient();
460
-
461
- // 查询用户列表
462
- const { data, isLoading, error } = useQuery({
463
- queryKey: ['users'],
464
- queryFn: getUsers,
465
- });
466
-
467
- // 删除用户 mutation
468
- const deleteMutation = useMutation({
469
- mutationFn: deleteUser,
470
- onSuccess: () => {
471
- // 刷新用户列表
472
- queryClient.invalidateQueries({ queryKey: ['users'] });
473
- },
474
- });
475
-
476
- if (isLoading) return <div>加载中...</div>;
477
- if (error) return <div>错误: {error.message}</div>;
478
-
479
- return (
480
- <div>
481
- {data?.items.map((user) => (
482
- <div key={user.id}>
483
- <span>{user.name}</span>
484
- <button onClick={() => deleteMutation.mutate(user.id)}>
485
- 删除
486
- </button>
487
- </div>
488
- ))}
489
- </div>
490
- );
491
- };
492
- ```
493
-
494
- ---
495
-
496
- ## 状态管理方案选择
497
-
498
- | 状态类型 | 复杂度 | 推荐方案 | 示例场景 |
499
- |---------|--------|---------|---------|
500
- | **本地状态** | 简单 | `useState` | 表单输入、UI切换 |
501
- | **跨组件状态** | 中等 | Context + `useContext` | 用户认证、主题设置 |
502
- | **全局复杂状态** | 复杂 | Zustand | 购物车、通知队列 |
503
- | **超大型应用** | 极复杂 | Redux Toolkit | 企业级应用 |
504
- | **服务器状态** | - | React Query | API数据缓存 |
505
-
506
- ---
507
-
508
- ## 性能优化
509
-
510
- ### 1. 避免不必要的重渲染
511
-
512
- **使用 selector 精确订阅**:
513
- ```typescript
514
- // ❌ 避免:订阅整个 store
515
- const store = useCartStore();
516
-
517
- // ✅ 推荐:只订阅需要的状态
518
- const items = useCartStore((state) => state.items);
519
- const total = useCartStore((state) => state.total());
520
- ```
521
-
522
- ### 2. 使用 memo 优化组件
523
-
524
- ```typescript
525
- import { memo } from 'react';
526
-
527
- const CartItem = memo(({ item, onRemove }: CartItemProps) => {
528
- return (
529
- <div>
530
- <span>{item.product.name}</span>
531
- <button onClick={() => onRemove(item.product.id)}>删除</button>
532
- </div>
533
- );
534
- });
535
- ```
536
-
537
- ### 3. 使用 useMemo 缓存计算结果
538
-
539
- ```typescript
540
- const CartSummary = () => {
541
- const items = useCartStore((state) => state.items);
542
-
543
- const total = useMemo(() => {
544
- return items.reduce(
545
- (sum, item) => sum + item.product.price * item.quantity,
546
- 0
547
- );
548
- }, [items]);
549
-
550
- return <div>总计: ¥{total}</div>;
551
- };
552
- ```
553
-
554
- ---
555
-
556
- ## 检查清单
557
-
558
- 状态管理实现完成前,确保:
559
-
560
- - [ ] 本地状态使用 `useState`
561
- - [ ] 跨组件状态使用 Context 或 Zustand
562
- - [ ] 服务器状态使用 React Query
563
- - [ ] 所有状态有类型定义
564
- - [ ] 避免不必要的重渲染(使用 selector)
565
- - [ ] 复杂计算使用 `useMemo` 缓存
566
- - [ ] 状态更新逻辑清晰可追踪
567
-
568
- ---
569
-
570
- ## 常见问题
571
-
572
- ### Q: 什么时候使用 Context,什么时候使用 Zustand?
573
- A:
574
- - **Context**:简单跨组件状态(用户认证、主题设置)
575
- - **Zustand**:复杂状态操作、需要频繁更新(购物车、通知)
576
-
577
- ### Q: Redux 和 Zustand 如何选择?
578
- A:
579
- - **Zustand**:中小型应用,API 简单,性能好
580
- - **Redux**:大型企业应用,需要严格的状态管理规范
581
-
582
- ### Q: 如何处理状态持久化?
583
- A:
584
- - **localStorage**:Zustand persist 中间件
585
- - **sessionStorage**:配置 `getStorage: () => sessionStorage`
586
-
587
- ### Q: React Query 和 Zustand 如何配合?
588
- A:
589
- - **React Query**:管理服务器状态(API 数据)
590
- - **Zustand**:管理客户端状态(购物车、UI设置)
591
-
592
- ---
593
-
594
- ## 相关文档
595
-
596
- - [API 集成指南](./api-integration.md)
597
- - [Frontend 工作规范](./index.md)
598
- - [React Query 官方文档](https://tanstack.com/query/latest)
599
- - [Zustand 官方文档](https://zustand-demo.pmnd.rs/)
@@ -1,112 +0,0 @@
1
- # PM (Product Manager) 工作规范
2
-
3
- > 产品经理在三角色协作中的职责、标准和工作流程
4
-
5
- ---
6
-
7
- ## 角色定位
8
-
9
- **产品经理(PM)** 是三角色协作流水线的**第一环**:
10
- - 负责需求分析和产品定义
11
- - 输出 PRD(Product Requirements Document)和用户故事
12
- - 产出物进入 `requirements` 池,供 Designer 消费
13
-
14
- ---
15
-
16
- ## 工作流程
17
-
18
- ### 1. 创建任务
19
- ```bash
20
- python3 .trellis/scripts/task.py create "功能标题" --slug feature-name
21
- python3 .trellis/scripts/task.py set-role <task-dir> pm
22
- ```
23
-
24
- ### 2. 编写PRD
25
- 在任务目录创建 `prd.md`,参考模板:`.trellis/spec/roles/pm/prd-template.md`
26
-
27
- ### 3. 完成并交接
28
- ```bash
29
- # AI会自动生成 HANDOFF.md
30
- /trellis:handoff
31
- ```
32
-
33
- 产出自动进入 `deliverables/requirements/{task-id}/`
34
-
35
- ---
36
-
37
- ## PRD标准
38
-
39
- ### 必需章节
40
- 1. **功能概述** - 一句话说明这是什么功能
41
- 2. **用户故事** - As a [角色], I want [功能], So that [价值]
42
- 3. **功能需求** - 详细功能点列表
43
- 4. **验收标准** - 如何判断功能完成
44
- 5. **非功能需求** - 性能、安全、兼容性等
45
-
46
- ### 推荐章节
47
- - 竞品分析
48
- - 数据埋点需求
49
- - 上线计划
50
-
51
- ### 禁止内容
52
- - ❌ 技术实现细节(由Designer和Frontend决定)
53
- - ❌ UI设计细节(在PRD中仅描述布局要求,具体设计由Designer完成)
54
-
55
- ---
56
-
57
- ## HANDOFF文档要点
58
-
59
- AI生成的 `HANDOFF.md` 应包含:
60
-
61
- ### 核心需求总结
62
- - 2-3段文字提炼PRD核心要点
63
- - 突出重点功能和优先级
64
-
65
- ### 关键设计要点
66
- - Designer需要重点关注的UI/交互需求
67
- - 特殊布局要求
68
- - 品牌规范要求
69
-
70
- ### 特别注意事项
71
- - 已知的技术限制(如兼容性要求)
72
- - 外部依赖(如第三方SDK)
73
- - 时间节点要求
74
-
75
- ### 相关资源
76
- - 设计稿链接(如已有)
77
- - API文档链接
78
- - 参考资料链接
79
-
80
- ---
81
-
82
- ## 质量检查清单
83
-
84
- 在执行 `/trellis:handoff` 前,确保:
85
-
86
- - [ ] PRD包含所有必需章节
87
- - [ ] 用户故事清晰完整
88
- - [ ] 验收标准可测试
89
- - [ ] 非功能需求已明确
90
- - [ ] 相关资源链接有效
91
- - [ ] 没有遗漏关键业务逻辑
92
-
93
- ---
94
-
95
- ## 常见问题
96
-
97
- ### Q: PRD应该写多详细?
98
- A: 足够Designer理解要做什么,但不要限制实现方式。描述"什么"和"为什么",不描述"怎么做"。
99
-
100
- ### Q: 需要提供UI设计稿吗?
101
- A: 如果有现成设计稿,在HANDOFF中提供链接。如果没有,Designer会根据PRD创建原型。
102
-
103
- ### Q: 如何处理需求变更?
104
- A: 小变更直接更新PRD和HANDOFF;大变更建议创建新任务,标注基于原任务。
105
-
106
- ---
107
-
108
- ## 参考资料
109
-
110
- - [PRD模板](./prd-template.md)
111
- - [用户故事编写指南](./user-story-guide.md)
112
- - [需求检查清单](./requirement-checklist.md)