@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,1024 +1,911 @@
1
- /**
2
- * HCOSS インセプションデッキ PowerPoint 生成スクリプト
3
- *
4
- * テンプレート: docs/template/インセプションデッキ.pptx のスライド構成に準拠
5
- * データソース: docs/analysis/inception-deck.md, docs/analysis/business_architecture.md
6
- */
7
- import PptxGenJS from "pptxgenjs";
8
- import { writeFileSync } from "fs";
9
- import { resolve } from "path";
10
-
11
- // ── テーマ設定(テンプレートから抽出) ──
12
- const COLORS = {
13
- black: "000000",
14
- white: "FFFFFF",
15
- darkBlue: "333399",
16
- teal: "009999",
17
- lightTeal: "BBE0E3",
18
- paleBlue: "DAEDEF",
19
- green: "99CC00",
20
- gray: "808080",
21
- lightGray: "D0D0D0",
22
- orange: "FF6600",
23
- red: "CC3333",
24
- yellow: "FFCC00",
25
- };
26
-
27
- const FONT = {
28
- title: "Yu Gothic",
29
- body: "Yu Gothic",
30
- code: "Courier New",
31
- };
32
-
33
- // ── ヘルパー ──
34
- function titleSlideOpts(title, subtitle) {
35
- return {
36
- color: COLORS.white,
37
- fontFace: FONT.title,
38
- bold: true,
39
- fontSize: subtitle ? 32 : 40,
40
- };
41
- }
42
-
43
- function addTitle(slide, text) {
44
- slide.addText(text, {
45
- x: 0.5,
46
- y: 0.2,
47
- w: 9.0,
48
- h: 1.0,
49
- fontSize: 28,
50
- fontFace: FONT.title,
51
- bold: true,
52
- color: COLORS.darkBlue,
53
- });
54
- }
55
-
56
- function addSubtitle(slide, text) {
57
- slide.addText(text, {
58
- x: 0.5,
59
- y: 1.1,
60
- w: 9.0,
61
- h: 0.5,
62
- fontSize: 14,
63
- fontFace: FONT.body,
64
- color: COLORS.gray,
65
- });
66
- }
67
-
68
- function addBullets(slide, items, opts = {}) {
69
- const top = opts.y ?? 1.6;
70
- const textRows = items.map((item) => ({
71
- text: item,
72
- options: {
73
- fontSize: opts.fontSize ?? 14,
74
- fontFace: FONT.body,
75
- color: opts.color ?? COLORS.black,
76
- bullet: { type: "bullet" },
77
- paraSpaceAfter: 6,
78
- },
79
- }));
80
- slide.addText(textRows, {
81
- x: opts.x ?? 0.7,
82
- y: top,
83
- w: opts.w ?? 8.6,
84
- h: opts.h ?? 5.5 - (top - 1.0),
85
- valign: "top",
86
- });
87
- }
88
-
89
- function addTable(slide, header, rows, opts = {}) {
90
- const top = opts.y ?? 1.8;
91
- const tableData = [
92
- header.map((h) => ({
93
- text: h,
94
- options: {
95
- bold: true,
96
- fontSize: 11,
97
- fontFace: FONT.body,
98
- color: COLORS.white,
99
- fill: { color: COLORS.darkBlue },
100
- align: "left",
101
- valign: "middle",
102
- },
103
- })),
104
- ...rows.map((row) =>
105
- row.map((cell) => ({
106
- text: cell,
107
- options: {
108
- fontSize: 10,
109
- fontFace: FONT.body,
110
- color: COLORS.black,
111
- align: "left",
112
- valign: "top",
113
- },
114
- }))
115
- ),
116
- ];
117
- slide.addTable(tableData, {
118
- x: opts.x ?? 0.5,
119
- y: top,
120
- w: opts.w ?? 9.0,
121
- colW: opts.colW,
122
- border: { type: "solid", pt: 0.5, color: COLORS.lightGray },
123
- rowH: opts.rowH,
124
- autoPage: false,
125
- });
126
- }
127
-
128
- function addHighlightBox(slide, text, opts = {}) {
129
- slide.addText(text, {
130
- x: opts.x ?? 0.5,
131
- y: opts.y ?? 1.5,
132
- w: opts.w ?? 9.0,
133
- h: opts.h ?? 1.0,
134
- fontSize: opts.fontSize ?? 16,
135
- fontFace: FONT.body,
136
- color: COLORS.darkBlue,
137
- bold: true,
138
- fill: { color: COLORS.paleBlue },
139
- align: "center",
140
- valign: "middle",
141
- });
142
- }
143
-
144
- function addSliderBar(slide, label, level, y) {
145
- // level: 1-4 (1=MIN, 4=MAX)
146
- const barX = 3.5;
147
- const barW = 5.0;
148
- const segW = barW / 4;
149
-
150
- slide.addText(label, {
151
- x: 0.5,
152
- y,
153
- w: 3.0,
154
- h: 0.45,
155
- fontSize: 11,
156
- fontFace: FONT.body,
157
- color: COLORS.black,
158
- valign: "middle",
159
- });
160
-
161
- for (let i = 0; i < 4; i++) {
162
- const isFilled = i < level;
163
- slide.addShape("rect", {
164
- x: barX + i * segW,
165
- y: y + 0.05,
166
- w: segW - 0.05,
167
- h: 0.35,
168
- fill: { color: isFilled ? COLORS.darkBlue : COLORS.lightGray },
169
- line: { color: COLORS.gray, width: 0.5 },
170
- });
171
- }
172
-
173
- slide.addText("MIN", {
174
- x: barX - 0.05,
175
- y: y + 0.38,
176
- w: 0.5,
177
- h: 0.2,
178
- fontSize: 7,
179
- fontFace: FONT.body,
180
- color: COLORS.gray,
181
- });
182
- slide.addText("MAX", {
183
- x: barX + barW - 0.45,
184
- y: y + 0.38,
185
- w: 0.5,
186
- h: 0.2,
187
- fontSize: 7,
188
- fontFace: FONT.body,
189
- color: COLORS.gray,
190
- });
191
- }
192
-
193
- // ── メイン ──
194
- async function main() {
195
- const pptx = new PptxGenJS();
196
- pptx.defineLayout({ name: "SCREEN_4x3", width: 10, height: 7.5 });
197
- pptx.layout = "SCREEN_4x3";
198
- pptx.author = "HCOSS Project";
199
- pptx.title = "HCOSS インセプションデッキ v0.1.0";
200
-
201
- // ───────────────────────────────────────
202
- // Slide 1: タイトル
203
- // ───────────────────────────────────────
204
- {
205
- const slide = pptx.addSlide();
206
- slide.background = { color: COLORS.darkBlue };
207
- slide.addText(
208
- [
209
- {
210
- text: "HCOSS",
211
- options: {
212
- fontSize: 48,
213
- fontFace: FONT.title,
214
- bold: true,
215
- color: COLORS.white,
216
- breakLine: true,
217
- },
218
- },
219
- {
220
- text: "統合業務管理システム",
221
- options: {
222
- fontSize: 28,
223
- fontFace: FONT.title,
224
- color: COLORS.lightTeal,
225
- breakLine: true,
226
- },
227
- },
228
- {
229
- text: "インセプションデッキ",
230
- options: {
231
- fontSize: 24,
232
- fontFace: FONT.title,
233
- color: COLORS.white,
234
- breakLine: true,
235
- },
236
- },
237
- ],
238
- { x: 1.0, y: 1.5, w: 8.0, h: 3.5, align: "center", valign: "middle" }
239
- );
240
- slide.addText("ヘルシーカンパニー株式会社", {
241
- x: 1.0,
242
- y: 5.5,
243
- w: 8.0,
244
- h: 0.5,
245
- fontSize: 16,
246
- fontFace: FONT.body,
247
- color: COLORS.lightTeal,
248
- align: "center",
249
- });
250
- slide.addText("v0.1.0 | 2026-02-27", {
251
- x: 1.0,
252
- y: 6.2,
253
- w: 8.0,
254
- h: 0.4,
255
- fontSize: 12,
256
- fontFace: FONT.body,
257
- color: COLORS.gray,
258
- align: "center",
259
- });
260
- }
261
-
262
- // ───────────────────────────────────────
263
- // Slide 2: 我われはなぜここにいるのか
264
- // ───────────────────────────────────────
265
- {
266
- const slide = pptx.addSlide();
267
- addTitle(slide, "我われはなぜここにいるのか");
268
- addSubtitle(
269
- slide,
270
- "正社員 6 名・パート 10 名の小規模体制で 4 つのショッピングモールを運営する課題"
271
- );
272
- addBullets(slide, [
273
- "受注管理の分散:4 モールからの受注データが統合されておらず、個別処理の非効率が発生",
274
- "在庫管理の複雑性:自社在庫と Amazon FBA 在庫の二元管理が手作業中心",
275
- "データ分析の不在:売上・顧客データの分析基盤がなく、データに基づく意思決定ができていない",
276
- "マーケティング戦略の未整備:効果的なマーケティング施策を立案・実行できていない",
277
- "コーポレートサイトの活用不足:企業情報・製造所情報の発信が不十分",
278
- ]);
279
-
280
- addHighlightBox(slide, "小規模組織の手作業の限界が、業務の品質と効率を圧迫している", {
281
- y: 5.8,
282
- h: 0.7,
283
- fontSize: 14,
284
- });
285
- }
286
-
287
- // ───────────────────────────────────────
288
- // Slide 3: エレベーターピッチ
289
- // ───────────────────────────────────────
290
- {
291
- const slide = pptx.addSlide();
292
- addTitle(slide, "エレベーターピッチ");
293
-
294
- const pitchParts = [
295
- {
296
- text: "マルチモール運営を効率化",
297
- options: {
298
- fontSize: 14,
299
- fontFace: FONT.body,
300
- color: COLORS.darkBlue,
301
- bold: true,
302
- },
303
- },
304
- {
305
- text: " したい\n",
306
- options: { fontSize: 14, fontFace: FONT.body, color: COLORS.black },
307
- },
308
- {
309
- text: "正社員 6 名・パート 10 名の小規模食品加工業者",
310
- options: {
311
- fontSize: 14,
312
- fontFace: FONT.body,
313
- color: COLORS.darkBlue,
314
- bold: true,
315
- },
316
- },
317
- {
318
- text: " 向けの、\n",
319
- options: { fontSize: 14, fontFace: FONT.body, color: COLORS.black },
320
- },
321
- {
322
- text: "HCOSS(統合業務管理システム)",
323
- options: {
324
- fontSize: 14,
325
- fontFace: FONT.body,
326
- color: COLORS.darkBlue,
327
- bold: true,
328
- },
329
- },
330
- {
331
- text: " というプロダクトは、\n",
332
- options: { fontSize: 14, fontFace: FONT.body, color: COLORS.black },
333
- },
334
- {
335
- text: "マルチモール統合業務管理システム",
336
- options: {
337
- fontSize: 14,
338
- fontFace: FONT.body,
339
- color: COLORS.darkBlue,
340
- bold: true,
341
- },
342
- },
343
- {
344
- text: " です。\nこれは ",
345
- options: { fontSize: 14, fontFace: FONT.body, color: COLORS.black },
346
- },
347
- {
348
- text: "4 モールの受注・在庫・出荷を統合管理し、\n食品トレーサビリティを一貫して管理",
349
- options: {
350
- fontSize: 14,
351
- fontFace: FONT.body,
352
- color: COLORS.darkBlue,
353
- bold: true,
354
- },
355
- },
356
- {
357
- text: " ができ、\n",
358
- options: { fontSize: 14, fontFace: FONT.body, color: COLORS.black },
359
- },
360
- {
361
- text: "各モール個別の手作業管理",
362
- options: {
363
- fontSize: 14,
364
- fontFace: FONT.body,
365
- color: COLORS.darkBlue,
366
- bold: true,
367
- },
368
- },
369
- {
370
- text: " とは違って、\n",
371
- options: { fontSize: 14, fontFace: FONT.body, color: COLORS.black },
372
- },
373
- {
374
- text: "シンプルで運用負荷の低い統合基盤",
375
- options: {
376
- fontSize: 14,
377
- fontFace: FONT.body,
378
- color: COLORS.darkBlue,
379
- bold: true,
380
- },
381
- },
382
- {
383
- text: " が備わっている。",
384
- options: { fontSize: 14, fontFace: FONT.body, color: COLORS.black },
385
- },
386
- ];
387
-
388
- slide.addText(pitchParts, {
389
- x: 0.8,
390
- y: 1.5,
391
- w: 8.4,
392
- h: 4.5,
393
- fill: { color: COLORS.paleBlue },
394
- valign: "middle",
395
- paraSpaceAfter: 8,
396
- });
397
- }
398
-
399
- // ───────────────────────────────────────
400
- // Slide 4: どんな価値をもたらすのか?
401
- // ───────────────────────────────────────
402
- {
403
- const slide = pptx.addSlide();
404
- addTitle(slide, "どんな価値をもたらすのか?");
405
- addTable(
406
- slide,
407
- ["#", "ビジネス目標", "期待される効果"],
408
- [
409
- ["1", "マルチモール受注の統合管理", "4 モールの受注を一元管理し、処理時間を短縮"],
410
- [
411
- "2",
412
- "在庫の統合管理",
413
- "自社在庫と FBA 在庫を統合管理し、在庫切れ・過剰在庫を防止",
414
- ],
415
- [
416
- "3",
417
- "トレーサビリティの確保",
418
- "原材料から出荷までの追跡で食品安全基準への対応を強化",
419
- ],
420
- [
421
- "4",
422
- "データに基づく意思決定",
423
- "売上・顧客データの分析基盤を構築しマーケティング戦略を立案可能に",
424
- ],
425
- [
426
- "5",
427
- "業務効率の向上",
428
- "手作業を削減し、小規模体制でも持続可能な業務運営を実現",
429
- ],
430
- [
431
- "6",
432
- "顧客満足度の向上",
433
- "迅速かつ正確な受注・出荷処理により顧客体験を改善",
434
- ],
435
- ],
436
- { colW: [0.4, 3.0, 5.6] }
437
- );
438
- }
439
-
440
- // ───────────────────────────────────────
441
- // Slide 5: やらないことリスト(スコープ)
442
- // ───────────────────────────────────────
443
- {
444
- const slide = pptx.addSlide();
445
- addTitle(slide, "やらないことリスト");
446
- addSubtitle(slide, "スコープの範囲");
447
-
448
- // Three columns
449
- const colW = 2.85;
450
- const colGap = 0.15;
451
- const cols = [
452
- {
453
- title: "やる(スコープ内)",
454
- color: COLORS.teal,
455
- items: [
456
- "マルチモール受注管理",
457
- "在庫管理(自社 + FBA)",
458
- "出荷管理",
459
- "商品管理",
460
- "品質管理・トレーサビリティ",
461
- "調達管理",
462
- "売上・顧客データ分析",
463
- "カスタマーサポート管理",
464
- ],
465
- },
466
- {
467
- title: "やらない(スコープ外)",
468
- color: COLORS.red,
469
- items: [
470
- "財務・会計管理",
471
- "人事・労務管理",
472
- "コーポレートサイトの構築",
473
- "モール API 以外の外部連携",
474
- ],
475
- },
476
- {
477
- title: "あとで決める",
478
- color: COLORS.orange,
479
- items: [
480
- "外部製造委託管理の範囲",
481
- "製造所固有記号管理",
482
- "マーケティング自動化",
483
- ],
484
- },
485
- ];
486
-
487
- cols.forEach((col, i) => {
488
- const x = 0.5 + i * (colW + colGap);
489
- slide.addText(col.title, {
490
- x,
491
- y: 1.7,
492
- w: colW,
493
- h: 0.45,
494
- fontSize: 13,
495
- fontFace: FONT.body,
496
- bold: true,
497
- color: COLORS.white,
498
- fill: { color: col.color },
499
- align: "center",
500
- valign: "middle",
501
- });
502
- const bullets = col.items.map((item) => ({
503
- text: item,
504
- options: {
505
- fontSize: 11,
506
- fontFace: FONT.body,
507
- color: COLORS.black,
508
- bullet: { type: "bullet" },
509
- paraSpaceAfter: 4,
510
- },
511
- }));
512
- slide.addText(bullets, {
513
- x,
514
- y: 2.2,
515
- w: colW,
516
- h: 4.8,
517
- valign: "top",
518
- });
519
- });
520
- }
521
-
522
- // ───────────────────────────────────────
523
- // Slide 6: 主なステークホルダー
524
- // ───────────────────────────────────────
525
- {
526
- const slide = pptx.addSlide();
527
- addTitle(slide, "プロジェクトコミュニティ");
528
- addSubtitle(slide, "主なステークホルダーと関心事");
529
- addTable(
530
- slide,
531
- ["ステークホルダー", "役割", "主な関心事"],
532
- [
533
- [
534
- "経営者",
535
- "プロジェクトオーナー",
536
- "投資対効果、業務効率化、売上向上",
537
- ],
538
- [
539
- "販売部門",
540
- "主要ユーザー",
541
- "受注・出荷業務の効率化、在庫可視化",
542
- ],
543
- [
544
- "製造部門",
545
- "ユーザー",
546
- "在庫引当の正確性、品質管理の効率化",
547
- ],
548
- ["顧客", "エンドユーザー", "正確な在庫情報、迅速な配送"],
549
- [
550
- "提携製造所",
551
- "外部パートナー",
552
- "製造指示の明確化、納品プロセスの効率化",
553
- ],
554
- [
555
- "モール運営会社",
556
- "プラットフォーム",
557
- "API 連携の安定性、商品情報の正確性",
558
- ],
559
- [
560
- "配送業者",
561
- "外部パートナー",
562
- "出荷情報の正確性、集荷スケジュールの安定",
563
- ],
564
- ],
565
- { y: 1.7, colW: [2.0, 2.2, 4.8] }
566
- );
567
- }
568
-
569
- // ───────────────────────────────────────
570
- // Slide 7: 技術的な解決策の概要
571
- // ───────────────────────────────────────
572
- {
573
- const slide = pptx.addSlide();
574
- addTitle(slide, "技術的な解決策の概要");
575
-
576
- // Architecture diagram using shapes
577
- const boxH = 0.5;
578
-
579
- // Mall boxes at top
580
- const malls = ["楽天市場", "Yahoo!", "Amazon", "au PAY"];
581
- malls.forEach((name, i) => {
582
- slide.addShape("rect", {
583
- x: 0.5 + i * 2.2,
584
- y: 1.5,
585
- w: 2.0,
586
- h: boxH,
587
- fill: { color: COLORS.lightTeal },
588
- line: { color: COLORS.teal, width: 1 },
589
- });
590
- slide.addText(name, {
591
- x: 0.5 + i * 2.2,
592
- y: 1.5,
593
- w: 2.0,
594
- h: boxH,
595
- fontSize: 10,
596
- fontFace: FONT.body,
597
- color: COLORS.black,
598
- align: "center",
599
- valign: "middle",
600
- });
601
- });
602
-
603
- // Arrow label
604
- slide.addText("API", {
605
- x: 4.0,
606
- y: 2.05,
607
- w: 1.0,
608
- h: 0.3,
609
- fontSize: 9,
610
- fontFace: FONT.body,
611
- color: COLORS.gray,
612
- align: "center",
613
- });
614
-
615
- // HCOSS main box
616
- slide.addShape("rect", {
617
- x: 0.5,
618
- y: 2.5,
619
- w: 9.0,
620
- h: 2.8,
621
- fill: { color: "F8F8FF" },
622
- line: { color: COLORS.darkBlue, width: 2 },
623
- });
624
- slide.addText("HCOSS 統合業務管理システム", {
625
- x: 0.5,
626
- y: 2.5,
627
- w: 9.0,
628
- h: 0.4,
629
- fontSize: 12,
630
- fontFace: FONT.body,
631
- bold: true,
632
- color: COLORS.darkBlue,
633
- align: "center",
634
- });
635
-
636
- // Internal modules
637
- const modules = [
638
- "受注管理",
639
- "在庫管理",
640
- "出荷管理",
641
- "商品管理",
642
- "品質管理",
643
- "調達管理",
644
- "分析",
645
- ];
646
- modules.forEach((name, i) => {
647
- const row = Math.floor(i / 4);
648
- const col = i % 4;
649
- slide.addShape("roundRect", {
650
- x: 0.8 + col * 2.15,
651
- y: 3.0 + row * 0.7,
652
- w: 1.95,
653
- h: 0.55,
654
- fill: { color: COLORS.darkBlue },
655
- rectRadius: 0.05,
656
- });
657
- slide.addText(name, {
658
- x: 0.8 + col * 2.15,
659
- y: 3.0 + row * 0.7,
660
- w: 1.95,
661
- h: 0.55,
662
- fontSize: 10,
663
- fontFace: FONT.body,
664
- color: COLORS.white,
665
- align: "center",
666
- valign: "middle",
667
- });
668
- });
669
-
670
- // External services at bottom
671
- const extServices = [
672
- { name: "Amazon FBA", x: 0.5 },
673
- { name: "配送業者", x: 3.0 },
674
- { name: "自社工場", x: 5.5 },
675
- { name: "提携製造所", x: 7.5 },
676
- ];
677
- extServices.forEach((svc) => {
678
- slide.addShape("rect", {
679
- x: svc.x,
680
- y: 5.6,
681
- w: 2.0,
682
- h: boxH,
683
- fill: { color: "FFF3E0" },
684
- line: { color: COLORS.orange, width: 1 },
685
- });
686
- slide.addText(svc.name, {
687
- x: svc.x,
688
- y: 5.6,
689
- w: 2.0,
690
- h: boxH,
691
- fontSize: 10,
692
- fontFace: FONT.body,
693
- color: COLORS.black,
694
- align: "center",
695
- valign: "middle",
696
- });
697
- });
698
-
699
- // Tech stack note
700
- slide.addText("技術方針: シンプルで運用負荷の低いシステム / マルチモール統合基盤 / トレーサビリティ対応", {
701
- x: 0.5,
702
- y: 6.4,
703
- w: 9.0,
704
- h: 0.4,
705
- fontSize: 10,
706
- fontFace: FONT.body,
707
- color: COLORS.gray,
708
- align: "center",
709
- });
710
- }
711
-
712
- // ───────────────────────────────────────
713
- // Slide 8: 夜も眠れなくなるような問題
714
- // ───────────────────────────────────────
715
- {
716
- const slide = pptx.addSlide();
717
- addTitle(slide, "夜も眠れなくなるような問題は何だろう?");
718
- addTable(
719
- slide,
720
- ["#", "リスク", "影響度", "対策"],
721
- [
722
- [
723
- "1",
724
- "モール API の変更・制約",
725
- "高",
726
- "アダプタパターンによる API 変更への対応力確保",
727
- ],
728
- [
729
- "2",
730
- "小規模チームでの開発・運用リソース不足",
731
- "高",
732
- "シンプルな設計を最優先。段階的リリース",
733
- ],
734
- [
735
- "3",
736
- "FBA 在庫と自社在庫の同期ズレ",
737
- "中",
738
- "Amazon API での定期的な在庫同期。差異検知アラート",
739
- ],
740
- [
741
- "4",
742
- "既存業務プロセスとの不整合",
743
- "中",
744
- "現場ヒアリングの徹底。段階的な業務移行",
745
- ],
746
- [
747
- "5",
748
- "食品安全・法令遵守の不備",
749
- "高",
750
- "食品衛生法の要件を設計段階から組み込む",
751
- ],
752
- [
753
- "6",
754
- "データ移行の失敗",
755
- "中",
756
- "段階的な移行計画。並行稼動期間の確保",
757
- ],
758
- ],
759
- { colW: [0.4, 3.0, 0.8, 4.8] }
760
- );
761
- }
762
-
763
- // ───────────────────────────────────────
764
- // Slide 9: 俺たちの "A チーム"
765
- // ───────────────────────────────────────
766
- {
767
- const slide = pptx.addSlide();
768
- addTitle(slide, '俺たちの "A チーム"');
769
- addTable(
770
- slide,
771
- ["役割", "人数", "備考"],
772
- [
773
- ["プロジェクトオーナー", "1 名", "経営者が兼務"],
774
- ["開発者", "1〜2 名", "AI エージェントとの協働開発"],
775
- [
776
- "業務担当(販売・製造)",
777
- "2〜3 名",
778
- "要件確認・受入テスト",
779
- ],
780
- ],
781
- { y: 1.8, colW: [2.5, 1.5, 5.0] }
782
- );
783
-
784
- addHighlightBox(
785
- slide,
786
- "AI エージェント(Claude Code)との協働開発により、少人数でも高品質な開発を実現",
787
- { y: 4.0, h: 0.8, fontSize: 14 }
788
- );
789
- }
790
-
791
- // ───────────────────────────────────────
792
- // Slide 10: 期間を見極める
793
- // ───────────────────────────────────────
794
- {
795
- const slide = pptx.addSlide();
796
- addTitle(slide, "期間を見極める");
797
-
798
- const phases = [
799
- {
800
- name: "Phase 1: 分析・設計",
801
- desc: "要件定義、アーキテクチャ設計、データモデル設計",
802
- weeks: "2〜3 週間",
803
- color: COLORS.lightTeal,
804
- },
805
- {
806
- name: "Phase 2: コア機能開発",
807
- desc: "受注管理、在庫管理、出荷管理、商品管理",
808
- weeks: "4〜6 週間",
809
- color: COLORS.teal,
810
- },
811
- {
812
- name: "Phase 3: 品質管理・調達管理",
813
- desc: "品質管理、調達管理機能の開発",
814
- weeks: "2〜3 週間",
815
- color: COLORS.lightTeal,
816
- },
817
- {
818
- name: "Phase 4: 分析・サポート",
819
- desc: "分析ダッシュボード、カスタマーサポート",
820
- weeks: "2〜3 週間",
821
- color: COLORS.teal,
822
- },
823
- {
824
- name: "Phase 5: リリース準備",
825
- desc: "受入テスト、データ移行、本番稼動",
826
- weeks: "2〜3 週間",
827
- color: COLORS.lightTeal,
828
- },
829
- ];
830
-
831
- const barStartX = 0.5;
832
- const barMaxW = 9.0;
833
- const totalWeeks = 18;
834
- const phaseWeeks = [3, 6, 3, 3, 3];
835
-
836
- phases.forEach((phase, i) => {
837
- const y = 1.8 + i * 1.0;
838
- const startWeek = phaseWeeks.slice(0, i).reduce((a, b) => a + b, 0);
839
- const x = barStartX + (startWeek / totalWeeks) * barMaxW;
840
- const w = (phaseWeeks[i] / totalWeeks) * barMaxW;
841
-
842
- slide.addShape("rect", {
843
- x,
844
- y,
845
- w,
846
- h: 0.45,
847
- fill: { color: phase.color },
848
- line: { color: COLORS.teal, width: 1 },
849
- });
850
- slide.addText(phase.name, {
851
- x,
852
- y,
853
- w,
854
- h: 0.45,
855
- fontSize: 10,
856
- fontFace: FONT.body,
857
- bold: true,
858
- color: COLORS.darkBlue,
859
- align: "center",
860
- valign: "middle",
861
- });
862
- slide.addText(`${phase.desc}(${phase.weeks})`, {
863
- x,
864
- y: y + 0.45,
865
- w,
866
- h: 0.35,
867
- fontSize: 8,
868
- fontFace: FONT.body,
869
- color: COLORS.gray,
870
- align: "center",
871
- });
872
- });
873
-
874
- // MVP marker
875
- const mvpX =
876
- barStartX +
877
- ((phaseWeeks[0] + phaseWeeks[1]) / totalWeeks) * barMaxW;
878
- slide.addShape("line", {
879
- x: mvpX,
880
- y: 1.5,
881
- w: 0,
882
- h: 5.0,
883
- line: { color: COLORS.red, width: 2, dashType: "dash" },
884
- });
885
- slide.addText("MVP\nリリース", {
886
- x: mvpX - 0.5,
887
- y: 6.5,
888
- w: 1.2,
889
- h: 0.5,
890
- fontSize: 10,
891
- fontFace: FONT.body,
892
- bold: true,
893
- color: COLORS.red,
894
- align: "center",
895
- });
896
-
897
- slide.addText("あくまで推測であって、確約するものではありません。", {
898
- x: 0.5,
899
- y: 7.0,
900
- w: 9.0,
901
- h: 0.3,
902
- fontSize: 9,
903
- fontFace: FONT.body,
904
- color: COLORS.gray,
905
- align: "right",
906
- });
907
- }
908
-
909
- // ───────────────────────────────────────
910
- // Slide 11: トレードオフ・スライダー
911
- // ───────────────────────────────────────
912
- {
913
- const slide = pptx.addSlide();
914
- addTitle(slide, "トレードオフ・スライダー");
915
-
916
- // labels and levels (1=MIN..4=MAX)
917
- addSliderBar(
918
- slide,
919
- "機能をぜんぶ揃える(スコープ)",
920
- 3,
921
- 1.8
922
- );
923
- addSliderBar(slide, "予算内に収める(予算)", 2, 2.5);
924
- addSliderBar(slide, "期日を死守する(時間)", 2, 3.2);
925
- addSliderBar(
926
- slide,
927
- "高い品質、少ない欠陥(品質)",
928
- 4,
929
- 3.9
930
- );
931
-
932
- // Additional quality characteristics
933
- slide.addText("品質特性の優先順位", {
934
- x: 0.5,
935
- y: 4.8,
936
- w: 9.0,
937
- h: 0.4,
938
- fontSize: 14,
939
- fontFace: FONT.body,
940
- bold: true,
941
- color: COLORS.darkBlue,
942
- });
943
-
944
- addTable(
945
- slide,
946
- ["優先度", "品質特性", "理由"],
947
- [
948
- ["1", "正確性", "受注・在庫データの正確性は業務の根幹"],
949
- ["2", "使いやすさ", "小規模チームが日常的に使うため、直感的な操作性が必須"],
950
- ["3", "信頼性", "受注処理の停止は直接的な売上損失につながる"],
951
- ["4", "保守性", "小規模チームでの長期運用を見据えたシンプルな設計"],
952
- ],
953
- { y: 5.2, colW: [0.8, 1.8, 6.4] }
954
- );
955
- }
956
-
957
- // ───────────────────────────────────────
958
- // Slide 12: 初回のリリースに必要なもの
959
- // ───────────────────────────────────────
960
- {
961
- const slide = pptx.addSlide();
962
- addTitle(slide, "初回のリリースに必要なもの");
963
-
964
- addHighlightBox(
965
- slide,
966
- "Phase 2 完了時点で MVP(最小実行可能製品)をリリース",
967
- { y: 1.5, h: 0.7, fontSize: 16 }
968
- );
969
-
970
- slide.addText("MVP スコープ", {
971
- x: 0.5,
972
- y: 2.5,
973
- w: 9.0,
974
- h: 0.4,
975
- fontSize: 14,
976
- fontFace: FONT.body,
977
- bold: true,
978
- color: COLORS.darkBlue,
979
- });
980
-
981
- addBullets(
982
- slide,
983
- [
984
- "マルチモール受注管理(楽天市場、Yahoo!、Amazon、au PAY)",
985
- "在庫管理(自社在庫 + Amazon FBA 在庫の統合管理)",
986
- "出荷管理(受注に基づく出荷指示・梱包・配送手配)",
987
- "商品管理(商品マスタの一元管理、各モールへの同期)",
988
- ],
989
- { y: 2.9, h: 2.5, fontSize: 13 }
990
- );
991
-
992
- slide.addText("リリース戦略", {
993
- x: 0.5,
994
- y: 5.2,
995
- w: 9.0,
996
- h: 0.4,
997
- fontSize: 14,
998
- fontFace: FONT.body,
999
- bold: true,
1000
- color: COLORS.darkBlue,
1001
- });
1002
-
1003
- addBullets(
1004
- slide,
1005
- [
1006
- "以降のフェーズは段階的にリリースし、フィードバックを反映しながら改善",
1007
- "各フェーズ完了時にステークホルダーレビューを実施し、次フェーズの優先順位を見直す",
1008
- ],
1009
- { y: 5.6, h: 1.5, fontSize: 12 }
1010
- );
1011
- }
1012
-
1013
- // ───────────────────────────────────────
1014
- // Save
1015
- // ───────────────────────────────────────
1016
- const outputPath = resolve(
1017
- "docs/analysis/slide/HCOSS_v0.1.0.pptx"
1018
- );
1019
- const dataBuffer = await pptx.write({ outputType: "nodebuffer" });
1020
- writeFileSync(outputPath, dataBuffer);
1021
- console.log("Generated:", outputPath);
1022
- }
1023
-
1024
- main().catch(console.error);
1
+ /**
2
+ * インセプションデッキ PowerPoint 生成スクリプト(汎用テンプレート)
3
+ *
4
+ * テンプレート: docs/template/インセプションデッキ.pptx のスライド構成に準拠
5
+ * データソース: docs/analysis/inception-deck.md, docs/analysis/business_architecture.md
6
+ *
7
+ * 使い方:
8
+ * 1. SLIDE_DATA セクションのプレースホルダーをプロジェクト固有の内容に書き換える
9
+ * 2. node .claude/scripts/generate-inception-deck.mjs を実行
10
+ */
11
+ import PptxGenJS from "pptxgenjs";
12
+ import { writeFileSync } from "fs";
13
+ import { resolve } from "path";
14
+
15
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
16
+ // SLIDE_DATA: プロジェクト固有データ(ここを書き換える)
17
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
+ const SLIDE_DATA = {
19
+ // ── メタ情報 ──
20
+ meta: {
21
+ author: "プロジェクトチーム",
22
+ title: "プロジェクト名 インセプションデッキ",
23
+ version: "v0.1.0",
24
+ date: "YYYY-MM-DD",
25
+ outputFileName: "PROJECT_v0.1.0.pptx",
26
+ },
27
+
28
+ // ── Slide 1: タイトル ──
29
+ titleSlide: {
30
+ projectName: "プロジェクト名",
31
+ subtitle: "プロジェクトの説明",
32
+ deckLabel: "インセプションデッキ",
33
+ organization: "組織名",
34
+ },
35
+
36
+ // ── Slide 2: 我われはなぜここにいるのか ──
37
+ whyAreWeHere: {
38
+ subtitle: "プロジェクトが解決すべき課題の概要",
39
+ bullets: [
40
+ "課題 1: 現状の問題点を記述",
41
+ "課題 2: 現状の問題点を記述",
42
+ "課題 3: 現状の問題点を記述",
43
+ ],
44
+ highlight: "課題を一文で要約するメッセージ",
45
+ },
46
+
47
+ // ── Slide 3: エレベーターピッチ ──
48
+ elevatorPitch: {
49
+ want: "〇〇を実現",
50
+ targetUser: "ターゲットユーザーの説明",
51
+ productName: "プロダクト名",
52
+ category: "プロダクトカテゴリ",
53
+ keyBenefit: "主要な機能・利点の説明",
54
+ competitor: "既存の代替手段",
55
+ differentiator: "差別化ポイント",
56
+ },
57
+
58
+ // ── Slide 4: どんな価値をもたらすのか? ──
59
+ values: {
60
+ rows: [
61
+ // [番号, ビジネス目標, 期待される効果]
62
+ ["1", "ビジネス目標 1", "期待される効果 1"],
63
+ ["2", "ビジネス目標 2", "期待される効果 2"],
64
+ ["3", "ビジネス目標 3", "期待される効果 3"],
65
+ ],
66
+ },
67
+
68
+ // ── Slide 5: やらないことリスト ──
69
+ scope: {
70
+ inScope: [
71
+ "スコープ内の機能 1",
72
+ "スコープ内の機能 2",
73
+ "スコープ内の機能 3",
74
+ ],
75
+ outOfScope: [
76
+ "スコープ外の項目 1",
77
+ "スコープ外の項目 2",
78
+ ],
79
+ decideLater: [
80
+ "後で決める項目 1",
81
+ "後で決める項目 2",
82
+ ],
83
+ },
84
+
85
+ // ── Slide 6: プロジェクトコミュニティ ──
86
+ stakeholders: {
87
+ rows: [
88
+ // [ステークホルダー, 役割, 主な関心事]
89
+ ["ステークホルダー 1", "役割", "関心事"],
90
+ ["ステークホルダー 2", "役割", "関心事"],
91
+ ["ステークホルダー 3", "役割", "関心事"],
92
+ ],
93
+ },
94
+
95
+ // ── Slide 7: 技術的な解決策の概要 ──
96
+ technicalSolution: {
97
+ // 上部の外部チャネル(モール、外部 API など)
98
+ externalChannels: [
99
+ { name: "チャネル 1" },
100
+ { name: "チャネル 2" },
101
+ { name: "チャネル 3" },
102
+ ],
103
+ // 中央のシステム
104
+ systemName: "システム名",
105
+ modules: [
106
+ "モジュール 1",
107
+ "モジュール 2",
108
+ "モジュール 3",
109
+ "モジュール 4",
110
+ ],
111
+ // 下部の外部連携先
112
+ externalServices: [
113
+ { name: "外部サービス 1" },
114
+ { name: "外部サービス 2" },
115
+ { name: "外部サービス 3" },
116
+ ],
117
+ techNote: "技術方針の概要を一文で記述",
118
+ },
119
+
120
+ // ── Slide 8: 夜も眠れなくなるような問題 ──
121
+ risks: {
122
+ rows: [
123
+ // [番号, リスク, 影響度, 対策]
124
+ ["1", "リスク 1", "高", "対策 1"],
125
+ ["2", "リスク 2", "中", "対策 2"],
126
+ ["3", "リスク 3", "低", "対策 3"],
127
+ ],
128
+ },
129
+
130
+ // ── Slide 9: 俺たちの "A チーム" ──
131
+ team: {
132
+ rows: [
133
+ // [役割, 人数, 備考]
134
+ ["役割 1", "N 名", "備考"],
135
+ ["役割 2", "N 名", "備考"],
136
+ ],
137
+ highlight: "チーム体制の特徴やポイントを一文で記述",
138
+ },
139
+
140
+ // ── Slide 10: 期間を見極める ──
141
+ timeline: {
142
+ totalWeeks: 12,
143
+ phases: [
144
+ // weeks: ガントバー上の幅(週数)
145
+ {
146
+ name: "Phase 1: フェーズ名",
147
+ desc: "主な作業内容",
148
+ weeksLabel: "N 週間",
149
+ weeks: 3,
150
+ },
151
+ {
152
+ name: "Phase 2: フェーズ名",
153
+ desc: "主な作業内容",
154
+ weeksLabel: "N 週間",
155
+ weeks: 4,
156
+ },
157
+ {
158
+ name: "Phase 3: フェーズ名",
159
+ desc: "主な作業内容",
160
+ weeksLabel: "N 週間",
161
+ weeks: 3,
162
+ },
163
+ {
164
+ name: "Phase 4: フェーズ名",
165
+ desc: "主な作業内容",
166
+ weeksLabel: "N 週間",
167
+ weeks: 2,
168
+ },
169
+ ],
170
+ // MVP マーカーを表示するフェーズ番号(0 始まり。先頭から N フェーズ完了時点)
171
+ // null の場合はマーカーを表示しない
172
+ mvpAfterPhase: 1,
173
+ },
174
+
175
+ // ── Slide 11: トレードオフ・スライダー ──
176
+ tradeoffs: {
177
+ // level: 1=MIN 〜 4=MAX
178
+ sliders: [
179
+ { label: "機能をぜんぶ揃える(スコープ)", level: 2 },
180
+ { label: "予算内に収める(予算)", level: 2 },
181
+ { label: "期日を死守する(時間)", level: 2 },
182
+ { label: "高い品質、少ない欠陥(品質)", level: 3 },
183
+ ],
184
+ qualityPriorities: [
185
+ // [優先度, 品質特性, 理由]
186
+ ["1", "品質特性 1", "理由 1"],
187
+ ["2", "品質特性 2", "理由 2"],
188
+ ["3", "品質特性 3", "理由 3"],
189
+ ],
190
+ },
191
+
192
+ // ── Slide 12: 初回のリリースに必要なもの ──
193
+ initialRelease: {
194
+ highlight: "MVP の概要を一文で記述",
195
+ mvpScope: [
196
+ "MVP 機能 1",
197
+ "MVP 機能 2",
198
+ "MVP 機能 3",
199
+ ],
200
+ releaseStrategy: [
201
+ "リリース戦略 1",
202
+ "リリース戦略 2",
203
+ ],
204
+ },
205
+ };
206
+
207
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
208
+ // テーマ設定(テンプレートから抽出)
209
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
210
+ const COLORS = {
211
+ black: "000000",
212
+ white: "FFFFFF",
213
+ darkBlue: "333399",
214
+ teal: "009999",
215
+ lightTeal: "BBE0E3",
216
+ paleBlue: "DAEDEF",
217
+ green: "99CC00",
218
+ gray: "808080",
219
+ lightGray: "D0D0D0",
220
+ orange: "FF6600",
221
+ red: "CC3333",
222
+ yellow: "FFCC00",
223
+ };
224
+
225
+ const FONT = {
226
+ title: "Yu Gothic",
227
+ body: "Yu Gothic",
228
+ code: "Courier New",
229
+ };
230
+
231
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
232
+ // ヘルパー関数
233
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
234
+ function addTitle(slide, text) {
235
+ slide.addText(text, {
236
+ x: 0.5,
237
+ y: 0.2,
238
+ w: 9.0,
239
+ h: 1.0,
240
+ fontSize: 28,
241
+ fontFace: FONT.title,
242
+ bold: true,
243
+ color: COLORS.darkBlue,
244
+ });
245
+ }
246
+
247
+ function addSubtitle(slide, text) {
248
+ slide.addText(text, {
249
+ x: 0.5,
250
+ y: 1.1,
251
+ w: 9.0,
252
+ h: 0.5,
253
+ fontSize: 14,
254
+ fontFace: FONT.body,
255
+ color: COLORS.gray,
256
+ });
257
+ }
258
+
259
+ function addBullets(slide, items, opts = {}) {
260
+ const top = opts.y ?? 1.6;
261
+ const textRows = items.map((item) => ({
262
+ text: item,
263
+ options: {
264
+ fontSize: opts.fontSize ?? 14,
265
+ fontFace: FONT.body,
266
+ color: opts.color ?? COLORS.black,
267
+ bullet: { type: "bullet" },
268
+ paraSpaceAfter: 6,
269
+ },
270
+ }));
271
+ slide.addText(textRows, {
272
+ x: opts.x ?? 0.7,
273
+ y: top,
274
+ w: opts.w ?? 8.6,
275
+ h: opts.h ?? 5.5 - (top - 1.0),
276
+ valign: "top",
277
+ });
278
+ }
279
+
280
+ function addTable(slide, header, rows, opts = {}) {
281
+ const top = opts.y ?? 1.8;
282
+ const tableData = [
283
+ header.map((h) => ({
284
+ text: h,
285
+ options: {
286
+ bold: true,
287
+ fontSize: 11,
288
+ fontFace: FONT.body,
289
+ color: COLORS.white,
290
+ fill: { color: COLORS.darkBlue },
291
+ align: "left",
292
+ valign: "middle",
293
+ },
294
+ })),
295
+ ...rows.map((row) =>
296
+ row.map((cell) => ({
297
+ text: cell,
298
+ options: {
299
+ fontSize: 10,
300
+ fontFace: FONT.body,
301
+ color: COLORS.black,
302
+ align: "left",
303
+ valign: "top",
304
+ },
305
+ }))
306
+ ),
307
+ ];
308
+ slide.addTable(tableData, {
309
+ x: opts.x ?? 0.5,
310
+ y: top,
311
+ w: opts.w ?? 9.0,
312
+ colW: opts.colW,
313
+ border: { type: "solid", pt: 0.5, color: COLORS.lightGray },
314
+ rowH: opts.rowH,
315
+ autoPage: false,
316
+ });
317
+ }
318
+
319
+ function addHighlightBox(slide, text, opts = {}) {
320
+ slide.addText(text, {
321
+ x: opts.x ?? 0.5,
322
+ y: opts.y ?? 1.5,
323
+ w: opts.w ?? 9.0,
324
+ h: opts.h ?? 1.0,
325
+ fontSize: opts.fontSize ?? 16,
326
+ fontFace: FONT.body,
327
+ color: COLORS.darkBlue,
328
+ bold: true,
329
+ fill: { color: COLORS.paleBlue },
330
+ align: "center",
331
+ valign: "middle",
332
+ });
333
+ }
334
+
335
+ function addSliderBar(slide, label, level, y) {
336
+ const barX = 3.5;
337
+ const barW = 5.0;
338
+ const segW = barW / 4;
339
+
340
+ slide.addText(label, {
341
+ x: 0.5,
342
+ y,
343
+ w: 3.0,
344
+ h: 0.45,
345
+ fontSize: 11,
346
+ fontFace: FONT.body,
347
+ color: COLORS.black,
348
+ valign: "middle",
349
+ });
350
+
351
+ for (let i = 0; i < 4; i++) {
352
+ const isFilled = i < level;
353
+ slide.addShape("rect", {
354
+ x: barX + i * segW,
355
+ y: y + 0.05,
356
+ w: segW - 0.05,
357
+ h: 0.35,
358
+ fill: { color: isFilled ? COLORS.darkBlue : COLORS.lightGray },
359
+ line: { color: COLORS.gray, width: 0.5 },
360
+ });
361
+ }
362
+
363
+ slide.addText("MIN", {
364
+ x: barX - 0.05,
365
+ y: y + 0.38,
366
+ w: 0.5,
367
+ h: 0.2,
368
+ fontSize: 7,
369
+ fontFace: FONT.body,
370
+ color: COLORS.gray,
371
+ });
372
+ slide.addText("MAX", {
373
+ x: barX + barW - 0.45,
374
+ y: y + 0.38,
375
+ w: 0.5,
376
+ h: 0.2,
377
+ fontSize: 7,
378
+ fontFace: FONT.body,
379
+ color: COLORS.gray,
380
+ });
381
+ }
382
+
383
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
384
+ // スライド生成
385
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
386
+ async function main() {
387
+ const { meta } = SLIDE_DATA;
388
+
389
+ const pptx = new PptxGenJS();
390
+ pptx.defineLayout({ name: "SCREEN_4x3", width: 10, height: 7.5 });
391
+ pptx.layout = "SCREEN_4x3";
392
+ pptx.author = meta.author;
393
+ pptx.title = meta.title;
394
+
395
+ // ─── Slide 1: タイトル ───
396
+ {
397
+ const d = SLIDE_DATA.titleSlide;
398
+ const slide = pptx.addSlide();
399
+ slide.background = { color: COLORS.darkBlue };
400
+ slide.addText(
401
+ [
402
+ {
403
+ text: d.projectName,
404
+ options: {
405
+ fontSize: 48,
406
+ fontFace: FONT.title,
407
+ bold: true,
408
+ color: COLORS.white,
409
+ breakLine: true,
410
+ },
411
+ },
412
+ {
413
+ text: d.subtitle,
414
+ options: {
415
+ fontSize: 28,
416
+ fontFace: FONT.title,
417
+ color: COLORS.lightTeal,
418
+ breakLine: true,
419
+ },
420
+ },
421
+ {
422
+ text: d.deckLabel,
423
+ options: {
424
+ fontSize: 24,
425
+ fontFace: FONT.title,
426
+ color: COLORS.white,
427
+ breakLine: true,
428
+ },
429
+ },
430
+ ],
431
+ { x: 1.0, y: 1.5, w: 8.0, h: 3.5, align: "center", valign: "middle" }
432
+ );
433
+ slide.addText(d.organization, {
434
+ x: 1.0,
435
+ y: 5.5,
436
+ w: 8.0,
437
+ h: 0.5,
438
+ fontSize: 16,
439
+ fontFace: FONT.body,
440
+ color: COLORS.lightTeal,
441
+ align: "center",
442
+ });
443
+ slide.addText(`${meta.version} | ${meta.date}`, {
444
+ x: 1.0,
445
+ y: 6.2,
446
+ w: 8.0,
447
+ h: 0.4,
448
+ fontSize: 12,
449
+ fontFace: FONT.body,
450
+ color: COLORS.gray,
451
+ align: "center",
452
+ });
453
+ }
454
+
455
+ // ─── Slide 2: 我われはなぜここにいるのか ───
456
+ {
457
+ const d = SLIDE_DATA.whyAreWeHere;
458
+ const slide = pptx.addSlide();
459
+ addTitle(slide, "我われはなぜここにいるのか");
460
+ addSubtitle(slide, d.subtitle);
461
+ addBullets(slide, d.bullets);
462
+ addHighlightBox(slide, d.highlight, {
463
+ y: 5.8,
464
+ h: 0.7,
465
+ fontSize: 14,
466
+ });
467
+ }
468
+
469
+ // ─── Slide 3: エレベーターピッチ ───
470
+ {
471
+ const d = SLIDE_DATA.elevatorPitch;
472
+ const slide = pptx.addSlide();
473
+ addTitle(slide, "エレベーターピッチ");
474
+
475
+ const bold = {
476
+ fontSize: 14,
477
+ fontFace: FONT.body,
478
+ color: COLORS.darkBlue,
479
+ bold: true,
480
+ };
481
+ const normal = {
482
+ fontSize: 14,
483
+ fontFace: FONT.body,
484
+ color: COLORS.black,
485
+ };
486
+
487
+ const pitchParts = [
488
+ { text: d.want, options: bold },
489
+ { text: " したい\n", options: normal },
490
+ { text: d.targetUser, options: bold },
491
+ { text: " 向けの、\n", options: normal },
492
+ { text: d.productName, options: bold },
493
+ { text: " というプロダクトは、\n", options: normal },
494
+ { text: d.category, options: bold },
495
+ { text: " です。\nこれは ", options: normal },
496
+ { text: d.keyBenefit, options: bold },
497
+ { text: " ができ、\n", options: normal },
498
+ { text: d.competitor, options: bold },
499
+ { text: " とは違って、\n", options: normal },
500
+ { text: d.differentiator, options: bold },
501
+ { text: " が備わっている。", options: normal },
502
+ ];
503
+
504
+ slide.addText(pitchParts, {
505
+ x: 0.8,
506
+ y: 1.5,
507
+ w: 8.4,
508
+ h: 4.5,
509
+ fill: { color: COLORS.paleBlue },
510
+ valign: "middle",
511
+ paraSpaceAfter: 8,
512
+ });
513
+ }
514
+
515
+ // ─── Slide 4: どんな価値をもたらすのか? ───
516
+ {
517
+ const d = SLIDE_DATA.values;
518
+ const slide = pptx.addSlide();
519
+ addTitle(slide, "どんな価値をもたらすのか?");
520
+ addTable(
521
+ slide,
522
+ ["#", "ビジネス目標", "期待される効果"],
523
+ d.rows,
524
+ { colW: [0.4, 3.0, 5.6] }
525
+ );
526
+ }
527
+
528
+ // ─── Slide 5: やらないことリスト ───
529
+ {
530
+ const d = SLIDE_DATA.scope;
531
+ const slide = pptx.addSlide();
532
+ addTitle(slide, "やらないことリスト");
533
+ addSubtitle(slide, "スコープの範囲");
534
+
535
+ const colW = 2.85;
536
+ const colGap = 0.15;
537
+ const cols = [
538
+ { title: "やる(スコープ内)", color: COLORS.teal, items: d.inScope },
539
+ { title: "やらない(スコープ外)", color: COLORS.red, items: d.outOfScope },
540
+ { title: "あとで決める", color: COLORS.orange, items: d.decideLater },
541
+ ];
542
+
543
+ cols.forEach((col, i) => {
544
+ const x = 0.5 + i * (colW + colGap);
545
+ slide.addText(col.title, {
546
+ x,
547
+ y: 1.7,
548
+ w: colW,
549
+ h: 0.45,
550
+ fontSize: 13,
551
+ fontFace: FONT.body,
552
+ bold: true,
553
+ color: COLORS.white,
554
+ fill: { color: col.color },
555
+ align: "center",
556
+ valign: "middle",
557
+ });
558
+ const bullets = col.items.map((item) => ({
559
+ text: item,
560
+ options: {
561
+ fontSize: 11,
562
+ fontFace: FONT.body,
563
+ color: COLORS.black,
564
+ bullet: { type: "bullet" },
565
+ paraSpaceAfter: 4,
566
+ },
567
+ }));
568
+ slide.addText(bullets, {
569
+ x,
570
+ y: 2.2,
571
+ w: colW,
572
+ h: 4.8,
573
+ valign: "top",
574
+ });
575
+ });
576
+ }
577
+
578
+ // ─── Slide 6: プロジェクトコミュニティ ───
579
+ {
580
+ const d = SLIDE_DATA.stakeholders;
581
+ const slide = pptx.addSlide();
582
+ addTitle(slide, "プロジェクトコミュニティ");
583
+ addSubtitle(slide, "主なステークホルダーと関心事");
584
+ addTable(
585
+ slide,
586
+ ["ステークホルダー", "役割", "主な関心事"],
587
+ d.rows,
588
+ { y: 1.7, colW: [2.0, 2.2, 4.8] }
589
+ );
590
+ }
591
+
592
+ // ─── Slide 7: 技術的な解決策の概要 ───
593
+ {
594
+ const d = SLIDE_DATA.technicalSolution;
595
+ const slide = pptx.addSlide();
596
+ addTitle(slide, "技術的な解決策の概要");
597
+
598
+ const boxH = 0.5;
599
+
600
+ // 上部: 外部チャネル
601
+ const channelCount = d.externalChannels.length;
602
+ const channelW = Math.min(2.0, (9.0 - 0.2 * (channelCount - 1)) / channelCount);
603
+ const channelGap = channelCount > 1 ? (9.0 - channelW * channelCount) / (channelCount - 1) : 0;
604
+ d.externalChannels.forEach((ch, i) => {
605
+ const x = 0.5 + i * (channelW + channelGap);
606
+ slide.addShape("rect", {
607
+ x,
608
+ y: 1.5,
609
+ w: channelW,
610
+ h: boxH,
611
+ fill: { color: COLORS.lightTeal },
612
+ line: { color: COLORS.teal, width: 1 },
613
+ });
614
+ slide.addText(ch.name, {
615
+ x,
616
+ y: 1.5,
617
+ w: channelW,
618
+ h: boxH,
619
+ fontSize: 10,
620
+ fontFace: FONT.body,
621
+ color: COLORS.black,
622
+ align: "center",
623
+ valign: "middle",
624
+ });
625
+ });
626
+
627
+ // 接続ラベル
628
+ slide.addText("API", {
629
+ x: 4.0,
630
+ y: 2.05,
631
+ w: 1.0,
632
+ h: 0.3,
633
+ fontSize: 9,
634
+ fontFace: FONT.body,
635
+ color: COLORS.gray,
636
+ align: "center",
637
+ });
638
+
639
+ // 中央: メインシステム
640
+ slide.addShape("rect", {
641
+ x: 0.5,
642
+ y: 2.5,
643
+ w: 9.0,
644
+ h: 2.8,
645
+ fill: { color: "F8F8FF" },
646
+ line: { color: COLORS.darkBlue, width: 2 },
647
+ });
648
+ slide.addText(d.systemName, {
649
+ x: 0.5,
650
+ y: 2.5,
651
+ w: 9.0,
652
+ h: 0.4,
653
+ fontSize: 12,
654
+ fontFace: FONT.body,
655
+ bold: true,
656
+ color: COLORS.darkBlue,
657
+ align: "center",
658
+ });
659
+
660
+ // 内部モジュール
661
+ d.modules.forEach((name, i) => {
662
+ const row = Math.floor(i / 4);
663
+ const col = i % 4;
664
+ slide.addShape("roundRect", {
665
+ x: 0.8 + col * 2.15,
666
+ y: 3.0 + row * 0.7,
667
+ w: 1.95,
668
+ h: 0.55,
669
+ fill: { color: COLORS.darkBlue },
670
+ rectRadius: 0.05,
671
+ });
672
+ slide.addText(name, {
673
+ x: 0.8 + col * 2.15,
674
+ y: 3.0 + row * 0.7,
675
+ w: 1.95,
676
+ h: 0.55,
677
+ fontSize: 10,
678
+ fontFace: FONT.body,
679
+ color: COLORS.white,
680
+ align: "center",
681
+ valign: "middle",
682
+ });
683
+ });
684
+
685
+ // 下部: 外部連携先
686
+ const svcCount = d.externalServices.length;
687
+ const svcW = Math.min(2.0, (9.0 - 0.2 * (svcCount - 1)) / svcCount);
688
+ const svcGap = svcCount > 1 ? (9.0 - svcW * svcCount) / (svcCount - 1) : 0;
689
+ d.externalServices.forEach((svc, i) => {
690
+ const x = 0.5 + i * (svcW + svcGap);
691
+ slide.addShape("rect", {
692
+ x,
693
+ y: 5.6,
694
+ w: svcW,
695
+ h: boxH,
696
+ fill: { color: "FFF3E0" },
697
+ line: { color: COLORS.orange, width: 1 },
698
+ });
699
+ slide.addText(svc.name, {
700
+ x,
701
+ y: 5.6,
702
+ w: svcW,
703
+ h: boxH,
704
+ fontSize: 10,
705
+ fontFace: FONT.body,
706
+ color: COLORS.black,
707
+ align: "center",
708
+ valign: "middle",
709
+ });
710
+ });
711
+
712
+ // 技術方針ノート
713
+ slide.addText(d.techNote, {
714
+ x: 0.5,
715
+ y: 6.4,
716
+ w: 9.0,
717
+ h: 0.4,
718
+ fontSize: 10,
719
+ fontFace: FONT.body,
720
+ color: COLORS.gray,
721
+ align: "center",
722
+ });
723
+ }
724
+
725
+ // ─── Slide 8: 夜も眠れなくなるような問題 ───
726
+ {
727
+ const d = SLIDE_DATA.risks;
728
+ const slide = pptx.addSlide();
729
+ addTitle(slide, "夜も眠れなくなるような問題は何だろう?");
730
+ addTable(
731
+ slide,
732
+ ["#", "リスク", "影響度", "対策"],
733
+ d.rows,
734
+ { colW: [0.4, 3.0, 0.8, 4.8] }
735
+ );
736
+ }
737
+
738
+ // ─── Slide 9: 俺たちの "A チーム" ───
739
+ {
740
+ const d = SLIDE_DATA.team;
741
+ const slide = pptx.addSlide();
742
+ addTitle(slide, '俺たちの "A チーム"');
743
+ addTable(
744
+ slide,
745
+ ["役割", "人数", "備考"],
746
+ d.rows,
747
+ { y: 1.8, colW: [2.5, 1.5, 5.0] }
748
+ );
749
+ addHighlightBox(slide, d.highlight, { y: 4.0, h: 0.8, fontSize: 14 });
750
+ }
751
+
752
+ // ─── Slide 10: 期間を見極める ───
753
+ {
754
+ const d = SLIDE_DATA.timeline;
755
+ const slide = pptx.addSlide();
756
+ addTitle(slide, "期間を見極める");
757
+
758
+ const barStartX = 0.5;
759
+ const barMaxW = 9.0;
760
+ const phaseWeeks = d.phases.map((p) => p.weeks);
761
+
762
+ d.phases.forEach((phase, i) => {
763
+ const y = 1.8 + i * 1.0;
764
+ const startWeek = phaseWeeks.slice(0, i).reduce((a, b) => a + b, 0);
765
+ const x = barStartX + (startWeek / d.totalWeeks) * barMaxW;
766
+ const w = (phaseWeeks[i] / d.totalWeeks) * barMaxW;
767
+ const fillColor = i % 2 === 0 ? COLORS.lightTeal : COLORS.teal;
768
+
769
+ slide.addShape("rect", {
770
+ x,
771
+ y,
772
+ w,
773
+ h: 0.45,
774
+ fill: { color: fillColor },
775
+ line: { color: COLORS.teal, width: 1 },
776
+ });
777
+ slide.addText(phase.name, {
778
+ x,
779
+ y,
780
+ w,
781
+ h: 0.45,
782
+ fontSize: 10,
783
+ fontFace: FONT.body,
784
+ bold: true,
785
+ color: COLORS.darkBlue,
786
+ align: "center",
787
+ valign: "middle",
788
+ });
789
+ slide.addText(`${phase.desc}(${phase.weeksLabel})`, {
790
+ x,
791
+ y: y + 0.45,
792
+ w,
793
+ h: 0.35,
794
+ fontSize: 8,
795
+ fontFace: FONT.body,
796
+ color: COLORS.gray,
797
+ align: "center",
798
+ });
799
+ });
800
+
801
+ // MVP マーカー
802
+ if (d.mvpAfterPhase != null) {
803
+ const mvpWeeks = phaseWeeks
804
+ .slice(0, d.mvpAfterPhase + 1)
805
+ .reduce((a, b) => a + b, 0);
806
+ const mvpX = barStartX + (mvpWeeks / d.totalWeeks) * barMaxW;
807
+ slide.addShape("line", {
808
+ x: mvpX,
809
+ y: 1.5,
810
+ w: 0,
811
+ h: 5.0,
812
+ line: { color: COLORS.red, width: 2, dashType: "dash" },
813
+ });
814
+ slide.addText("MVP\nリリース", {
815
+ x: mvpX - 0.5,
816
+ y: 6.5,
817
+ w: 1.2,
818
+ h: 0.5,
819
+ fontSize: 10,
820
+ fontFace: FONT.body,
821
+ bold: true,
822
+ color: COLORS.red,
823
+ align: "center",
824
+ });
825
+ }
826
+
827
+ slide.addText("あくまで推測であって、確約するものではありません。", {
828
+ x: 0.5,
829
+ y: 7.0,
830
+ w: 9.0,
831
+ h: 0.3,
832
+ fontSize: 9,
833
+ fontFace: FONT.body,
834
+ color: COLORS.gray,
835
+ align: "right",
836
+ });
837
+ }
838
+
839
+ // ─── Slide 11: トレードオフ・スライダー ───
840
+ {
841
+ const d = SLIDE_DATA.tradeoffs;
842
+ const slide = pptx.addSlide();
843
+ addTitle(slide, "トレードオフ・スライダー");
844
+
845
+ d.sliders.forEach((s, i) => {
846
+ addSliderBar(slide, s.label, s.level, 1.8 + i * 0.7);
847
+ });
848
+
849
+ const qualityY = 1.8 + d.sliders.length * 0.7 + 0.3;
850
+ slide.addText("品質特性の優先順位", {
851
+ x: 0.5,
852
+ y: qualityY,
853
+ w: 9.0,
854
+ h: 0.4,
855
+ fontSize: 14,
856
+ fontFace: FONT.body,
857
+ bold: true,
858
+ color: COLORS.darkBlue,
859
+ });
860
+
861
+ addTable(
862
+ slide,
863
+ ["優先度", "品質特性", "理由"],
864
+ d.qualityPriorities,
865
+ { y: qualityY + 0.4, colW: [0.8, 1.8, 6.4] }
866
+ );
867
+ }
868
+
869
+ // ─── Slide 12: 初回のリリースに必要なもの ───
870
+ {
871
+ const d = SLIDE_DATA.initialRelease;
872
+ const slide = pptx.addSlide();
873
+ addTitle(slide, "初回のリリースに必要なもの");
874
+
875
+ addHighlightBox(slide, d.highlight, { y: 1.5, h: 0.7, fontSize: 16 });
876
+
877
+ slide.addText("MVP スコープ", {
878
+ x: 0.5,
879
+ y: 2.5,
880
+ w: 9.0,
881
+ h: 0.4,
882
+ fontSize: 14,
883
+ fontFace: FONT.body,
884
+ bold: true,
885
+ color: COLORS.darkBlue,
886
+ });
887
+
888
+ addBullets(slide, d.mvpScope, { y: 2.9, h: 2.5, fontSize: 13 });
889
+
890
+ slide.addText("リリース戦略", {
891
+ x: 0.5,
892
+ y: 5.2,
893
+ w: 9.0,
894
+ h: 0.4,
895
+ fontSize: 14,
896
+ fontFace: FONT.body,
897
+ bold: true,
898
+ color: COLORS.darkBlue,
899
+ });
900
+
901
+ addBullets(slide, d.releaseStrategy, { y: 5.6, h: 1.5, fontSize: 12 });
902
+ }
903
+
904
+ // ─── 保存 ───
905
+ const outputPath = resolve(`docs/analysis/slide/${meta.outputFileName}`);
906
+ const dataBuffer = await pptx.write({ outputType: "nodebuffer" });
907
+ writeFileSync(outputPath, dataBuffer);
908
+ console.log("Generated:", outputPath);
909
+ }
910
+
911
+ main().catch(console.error);