create-ai-project 1.23.2 → 1.23.3

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.
@@ -68,6 +68,7 @@ For each valid AC from Phase 1:
68
68
  - Happy path (1 test mandatory)
69
69
  - Error handling (only user-visible errors)
70
70
  - Edge cases (only if high business impact)
71
+ - Boundary path (behavior-changing AC only): when the AC can hold on the main path while a distinct branch, state, input class, lifecycle step, or fallback regresses, capture that boundary as a proof obligation so the test exercises it
71
72
 
72
73
  2. **Classify test level**:
73
74
  - Integration test candidate (feature-level interaction)
@@ -190,7 +191,7 @@ describe('[Feature Name] Integration Test', () => {
190
191
 
191
192
  **Proof annotations** (apply to every skeleton, alongside the metadata above): each `it.todo` carries two comment lines that hand the proof contract to the test implementer and to integration-test-reviewer (these map to the task template's Proof Obligations fields):
192
193
  - `Primary failure mode`: the specific regression that turns this test red — the behavior the AC promises and would break
193
- - `Proof obligation`: what the implemented test must assert to prove the claim — the boundary to traverse, the observable state before/after for state-changing ACs, and which boundaries may be mocked and why. Phrase it as design intent describing what to assert; the implementer writes the executable assertions and mock setup
194
+ - `Proof obligation`: what the implemented test must assert to prove the claim — the boundary to traverse, the observable state before/after for state-changing ACs, and which boundaries may be mocked and why. For behavior-changing ACs, name the boundary path (branch, state, input class, lifecycle step, or fallback) the test must traverse when the main path alone would stay green through the regression. Phrase it as design intent describing what to assert; the implementer writes the executable assertions and mock setup
194
195
 
195
196
  ### E2E Test Files
196
197
 
@@ -62,6 +62,9 @@ For each acceptance criterion extracted in Step 1:
62
62
  - Determine status: fulfilled / partially fulfilled / unfulfilled
63
63
  - Record the file path and relevant code location
64
64
  - Note any deviations from the Design Doc specification
65
+ - For behavior-changing ACs, confirm the evidence covers the boundary paths, not only the main path: where a distinct branch, state, input class, lifecycle step, or fallback governs the behavior, verify it is exercised. Compare the source/referenced behavior and the implemented behavior at the same granularity; an unsupported change in a boundary dimension is a `dd_violation`
66
+ - Confirm the implementation keeps the core mechanism the AC, Design Doc, or referenced materials explicitly require; cite the source phrase. A simpler substitute that passes tests but drops the required mechanism is a `dd_violation`
67
+ - For changes to persisted, shared, or externally observable state, identify the publication boundary (where the new state becomes observable to another process, component, user, or later step). State that is observable as complete while still partial, uninitialized, stale, or rollback-only is a `reliability` finding, because a downstream consumer can treat the incomplete state as complete and fail
65
68
 
66
69
  #### 2-2. Identifier Verification
67
70
 
@@ -94,6 +94,12 @@ Escalation thresholds:
94
94
  - Exactly the pair (a+c) or (b+c) → Escalation; any other 2-indicator combination → Continue
95
95
  - 1 or fewer indicators match → Continue implementation
96
96
 
97
+ ### Step4: Core Mechanism Preservation Check (Any YES → Immediate Escalation)
98
+ Preserve the core mechanism the task, AC, Design Doc, or UI Spec requires. Implementation details (variable names, internal logic order, local structure) stay free to change; the required mechanism itself stays intact.
99
+ □ Required core mechanism replaced by a simpler or weaker substitute? (passing tests do not make a substitute acceptable)
100
+ □ Required core mechanism infeasible as specified?
101
+ Any YES → stop and escalate with `escalation_type: "design_compliance_violation"` per the Escalation Response table, mapping the case to the contract fields: `design_doc_expectation` = the required mechanism and the source phrase it cites (task/AC/Design Doc/UI Spec); `actual_situation` = the proposed substitute and the resulting behavioral delta; `why_cannot_implement` = why the required mechanism was replaced or is infeasible as specified; `attempted_approaches[]` = the ways attempted to preserve the required mechanism, or `[]` when infeasibility is known before implementation; `claude_recommendation` = the condition that would lift the block.
102
+
97
103
  ### Boundary Cases and Iron Rule
98
104
 
99
105
  | Case | Continue | Escalate |
@@ -105,7 +111,7 @@ Escalation thresholds:
105
111
 
106
112
  **Iron Rule — escalate when objectively undeterminable**: 2+ valid interpretations for a judgment item; pattern unprecedented in past implementation experience; required information not in Design Doc; equivalent engineers would split on the call.
107
113
 
108
- ### Implementation Continuable (all Step1-3 checks NO and clearly applicable)
114
+ ### Implementation Continuable (all Step1-4 checks NO and clearly applicable)
109
115
  Internal detail optimization (variable names, logic order); specs not in Design Doc; safe `unknown` → concrete type guard for external API responses; minor UI/message text adjustments.
110
116
 
111
117
  ## Responsibilities, Authority, and Boundaries
@@ -94,6 +94,12 @@ Escalation thresholds:
94
94
  - Exactly the pair (a+c) or (b+c) → Escalation; any other 2-indicator combination → Continue
95
95
  - 1 or fewer indicators match → Continue implementation
96
96
 
97
+ ### Step4: Core Mechanism Preservation Check (Any YES → Immediate Escalation)
98
+ Preserve the core mechanism the task, AC, Design Doc, or referenced materials require. Implementation details (variable names, internal ordering, local structure) stay free to change; the required mechanism itself stays intact.
99
+ □ Required core mechanism replaced by a simpler or weaker substitute? (passing tests do not make a substitute acceptable)
100
+ □ Required core mechanism infeasible as specified?
101
+ Any YES → stop and escalate with `escalation_type: "design_compliance_violation"` per the Escalation Response table, mapping the case to the contract fields: `design_doc_expectation` = the required mechanism and the source phrase it cites (task/AC/Design Doc/referenced material); `actual_situation` = the proposed substitute and the resulting behavioral delta; `why_cannot_implement` = why the required mechanism was replaced or is infeasible as specified; `attempted_approaches[]` = the ways attempted to preserve the required mechanism, or `[]` when infeasibility is known before implementation; `claude_recommendation` = the condition that would lift the block.
102
+
97
103
  ### Boundary Cases and Iron Rule
98
104
 
99
105
  | Case | Continue | Escalate |
@@ -105,7 +111,7 @@ Escalation thresholds:
105
111
 
106
112
  **Iron Rule — escalate when objectively undeterminable**: 2+ valid interpretations for a judgment item; pattern unprecedented in past implementation experience; required information not in Design Doc; equivalent engineers would split on the call.
107
113
 
108
- ### Implementation Continuable (all Step1-3 checks NO and clearly applicable)
114
+ ### Implementation Continuable (all Step1-4 checks NO and clearly applicable)
109
115
  Internal detail optimization (variable names, processing order); specs not in Design Doc; safe `unknown` → concrete type guard; minor UI/message text adjustments.
110
116
 
111
117
  ## Responsibilities, Authority, and Boundaries
@@ -30,29 +30,7 @@ Follow documentation-criteria skill for ADR/Design Doc creation thresholds. If a
30
30
 
31
31
  ### Gate Ordering [BLOCKING]
32
32
 
33
- The subsections below are not parallel mandates; they form four serial gates. Complete each gate fully before starting the next. Within a gate, all listed subsections are required (subject to each subsection's own conditions).
34
-
35
- **Gate 0 — Inputs and Standards** (no upstream dependencies):
36
- - Agreement Checklist
37
- - Standards Identification
38
-
39
- **Gate 1 — Existing State Analysis** (depends on Gate 0):
40
- - Existing Code Investigation
41
- - Fact Disposition (when Codebase Analysis input is provided)
42
- - Minimal Surface Alternatives (when introducing persistent client/server state, props or fields crossing ownership boundaries — public API props of exported reusable components, Context values, or state lifted across ownership boundaries — behavioral modes/variants that change observable behavior, or reusable component splits)
43
-
44
- **Gate 2 — Design Decisions** (depends on Gate 1):
45
- - Implementation Approach Decision
46
- - Common ADR Process
47
- - Data Contracts
48
- - State Transitions (when applicable)
49
-
50
- **Gate 3 — Impact Documentation** (depends on Gate 2):
51
- - Integration Point Analysis
52
- - Change Impact Map
53
- - Interface Change Impact Analysis
54
-
55
- Each subsection below carries a `[Gate N — ...]` annotation in its heading. Subsections appear in Gate order (Gate 0 → 1 → 2 → 3); execute them in document order.
33
+ The subsections below are not parallel mandates; they form four serial gates: **Gate 0** Inputs & Standards → **Gate 1** Existing-State Analysis → **Gate 2** Design Decisions → **Gate 3** Impact Documentation. Complete each gate fully before starting the next. Each subsection below carries a `[Gate N ...]` annotation (with its own applicability condition) in its heading and appears in Gate order; execute them in document order.
56
34
 
57
35
  ### Agreement Checklist [Gate 0 — Required]
58
36
  Must be performed at the beginning of Design Doc creation:
@@ -331,31 +309,7 @@ Consistency first (follow existing React component patterns; document reason whe
331
309
 
332
310
  **MANDATORY**: implementation samples in ADR/Design Docs MUST comply with frontend-typescript-rules skill. Required: function components (class components deprecated); Props type definitions on all components; custom hooks for logic reuse; strict types (`unknown` + type guards for external API responses, `any` prohibited); Error Boundary / error state management; environment variables — secrets server-side only.
333
311
 
334
- Compliant sample (function component with Props type, custom hook with `unknown` type-guarded fetch):
335
-
336
- ```typescript
337
- type ButtonProps = { label: string; onClick: () => void; disabled?: boolean }
338
- export function Button({ label, onClick, disabled = false }: ButtonProps) {
339
- return <button onClick={onClick} disabled={disabled}>{label}</button>
340
- }
341
-
342
- function useUserData(userId: string) {
343
- const [user, setUser] = useState<User | null>(null)
344
- const [error, setError] = useState<Error | null>(null)
345
- useEffect(() => {
346
- void (async () => {
347
- try {
348
- const data: unknown = await (await fetch(`/api/users/${userId}`)).json()
349
- if (!isUser(data)) throw new Error('Invalid user data')
350
- setUser(data)
351
- } catch (e) { setError(e instanceof Error ? e : new Error('Unknown error')) }
352
- })()
353
- }, [userId])
354
- return { user, error }
355
- }
356
- ```
357
-
358
- Non-compliant: class components, `any`, untyped responses without guards, secrets embedded client-side.
312
+ Non-compliant: class components (except Error Boundaries), `any`, untyped responses without guards, secrets embedded client-side.
359
313
 
360
314
  ## Diagram Creation (mermaid)
361
315
 
@@ -394,6 +348,14 @@ Non-compliant: class components, `any`, untyped responses without guards, secret
394
348
 
395
349
  ## Acceptance Criteria Creation Guidelines
396
350
 
351
+ ### Value-First Drafting and Boundary Expansion
352
+
353
+ Draft each AC value-first, then expand it across requirement boundaries before applying the scoping rules below:
354
+
355
+ 1. **Value first**: name the user value, then the observable UI behavior that delivers it, then the technical boundary that realizes it.
356
+ 2. **Expand across boundaries** (candidate extraction — the scoping rules below decide which to keep): a behavior can hold on the happy path while regressing on a separate state. For each behavior-changing AC, consider an AC wherever the promised behavior must also hold — single/latest/full list rendering, sibling props or fields, loading/empty/error and later interaction states, stale or missing data, failed fetches or fallback UI, permission/validation gating, input scope and ordering/selection, side effects, and visibility or route boundaries (state becoming observable on another screen, to another component, or after navigation).
357
+ 3. **Compare at the same granularity**: when the AC concerns existing or referenced behavior, state the source behavior and the target behavior at the same level of detail, so a reviewer can confirm each boundary is preserved or intentionally changed.
358
+
397
359
  ### AC Scoping for Autonomous Implementation (Frontend)
398
360
 
399
361
  **Principle**: AC = User-observable behavior in browser verifiable in isolated CI environment. Cover happy path, unhappy path (errors), and edge cases (empty/loading states); prioritize important ACs at the top; document non-functional requirements in a separate section.
@@ -29,31 +29,7 @@ Follow documentation-criteria skill for ADR/Design Doc creation thresholds. If a
29
29
 
30
30
  ### Gate Ordering [BLOCKING]
31
31
 
32
- The subsections below are not parallel mandates; they form four serial gates. Complete each gate fully before starting the next. Within a gate, all listed subsections are required (subject to each subsection's own conditions).
33
-
34
- **Gate 0 — Inputs and Standards** (no upstream dependencies):
35
- - Agreement Checklist
36
- - Standards Identification
37
-
38
- **Gate 1 — Existing State Analysis** (depends on Gate 0):
39
- - Existing Code Investigation
40
- - Fact Disposition (when Codebase Analysis input is provided)
41
- - Data Representation Decision (when new or modified data structures are introduced)
42
- - Minimal Surface Alternatives (when introducing persistent state, public-contract elements or cross-boundary fields, behavioral modes/flags, or reusable abstractions)
43
-
44
- **Gate 2 — Design Decisions** (depends on Gate 1):
45
- - Implementation Approach Decision
46
- - Common ADR Process
47
- - Data Contracts
48
- - State Transitions (when applicable)
49
-
50
- **Gate 3 — Impact Documentation** (depends on Gate 2):
51
- - Integration Points
52
- - Change Impact Map
53
- - Field Propagation Map (when fields cross component boundaries)
54
- - Interface Change Impact Analysis
55
-
56
- Each subsection below carries a `[Gate N — ...]` annotation in its heading. Subsections appear in Gate order (Gate 0 → 1 → 2 → 3); execute them in document order.
32
+ The subsections below are not parallel mandates; they form four serial gates: **Gate 0** Inputs & Standards → **Gate 1** Existing-State Analysis → **Gate 2** Design Decisions → **Gate 3** Impact Documentation. Complete each gate fully before starting the next. Each subsection below carries a `[Gate N ...]` annotation (with its own applicability condition) in its heading and appears in Gate order; execute them in document order.
57
33
 
58
34
  ### Agreement Checklist [Gate 0 — Required]
59
35
  Must be performed at the beginning of Design Doc creation:
@@ -370,6 +346,14 @@ Consistency first (follow existing patterns; document reason when introducing ne
370
346
 
371
347
  ## Acceptance Criteria Creation Guidelines
372
348
 
349
+ ### Value-First Drafting and Boundary Expansion
350
+
351
+ Draft each AC value-first, then expand it across requirement boundaries before applying the rules below:
352
+
353
+ 1. **Value first**: name the user/operator/maintainer value, then the observable behavior that delivers it, then the technical boundary that realizes it.
354
+ 2. **Expand across boundaries** (candidate extraction — the rules below decide which to keep): a behavior can hold on the main path while regressing on a separate dimension. For each behavior-changing AC, consider an AC wherever the promised behavior must also hold — single/latest/full collection, sibling fields on the same surface, later lifecycle states and retries, stale/missing/empty values, failed refreshes or unavailable fallbacks, permission/validation/policy boundaries, input scope and selection/ordering/identity keys, side effects, and publication or visibility boundaries (state becoming observable to another process, component, user, or later step).
355
+ 3. **Compare at the same granularity**: when the AC concerns existing or referenced behavior, state the source behavior and the target behavior at the same level of detail, so a reviewer can confirm each boundary is preserved or intentionally changed.
356
+
373
357
  ### Writing Measurable ACs
374
358
 
375
359
  **Core Principle**: AC = User-observable behavior verifiable in isolated environment. Cover happy path, unhappy path, and edge cases. Non-functional requirements (performance, reliability, scalability) live in a separate "Non-functional Requirements" section.
@@ -453,4 +437,4 @@ Mode for documenting existing architecture as-is. Used when creating Design Docs
453
437
  ### Reverse-Engineer Mode Quality Standard
454
438
  - Every claim cites file:line as evidence
455
439
  - Identifiers transcribed exactly from code
456
- - Test existence confirmed by Glob, not assumed
440
+ - Test existence confirmed by Glob, not assumed
@@ -68,6 +68,7 @@ Phase 1から有効な各ACについて:
68
68
  - ハッピーパス(1テスト必須)
69
69
  - エラーハンドリング(ユーザーから見えるエラーのみ)
70
70
  - エッジケース(ビジネス影響が高い場合のみ)
71
+ - 境界パス(振る舞いを変えるACのみ): ACがメインパスでは成立しつつ、別個の分岐・状態・入力クラス・ライフサイクルステップ・フォールバックで退行しうる場合、その境界を証明義務として捉え、テストがそこを通過するようにする
71
72
 
72
73
  2. **テストレベルを分類**:
73
74
  - 統合テスト候補(機能レベルの相互作用)
@@ -192,7 +193,7 @@ describe('[機能名] Integration Test', () => {
192
193
 
193
194
  **証明注釈**(すべてのスケルトンに、上記メタ情報とともに付与): 各 `it.todo` は証明コントラクトをテスト実装者と integration-test-reviewer に渡す2行のコメントを持つ(これらは task template の Proof Obligations フィールドに対応する):
194
195
  - `主要な故障モード`: このテストをレッドにする具体的なリグレッション — ACが約束し、壊れると失われる振る舞い
195
- - `証明義務`: 実装されたテストが主張を証明するためにアサートすべき内容 — 通過する境界、状態変更を伴うACでは操作前後の観測可能な状態、どの境界をなぜモックしてよいか。アサート対象を記述する設計意図として書き、実行可能なアサーションとモック設定は実装者が書く
196
+ - `証明義務`: 実装されたテストが主張を証明するためにアサートすべき内容 — 通過する境界、状態変更を伴うACでは操作前後の観測可能な状態、どの境界をなぜモックしてよいか。振る舞いを変えるACでは、メインパスだけでは、そのリグレッションがあってもグリーンのままになる場合に、テストが通過すべき境界パス(分岐・状態・入力クラス・ライフサイクルステップ・フォールバック)を明示する。アサート対象を記述する設計意図として書き、実行可能なアサーションとモック設定は実装者が書く
196
197
 
197
198
  ### E2Eテストファイル群
198
199
 
@@ -62,6 +62,9 @@ Step 1で抽出した各受入条件について:
62
62
  - ステータスを判定: fulfilled / partially fulfilled / unfulfilled
63
63
  - ファイルパスと関連コード箇所を記録
64
64
  - Design Doc仕様からの逸脱を記録
65
+ - 振る舞いを変えるACでは、エビデンスがメインパスだけでなく境界パスもカバーしていることを確認する。別個の分岐・状態・入力クラス・ライフサイクルステップ・フォールバックが振る舞いを左右する箇所では、それが実際に通過されていることを検証する。参照元(source)/参照先の振る舞いと実装された振る舞いを同一粒度で比較し、境界次元における根拠のない変更は `dd_violation` とする
66
+ - 実装が AC・Design Doc・参照資料が明示的に要求する中核メカニズムを保持していることを確認し、出所となる文言を引用する。テストは通るが要求された中核メカニズムを落とす単純な代替は `dd_violation` とする
67
+ - 永続化・共有・外部から観測可能な状態への変更では、公開境界(新しい状態が別プロセス・コンポーネント・ユーザー・後続ステップから観測可能になる箇所)を特定する。部分的・未初期化・stale・ロールバックのみでありながら完了として観測可能な状態は `reliability` の検出事項とする。下流の利用者が不完全な状態を完了とみなして失敗しうるためである
65
68
 
66
69
  #### 2-2. 識別子の検証
67
70
 
@@ -94,6 +94,12 @@ package.json の `packageManager` フィールドに従って実行コマンド
94
94
  - 一致したのが (a+c) または (b+c) の組み合わせのみ → エスカレーション。その他の2項目組み合わせ → 継続実装
95
95
  - 1項目以下一致 → 継続実装
96
96
 
97
+ ### Step4: 中核メカニズム保全チェック(以下1つでもYES → 即エスカレーション)
98
+ タスク・AC・Design Doc・UI Spec が要求する中核メカニズムを保全する。実装詳細(変数名、内部のロジック順序、ローカルな構造)は自由に変更してよいが、要求された中核メカニズムそのものは保つ。
99
+ □ 要求された中核メカニズムを、より単純または弱い代替で置き換えようとしている?(テストが通ることは代替を正当化しない)
100
+ □ 要求された中核メカニズムが仕様どおりには実現不可能?
101
+ 1つでもYES → 実装を中止し、`escalation_type: "design_compliance_violation"` でエスカレーション(エスカレーションレスポンス表に従い、ケースを契約フィールドに対応づける): `design_doc_expectation` = 要求された中核メカニズムと、その出所となる文言(task/AC/Design Doc/UI Spec); `actual_situation` = 提案された代替と、結果として生じる振る舞いの差分; `why_cannot_implement` = 中核メカニズムを置き換えた、または仕様どおりに実現できない理由; `attempted_approaches[]` = 中核メカニズムを保全するために試みた方法。実装前に実現不可能と判明している場合は `[]`; `claude_recommendation` = ブロックを解除する条件。
102
+
97
103
  ### 境界ケースと鉄則
98
104
 
99
105
  | ケース | 継続 | エスカレーション |
@@ -105,7 +111,7 @@ package.json の `packageManager` フィールドに従って実行コマンド
105
111
 
106
112
  **鉄則 — 客観的に判定不可のときはエスカレーション**: 判定項目について2通り以上の解釈が成り立つ; 過去の実装経験で遭遇していないパターン; 判定に必要な情報がDesign Docにない; 同等の技術者でも判断が分かれる。
107
113
 
108
- ### 継続実装可(Step1-3 の全チェックが NO かつ明確に該当)
114
+ ### 継続実装可(Step1-4 の全チェックが NO かつ明確に該当)
109
115
  内部詳細の最適化(変数名、ロジック順序); Design Doc 未記載の詳細仕様; 外部 API レスポンス用の `unknown` → 具体型への安全な型ガード; 軽微なUI・メッセージ文言調整。
110
116
 
111
117
  ## 責務・権限・境界
@@ -94,6 +94,12 @@ package.json の `packageManager` フィールドに従って実行コマンド
94
94
  - 一致したのが (a+c) または (b+c) の組み合わせのみ → エスカレーション。その他の2項目組み合わせ → 継続実装
95
95
  - 1項目以下一致 → 継続実装
96
96
 
97
+ ### Step4: 中核メカニズム保全チェック(以下1つでもYES → 即エスカレーション)
98
+ タスク・AC・Design Doc・参照資料が要求する中核メカニズムを保全する。実装詳細(変数名、内部の処理順序、ローカルな構造)は自由に変更してよいが、要求された中核メカニズムそのものは保つ。
99
+ □ 要求された中核メカニズムを、より単純または弱い代替で置き換えようとしている?(テストが通ることは代替を正当化しない)
100
+ □ 要求された中核メカニズムが仕様どおりには実現不可能?
101
+ 1つでもYES → 実装を中止し、`escalation_type: "design_compliance_violation"` でエスカレーション(エスカレーションレスポンス表に従い、ケースを契約フィールドに対応づける): `design_doc_expectation` = 要求された中核メカニズムと、その出所となる文言(task/AC/Design Doc/参照資料); `actual_situation` = 提案された代替と、結果として生じる振る舞いの差分; `why_cannot_implement` = 中核メカニズムを置き換えた、または仕様どおりに実現できない理由; `attempted_approaches[]` = 中核メカニズムを保全するために試みた方法。実装前に実現不可能と判明している場合は `[]`; `claude_recommendation` = ブロックを解除する条件。
102
+
97
103
  ### 境界ケースと鉄則
98
104
 
99
105
  | ケース | 継続 | エスカレーション |
@@ -105,7 +111,7 @@ package.json の `packageManager` フィールドに従って実行コマンド
105
111
 
106
112
  **鉄則 — 客観的に判定不可のときはエスカレーション**: 判定項目について2通り以上の解釈が成り立つ; 過去の実装経験で遭遇していないパターン; 判定に必要な情報がDesign Docにない; 同等の技術者でも判断が分かれる。
107
113
 
108
- ### 継続実装可(Step1-3 の全チェックが NO かつ明確に該当)
114
+ ### 継続実装可(Step1-4 の全チェックが NO かつ明確に該当)
109
115
  内部詳細の最適化(変数名、処理順序); Design Doc 未記載の詳細仕様; `unknown` → 具体型への安全な型ガード; 軽微なUI・メッセージ文言調整。
110
116
 
111
117
  ## 責務・権限・境界
@@ -30,29 +30,7 @@ ADR/Design Docの作成閾値はdocumentation-criteriaスキルに準拠。判
30
30
 
31
31
  ### ゲート順序 [BLOCKING]
32
32
 
33
- 以下のサブセクションは並列の必須事項ではなく、4段階の直列ゲートを構成する。各ゲートを完了してから次のゲートに進むこと。各ゲート内では列挙されたサブセクションすべてが必須(各サブセクションの条件に従う)。
34
-
35
- **Gate 0 — Inputs and Standards**(上流依存なし):
36
- - Agreement Checklist
37
- - Standards Identification
38
-
39
- **Gate 1 — Existing State Analysis**(Gate 0 に依存):
40
- - Existing Code Investigation
41
- - Fact Disposition(Codebase Analysis 入力が提供される場合)
42
- - Minimal Surface Alternatives(永続化されるクライアント/サーバー状態、所有境界を越える Props またはフィールド — エクスポートされた再利用可能コンポーネントの公開 API Props、Context 値、所有境界を越えて持ち上げられた状態 — 観測可能な振る舞いを変える振る舞いモード/バリアント、または再利用可能なコンポーネント分割を導入する場合)
43
-
44
- **Gate 2 — Design Decisions**(Gate 1 に依存):
45
- - Implementation Approach Decision
46
- - Common ADR Process
47
- - Data Contracts
48
- - State Transitions(該当する場合)
49
-
50
- **Gate 3 — Impact Documentation**(Gate 2 に依存):
51
- - Integration Point Analysis
52
- - Change Impact Map
53
- - Interface Change Impact Analysis
54
-
55
- 各サブセクションには見出しに `[Gate N — ...]` の注記を付す。サブセクションはゲート順(Gate 0 → 1 → 2 → 3)で記載されており、文書順に実行すること。
33
+ 以下のサブセクションは並列の必須事項ではなく、4段階の直列ゲートを構成する: **Gate 0** Inputs & Standards → **Gate 1** Existing-State Analysis → **Gate 2** Design Decisions → **Gate 3** Impact Documentation。各ゲートを完了してから次のゲートに進むこと。各サブセクションには見出しに `[Gate N — ...]` の注記(適用条件を含む)が付き、ゲート順に記載されている。文書順に実行すること。
56
34
 
57
35
  ### 合意事項チェックリスト [Gate 0 — Required]
58
36
  Design Doc作成の最初に必ず実施:
@@ -331,31 +309,7 @@ UI Specが存在する場合(`docs/ui-spec/{feature-name}-ui-spec.md`):
331
309
 
332
310
  **必須**: ADR/Design Doc 内の実装サンプルは frontend-typescript-rules スキルに必ず準拠すること。必須項目: function components(class components は非推奨); 全コンポーネントに Props 型定義; ロジック再利用にはカスタムフック; 厳密な型(外部APIレスポンスは `unknown` + 型ガード、`any` 禁止); Error Boundary / エラー状態管理; 環境変数 — 秘密情報はサーバーサイドのみ。
333
311
 
334
- 準拠サンプル(Props型付き function component、`unknown` を型ガードする fetch のカスタムフック):
335
-
336
- ```typescript
337
- type ButtonProps = { label: string; onClick: () => void; disabled?: boolean }
338
- export function Button({ label, onClick, disabled = false }: ButtonProps) {
339
- return <button onClick={onClick} disabled={disabled}>{label}</button>
340
- }
341
-
342
- function useUserData(userId: string) {
343
- const [user, setUser] = useState<User | null>(null)
344
- const [error, setError] = useState<Error | null>(null)
345
- useEffect(() => {
346
- void (async () => {
347
- try {
348
- const data: unknown = await (await fetch(`/api/users/${userId}`)).json()
349
- if (!isUser(data)) throw new Error('Invalid user data')
350
- setUser(data)
351
- } catch (e) { setError(e instanceof Error ? e : new Error('Unknown error')) }
352
- })()
353
- }, [userId])
354
- return { user, error }
355
- }
356
- ```
357
-
358
- 非準拠: class components、`any`、ガードなし型なしレスポンス、クライアントサイドに埋め込まれた秘密情報。
312
+ 非準拠: class components(Error Boundary を除く)、`any`、ガードなし型なしレスポンス、クライアントサイドに埋め込まれた秘密情報。
359
313
 
360
314
  ## 図表作成(mermaid)
361
315
 
@@ -394,6 +348,14 @@ function useUserData(userId: string) {
394
348
 
395
349
  ## 受け入れ基準作成ガイドライン
396
350
 
351
+ ### 価値起点のドラフトと境界拡張
352
+
353
+ 各ACは価値起点でドラフトし、下記のスコーピングルールを適用する前に要件境界へ展開する:
354
+
355
+ 1. **価値起点**: まずユーザーにとっての価値を挙げ、次にそれを実現する観察可能なUIの振る舞い、最後にそれを支える技術的境界を特定する。
356
+ 2. **境界への展開**(候補抽出 — 採否は下記のスコーピングルールが決定): ある振る舞いはハッピーパスでは成立しつつ、別の状態で退行しうる。振る舞いを変えるACごとに、約束した振る舞いが成立すべき箇所すべてでACを検討する — 単一/最新/全件のリスト描画、隣接する Props やフィールド、ローディング/空/エラーおよび後続のインタラクション状態、stale または欠損データ、フェッチ失敗やフォールバックUI、権限/バリデーションのゲーティング、入力スコープと順序/選択、副作用、可視性やルートの境界(状態が別画面・別コンポーネント・ナビゲーション後に観察可能になる箇所)。
357
+ 3. **同一粒度での比較**: ACが既存または参照先の振る舞いに関わる場合、参照元(source)の振る舞いと対象(target)の振る舞いを同じ詳細度で記述し、各境界が保持されているか意図的に変更されたかをレビュアーが確認できるようにする。
358
+
397
359
  ### 自律実装のためのACスコーピング(フロントエンド)
398
360
 
399
361
  **原則**: AC = 隔離されたCI環境でブラウザ上で検証可能なユーザー観察可能動作。ハッピーパス、アンハッピーパス(エラー)、エッジケース(空状態・ローディング状態)をカバー。重要なACを上位に配置し、非機能要件は別セクションで定義する。
@@ -29,31 +29,7 @@ ADR/Design Docの作成閾値はdocumentation-criteriaスキルに準拠。判
29
29
 
30
30
  ### ゲート順序 [BLOCKING]
31
31
 
32
- 以下のサブセクションは並列の必須事項ではなく、4段階の直列ゲートを構成する。各ゲートを完了してから次のゲートに進むこと。各ゲート内では列挙されたサブセクションすべてが必須(各サブセクションの条件に従う)。
33
-
34
- **Gate 0 — Inputs and Standards**(上流依存なし):
35
- - Agreement Checklist
36
- - Standards Identification
37
-
38
- **Gate 1 — Existing State Analysis**(Gate 0 に依存):
39
- - Existing Code Investigation
40
- - Fact Disposition(Codebase Analysis 入力が提供される場合)
41
- - Data Representation Decision(新規または変更されるデータ構造を導入する場合)
42
- - Minimal Surface Alternatives(永続状態、公開コントラクト要素または境界を越えるフィールド、振る舞いモード/フラグ、再利用可能な抽象を導入する場合)
43
-
44
- **Gate 2 — Design Decisions**(Gate 1 に依存):
45
- - Implementation Approach Decision
46
- - Common ADR Process
47
- - Data Contracts
48
- - State Transitions(該当する場合)
49
-
50
- **Gate 3 — Impact Documentation**(Gate 2 に依存):
51
- - Integration Points
52
- - Change Impact Map
53
- - Field Propagation Map(フィールドがコンポーネント境界を越える場合)
54
- - Interface Change Impact Analysis
55
-
56
- 各サブセクションには見出しに `[Gate N — ...]` の注記を付す。サブセクションはゲート順(Gate 0 → 1 → 2 → 3)で記載されており、文書順に実行すること。
32
+ 以下のサブセクションは並列の必須事項ではなく、4段階の直列ゲートを構成する: **Gate 0** Inputs & Standards → **Gate 1** Existing-State Analysis → **Gate 2** Design Decisions → **Gate 3** Impact Documentation。各ゲートを完了してから次のゲートに進むこと。各サブセクションには見出しに `[Gate N — ...]` の注記(適用条件を含む)が付き、ゲート順に記載されている。文書順に実行すること。
57
33
 
58
34
  ### 合意事項チェックリスト [Gate 0 — Required]
59
35
  Design Doc作成の最初に必ず実施:
@@ -370,6 +346,14 @@ Design Doc作成時に必ず含める:
370
346
 
371
347
  ## 受け入れ基準作成ガイドライン
372
348
 
349
+ ### 価値起点のドラフトと境界拡張
350
+
351
+ 各ACは価値起点でドラフトし、下記のルールを適用する前に要件境界へ展開する:
352
+
353
+ 1. **価値起点**: まずユーザー/オペレーター/保守者にとっての価値を挙げ、次にそれを実現する観測可能な振る舞い、最後にそれを支える技術的境界を特定する。
354
+ 2. **境界への展開**(候補抽出 — 採否は下記ルールが決定): ある振る舞いはメインパスでは成立しつつ、別の次元で退行しうる。振る舞いを変えるACごとに、約束した振る舞いが成立すべき箇所すべてでACを検討する — 単一/最新/全件のコレクション、同一サーフェス上の隣接フィールド、後続のライフサイクル状態やリトライ、stale/欠損/空の値、リフレッシュ失敗やフォールバック不在、権限/バリデーション/ポリシーの境界、入力スコープと選択/順序/識別キー、副作用、公開・可視性の境界(状態が別プロセス・コンポーネント・ユーザー・後続ステップから観測可能になる箇所)。
355
+ 3. **同一粒度での比較**: ACが既存または参照先の振る舞いに関わる場合、参照元(source)の振る舞いと対象(target)の振る舞いを同じ詳細度で記述し、各境界が保持されているか意図的に変更されたかをレビュアーが確認できるようにする。
356
+
373
357
  ### 測定可能なACの書き方
374
358
 
375
359
  **原則**: AC = 独立した環境で検証可能かつユーザーが観測可能な振る舞い。正常系・異常系・エッジケースをカバー。非機能要件(パフォーマンス、信頼性、スケーラビリティ)は別の「非機能要件」セクションで定義する。
@@ -17,10 +17,10 @@ TypeScript-based React application implementation. Architecture patterns should
17
17
  - Properly implement default value settings and mandatory checks
18
18
 
19
19
  ```typescript
20
- // Build tool environment variables (public values only)
20
+ // Build tool environment variables (public values only; client-exposed vars need the VITE_ prefix)
21
21
  const config = {
22
- apiUrl: import.meta.env.API_URL || 'http://localhost:3000',
23
- appName: import.meta.env.APP_NAME || 'My App'
22
+ apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000',
23
+ appName: import.meta.env.VITE_APP_NAME || 'My App'
24
24
  }
25
25
 
26
26
  // Does not work in frontend
@@ -37,7 +37,7 @@ const apiUrl = process.env.API_URL
37
37
  **Correct Approach for Secrets**:
38
38
  ```typescript
39
39
  // Security risk: API key exposed in browser
40
- const apiKey = import.meta.env.API_KEY
40
+ const apiKey = import.meta.env.VITE_API_KEY
41
41
  const response = await fetch(`https://api.example.com/data?key=${apiKey}`)
42
42
 
43
43
  // Correct: Backend manages secrets, frontend accesses via proxy
@@ -5,132 +5,66 @@ description: Applies React/TypeScript type safety, component design, and state m
5
5
 
6
6
  # TypeScript Development Rules (Frontend)
7
7
 
8
- ## Frontend-Specific Anti-patterns
8
+ Frontend-specific React/TypeScript rules for implementation: thresholds, boundary type safety, component/state design, error handling, and project conventions.
9
9
 
10
- In addition to universal anti-patterns, watch for these Frontend-specific issues:
10
+ ## Anti-patterns and Thresholds
11
+ Signals that trigger a design change:
12
+ - Prop drilling through 3+ levels → lift to Context or state management
13
+ - Component over 300 lines → split
14
+ - Props count over 10 → split the component (3-7 is the working range)
15
+ - Optional props over 50% → introduce defaults or Context
16
+ - Props nesting deeper than 2 levels → flatten
17
+ - The same `as` assertion appearing 3+ times → revisit the type design
11
18
 
12
- - **Prop drilling through 3+ levels** - Should use Context API or state management
13
- - **Massive components (300+ lines)** - Split into smaller components
19
+ ## Type Safety at Boundaries
20
+ Prohibit `any`; when a type is unavailable, receive it as `unknown` and narrow with a type guard. Minimize `as` (justify with a comment when unavoidable).
14
21
 
15
- ## Type Safety in Frontend Implementation
22
+ Inside the app, React Props/State are type-guaranteed — no `unknown` needed. At every external boundary, receive as `unknown` and narrow with a type guard before use: API responses, `localStorage`/`sessionStorage`, URL parameters, parsed JSON. Controlled-component form input stays type-safe through React synthetic events.
16
23
 
17
- **Type Safety in Data Flow**
18
- - **Frontend -> Backend**: Props/State (Type Guaranteed) -> API Request (Serialization)
19
- - **Backend -> Frontend**: API Response (`unknown`) -> Type Guard -> State (Type Guaranteed)
20
-
21
- **Frontend-Specific Type Scenarios**:
22
- - **React Props/State**: TypeScript manages types, unknown unnecessary
23
- - **External API Responses**: Always receive as `unknown`, validate with type guards
24
- - **localStorage/sessionStorage**: Treat as `unknown`, validate
25
- - **URL Parameters**: Treat as `unknown`, validate
26
- - **Form Input (Controlled Components)**: Type-safe with React synthetic events
27
-
28
- **Type Complexity Management (Frontend)**
29
- - **Props Design**:
30
- - Props count: 3-7 props ideal (consider component splitting if exceeds 10)
31
- - Optional Props: 50% or less (consider default values or Context if excessive)
32
- - Nesting: Up to 2 levels (flatten deeper structures)
33
- - Type Assertions: Review design if used 3+ times
34
- - **External API Types**: Relax constraints and define according to reality (convert appropriately internally)
35
-
36
- ## Coding Conventions
37
-
38
- **Component Design Criteria**
39
- - **Function Components (Mandatory)**: Official React recommendation, optimizable by modern tooling
40
- - **Classes Prohibited**: Class components completely deprecated (Exception: Error Boundary)
41
- - **Custom Hooks**: Standard pattern for logic reuse
42
-
43
- **Function Design**
44
- - **0-2 parameters maximum**: Use object for 3+ parameters
45
- ```typescript
46
- // Object parameter
47
- function createUser({ name, email, role }: CreateUserParams) {}
48
- ```
49
-
50
- **Props Design (Props-driven Approach)**
51
- - Props are the interface: Define all necessary information as props
52
- - Avoid implicit dependencies: Do not depend on global state or context without necessity
53
- - Type-safe: Always define Props type explicitly
54
-
55
- **Environment Variables**
56
- - **Use build tool's environment variable system**: `process.env` does not work in browsers
57
- - **No secrets on client-side**: All frontend code is public, manage secrets in backend
58
-
59
- **Dependency Injection**
60
- - **Custom Hooks for dependency injection**: Ensure testability and modularity
61
-
62
- **Asynchronous Processing**
63
- - Promise Handling: Always use `async/await`
64
- - Error Handling: Always handle with `try-catch` or Error Boundary
65
- - Type Definition: Explicitly define return value types (e.g., `Promise<Result>`)
66
-
67
- **Format Rules**
68
- - Semicolon omission (follow Biome settings)
69
- - Types in `PascalCase`, variables/functions in `camelCase`
70
- - Imports use absolute paths (`src/`)
24
+ ```typescript
25
+ const raw: unknown = await (await fetch(url)).json()
26
+ if (!isUser(raw)) throw new ValidationError('invalid user')
27
+ const user = raw // narrowed to User
28
+ ```
71
29
 
72
- **Clean Code Principles**
73
- - Delete unused code immediately
74
- - Delete debug `console.log()`
75
- - No commented-out code (manage history with version control)
76
- - Comments explain "why" (not "what")
30
+ ## Component and State Design
31
+ - **Function components only.** Class components are allowed solely for Error Boundaries (no hook equivalent exists).
32
+ - **Type Props explicitly** with a named type and destructure: `function UserCard({ user, onSelect }: UserCardProps)`. Avoid `React.FC`; type props directly on the function so the props contract stays explicit.
33
+ - **Props-driven:** pass dependencies as props; reach into global state or Context only when needed.
34
+ - **Custom hooks** are the unit of logic reuse and dependency injection (inject collaborators through the hook for testability).
35
+ - **Function parameters:** 0-2 positional; for 3+ take a single options object.
36
+ - **State shape:** type state explicitly; for multi-field state with discrete transitions, use `useReducer` with a discriminated-union action type rather than many `useState` calls.
77
37
 
78
38
  ## Error Handling
39
+ - Surface every error: log and handle, or propagate — never swallow.
40
+ - **Fail fast:** on an invalid state, throw rather than returning a silent fallback.
41
+ - Represent expected failures as values with a `Result` type; reserve `throw` for unexpected/unrecoverable cases.
42
+ - Use purpose-specific error classes extending a base `AppError` carrying a `code` (e.g. ValidationError, ApiError, NotFoundError).
43
+ - **Layer responsibilities:** the API layer converts transport errors into domain errors; hooks propagate `AppError` upward; an Error Boundary catches render-time errors and shows fallback UI.
44
+ - Never log secrets (password, token, apiKey, creditCard).
79
45
 
80
- **Absolute Rule**: Error suppression prohibited. All errors must have log output and appropriate handling.
81
-
82
- **Fail-Fast Principle**: Fail quickly on errors to prevent continued processing in invalid states
83
- ```typescript
84
- // Prohibited: Unconditional fallback
85
- catch (error) {
86
- return defaultValue // Hides error
87
- }
88
-
89
- // Required: Explicit failure
90
- catch (error) {
91
- logger.error('Processing failed', error)
92
- throw error // Handle with Error Boundary or higher layer
93
- }
94
- ```
95
-
96
- **Result Type Pattern**: Express errors with types for explicit handling
97
46
  ```typescript
98
47
  type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
99
48
 
100
- // Example: Express error possibility with types
101
- function parseUser(data: unknown): Result<User, ValidationError> {
102
- if (!isValid(data)) return { ok: false, error: new ValidationError() }
103
- return { ok: true, value: data as User }
49
+ class AppError extends Error {
50
+ constructor(message: string, readonly code: string, readonly statusCode = 500) {
51
+ super(message); this.name = this.constructor.name
52
+ }
104
53
  }
105
54
  ```
106
55
 
107
- **Custom Error Classes**
56
+ Error Boundary — the one place a class component is required:
108
57
  ```typescript
109
- export class AppError extends Error {
110
- constructor(message: string, public readonly code: string, public readonly statusCode = 500) {
111
- super(message)
112
- this.name = this.constructor.name
113
- }
58
+ class ErrorBoundary extends React.Component<{ children: React.ReactNode; fallback: React.ReactNode }, { hasError: boolean }> {
59
+ state = { hasError: false }
60
+ static getDerivedStateFromError() { return { hasError: true } }
61
+ render() { return this.state.hasError ? this.props.fallback : this.props.children }
114
62
  }
115
- // Purpose-specific: ValidationError(400), ApiError(502), NotFoundError(404)
116
63
  ```
117
64
 
118
- **Layer-Specific Error Handling (React)**
119
- - Error Boundary: Catch React component errors, display fallback UI
120
- - Custom Hook: Detect business rule violations, propagate AppError as-is
121
- - API Layer: Convert fetch errors to domain errors
122
-
123
- **Structured Logging and Sensitive Information Protection**
124
- Never include sensitive information (password, token, apiKey, secret, creditCard) in logs
125
-
126
- **Asynchronous Error Handling in React**
127
- - Error Boundary setup mandatory: Catch rendering errors
128
- - Use try-catch with all async/await in event handlers
129
- - Always log and re-throw errors or display error state
130
-
131
- ## Performance Optimization
132
-
133
- - Component Memoization: Use React.memo for expensive components
134
- - State Optimization: Minimize re-renders with proper state structure
135
- - Lazy Loading: Use React.lazy and Suspense for code splitting
136
- - Bundle Size: Monitor with the `build` script and keep under 500KB
65
+ ## Project Conventions
66
+ - **Environment variables:** read through the build tool's env system (`process.env` is absent in the browser). Keep all secrets server-side — frontend code ships to the client.
67
+ - **Bundle & performance:** monitor with the `build` script, keep under 500KB; memoize expensive components (`React.memo`); code-split with `React.lazy` + `Suspense`; structure state to minimize re-renders.
68
+ - **Naming:** components/types `PascalCase`; variables/functions `camelCase`; hooks `use`-prefixed; constants `SCREAMING_SNAKE_CASE`.
69
+ - **Imports:** absolute paths from `src/`; order: React → external libs → internal (absolute) → internal (relative) → type-only → styles/assets.
70
+ - **Formatting:** follow Biome (semicolons and style come from project config).
@@ -140,8 +140,10 @@ describe('Button', () => {
140
140
 
141
141
  ## Test Design Patterns
142
142
 
143
+ Test user-visible results, not implementation details. Query by accessibility (`getByRole`/`getByLabelText`/`getByText`), not `getByTestId` or `container.querySelector`. Cover empty, error, and loading/async states, not only the happy path; await async UI with `findBy*`.
144
+
143
145
  ```typescript
144
- // Correct: test user-visible results
146
+ // Test the user-visible result
145
147
  it('increments count when clicked', async () => {
146
148
  const user = userEvent.setup()
147
149
  render(<Counter />)
@@ -149,10 +151,10 @@ it('increments count when clicked', async () => {
149
151
  expect(screen.getByText('Count: 1')).toBeInTheDocument()
150
152
  })
151
153
 
152
- // Avoid: testing implementation details
153
- it('calls setState', () => {
154
- const setState = vi.spyOn(React, 'useState')
155
- render(<Counter />)
156
- // ...
154
+ // Error state: override the handler for one test
155
+ it('shows an error message on API failure', async () => {
156
+ server.use(http.get('/api/users', () => new HttpResponse(null, { status: 500 })))
157
+ render(<UserList />)
158
+ expect(await screen.findByText('Something went wrong')).toBeInTheDocument()
157
159
  })
158
160
  ```
@@ -192,21 +192,19 @@ skills:
192
192
  # Frontend-specific Skills
193
193
  frontend-typescript-rules:
194
194
  skill: "frontend-typescript-rules"
195
- tags: [frontend, react, implementation, type-safety, function-components, props-driven, async, refactoring, coding-style]
196
- typical-use: "React component creation, Props type definitions, frontend TypeScript development"
195
+ tags: [frontend, react, implementation, type-safety, component-design, props-driven, hooks, error-handling, conventions]
196
+ typical-use: "React component creation, Props/state design, error handling, frontend TypeScript implementation rules"
197
197
  size: small
198
198
  key-references:
199
- - "React Function Components - React Official"
200
- - "Props-driven Design - React Best Practices"
201
- - "YAGNI Principle - Kent Beck"
202
- - "Clean Code - Robert C. Martin"
203
- - "TypeScript satisfies Operator - Microsoft"
199
+ - "React Function Components - React docs"
200
+ - "Type guards at external boundaries (unknown narrowing)"
201
+ - "Result type and Error Boundary error handling"
204
202
  sections:
205
- - "Frontend-Specific Anti-patterns"
206
- - "Type Safety in Frontend Implementation"
207
- - "Coding Conventions"
203
+ - "Anti-patterns and Thresholds"
204
+ - "Type Safety at Boundaries"
205
+ - "Component and State Design"
208
206
  - "Error Handling"
209
- - "Performance Optimization"
207
+ - "Project Conventions"
210
208
 
211
209
  frontend-typescript-testing:
212
210
  skill: "frontend-typescript-testing"
@@ -17,10 +17,10 @@ TypeScriptベースのReactアプリケーション実装。アーキテクチ
17
17
  - デフォルト値設定と必須チェックの適切な実装
18
18
 
19
19
  ```typescript
20
- // ビルドツールの環境変数(公開値のみ)
20
+ // ビルドツールの環境変数(公開値のみ。クライアント公開変数は VITE_ 接頭辞が必要)
21
21
  const config = {
22
- apiUrl: import.meta.env.API_URL || 'http://localhost:3000',
23
- appName: import.meta.env.APP_NAME || 'My App'
22
+ apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000',
23
+ appName: import.meta.env.VITE_APP_NAME || 'My App'
24
24
  }
25
25
 
26
26
  // フロントエンドでは動作しない
@@ -5,311 +5,66 @@ description: React/TypeScriptの型安全性、コンポーネント設計、状
5
5
 
6
6
  # TypeScript 開発ルール(フロントエンド)
7
7
 
8
- ## 型システム
8
+ 実装向けの frontend 固有 React/TypeScript ルール: しきい値、境界での型安全性、コンポーネント/状態の設計、エラーハンドリング、プロジェクト規約。
9
9
 
10
- ### 型安全性の原則
11
- - **strictモード必須**: tsconfig.jsonでstrict: trueを設定
12
- - **any型使用禁止**: コードベースでany型を使用しない
13
- - **as使用最小化**: 型キャストはやむを得ない場合のみ(理由をコメント)
14
- - **unknown優先**: any型が必要な場合はunknown + 型ガード
10
+ ## アンチパターンとしきい値
11
+ 設計変更を促すシグナル:
12
+ - prop drilling が 3 階層以上 → Context または状態管理へ持ち上げる
13
+ - コンポーネントが 300 行超 → 分割する
14
+ - Props 10 個超 → コンポーネントを分割(3〜7 個が適正範囲)
15
+ - optional Props が 50% 超 → デフォルト値または Context を導入する
16
+ - Props のネストが 2 階層超 → フラット化する
17
+ - 同一の `as` アサーションが 3 回以上出現 → 型設計を見直す
15
18
 
16
- ```typescript
17
- // 良い: 型ガード付きのunknown
18
- function processData(data: unknown): User {
19
- if (!isUser(data)) throw new Error('Invalid user data')
20
- return data
21
- }
22
-
23
- // 悪い: any型の使用
24
- function processData(data: any): User {
25
- return data as User
26
- }
27
- ```
28
-
29
- ### 型定義のベストプラクティス
30
-
31
- #### オブジェクト型
32
- - **interface優先**: 拡張可能なオブジェクト型にはinterfaceを使用
33
- - **typeはunion/intersection用**: 複合型やユーティリティ型に使用
34
- - **readonlyの活用**: 不変なプロパティにはreadonlyを明示
35
-
36
- ```typescript
37
- // 良い: 明確な型定義
38
- interface User {
39
- readonly id: string
40
- name: string
41
- email: string
42
- }
43
-
44
- type UserWithRole = User & { role: 'admin' | 'user' }
45
- ```
46
-
47
- #### 関数型
48
- - **戻り値型を明示**: 複雑なロジックを持つ関数
49
- - **ジェネリクスの活用**: 再利用可能な型安全な関数
50
-
51
- ```typescript
52
- // 良い: 戻り値型を明示
53
- function calculateTotal(items: CartItem[]): number {
54
- return items.reduce((sum, item) => sum + item.price, 0)
55
- }
56
-
57
- // 良い: ジェネリクスの活用
58
- function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
59
- // implementation
60
- }
61
- ```
62
-
63
- ## Reactコンポーネント設計
64
-
65
- ### Function Components必須
66
-
67
- ```typescript
68
- // 良い: Function Component
69
- const UserCard: React.FC<UserCardProps> = ({ user, onSelect }) => {
70
- return (
71
- <div onClick={() => onSelect(user.id)}>
72
- {user.name}
73
- </div>
74
- )
75
- }
76
-
77
- // 悪い: Class Component(非推奨)
78
- class UserCard extends React.Component<UserCardProps> { }
79
- ```
19
+ ## 境界での型安全性
20
+ `any` を禁止する。型が得られない場合は `unknown` で受けて型ガードで絞り込む。`as` は最小化する(やむを得ない場合は理由をコメント)。
80
21
 
81
- ### Props型定義
22
+ アプリ内部では React の Props/State は型保証されており `unknown` は不要。外部境界では必ず `unknown` で受け、使用前に型ガードで絞り込む: API レスポンス、`localStorage`/`sessionStorage`、URL パラメータ、パースした JSON。制御コンポーネントのフォーム入力は React 合成イベントを通じて型安全に保たれる。
82
23
 
83
24
  ```typescript
84
- interface ButtonProps {
85
- label: string
86
- onClick: () => void
87
- variant?: 'primary' | 'secondary'
88
- disabled?: boolean
89
- }
90
-
91
- const Button: React.FC<ButtonProps> = ({
92
- label,
93
- onClick,
94
- variant = 'primary',
95
- disabled = false
96
- }) => {
97
- // implementation
98
- }
99
- ```
100
-
101
- ### Children Props
102
-
103
- ```typescript
104
- interface LayoutProps {
105
- children: React.ReactNode
106
- sidebar?: React.ReactNode
107
- }
108
-
109
- const Layout: React.FC<LayoutProps> = ({ children, sidebar }) => (
110
- <div>
111
- <main>{children}</main>
112
- {sidebar && <aside>{sidebar}</aside>}
113
- </div>
114
- )
115
- ```
116
-
117
- ## 状態管理
118
-
119
- ### useState型定義
120
-
121
- ```typescript
122
- // 良い: 明示的な型
123
- const [user, setUser] = useState<User | null>(null)
124
- const [items, setItems] = useState<Item[]>([])
125
-
126
- // 良い: 初期値から推論可能な場合
127
- const [count, setCount] = useState(0)
128
- ```
129
-
130
- ### useReducerの型安全性
131
-
132
- ```typescript
133
- type Action =
134
- | { type: 'SET_USER'; payload: User }
135
- | { type: 'CLEAR_USER' }
136
- | { type: 'SET_ERROR'; payload: string }
137
-
138
- interface State {
139
- user: User | null
140
- error: string | null
141
- }
142
-
143
- const reducer = (state: State, action: Action): State => {
144
- switch (action.type) {
145
- case 'SET_USER':
146
- return { ...state, user: action.payload, error: null }
147
- case 'CLEAR_USER':
148
- return { ...state, user: null }
149
- case 'SET_ERROR':
150
- return { ...state, error: action.payload }
151
- }
152
- }
25
+ const raw: unknown = await (await fetch(url)).json()
26
+ if (!isUser(raw)) throw new ValidationError('invalid user')
27
+ const user = raw // User に絞り込み済み
153
28
  ```
154
29
 
155
- ### Custom Hooks
156
-
157
- ```typescript
158
- interface UseUserReturn {
159
- user: User | null
160
- loading: boolean
161
- error: Error | null
162
- refetch: () => Promise<void>
163
- }
164
-
165
- function useUser(userId: string): UseUserReturn {
166
- const [user, setUser] = useState<User | null>(null)
167
- const [loading, setLoading] = useState(true)
168
- const [error, setError] = useState<Error | null>(null)
169
-
170
- const refetch = useCallback(async () => {
171
- setLoading(true)
172
- try {
173
- const data = await fetchUser(userId)
174
- setUser(data)
175
- } catch (e) {
176
- setError(e instanceof Error ? e : new Error('Unknown error'))
177
- } finally {
178
- setLoading(false)
179
- }
180
- }, [userId])
181
-
182
- useEffect(() => { refetch() }, [refetch])
183
-
184
- return { user, loading, error, refetch }
185
- }
186
- ```
30
+ ## コンポーネントと状態の設計
31
+ - **Function component のみ。** class component は Error Boundary に限り許可(hook の代替が存在しないため)。
32
+ - **Props は名前付き型で明示**し分割代入する: `function UserCard({ user, onSelect }: UserCardProps)`。`React.FC` は使わず、props を関数に直接型付けして Props 契約を明示する。
33
+ - **Props 駆動:** 依存は Props で渡す。グローバル状態や Context へは必要なときだけアクセスする。
34
+ - **Custom hook** をロジック再利用と依存注入の単位とする(テスト容易性のため、協調オブジェクトは hook 経由で注入する)。
35
+ - **関数引数:** 位置引数は 0〜2 個。3 個以上は単一の options オブジェクトで受ける。
36
+ - **状態の形:** 状態は明示的に型付けする。複数フィールドかつ離散的な遷移を持つ状態は、複数の `useState` ではなく discriminated union の action 型を用いた `useReducer` にする。
187
37
 
188
38
  ## エラーハンドリング
189
-
190
- ### Error Boundary
39
+ - すべてのエラーを表に出す: ログして処理するか伝播する — 握り潰さない。
40
+ - **Fail fast:** 不正な状態では、無言のフォールバックを返さず throw する。
41
+ - 想定内の失敗は `Result` 型で値として表現する。`throw` は想定外/回復不能なケースに限る。
42
+ - 目的別のエラークラスは `code` を持つ基底 `AppError` を継承する(例: ValidationError, ApiError, NotFoundError)。
43
+ - **層の責務:** API 層は transport エラーをドメインエラーへ変換する。hook は `AppError` を上位へ伝播する。Error Boundary はレンダリング時のエラーを捕捉しフォールバック UI を表示する。
44
+ - 機微情報(password, token, apiKey, creditCard)をログに出さない。
191
45
 
192
46
  ```typescript
193
- interface ErrorBoundaryProps {
194
- children: React.ReactNode
195
- fallback: React.ReactNode
196
- }
197
-
198
- interface ErrorBoundaryState {
199
- hasError: boolean
200
- }
47
+ type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
201
48
 
202
- class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
203
- state = { hasError: false }
204
-
205
- static getDerivedStateFromError(): ErrorBoundaryState {
206
- return { hasError: true }
207
- }
208
-
209
- render() {
210
- if (this.state.hasError) return this.props.fallback
211
- return this.props.children
49
+ class AppError extends Error {
50
+ constructor(message: string, readonly code: string, readonly statusCode = 500) {
51
+ super(message); this.name = this.constructor.name
212
52
  }
213
53
  }
214
54
  ```
215
55
 
216
- ### APIエラーハンドリング
217
-
56
+ Error Boundary — class component が必要となる唯一の箇所:
218
57
  ```typescript
219
- interface ApiError {
220
- code: string
221
- message: string
222
- details?: Record<string, string>
223
- }
224
-
225
- function isApiError(error: unknown): error is ApiError {
226
- return (
227
- typeof error === 'object' &&
228
- error !== null &&
229
- 'code' in error &&
230
- 'message' in error
231
- )
232
- }
233
-
234
- async function fetchWithErrorHandling<T>(url: string): Promise<T> {
235
- const response = await fetch(url)
236
-
237
- if (!response.ok) {
238
- const error: unknown = await response.json()
239
- if (isApiError(error)) {
240
- throw new ApiError(error.code, error.message)
241
- }
242
- throw new Error('Unknown API error')
243
- }
244
-
245
- return response.json() as Promise<T>
246
- }
247
- ```
248
-
249
- ## イベントハンドリング
250
-
251
- ### イベント型
252
-
253
- ```typescript
254
- const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
255
- e.preventDefault()
256
- // handle click
257
- }
258
-
259
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
260
- const value = e.target.value
261
- // handle change
262
- }
263
-
264
- const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
265
- e.preventDefault()
266
- // handle submit
58
+ class ErrorBoundary extends React.Component<{ children: React.ReactNode; fallback: React.ReactNode }, { hasError: boolean }> {
59
+ state = { hasError: false }
60
+ static getDerivedStateFromError() { return { hasError: true } }
61
+ render() { return this.state.hasError ? this.props.fallback : this.props.children }
267
62
  }
268
63
  ```
269
64
 
270
- ## コーディング規約
271
-
272
- ### 命名規則
273
- - **コンポーネント**: PascalCase(例: `UserProfile`)
274
- - **フック**: camelCase + use接頭辞(例: `useUserData`)
275
- - **型/インターフェース**: PascalCase(例: `UserProps`)
276
- - **定数**: SCREAMING_SNAKE_CASE(例: `MAX_RETRY_COUNT`)
277
- - **ファイル名**: コンポーネントはPascalCase、その他はcamelCase
278
-
279
- ### インポート順序
280
- 1. React関連
281
- 2. 外部ライブラリ
282
- 3. 内部モジュール(絶対パス)
283
- 4. 内部モジュール(相対パス)
284
- 5. 型のみのインポート
285
- 6. スタイル/アセット
286
-
287
- ```typescript
288
- import { useState, useEffect } from 'react'
289
- import { useQuery } from '@tanstack/react-query'
290
- import { api } from '@/lib/api'
291
- import { formatDate } from '../utils'
292
- import type { User } from '@/types'
293
- import styles from './Component.module.css'
294
- ```
295
-
296
- ## アンチパターン
297
-
298
- ### 避けるべきパターン
299
-
300
- ```typescript
301
- // 悪い: Propsのスプレッド展開
302
- const Button = (props: ButtonProps) => <button {...props} />
303
-
304
- // 良い: 明示的なPropsの受け渡し
305
- const Button = ({ label, onClick, disabled }: ButtonProps) => (
306
- <button onClick={onClick} disabled={disabled}>{label}</button>
307
- )
308
-
309
- // 悪い: インラインでの複雑なロジック
310
- {items.filter(i => i.active).map(i => <Item key={i.id} {...i} />)}
311
-
312
- // 良い: 事前に変数として抽出
313
- const activeItems = items.filter(item => item.active)
314
- {activeItems.map(item => <Item key={item.id} item={item} />)}
315
- ```
65
+ ## プロジェクト規約
66
+ - **環境変数:** ビルドツールの環境変数システム経由で読む(ブラウザに `process.env` は存在しない)。秘密情報はすべてサーバーサイドに置く — フロントエンドのコードはクライアントに配信される。
67
+ - **バンドルとパフォーマンス:** `build` スクリプトで監視し 500KB 未満に保つ。高コストなコンポーネントは `React.memo` でメモ化する。`React.lazy` + `Suspense` でコード分割する。再レンダリングを最小化する状態構造にする。
68
+ - **命名:** コンポーネント/型は `PascalCase`、変数/関数は `camelCase`、hook は `use` 接頭辞、定数は `SCREAMING_SNAKE_CASE`。
69
+ - **インポート:** `src/` からの絶対パス。順序: React → 外部ライブラリ → 内部(絶対)→ 内部(相対)→ 型のみ → スタイル/アセット。
70
+ - **フォーマット:** Biome に従う(セミコロンやスタイルはプロジェクト設定に従う)。
@@ -5,6 +5,13 @@ description: React Testing Library、MSW、Playwright E2Eでテストを設計
5
5
 
6
6
  # TypeScript テストルール(フロントエンド)
7
7
 
8
+ ## 参照
9
+
10
+ | テスト種別 | 参照先 | 用途 |
11
+ |-----------|--------|------|
12
+ | **ユニット / 統合** | 本ドキュメント | RTL + Vitest + MSW での React コンポーネントテスト |
13
+ | **E2E** | [references/e2e.md](references/e2e.md) | Playwright によるブラウザレベル E2E テスト |
14
+
8
15
  ## テストフレームワーク
9
16
  - **Vitest**: このプロジェクトではVitestを使用
10
17
  - **React Testing Library**: コンポーネントテスト用
@@ -131,75 +138,12 @@ describe('Button', () => {
131
138
  })
132
139
  ```
133
140
 
134
- ## テスト品質基準
135
-
136
- ### 境界値・異常系の網羅
137
- 正常系に加え、境界値と異常系を含める。
138
- ```typescript
139
- it('renders empty state for empty array', () => {
140
- render(<UserList users={[]} />)
141
- expect(screen.getByText('ユーザーがいません')).toBeInTheDocument()
142
- })
143
-
144
- it('displays error message on API failure', async () => {
145
- server.use(rest.get('/api/users', (req, res, ctx) => res(ctx.status(500))))
146
- render(<UserList />)
147
- expect(await screen.findByText('エラーが発生しました')).toBeInTheDocument()
148
- })
149
- ```
150
-
151
- ### ユーザー中心のクエリ
152
-
153
- ```typescript
154
- // 良い: アクセシブルなクエリ
155
- screen.getByRole('button', { name: 'Submit' })
156
- screen.getByLabelText('Email')
157
- screen.getByText('Welcome')
158
-
159
- // 悪い: 実装詳細への依存
160
- screen.getByTestId('submit-btn')
161
- container.querySelector('.btn-primary')
162
- ```
163
-
164
- ### 非同期処理のテスト
165
-
166
- ```typescript
167
- it('loads and displays user data', async () => {
168
- render(<UserProfile userId="1" />)
169
-
170
- // ローディング状態を確認
171
- expect(screen.getByText('Loading...')).toBeInTheDocument()
172
-
173
- // データ表示を待機
174
- expect(await screen.findByText('John Doe')).toBeInTheDocument()
175
-
176
- // ローディングが消えていることを確認
177
- expect(screen.queryByText('Loading...')).not.toBeInTheDocument()
178
- })
179
- ```
180
-
181
- ### フォームテスト
182
-
183
- ```typescript
184
- it('submits form with valid data', async () => {
185
- const onSubmit = vi.fn()
186
- render(<LoginForm onSubmit={onSubmit} />)
187
-
188
- await userEvent.type(screen.getByLabelText('Email'), 'test@example.com')
189
- await userEvent.type(screen.getByLabelText('Password'), 'password123')
190
- await userEvent.click(screen.getByRole('button', { name: 'Login' }))
191
-
192
- expect(onSubmit).toHaveBeenCalledWith({
193
- email: 'test@example.com',
194
- password: 'password123'
195
- })
196
- })
197
- ```
198
-
199
141
  ## テスト設計パターン
200
142
 
143
+ 実装詳細ではなくユーザーから見える結果を検証する。クエリはアクセシビリティ優先(`getByRole`/`getByLabelText`/`getByText`)で、`getByTestId` や `container.querySelector` に依存しない。正常系だけでなく空・エラー・ローディング/非同期の状態も網羅し、非同期UIは `findBy*` で待機する。
144
+
201
145
  ```typescript
202
- // Correct: test user-visible results
146
+ // ユーザーから見える結果を検証
203
147
  it('increments count when clicked', async () => {
204
148
  const user = userEvent.setup()
205
149
  render(<Counter />)
@@ -207,10 +151,10 @@ it('increments count when clicked', async () => {
207
151
  expect(screen.getByText('Count: 1')).toBeInTheDocument()
208
152
  })
209
153
 
210
- // Avoid: testing implementation details
211
- it('calls setState', () => {
212
- const setState = vi.spyOn(React, 'useState')
213
- render(<Counter />)
214
- // ...
154
+ // エラー状態: 1テストだけハンドラを上書き
155
+ it('shows an error message on API failure', async () => {
156
+ server.use(http.get('/api/users', () => new HttpResponse(null, { status: 500 })))
157
+ render(<UserList />)
158
+ expect(await screen.findByText('エラーが発生しました')).toBeInTheDocument()
215
159
  })
216
160
  ```
@@ -183,20 +183,19 @@ skills:
183
183
  # フロントエンド固有スキル
184
184
  frontend-typescript-rules:
185
185
  skill: "frontend-typescript-rules"
186
- tags: [frontend, react, implementation, type-safety, props-driven, hooks, component-design, vite, error-boundary]
187
- typical-use: "React/Viteでのフロントエンド開発、コンポーネント設計、Props設計、環境変数管理"
186
+ tags: [frontend, react, implementation, type-safety, component-design, props-driven, hooks, error-handling, conventions]
187
+ typical-use: "Reactコンポーネント実装、Props/状態設計、エラーハンドリング、frontend TypeScript実装ルール"
188
188
  size: small
189
189
  key-references:
190
- - "React公式ドキュメント - Function Components"
191
- - "Props-driven開発 - React Patterns"
190
+ - "React Function Components - React docs"
191
+ - "Type guards at external boundaries (unknown narrowing)"
192
+ - "Result type and Error Boundary error handling"
192
193
  sections:
193
- - "型システム"
194
- - "Reactコンポーネント設計"
195
- - "状態管理"
194
+ - "アンチパターンとしきい値"
195
+ - "境界での型安全性"
196
+ - "コンポーネントと状態の設計"
196
197
  - "エラーハンドリング"
197
- - "イベントハンドリング"
198
- - "コーディング規約"
199
- - "アンチパターン"
198
+ - "プロジェクト規約"
200
199
 
201
200
  frontend-typescript-testing:
202
201
  skill: "frontend-typescript-testing"
@@ -209,12 +208,12 @@ skills:
209
208
  - "ADR-0002 Co-location原則"
210
209
  - "references/e2e.md - Playwright E2Eパターン"
211
210
  sections:
211
+ - "参照"
212
212
  - "テストフレームワーク"
213
213
  - "テストの基本方針"
214
214
  - "テストの実装規約"
215
215
  - "モックの型安全性の徹底"
216
216
  - "React Testing Libraryの基本例"
217
- - "テスト品質基準"
218
217
  - "テスト設計パターン"
219
218
 
220
219
  frontend-technical-spec:
package/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.23.3] - 2026-06-06
9
+
10
+ ### Added
11
+
12
+ - **Requirement-boundary fidelity gates** (agents) — Behavior changes are specified, proven, and verified at the requirement boundaries where regressions hide (a behavior can hold on the main path while regressing on a separate branch / state / input / lifecycle / fallback dimension). `technical-designer` / `-frontend` draft each AC value-first and expand it across requirement boundaries before scoping; `acceptance-test-generator` records a boundary-path proof obligation so the generated test traverses the path that would otherwise stay green through a regression; `task-executor` / `-frontend` add a Step 4 Core Mechanism Preservation Check that escalates `design_compliance_violation` when a required mechanism would be replaced by a weaker substitute or is infeasible; `code-reviewer` verifies boundary-path evidence, core-mechanism preservation, and publication-boundary state at AC verification
13
+
14
+ ### Changed
15
+
16
+ - **technical-designer prompt trimming** (agents) — Compressed the Gate Ordering section to a single serial-gate line, with gate membership and applicability conditions retained in each subsection's `[Gate N — ...]` heading; removed the inline React implementation sample from `technical-designer-frontend` in favor of the loaded `frontend-typescript-rules` skill
17
+ - **Frontend skill alignment across en/ja** (skills) — `frontend-typescript-rules` is a rules-first, self-contained rewrite (thresholds, boundary type safety, component/state rules, and `Result` / `AppError` / Error Boundary idioms; generic syntax examples and `React.FC` dropped); `frontend-typescript-testing` unifies the en/ja structure, routes E2E to `references/e2e.md`, and uses MSW v2 (`http` / `HttpResponse`); `frontend-technical-spec` uses the `VITE_` prefix for client-exposed environment variables
18
+
8
19
  ## [1.23.2] - 2026-06-01
9
20
 
10
21
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ai-project",
3
- "version": "1.23.2",
3
+ "version": "1.23.3",
4
4
  "packageManager": "npm@10.8.2",
5
5
  "description": "TypeScript boilerplate with skills and sub-agents for Claude Code. Prevents context exhaustion through role-based task splitting.",
6
6
  "keywords": [