@k2works/claude-code-booster 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +42 -42
  3. package/bin/claude-code-booster +79 -79
  4. package/lib/assets/.claude/README.md +162 -162
  5. package/lib/assets/.claude/SKILLS_TEMPLATE.md +100 -100
  6. package/lib/assets/.claude/scripts/generate-inception-deck.mjs +911 -1024
  7. package/lib/assets/.claude/settings.json +11 -11
  8. package/lib/assets/.claude/skills/ai-agent-guidelines/SKILL.md +119 -119
  9. package/lib/assets/.claude/skills/analyzing-architecture/SKILL.md +87 -87
  10. package/lib/assets/.claude/skills/analyzing-business/SKILL.md +117 -117
  11. package/lib/assets/.claude/skills/analyzing-data-model/SKILL.md +80 -80
  12. package/lib/assets/.claude/skills/analyzing-domain-model/SKILL.md +88 -88
  13. package/lib/assets/.claude/skills/analyzing-inception-deck/SKILL.md +137 -137
  14. package/lib/assets/.claude/skills/analyzing-non-functional/SKILL.md +91 -91
  15. package/lib/assets/.claude/skills/analyzing-operation/SKILL.md +91 -91
  16. package/lib/assets/.claude/skills/analyzing-requirements/SKILL.md +87 -87
  17. package/lib/assets/.claude/skills/analyzing-tech-stack/SKILL.md +102 -102
  18. package/lib/assets/.claude/skills/analyzing-test-strategy/SKILL.md +87 -87
  19. package/lib/assets/.claude/skills/analyzing-ui-design/SKILL.md +86 -86
  20. package/lib/assets/.claude/skills/analyzing-usecases/SKILL.md +87 -87
  21. package/lib/assets/.claude/skills/creating-adr/SKILL.md +115 -115
  22. package/lib/assets/.claude/skills/developing-backend/SKILL.md +106 -106
  23. package/lib/assets/.claude/skills/developing-frontend/SKILL.md +96 -96
  24. package/lib/assets/.claude/skills/developing-release/SKILL.md +154 -154
  25. package/lib/assets/.claude/skills/generating-slides/SKILL.md +136 -106
  26. package/lib/assets/.claude/skills/git-commit/SKILL.md +106 -106
  27. package/lib/assets/.claude/skills/killing-processes/SKILL.md +98 -98
  28. package/lib/assets/.claude/skills/managing-docs/SKILL.md +200 -200
  29. package/lib/assets/.claude/skills/managing-operations/DEPLOY.md +77 -77
  30. package/lib/assets/.claude/skills/managing-operations/SETUP_CSHARP.md +80 -80
  31. package/lib/assets/.claude/skills/managing-operations/SETUP_FRONTEND.md +84 -84
  32. package/lib/assets/.claude/skills/managing-operations/SETUP_JAVA.md +75 -75
  33. package/lib/assets/.claude/skills/managing-operations/SKILL.md +156 -156
  34. package/lib/assets/.claude/skills/orchestrating-analysis/SKILL.md +134 -134
  35. package/lib/assets/.claude/skills/orchestrating-development/SKILL.md +243 -243
  36. package/lib/assets/.claude/skills/orchestrating-project/SKILL.md +193 -193
  37. package/lib/assets/.claude/skills/planning-releases/SKILL.md +222 -222
  38. package/lib/assets/.claude/skills/syncing-github-project/SKILL.md +181 -69
  39. package/lib/assets/.claude/skills/tracking-progress/SKILL.md +164 -164
  40. package/lib/assets/.devcontainer/devcontainer.json +34 -34
  41. package/lib/assets/.env.example +17 -17
  42. package/lib/assets/.gitattributes +4 -4
  43. package/lib/assets/.github/workflows/docker-publish.yml +77 -77
  44. package/lib/assets/.github/workflows/mkdocs.yml +39 -39
  45. package/lib/assets/AGENTS.md +94 -94
  46. package/lib/assets/CLAUDE.md +162 -162
  47. package/lib/assets/README.md +269 -269
  48. package/lib/assets/docker-compose.yml +33 -33
  49. package/lib/assets/docs/assets/css/extra.css +29 -29
  50. package/lib/assets/docs/assets/js/extra.js +44 -44
  51. package/lib/assets/docs/index.md +14 -14
  52. package/lib/assets/docs/reference/CodexCLIMCP/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/351/226/213/347/231/272/343/203/225/343/203/255/343/203/274.md +532 -532
  53. package/lib/assets/docs/reference/CodexCLIMCP/343/202/265/343/203/274/343/203/220/343/203/274/350/250/255/345/256/232/346/211/213/351/240/206.md +341 -341
  54. package/lib/assets/docs/reference/Java/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +578 -578
  55. package/lib/assets/docs/reference/TypeScript/343/202/242/343/203/227/343/203/252/343/202/261/343/203/274/343/202/267/343/203/247/343/203/263/347/222/260/345/242/203/346/247/213/347/257/211/343/202/254/343/202/244/343/203/211.md +465 -465
  56. package/lib/assets/docs/reference/UI/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +448 -448
  57. package/lib/assets/docs/reference//343/202/210/343/201/204/343/202/275/343/203/225/343/203/210/343/202/246/343/202/247/343/202/242/343/201/250/343/201/257.md +242 -242
  58. package/lib/assets/docs/reference//343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +2216 -2216
  59. package/lib/assets/docs/reference//343/202/244/343/203/263/343/203/225/343/203/251/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +1878 -1878
  60. package/lib/assets/docs/reference//343/202/250/343/202/257/343/202/271/343/203/210/343/203/252/343/203/274/343/203/240/343/203/227/343/203/255/343/202/260/343/203/251/343/203/237/343/203/263/343/202/260.md +554 -554
  61. package/lib/assets/docs/reference//343/202/263/343/203/274/343/203/207/343/202/243/343/203/263/343/202/260/343/201/250/343/203/206/343/202/271/343/203/210/343/202/254/343/202/244/343/203/211.md +705 -705
  62. package/lib/assets/docs/reference//343/203/206/343/202/271/343/203/210/346/210/246/347/225/245/343/202/254/343/202/244/343/203/211.md +1313 -1313
  63. package/lib/assets/docs/reference//343/203/207/343/203/274/343/202/277/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +311 -311
  64. package/lib/assets/docs/reference//343/203/211/343/203/241/343/202/244/343/203/263/343/203/242/343/203/207/343/203/253/350/250/255/350/250/210/343/202/254/343/202/244/343/203/211.md +599 -599
  65. package/lib/assets/docs/reference//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243/345/210/206/346/236/220/343/202/254/343/202/244/343/203/211.md +528 -528
  66. package/lib/assets/docs/reference//343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271/344/275/234/346/210/220/343/202/254/343/202/244/343/203/211.md +682 -682
  67. package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/202/254/343/202/244/343/203/211.md +442 -442
  68. package/lib/assets/docs/reference//343/203/252/343/203/252/343/203/274/343/202/271/343/203/273/343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/350/250/210/347/224/273/343/202/254/343/202/244/343/203/211.md +558 -558
  69. package/lib/assets/docs/reference//347/222/260/345/242/203/345/244/211/346/225/260/347/256/241/347/220/206/343/202/254/343/202/244/343/203/211.md +663 -663
  70. package/lib/assets/docs/reference//350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1248 -1248
  71. package/lib/assets/docs/reference//351/201/213/347/224/250/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +392 -392
  72. package/lib/assets/docs/reference//351/226/213/347/231/272/343/202/254/343/202/244/343/203/211.md +235 -235
  73. package/lib/assets/docs/reference//351/235/236/346/251/237/350/203/275/350/246/201/344/273/266/345/256/232/347/276/251/343/202/254/343/202/244/343/203/211.md +1236 -1236
  74. package/lib/assets/docs/template/ADR.md +30 -30
  75. package/lib/assets/docs/template/README.md +50 -50
  76. package/lib/assets/docs/template//343/201/276/343/201/232/343/201/223/343/202/214/343/202/222/350/252/255/343/202/202/343/201/206/343/203/252/343/202/271/343/203/210.md +12 -12
  77. package/lib/assets/docs/template//343/202/244/343/203/206/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/345/256/214/344/272/206/345/240/261/345/221/212/346/233/270.md +58 -58
  78. package/lib/assets/docs/template//343/202/244/343/203/263/343/202/273/343/203/227/343/202/267/343/203/247/343/203/263/343/203/207/343/203/203/343/202/255.md +13 -13
  79. package/lib/assets/docs/template//343/203/223/343/202/270/343/203/215/343/202/271/343/202/242/343/203/274/343/202/255/343/203/206/343/202/257/343/203/201/343/203/243.md +379 -379
  80. package/lib/assets/docs/template//345/256/214/345/205/250/345/275/242/345/274/217/343/201/256/343/203/246/343/203/274/343/202/271/343/202/261/343/203/274/343/202/271.md +68 -68
  81. package/lib/assets/docs/template//350/246/201/344/273/266/345/256/232/347/276/251.md +669 -669
  82. package/lib/assets/docs/template//350/250/255/350/250/210.md +163 -163
  83. package/lib/assets/gulpfile.js +23 -23
  84. package/lib/assets/mkdocs.yml +65 -65
  85. package/lib/assets/ops/docker/mkdoc/Dockerfile +19 -19
  86. package/lib/assets/ops/scripts/journal.js +180 -180
  87. package/lib/assets/ops/scripts/mkdocs.js +82 -82
  88. package/lib/assets/ops/scripts/release.js +431 -431
  89. package/lib/assets/ops/scripts/ssh.js +190 -190
  90. package/lib/assets/ops/scripts/vault.js +299 -299
  91. package/lib/assets/package-lock.json +1653 -1653
  92. package/lib/assets/package.json +40 -40
  93. package/lib/gulpfile.js +37 -37
  94. package/package.json +41 -41
@@ -1,449 +1,449 @@
1
- # UI設計ガイド
2
-
3
- ## オブジェクト指向UI設計(OOUX)
4
-
5
- ### 基本理念
6
-
7
- オブジェクト指向UI設計は、ユーザーが操作する「オブジェクト」を中心にUIを設計することで、より直感的で理解しやすいユーザーエクスペリエンスを提供する設計手法です。
8
-
9
- ### 4つの主要原則
10
-
11
- #### 1. オブジェクトの特定
12
-
13
- - ユーザーがシステム内で操作する主要な「モノ」を特定
14
- - 名詞で表現できるもの(例:生徒、教員、部、イベント、文書、商品など)
15
- - ドメインモデルと密接に関連
16
-
17
- #### 2. オブジェクト間の関係の定義
18
- - 特定されたオブジェクトが互いにどのように関連しているかを明確化
19
- - 関係の種類:
20
- - 一対一(1:1)
21
- - 一対多(1:N)
22
- - 多対多(M:N)
23
- - 集約・コンポジション
24
-
25
- #### 3. オブジェクトのアクションの定義
26
- - 各オブジェクトに対してユーザーがどのような操作を実行できるかを定義
27
- - 基本的なCRUD操作:
28
- - Create(作成)
29
- - Read(読み取り)
30
- - Update(更新)
31
- - Delete(削除)
32
- - ドメイン固有のアクション
33
-
34
- #### 4. オブジェクトの属性の定義
35
- - 各オブジェクトがどのような情報(属性)を持っているかを定義
36
- - 表示すべき属性の優先順位
37
- - 編集可能な属性の範囲
38
-
39
- ## UI構造パターン
40
-
41
- ### コレクションビュー
42
- オブジェクトの一覧を表示するビューパターン
43
-
44
- ```plantuml
45
- @startuml
46
- package "コレクションビュー" {
47
- rectangle "検索・フィルタ" as search
48
- rectangle "新規作成ボタン" as create
49
- rectangle "アイテムリスト" as list {
50
- rectangle "アイテム1" as item1
51
- rectangle "アイテム2" as item2
52
- rectangle "アイテム3" as item3
53
- }
54
- }
55
-
56
- search --> list : フィルタリング
57
- create --> "シングルビュー" : 新規作成
58
- item1 --> "シングルビュー" : 詳細表示
59
- @enduml
60
- ```
61
-
62
- **特徴**:
63
-
64
- - 複数のオブジェクトを一覧表示
65
- - 検索・フィルタリング機能
66
- - 新規作成のエントリーポイント
67
- - 個別オブジェクトへの navigation
68
-
69
- ### シングルビュー
70
- 個別オブジェクトの詳細を表示するビューパターン
71
-
72
- ```plantuml
73
- @startuml
74
- package "シングルビュー" {
75
- rectangle "ヘッダー" as header {
76
- rectangle "タイトル" as title
77
- rectangle "アクションボタン" as actions
78
- }
79
- rectangle "メインコンテンツ" as main {
80
- rectangle "属性表示" as props
81
- rectangle "関連オブジェクト1" as related1
82
- rectangle "関連オブジェクト2" as related2
83
- }
84
- }
85
-
86
- actions --> "編集モード" : 編集
87
- actions --> "削除確認" : 削除
88
- related1 --> "関連オブジェクトビュー" : 詳細
89
- @enduml
90
- ```
91
-
92
- **特徴**:
93
-
94
- - 単一オブジェクトの詳細情報表示
95
- - 編集・削除などのアクション
96
- - 関連オブジェクトへのナビゲーション
97
- - モード切り替え(表示⇔編集)
98
-
99
- ## レイアウトパターン
100
-
101
- ### ナビゲーション配置
102
-
103
- #### 左サイドナビゲーション
104
- ```plantuml
105
- @startuml
106
- rectangle "アプリケーション" {
107
- rectangle "サイドナビ" as nav {
108
- rectangle "生徒"
109
- rectangle "教員"
110
- rectangle "組"
111
- rectangle "部"
112
- rectangle "イベント"
113
- }
114
- rectangle "メインコンテンツ" as content {
115
- rectangle "コレクション/シングルビュー"
116
- }
117
- }
118
-
119
- nav -right-> content : オブジェクト選択
120
- @enduml
121
- ```
122
-
123
- #### トップナビゲーション
124
- ```plantuml
125
- @startuml
126
- rectangle "アプリケーション" {
127
- rectangle "トップナビ" as nav {
128
- rectangle "生徒 | 教員 | 組 | 部 | イベント"
129
- }
130
- rectangle "メインコンテンツ" as content {
131
- rectangle "コレクション/シングルビュー"
132
- }
133
- }
134
-
135
- nav -down-> content : オブジェクト選択
136
- @enduml
137
- ```
138
-
139
- ### ビュー配置パターン
140
-
141
- #### 単一メインオブジェクト
142
- - 画面を2つのペインに分割
143
- - 左:コレクションビュー、右:シングルビュー
144
-
145
- #### タブ式切り替え
146
- - タブでコレクションビューとシングルビューを切り替え
147
-
148
- #### モーダル式
149
- - コレクションビューをベースに、シングルビューをモーダルで表示
150
-
151
- ## アクションパターン
152
-
153
- ### Create(作成)アクション
154
-
155
- #### ブランクパターン
156
- ```javascript
157
- // 空のフォームを表示して新規作成
158
- const createStudent = () => {
159
- return {
160
- id: null,
161
- name: '',
162
- class: '',
163
- clubs: [],
164
- relatedStudents: []
165
- };
166
- };
167
- ```
168
-
169
- #### テンプレートパターン
170
- ```javascript
171
- // デフォルト値を持つテンプレートから作成
172
- const createStudentFromTemplate = (template) => {
173
- return {
174
- ...template,
175
- id: generateNewId(),
176
- name: '',
177
- createdAt: new Date()
178
- };
179
- };
180
- ```
181
-
182
- ### Update(更新)アクション
183
-
184
- #### モードレスエディットパターン
185
- ```javascript
186
- // 同一画面で表示と編集を切り替え
187
- const toggleEditMode = (student, isEditing) => {
188
- if (isEditing) {
189
- return renderEditForm(student);
190
- } else {
191
- return renderDisplayView(student);
192
- }
193
- };
194
- ```
195
-
196
- #### インラインエディットパターン
197
- ```javascript
198
- // 項目ごとに直接編集可能
199
- const renderInlineEdit = (property, value) => {
200
- return `
201
- <div class="inline-edit" data-property="${property}">
202
- <span class="display">${value}</span>
203
- <input class="edit" value="${value}" style="display:none">
204
- </div>
205
- `;
206
- };
207
- ```
208
-
209
- ### Delete(削除)アクション
210
-
211
- #### モーダル確認パターン
212
- ```javascript
213
- const deleteWithConfirmation = (student) => {
214
- const confirmed = confirm(`${student.name}を削除しますか?`);
215
- if (confirmed) {
216
- deleteStudent(student.id);
217
- refreshView();
218
- }
219
- };
220
- ```
221
-
222
- #### ソフトデリートパターン
223
- ```javascript
224
- const softDelete = (student) => {
225
- student.deletedAt = new Date();
226
- student.isActive = false;
227
- updateStudent(student);
228
- };
229
- ```
230
-
231
- ## 実装ガイドライン
232
-
233
- ### コンポーネント設計
234
-
235
- #### 責任の分離
236
- ```javascript
237
- // ❌ 悪い例:すべてが混在
238
- const StudentComponent = () => {
239
- // データ取得、状態管理、UI描画がすべて混在
240
- };
241
-
242
- // ✅ 良い例:責任を分離
243
- const StudentContainer = () => {
244
- // データ取得と状態管理
245
- };
246
-
247
- const StudentView = ({ students, onAction }) => {
248
- // UI描画のみ
249
- };
250
- ```
251
-
252
- #### 状態管理パターン
253
- ```javascript
254
- // 状態の構造化
255
- const studentState = {
256
- collection: {
257
- items: [],
258
- loading: false,
259
- filter: '',
260
- sortBy: 'name'
261
- },
262
- selected: {
263
- item: null,
264
- mode: 'READ' // READ, EDIT, CREATE
265
- }
266
- };
267
- ```
268
-
269
- ### アクセシビリティ考慮事項
270
-
271
- #### キーボードナビゲーション
272
- ```javascript
273
- // フォーカス管理
274
- const handleKeyDown = (event) => {
275
- switch (event.key) {
276
- case 'Enter':
277
- selectItem();
278
- break;
279
- case 'Escape':
280
- cancelEdit();
281
- break;
282
- case 'ArrowDown':
283
- moveToNextItem();
284
- break;
285
- }
286
- };
287
- ```
288
-
289
- #### スクリーンリーダー対応
290
- ```html
291
- <!-- セマンティックなHTML構造 -->
292
- <main role="main">
293
- <section aria-label="学生一覧">
294
- <h1>学生</h1>
295
- <ul role="list">
296
- <li role="listitem" tabindex="0">
297
- <span aria-label="学生名">田中太郎</span>
298
- </li>
299
- </ul>
300
- </section>
301
- </main>
302
- ```
303
-
304
- ### パフォーマンス最適化
305
-
306
- #### 仮想化
307
- ```javascript
308
- // 大量データの表示最適化
309
- const VirtualizedList = ({ items, itemHeight = 50 }) => {
310
- const [scrollTop, setScrollTop] = useState(0);
311
- const containerHeight = 400;
312
-
313
- const visibleStart = Math.floor(scrollTop / itemHeight);
314
- const visibleEnd = Math.min(
315
- visibleStart + Math.ceil(containerHeight / itemHeight),
316
- items.length
317
- );
318
-
319
- return (
320
- <div style={{ height: containerHeight, overflow: 'auto' }}>
321
- {items.slice(visibleStart, visibleEnd).map(renderItem)}
322
- </div>
323
- );
324
- };
325
- ```
326
-
327
- #### 遅延読み込み
328
- ```javascript
329
- // 関連データの段階的読み込み
330
- const loadStudentDetails = async (studentId) => {
331
- const student = await fetchStudent(studentId);
332
- // 基本情報をまず表示
333
-
334
- const [clubs, relatedStudents] = await Promise.all([
335
- fetchStudentClubs(studentId),
336
- fetchRelatedStudents(studentId)
337
- ]);
338
- // 関連情報を後から追加
339
- };
340
- ```
341
-
342
- ## 品質保証
343
-
344
- ### テスト戦略
345
-
346
- #### ユニットテスト
347
- ```javascript
348
- describe('StudentComponent', () => {
349
- test('should display student list', () => {
350
- const students = [{ id: 1, name: '田中太郎' }];
351
- render(<StudentComponent students={students} />);
352
- expect(screen.getByText('田中太郎')).toBeInTheDocument();
353
- });
354
-
355
- test('should handle create action', () => {
356
- const onCreateMock = jest.fn();
357
- render(<StudentComponent onCreate={onCreateMock} />);
358
- fireEvent.click(screen.getByText('新規'));
359
- expect(onCreateMock).toHaveBeenCalled();
360
- });
361
- });
362
- ```
363
-
364
- #### 統合テスト
365
- ```javascript
366
- describe('Student CRUD flow', () => {
367
- test('should complete full CRUD cycle', async () => {
368
- // Create
369
- await createStudent({ name: '田中太郎' });
370
- expect(await findByText('田中太郎')).toBeInTheDocument();
371
-
372
- // Read
373
- fireEvent.click(await findByText('田中太郎'));
374
- expect(await findByText('詳細情報')).toBeInTheDocument();
375
-
376
- // Update
377
- fireEvent.click(await findByText('編集'));
378
- fireEvent.change(getByDisplayValue('田中太郎'), {
379
- target: { value: '田中次郎' }
380
- });
381
- fireEvent.click(await findByText('保存'));
382
- expect(await findByText('田中次郎')).toBeInTheDocument();
383
-
384
- // Delete
385
- fireEvent.click(await findByText('削除'));
386
- fireEvent.click(await findByText('確認'));
387
- expect(queryByText('田中次郎')).not.toBeInTheDocument();
388
- });
389
- });
390
- ```
391
-
392
- ### エラーハンドリング
393
-
394
- #### ユーザーフレンドリーなエラー表示
395
- ```javascript
396
- const ErrorBoundary = ({ children }) => {
397
- const [hasError, setHasError] = useState(false);
398
- const [error, setError] = useState(null);
399
-
400
- if (hasError) {
401
- return (
402
- <div className="error-container">
403
- <h2>申し訳ございません</h2>
404
- <p>予期しないエラーが発生しました。</p>
405
- <button onClick={() => window.location.reload()}>
406
- ページを再読み込み
407
- </button>
408
- </div>
409
- );
410
- }
411
-
412
- return children;
413
- };
414
- ```
415
-
416
- #### バリデーション
417
- ```javascript
418
- const validateStudent = (student) => {
419
- const errors = {};
420
-
421
- if (!student.name?.trim()) {
422
- errors.name = '名前は必須です';
423
- }
424
-
425
- if (student.name?.length > 100) {
426
- errors.name = '名前は100文字以内で入力してください';
427
- }
428
-
429
- if (!student.class) {
430
- errors.class = '組を選択してください';
431
- }
432
-
433
- return {
434
- isValid: Object.keys(errors).length === 0,
435
- errors
436
- };
437
- };
438
- ```
439
-
440
- ## まとめ
441
-
442
- オブジェクト指向UI設計は、ユーザーにとって直感的で理解しやすいインターフェースを構築するための強力な手法です。4つの主要原則に従って設計することで、一貫性があり、保守性の高いUIを実現できます。
443
-
444
- 重要なポイント:
445
- - オブジェクト中心の設計思考
446
- - コレクション・シングルビューの適切な使い分け
447
- - アクションパターンの統一
448
- - アクセシビリティとパフォーマンスの考慮
1
+ # UI設計ガイド
2
+
3
+ ## オブジェクト指向UI設計(OOUX)
4
+
5
+ ### 基本理念
6
+
7
+ オブジェクト指向UI設計は、ユーザーが操作する「オブジェクト」を中心にUIを設計することで、より直感的で理解しやすいユーザーエクスペリエンスを提供する設計手法です。
8
+
9
+ ### 4つの主要原則
10
+
11
+ #### 1. オブジェクトの特定
12
+
13
+ - ユーザーがシステム内で操作する主要な「モノ」を特定
14
+ - 名詞で表現できるもの(例:生徒、教員、部、イベント、文書、商品など)
15
+ - ドメインモデルと密接に関連
16
+
17
+ #### 2. オブジェクト間の関係の定義
18
+ - 特定されたオブジェクトが互いにどのように関連しているかを明確化
19
+ - 関係の種類:
20
+ - 一対一(1:1)
21
+ - 一対多(1:N)
22
+ - 多対多(M:N)
23
+ - 集約・コンポジション
24
+
25
+ #### 3. オブジェクトのアクションの定義
26
+ - 各オブジェクトに対してユーザーがどのような操作を実行できるかを定義
27
+ - 基本的なCRUD操作:
28
+ - Create(作成)
29
+ - Read(読み取り)
30
+ - Update(更新)
31
+ - Delete(削除)
32
+ - ドメイン固有のアクション
33
+
34
+ #### 4. オブジェクトの属性の定義
35
+ - 各オブジェクトがどのような情報(属性)を持っているかを定義
36
+ - 表示すべき属性の優先順位
37
+ - 編集可能な属性の範囲
38
+
39
+ ## UI構造パターン
40
+
41
+ ### コレクションビュー
42
+ オブジェクトの一覧を表示するビューパターン
43
+
44
+ ```plantuml
45
+ @startuml
46
+ package "コレクションビュー" {
47
+ rectangle "検索・フィルタ" as search
48
+ rectangle "新規作成ボタン" as create
49
+ rectangle "アイテムリスト" as list {
50
+ rectangle "アイテム1" as item1
51
+ rectangle "アイテム2" as item2
52
+ rectangle "アイテム3" as item3
53
+ }
54
+ }
55
+
56
+ search --> list : フィルタリング
57
+ create --> "シングルビュー" : 新規作成
58
+ item1 --> "シングルビュー" : 詳細表示
59
+ @enduml
60
+ ```
61
+
62
+ **特徴**:
63
+
64
+ - 複数のオブジェクトを一覧表示
65
+ - 検索・フィルタリング機能
66
+ - 新規作成のエントリーポイント
67
+ - 個別オブジェクトへの navigation
68
+
69
+ ### シングルビュー
70
+ 個別オブジェクトの詳細を表示するビューパターン
71
+
72
+ ```plantuml
73
+ @startuml
74
+ package "シングルビュー" {
75
+ rectangle "ヘッダー" as header {
76
+ rectangle "タイトル" as title
77
+ rectangle "アクションボタン" as actions
78
+ }
79
+ rectangle "メインコンテンツ" as main {
80
+ rectangle "属性表示" as props
81
+ rectangle "関連オブジェクト1" as related1
82
+ rectangle "関連オブジェクト2" as related2
83
+ }
84
+ }
85
+
86
+ actions --> "編集モード" : 編集
87
+ actions --> "削除確認" : 削除
88
+ related1 --> "関連オブジェクトビュー" : 詳細
89
+ @enduml
90
+ ```
91
+
92
+ **特徴**:
93
+
94
+ - 単一オブジェクトの詳細情報表示
95
+ - 編集・削除などのアクション
96
+ - 関連オブジェクトへのナビゲーション
97
+ - モード切り替え(表示⇔編集)
98
+
99
+ ## レイアウトパターン
100
+
101
+ ### ナビゲーション配置
102
+
103
+ #### 左サイドナビゲーション
104
+ ```plantuml
105
+ @startuml
106
+ rectangle "アプリケーション" {
107
+ rectangle "サイドナビ" as nav {
108
+ rectangle "生徒"
109
+ rectangle "教員"
110
+ rectangle "組"
111
+ rectangle "部"
112
+ rectangle "イベント"
113
+ }
114
+ rectangle "メインコンテンツ" as content {
115
+ rectangle "コレクション/シングルビュー"
116
+ }
117
+ }
118
+
119
+ nav -right-> content : オブジェクト選択
120
+ @enduml
121
+ ```
122
+
123
+ #### トップナビゲーション
124
+ ```plantuml
125
+ @startuml
126
+ rectangle "アプリケーション" {
127
+ rectangle "トップナビ" as nav {
128
+ rectangle "生徒 | 教員 | 組 | 部 | イベント"
129
+ }
130
+ rectangle "メインコンテンツ" as content {
131
+ rectangle "コレクション/シングルビュー"
132
+ }
133
+ }
134
+
135
+ nav -down-> content : オブジェクト選択
136
+ @enduml
137
+ ```
138
+
139
+ ### ビュー配置パターン
140
+
141
+ #### 単一メインオブジェクト
142
+ - 画面を2つのペインに分割
143
+ - 左:コレクションビュー、右:シングルビュー
144
+
145
+ #### タブ式切り替え
146
+ - タブでコレクションビューとシングルビューを切り替え
147
+
148
+ #### モーダル式
149
+ - コレクションビューをベースに、シングルビューをモーダルで表示
150
+
151
+ ## アクションパターン
152
+
153
+ ### Create(作成)アクション
154
+
155
+ #### ブランクパターン
156
+ ```javascript
157
+ // 空のフォームを表示して新規作成
158
+ const createStudent = () => {
159
+ return {
160
+ id: null,
161
+ name: '',
162
+ class: '',
163
+ clubs: [],
164
+ relatedStudents: []
165
+ };
166
+ };
167
+ ```
168
+
169
+ #### テンプレートパターン
170
+ ```javascript
171
+ // デフォルト値を持つテンプレートから作成
172
+ const createStudentFromTemplate = (template) => {
173
+ return {
174
+ ...template,
175
+ id: generateNewId(),
176
+ name: '',
177
+ createdAt: new Date()
178
+ };
179
+ };
180
+ ```
181
+
182
+ ### Update(更新)アクション
183
+
184
+ #### モードレスエディットパターン
185
+ ```javascript
186
+ // 同一画面で表示と編集を切り替え
187
+ const toggleEditMode = (student, isEditing) => {
188
+ if (isEditing) {
189
+ return renderEditForm(student);
190
+ } else {
191
+ return renderDisplayView(student);
192
+ }
193
+ };
194
+ ```
195
+
196
+ #### インラインエディットパターン
197
+ ```javascript
198
+ // 項目ごとに直接編集可能
199
+ const renderInlineEdit = (property, value) => {
200
+ return `
201
+ <div class="inline-edit" data-property="${property}">
202
+ <span class="display">${value}</span>
203
+ <input class="edit" value="${value}" style="display:none">
204
+ </div>
205
+ `;
206
+ };
207
+ ```
208
+
209
+ ### Delete(削除)アクション
210
+
211
+ #### モーダル確認パターン
212
+ ```javascript
213
+ const deleteWithConfirmation = (student) => {
214
+ const confirmed = confirm(`${student.name}を削除しますか?`);
215
+ if (confirmed) {
216
+ deleteStudent(student.id);
217
+ refreshView();
218
+ }
219
+ };
220
+ ```
221
+
222
+ #### ソフトデリートパターン
223
+ ```javascript
224
+ const softDelete = (student) => {
225
+ student.deletedAt = new Date();
226
+ student.isActive = false;
227
+ updateStudent(student);
228
+ };
229
+ ```
230
+
231
+ ## 実装ガイドライン
232
+
233
+ ### コンポーネント設計
234
+
235
+ #### 責任の分離
236
+ ```javascript
237
+ // ❌ 悪い例:すべてが混在
238
+ const StudentComponent = () => {
239
+ // データ取得、状態管理、UI描画がすべて混在
240
+ };
241
+
242
+ // ✅ 良い例:責任を分離
243
+ const StudentContainer = () => {
244
+ // データ取得と状態管理
245
+ };
246
+
247
+ const StudentView = ({ students, onAction }) => {
248
+ // UI描画のみ
249
+ };
250
+ ```
251
+
252
+ #### 状態管理パターン
253
+ ```javascript
254
+ // 状態の構造化
255
+ const studentState = {
256
+ collection: {
257
+ items: [],
258
+ loading: false,
259
+ filter: '',
260
+ sortBy: 'name'
261
+ },
262
+ selected: {
263
+ item: null,
264
+ mode: 'READ' // READ, EDIT, CREATE
265
+ }
266
+ };
267
+ ```
268
+
269
+ ### アクセシビリティ考慮事項
270
+
271
+ #### キーボードナビゲーション
272
+ ```javascript
273
+ // フォーカス管理
274
+ const handleKeyDown = (event) => {
275
+ switch (event.key) {
276
+ case 'Enter':
277
+ selectItem();
278
+ break;
279
+ case 'Escape':
280
+ cancelEdit();
281
+ break;
282
+ case 'ArrowDown':
283
+ moveToNextItem();
284
+ break;
285
+ }
286
+ };
287
+ ```
288
+
289
+ #### スクリーンリーダー対応
290
+ ```html
291
+ <!-- セマンティックなHTML構造 -->
292
+ <main role="main">
293
+ <section aria-label="学生一覧">
294
+ <h1>学生</h1>
295
+ <ul role="list">
296
+ <li role="listitem" tabindex="0">
297
+ <span aria-label="学生名">田中太郎</span>
298
+ </li>
299
+ </ul>
300
+ </section>
301
+ </main>
302
+ ```
303
+
304
+ ### パフォーマンス最適化
305
+
306
+ #### 仮想化
307
+ ```javascript
308
+ // 大量データの表示最適化
309
+ const VirtualizedList = ({ items, itemHeight = 50 }) => {
310
+ const [scrollTop, setScrollTop] = useState(0);
311
+ const containerHeight = 400;
312
+
313
+ const visibleStart = Math.floor(scrollTop / itemHeight);
314
+ const visibleEnd = Math.min(
315
+ visibleStart + Math.ceil(containerHeight / itemHeight),
316
+ items.length
317
+ );
318
+
319
+ return (
320
+ <div style={{ height: containerHeight, overflow: 'auto' }}>
321
+ {items.slice(visibleStart, visibleEnd).map(renderItem)}
322
+ </div>
323
+ );
324
+ };
325
+ ```
326
+
327
+ #### 遅延読み込み
328
+ ```javascript
329
+ // 関連データの段階的読み込み
330
+ const loadStudentDetails = async (studentId) => {
331
+ const student = await fetchStudent(studentId);
332
+ // 基本情報をまず表示
333
+
334
+ const [clubs, relatedStudents] = await Promise.all([
335
+ fetchStudentClubs(studentId),
336
+ fetchRelatedStudents(studentId)
337
+ ]);
338
+ // 関連情報を後から追加
339
+ };
340
+ ```
341
+
342
+ ## 品質保証
343
+
344
+ ### テスト戦略
345
+
346
+ #### ユニットテスト
347
+ ```javascript
348
+ describe('StudentComponent', () => {
349
+ test('should display student list', () => {
350
+ const students = [{ id: 1, name: '田中太郎' }];
351
+ render(<StudentComponent students={students} />);
352
+ expect(screen.getByText('田中太郎')).toBeInTheDocument();
353
+ });
354
+
355
+ test('should handle create action', () => {
356
+ const onCreateMock = jest.fn();
357
+ render(<StudentComponent onCreate={onCreateMock} />);
358
+ fireEvent.click(screen.getByText('新規'));
359
+ expect(onCreateMock).toHaveBeenCalled();
360
+ });
361
+ });
362
+ ```
363
+
364
+ #### 統合テスト
365
+ ```javascript
366
+ describe('Student CRUD flow', () => {
367
+ test('should complete full CRUD cycle', async () => {
368
+ // Create
369
+ await createStudent({ name: '田中太郎' });
370
+ expect(await findByText('田中太郎')).toBeInTheDocument();
371
+
372
+ // Read
373
+ fireEvent.click(await findByText('田中太郎'));
374
+ expect(await findByText('詳細情報')).toBeInTheDocument();
375
+
376
+ // Update
377
+ fireEvent.click(await findByText('編集'));
378
+ fireEvent.change(getByDisplayValue('田中太郎'), {
379
+ target: { value: '田中次郎' }
380
+ });
381
+ fireEvent.click(await findByText('保存'));
382
+ expect(await findByText('田中次郎')).toBeInTheDocument();
383
+
384
+ // Delete
385
+ fireEvent.click(await findByText('削除'));
386
+ fireEvent.click(await findByText('確認'));
387
+ expect(queryByText('田中次郎')).not.toBeInTheDocument();
388
+ });
389
+ });
390
+ ```
391
+
392
+ ### エラーハンドリング
393
+
394
+ #### ユーザーフレンドリーなエラー表示
395
+ ```javascript
396
+ const ErrorBoundary = ({ children }) => {
397
+ const [hasError, setHasError] = useState(false);
398
+ const [error, setError] = useState(null);
399
+
400
+ if (hasError) {
401
+ return (
402
+ <div className="error-container">
403
+ <h2>申し訳ございません</h2>
404
+ <p>予期しないエラーが発生しました。</p>
405
+ <button onClick={() => window.location.reload()}>
406
+ ページを再読み込み
407
+ </button>
408
+ </div>
409
+ );
410
+ }
411
+
412
+ return children;
413
+ };
414
+ ```
415
+
416
+ #### バリデーション
417
+ ```javascript
418
+ const validateStudent = (student) => {
419
+ const errors = {};
420
+
421
+ if (!student.name?.trim()) {
422
+ errors.name = '名前は必須です';
423
+ }
424
+
425
+ if (student.name?.length > 100) {
426
+ errors.name = '名前は100文字以内で入力してください';
427
+ }
428
+
429
+ if (!student.class) {
430
+ errors.class = '組を選択してください';
431
+ }
432
+
433
+ return {
434
+ isValid: Object.keys(errors).length === 0,
435
+ errors
436
+ };
437
+ };
438
+ ```
439
+
440
+ ## まとめ
441
+
442
+ オブジェクト指向UI設計は、ユーザーにとって直感的で理解しやすいインターフェースを構築するための強力な手法です。4つの主要原則に従って設計することで、一貫性があり、保守性の高いUIを実現できます。
443
+
444
+ 重要なポイント:
445
+ - オブジェクト中心の設計思考
446
+ - コレクション・シングルビューの適切な使い分け
447
+ - アクションパターンの統一
448
+ - アクセシビリティとパフォーマンスの考慮
449
449
  - 包括的なテスト戦略