@k2works/claude-code-booster 1.9.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,14 +1,212 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* インセプションデッキ PowerPoint 生成スクリプト(汎用テンプレート)
|
|
3
3
|
*
|
|
4
4
|
* テンプレート: docs/template/インセプションデッキ.pptx のスライド構成に準拠
|
|
5
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 を実行
|
|
6
10
|
*/
|
|
7
11
|
import PptxGenJS from "pptxgenjs";
|
|
8
12
|
import { writeFileSync } from "fs";
|
|
9
13
|
import { resolve } from "path";
|
|
10
14
|
|
|
11
|
-
//
|
|
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
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
12
210
|
const COLORS = {
|
|
13
211
|
black: "000000",
|
|
14
212
|
white: "FFFFFF",
|
|
@@ -30,16 +228,9 @@ const FONT = {
|
|
|
30
228
|
code: "Courier New",
|
|
31
229
|
};
|
|
32
230
|
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
color: COLORS.white,
|
|
37
|
-
fontFace: FONT.title,
|
|
38
|
-
bold: true,
|
|
39
|
-
fontSize: subtitle ? 32 : 40,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
231
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
232
|
+
// ヘルパー関数
|
|
233
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
43
234
|
function addTitle(slide, text) {
|
|
44
235
|
slide.addText(text, {
|
|
45
236
|
x: 0.5,
|
|
@@ -142,7 +333,6 @@ function addHighlightBox(slide, text, opts = {}) {
|
|
|
142
333
|
}
|
|
143
334
|
|
|
144
335
|
function addSliderBar(slide, label, level, y) {
|
|
145
|
-
// level: 1-4 (1=MIN, 4=MAX)
|
|
146
336
|
const barX = 3.5;
|
|
147
337
|
const barW = 5.0;
|
|
148
338
|
const segW = barW / 4;
|
|
@@ -190,24 +380,27 @@ function addSliderBar(slide, label, level, y) {
|
|
|
190
380
|
});
|
|
191
381
|
}
|
|
192
382
|
|
|
193
|
-
//
|
|
383
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
384
|
+
// スライド生成
|
|
385
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
194
386
|
async function main() {
|
|
387
|
+
const { meta } = SLIDE_DATA;
|
|
388
|
+
|
|
195
389
|
const pptx = new PptxGenJS();
|
|
196
390
|
pptx.defineLayout({ name: "SCREEN_4x3", width: 10, height: 7.5 });
|
|
197
391
|
pptx.layout = "SCREEN_4x3";
|
|
198
|
-
pptx.author =
|
|
199
|
-
pptx.title =
|
|
392
|
+
pptx.author = meta.author;
|
|
393
|
+
pptx.title = meta.title;
|
|
200
394
|
|
|
201
|
-
//
|
|
202
|
-
// Slide 1: タイトル
|
|
203
|
-
// ───────────────────────────────────────
|
|
395
|
+
// ─── Slide 1: タイトル ───
|
|
204
396
|
{
|
|
397
|
+
const d = SLIDE_DATA.titleSlide;
|
|
205
398
|
const slide = pptx.addSlide();
|
|
206
399
|
slide.background = { color: COLORS.darkBlue };
|
|
207
400
|
slide.addText(
|
|
208
401
|
[
|
|
209
402
|
{
|
|
210
|
-
text:
|
|
403
|
+
text: d.projectName,
|
|
211
404
|
options: {
|
|
212
405
|
fontSize: 48,
|
|
213
406
|
fontFace: FONT.title,
|
|
@@ -217,7 +410,7 @@ async function main() {
|
|
|
217
410
|
},
|
|
218
411
|
},
|
|
219
412
|
{
|
|
220
|
-
text:
|
|
413
|
+
text: d.subtitle,
|
|
221
414
|
options: {
|
|
222
415
|
fontSize: 28,
|
|
223
416
|
fontFace: FONT.title,
|
|
@@ -226,7 +419,7 @@ async function main() {
|
|
|
226
419
|
},
|
|
227
420
|
},
|
|
228
421
|
{
|
|
229
|
-
text:
|
|
422
|
+
text: d.deckLabel,
|
|
230
423
|
options: {
|
|
231
424
|
fontSize: 24,
|
|
232
425
|
fontFace: FONT.title,
|
|
@@ -237,7 +430,7 @@ async function main() {
|
|
|
237
430
|
],
|
|
238
431
|
{ x: 1.0, y: 1.5, w: 8.0, h: 3.5, align: "center", valign: "middle" }
|
|
239
432
|
);
|
|
240
|
-
slide.addText(
|
|
433
|
+
slide.addText(d.organization, {
|
|
241
434
|
x: 1.0,
|
|
242
435
|
y: 5.5,
|
|
243
436
|
w: 8.0,
|
|
@@ -247,7 +440,7 @@ async function main() {
|
|
|
247
440
|
color: COLORS.lightTeal,
|
|
248
441
|
align: "center",
|
|
249
442
|
});
|
|
250
|
-
slide.addText(
|
|
443
|
+
slide.addText(`${meta.version} | ${meta.date}`, {
|
|
251
444
|
x: 1.0,
|
|
252
445
|
y: 6.2,
|
|
253
446
|
w: 8.0,
|
|
@@ -259,130 +452,53 @@ async function main() {
|
|
|
259
452
|
});
|
|
260
453
|
}
|
|
261
454
|
|
|
262
|
-
//
|
|
263
|
-
// Slide 2: 我われはなぜここにいるのか
|
|
264
|
-
// ───────────────────────────────────────
|
|
455
|
+
// ─── Slide 2: 我われはなぜここにいるのか ───
|
|
265
456
|
{
|
|
457
|
+
const d = SLIDE_DATA.whyAreWeHere;
|
|
266
458
|
const slide = pptx.addSlide();
|
|
267
459
|
addTitle(slide, "我われはなぜここにいるのか");
|
|
268
|
-
addSubtitle(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
);
|
|
272
|
-
addBullets(slide, [
|
|
273
|
-
"受注管理の分散:4 モールからの受注データが統合されておらず、個別処理の非効率が発生",
|
|
274
|
-
"在庫管理の複雑性:自社在庫と Amazon FBA 在庫の二元管理が手作業中心",
|
|
275
|
-
"データ分析の不在:売上・顧客データの分析基盤がなく、データに基づく意思決定ができていない",
|
|
276
|
-
"マーケティング戦略の未整備:効果的なマーケティング施策を立案・実行できていない",
|
|
277
|
-
"コーポレートサイトの活用不足:企業情報・製造所情報の発信が不十分",
|
|
278
|
-
]);
|
|
279
|
-
|
|
280
|
-
addHighlightBox(slide, "小規模組織の手作業の限界が、業務の品質と効率を圧迫している", {
|
|
460
|
+
addSubtitle(slide, d.subtitle);
|
|
461
|
+
addBullets(slide, d.bullets);
|
|
462
|
+
addHighlightBox(slide, d.highlight, {
|
|
281
463
|
y: 5.8,
|
|
282
464
|
h: 0.7,
|
|
283
465
|
fontSize: 14,
|
|
284
466
|
});
|
|
285
467
|
}
|
|
286
468
|
|
|
287
|
-
//
|
|
288
|
-
// Slide 3: エレベーターピッチ
|
|
289
|
-
// ───────────────────────────────────────
|
|
469
|
+
// ─── Slide 3: エレベーターピッチ ───
|
|
290
470
|
{
|
|
471
|
+
const d = SLIDE_DATA.elevatorPitch;
|
|
291
472
|
const slide = pptx.addSlide();
|
|
292
473
|
addTitle(slide, "エレベーターピッチ");
|
|
293
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
|
+
|
|
294
487
|
const pitchParts = [
|
|
295
|
-
{
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
},
|
|
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 },
|
|
386
502
|
];
|
|
387
503
|
|
|
388
504
|
slide.addText(pitchParts, {
|
|
@@ -396,92 +512,32 @@ async function main() {
|
|
|
396
512
|
});
|
|
397
513
|
}
|
|
398
514
|
|
|
399
|
-
//
|
|
400
|
-
// Slide 4: どんな価値をもたらすのか?
|
|
401
|
-
// ───────────────────────────────────────
|
|
515
|
+
// ─── Slide 4: どんな価値をもたらすのか? ───
|
|
402
516
|
{
|
|
517
|
+
const d = SLIDE_DATA.values;
|
|
403
518
|
const slide = pptx.addSlide();
|
|
404
519
|
addTitle(slide, "どんな価値をもたらすのか?");
|
|
405
520
|
addTable(
|
|
406
521
|
slide,
|
|
407
522
|
["#", "ビジネス目標", "期待される効果"],
|
|
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
|
-
],
|
|
523
|
+
d.rows,
|
|
436
524
|
{ colW: [0.4, 3.0, 5.6] }
|
|
437
525
|
);
|
|
438
526
|
}
|
|
439
527
|
|
|
440
|
-
//
|
|
441
|
-
// Slide 5: やらないことリスト(スコープ)
|
|
442
|
-
// ───────────────────────────────────────
|
|
528
|
+
// ─── Slide 5: やらないことリスト ───
|
|
443
529
|
{
|
|
530
|
+
const d = SLIDE_DATA.scope;
|
|
444
531
|
const slide = pptx.addSlide();
|
|
445
532
|
addTitle(slide, "やらないことリスト");
|
|
446
533
|
addSubtitle(slide, "スコープの範囲");
|
|
447
534
|
|
|
448
|
-
// Three columns
|
|
449
535
|
const colW = 2.85;
|
|
450
536
|
const colGap = 0.15;
|
|
451
537
|
const cols = [
|
|
452
|
-
{
|
|
453
|
-
|
|
454
|
-
|
|
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
|
-
},
|
|
538
|
+
{ title: "やる(スコープ内)", color: COLORS.teal, items: d.inScope },
|
|
539
|
+
{ title: "やらない(スコープ外)", color: COLORS.red, items: d.outOfScope },
|
|
540
|
+
{ title: "あとで決める", color: COLORS.orange, items: d.decideLater },
|
|
485
541
|
];
|
|
486
542
|
|
|
487
543
|
cols.forEach((col, i) => {
|
|
@@ -519,78 +575,46 @@ async function main() {
|
|
|
519
575
|
});
|
|
520
576
|
}
|
|
521
577
|
|
|
522
|
-
//
|
|
523
|
-
// Slide 6: 主なステークホルダー
|
|
524
|
-
// ───────────────────────────────────────
|
|
578
|
+
// ─── Slide 6: プロジェクトコミュニティ ───
|
|
525
579
|
{
|
|
580
|
+
const d = SLIDE_DATA.stakeholders;
|
|
526
581
|
const slide = pptx.addSlide();
|
|
527
582
|
addTitle(slide, "プロジェクトコミュニティ");
|
|
528
583
|
addSubtitle(slide, "主なステークホルダーと関心事");
|
|
529
584
|
addTable(
|
|
530
585
|
slide,
|
|
531
586
|
["ステークホルダー", "役割", "主な関心事"],
|
|
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
|
-
],
|
|
587
|
+
d.rows,
|
|
565
588
|
{ y: 1.7, colW: [2.0, 2.2, 4.8] }
|
|
566
589
|
);
|
|
567
590
|
}
|
|
568
591
|
|
|
569
|
-
//
|
|
570
|
-
// Slide 7: 技術的な解決策の概要
|
|
571
|
-
// ───────────────────────────────────────
|
|
592
|
+
// ─── Slide 7: 技術的な解決策の概要 ───
|
|
572
593
|
{
|
|
594
|
+
const d = SLIDE_DATA.technicalSolution;
|
|
573
595
|
const slide = pptx.addSlide();
|
|
574
596
|
addTitle(slide, "技術的な解決策の概要");
|
|
575
597
|
|
|
576
|
-
// Architecture diagram using shapes
|
|
577
598
|
const boxH = 0.5;
|
|
578
599
|
|
|
579
|
-
//
|
|
580
|
-
const
|
|
581
|
-
|
|
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);
|
|
582
606
|
slide.addShape("rect", {
|
|
583
|
-
x
|
|
607
|
+
x,
|
|
584
608
|
y: 1.5,
|
|
585
|
-
w:
|
|
609
|
+
w: channelW,
|
|
586
610
|
h: boxH,
|
|
587
611
|
fill: { color: COLORS.lightTeal },
|
|
588
612
|
line: { color: COLORS.teal, width: 1 },
|
|
589
613
|
});
|
|
590
|
-
slide.addText(name, {
|
|
591
|
-
x
|
|
614
|
+
slide.addText(ch.name, {
|
|
615
|
+
x,
|
|
592
616
|
y: 1.5,
|
|
593
|
-
w:
|
|
617
|
+
w: channelW,
|
|
594
618
|
h: boxH,
|
|
595
619
|
fontSize: 10,
|
|
596
620
|
fontFace: FONT.body,
|
|
@@ -600,7 +624,7 @@ async function main() {
|
|
|
600
624
|
});
|
|
601
625
|
});
|
|
602
626
|
|
|
603
|
-
//
|
|
627
|
+
// 接続ラベル
|
|
604
628
|
slide.addText("API", {
|
|
605
629
|
x: 4.0,
|
|
606
630
|
y: 2.05,
|
|
@@ -612,7 +636,7 @@ async function main() {
|
|
|
612
636
|
align: "center",
|
|
613
637
|
});
|
|
614
638
|
|
|
615
|
-
//
|
|
639
|
+
// 中央: メインシステム
|
|
616
640
|
slide.addShape("rect", {
|
|
617
641
|
x: 0.5,
|
|
618
642
|
y: 2.5,
|
|
@@ -621,7 +645,7 @@ async function main() {
|
|
|
621
645
|
fill: { color: "F8F8FF" },
|
|
622
646
|
line: { color: COLORS.darkBlue, width: 2 },
|
|
623
647
|
});
|
|
624
|
-
slide.addText(
|
|
648
|
+
slide.addText(d.systemName, {
|
|
625
649
|
x: 0.5,
|
|
626
650
|
y: 2.5,
|
|
627
651
|
w: 9.0,
|
|
@@ -633,17 +657,8 @@ async function main() {
|
|
|
633
657
|
align: "center",
|
|
634
658
|
});
|
|
635
659
|
|
|
636
|
-
//
|
|
637
|
-
|
|
638
|
-
"受注管理",
|
|
639
|
-
"在庫管理",
|
|
640
|
-
"出荷管理",
|
|
641
|
-
"商品管理",
|
|
642
|
-
"品質管理",
|
|
643
|
-
"調達管理",
|
|
644
|
-
"分析",
|
|
645
|
-
];
|
|
646
|
-
modules.forEach((name, i) => {
|
|
660
|
+
// 内部モジュール
|
|
661
|
+
d.modules.forEach((name, i) => {
|
|
647
662
|
const row = Math.floor(i / 4);
|
|
648
663
|
const col = i % 4;
|
|
649
664
|
slide.addShape("roundRect", {
|
|
@@ -667,26 +682,24 @@ async function main() {
|
|
|
667
682
|
});
|
|
668
683
|
});
|
|
669
684
|
|
|
670
|
-
//
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
];
|
|
677
|
-
extServices.forEach((svc) => {
|
|
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);
|
|
678
691
|
slide.addShape("rect", {
|
|
679
|
-
x
|
|
692
|
+
x,
|
|
680
693
|
y: 5.6,
|
|
681
|
-
w:
|
|
694
|
+
w: svcW,
|
|
682
695
|
h: boxH,
|
|
683
696
|
fill: { color: "FFF3E0" },
|
|
684
697
|
line: { color: COLORS.orange, width: 1 },
|
|
685
698
|
});
|
|
686
699
|
slide.addText(svc.name, {
|
|
687
|
-
x
|
|
700
|
+
x,
|
|
688
701
|
y: 5.6,
|
|
689
|
-
w:
|
|
702
|
+
w: svcW,
|
|
690
703
|
h: boxH,
|
|
691
704
|
fontSize: 10,
|
|
692
705
|
fontFace: FONT.body,
|
|
@@ -696,8 +709,8 @@ async function main() {
|
|
|
696
709
|
});
|
|
697
710
|
});
|
|
698
711
|
|
|
699
|
-
//
|
|
700
|
-
slide.addText(
|
|
712
|
+
// 技術方針ノート
|
|
713
|
+
slide.addText(d.techNote, {
|
|
701
714
|
x: 0.5,
|
|
702
715
|
y: 6.4,
|
|
703
716
|
w: 9.0,
|
|
@@ -709,142 +722,56 @@ async function main() {
|
|
|
709
722
|
});
|
|
710
723
|
}
|
|
711
724
|
|
|
712
|
-
//
|
|
713
|
-
// Slide 8: 夜も眠れなくなるような問題
|
|
714
|
-
// ───────────────────────────────────────
|
|
725
|
+
// ─── Slide 8: 夜も眠れなくなるような問題 ───
|
|
715
726
|
{
|
|
727
|
+
const d = SLIDE_DATA.risks;
|
|
716
728
|
const slide = pptx.addSlide();
|
|
717
729
|
addTitle(slide, "夜も眠れなくなるような問題は何だろう?");
|
|
718
730
|
addTable(
|
|
719
731
|
slide,
|
|
720
732
|
["#", "リスク", "影響度", "対策"],
|
|
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
|
-
],
|
|
733
|
+
d.rows,
|
|
759
734
|
{ colW: [0.4, 3.0, 0.8, 4.8] }
|
|
760
735
|
);
|
|
761
736
|
}
|
|
762
737
|
|
|
763
|
-
//
|
|
764
|
-
// Slide 9: 俺たちの "A チーム"
|
|
765
|
-
// ───────────────────────────────────────
|
|
738
|
+
// ─── Slide 9: 俺たちの "A チーム" ───
|
|
766
739
|
{
|
|
740
|
+
const d = SLIDE_DATA.team;
|
|
767
741
|
const slide = pptx.addSlide();
|
|
768
742
|
addTitle(slide, '俺たちの "A チーム"');
|
|
769
743
|
addTable(
|
|
770
744
|
slide,
|
|
771
745
|
["役割", "人数", "備考"],
|
|
772
|
-
|
|
773
|
-
["プロジェクトオーナー", "1 名", "経営者が兼務"],
|
|
774
|
-
["開発者", "1〜2 名", "AI エージェントとの協働開発"],
|
|
775
|
-
[
|
|
776
|
-
"業務担当(販売・製造)",
|
|
777
|
-
"2〜3 名",
|
|
778
|
-
"要件確認・受入テスト",
|
|
779
|
-
],
|
|
780
|
-
],
|
|
746
|
+
d.rows,
|
|
781
747
|
{ y: 1.8, colW: [2.5, 1.5, 5.0] }
|
|
782
748
|
);
|
|
783
|
-
|
|
784
|
-
addHighlightBox(
|
|
785
|
-
slide,
|
|
786
|
-
"AI エージェント(Claude Code)との協働開発により、少人数でも高品質な開発を実現",
|
|
787
|
-
{ y: 4.0, h: 0.8, fontSize: 14 }
|
|
788
|
-
);
|
|
749
|
+
addHighlightBox(slide, d.highlight, { y: 4.0, h: 0.8, fontSize: 14 });
|
|
789
750
|
}
|
|
790
751
|
|
|
791
|
-
//
|
|
792
|
-
// Slide 10: 期間を見極める
|
|
793
|
-
// ───────────────────────────────────────
|
|
752
|
+
// ─── Slide 10: 期間を見極める ───
|
|
794
753
|
{
|
|
754
|
+
const d = SLIDE_DATA.timeline;
|
|
795
755
|
const slide = pptx.addSlide();
|
|
796
756
|
addTitle(slide, "期間を見極める");
|
|
797
757
|
|
|
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
758
|
const barStartX = 0.5;
|
|
832
759
|
const barMaxW = 9.0;
|
|
833
|
-
const
|
|
834
|
-
const phaseWeeks = [3, 6, 3, 3, 3];
|
|
760
|
+
const phaseWeeks = d.phases.map((p) => p.weeks);
|
|
835
761
|
|
|
836
|
-
phases.forEach((phase, i) => {
|
|
762
|
+
d.phases.forEach((phase, i) => {
|
|
837
763
|
const y = 1.8 + i * 1.0;
|
|
838
764
|
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;
|
|
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;
|
|
841
768
|
|
|
842
769
|
slide.addShape("rect", {
|
|
843
770
|
x,
|
|
844
771
|
y,
|
|
845
772
|
w,
|
|
846
773
|
h: 0.45,
|
|
847
|
-
fill: { color:
|
|
774
|
+
fill: { color: fillColor },
|
|
848
775
|
line: { color: COLORS.teal, width: 1 },
|
|
849
776
|
});
|
|
850
777
|
slide.addText(phase.name, {
|
|
@@ -859,7 +786,7 @@ async function main() {
|
|
|
859
786
|
align: "center",
|
|
860
787
|
valign: "middle",
|
|
861
788
|
});
|
|
862
|
-
slide.addText(`${phase.desc}(${phase.
|
|
789
|
+
slide.addText(`${phase.desc}(${phase.weeksLabel})`, {
|
|
863
790
|
x,
|
|
864
791
|
y: y + 0.45,
|
|
865
792
|
w,
|
|
@@ -871,28 +798,31 @@ async function main() {
|
|
|
871
798
|
});
|
|
872
799
|
});
|
|
873
800
|
|
|
874
|
-
// MVP
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
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
|
+
}
|
|
896
826
|
|
|
897
827
|
slide.addText("あくまで推測であって、確約するものではありません。", {
|
|
898
828
|
x: 0.5,
|
|
@@ -906,33 +836,20 @@ async function main() {
|
|
|
906
836
|
});
|
|
907
837
|
}
|
|
908
838
|
|
|
909
|
-
//
|
|
910
|
-
// Slide 11: トレードオフ・スライダー
|
|
911
|
-
// ───────────────────────────────────────
|
|
839
|
+
// ─── Slide 11: トレードオフ・スライダー ───
|
|
912
840
|
{
|
|
841
|
+
const d = SLIDE_DATA.tradeoffs;
|
|
913
842
|
const slide = pptx.addSlide();
|
|
914
843
|
addTitle(slide, "トレードオフ・スライダー");
|
|
915
844
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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
|
-
);
|
|
845
|
+
d.sliders.forEach((s, i) => {
|
|
846
|
+
addSliderBar(slide, s.label, s.level, 1.8 + i * 0.7);
|
|
847
|
+
});
|
|
931
848
|
|
|
932
|
-
|
|
849
|
+
const qualityY = 1.8 + d.sliders.length * 0.7 + 0.3;
|
|
933
850
|
slide.addText("品質特性の優先順位", {
|
|
934
851
|
x: 0.5,
|
|
935
|
-
y:
|
|
852
|
+
y: qualityY,
|
|
936
853
|
w: 9.0,
|
|
937
854
|
h: 0.4,
|
|
938
855
|
fontSize: 14,
|
|
@@ -944,28 +861,18 @@ async function main() {
|
|
|
944
861
|
addTable(
|
|
945
862
|
slide,
|
|
946
863
|
["優先度", "品質特性", "理由"],
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
["2", "使いやすさ", "小規模チームが日常的に使うため、直感的な操作性が必須"],
|
|
950
|
-
["3", "信頼性", "受注処理の停止は直接的な売上損失につながる"],
|
|
951
|
-
["4", "保守性", "小規模チームでの長期運用を見据えたシンプルな設計"],
|
|
952
|
-
],
|
|
953
|
-
{ y: 5.2, colW: [0.8, 1.8, 6.4] }
|
|
864
|
+
d.qualityPriorities,
|
|
865
|
+
{ y: qualityY + 0.4, colW: [0.8, 1.8, 6.4] }
|
|
954
866
|
);
|
|
955
867
|
}
|
|
956
868
|
|
|
957
|
-
//
|
|
958
|
-
// Slide 12: 初回のリリースに必要なもの
|
|
959
|
-
// ───────────────────────────────────────
|
|
869
|
+
// ─── Slide 12: 初回のリリースに必要なもの ───
|
|
960
870
|
{
|
|
871
|
+
const d = SLIDE_DATA.initialRelease;
|
|
961
872
|
const slide = pptx.addSlide();
|
|
962
873
|
addTitle(slide, "初回のリリースに必要なもの");
|
|
963
874
|
|
|
964
|
-
addHighlightBox(
|
|
965
|
-
slide,
|
|
966
|
-
"Phase 2 完了時点で MVP(最小実行可能製品)をリリース",
|
|
967
|
-
{ y: 1.5, h: 0.7, fontSize: 16 }
|
|
968
|
-
);
|
|
875
|
+
addHighlightBox(slide, d.highlight, { y: 1.5, h: 0.7, fontSize: 16 });
|
|
969
876
|
|
|
970
877
|
slide.addText("MVP スコープ", {
|
|
971
878
|
x: 0.5,
|
|
@@ -978,16 +885,7 @@ async function main() {
|
|
|
978
885
|
color: COLORS.darkBlue,
|
|
979
886
|
});
|
|
980
887
|
|
|
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
|
-
);
|
|
888
|
+
addBullets(slide, d.mvpScope, { y: 2.9, h: 2.5, fontSize: 13 });
|
|
991
889
|
|
|
992
890
|
slide.addText("リリース戦略", {
|
|
993
891
|
x: 0.5,
|
|
@@ -1000,22 +898,11 @@ async function main() {
|
|
|
1000
898
|
color: COLORS.darkBlue,
|
|
1001
899
|
});
|
|
1002
900
|
|
|
1003
|
-
addBullets(
|
|
1004
|
-
slide,
|
|
1005
|
-
[
|
|
1006
|
-
"以降のフェーズは段階的にリリースし、フィードバックを反映しながら改善",
|
|
1007
|
-
"各フェーズ完了時にステークホルダーレビューを実施し、次フェーズの優先順位を見直す",
|
|
1008
|
-
],
|
|
1009
|
-
{ y: 5.6, h: 1.5, fontSize: 12 }
|
|
1010
|
-
);
|
|
901
|
+
addBullets(slide, d.releaseStrategy, { y: 5.6, h: 1.5, fontSize: 12 });
|
|
1011
902
|
}
|
|
1012
903
|
|
|
1013
|
-
//
|
|
1014
|
-
|
|
1015
|
-
// ───────────────────────────────────────
|
|
1016
|
-
const outputPath = resolve(
|
|
1017
|
-
"docs/analysis/slide/HCOSS_v0.1.0.pptx"
|
|
1018
|
-
);
|
|
904
|
+
// ─── 保存 ───
|
|
905
|
+
const outputPath = resolve(`docs/analysis/slide/${meta.outputFileName}`);
|
|
1019
906
|
const dataBuffer = await pptx.write({ outputType: "nodebuffer" });
|
|
1020
907
|
writeFileSync(outputPath, dataBuffer);
|
|
1021
908
|
console.log("Generated:", outputPath);
|
|
@@ -68,16 +68,45 @@ node .claude/scripts/generate-inception-deck.mjs
|
|
|
68
68
|
|
|
69
69
|
#### 生成スクリプトの更新
|
|
70
70
|
|
|
71
|
-
inception-deck.md
|
|
71
|
+
inception-deck.md の内容が更新された場合、生成スクリプトの `SLIDE_DATA` オブジェクトを更新してから再実行する。
|
|
72
72
|
|
|
73
73
|
1. @docs/analysis/inception-deck.md を読み込む
|
|
74
|
-
2. @.claude/scripts/generate-inception-deck.mjs
|
|
74
|
+
2. @.claude/scripts/generate-inception-deck.mjs の `SLIDE_DATA` セクションを更新
|
|
75
75
|
3. `node .claude/scripts/generate-inception-deck.mjs` で再生成
|
|
76
76
|
|
|
77
|
+
#### スクリプト構成
|
|
78
|
+
|
|
79
|
+
生成スクリプトは以下の 4 セクションで構成されている。
|
|
80
|
+
|
|
81
|
+
| セクション | 内容 | 編集対象 |
|
|
82
|
+
| :--- | :--- | :--- |
|
|
83
|
+
| `SLIDE_DATA` | プロジェクト固有のデータ(テキスト・数値) | 毎回更新 |
|
|
84
|
+
| テーマ設定 | カラー・フォント定義 | 通常変更不要 |
|
|
85
|
+
| ヘルパー関数 | スライド部品の描画ロジック | 通常変更不要 |
|
|
86
|
+
| スライド生成 | `SLIDE_DATA` を読み取り 12 枚を生成 | 通常変更不要 |
|
|
87
|
+
|
|
88
|
+
`SLIDE_DATA` の各キーがスライドに対応している。
|
|
89
|
+
|
|
90
|
+
| キー | 対応スライド |
|
|
91
|
+
| :--- | :--- |
|
|
92
|
+
| `meta` | メタ情報(author, title, version, date, outputFileName) |
|
|
93
|
+
| `titleSlide` | Slide 1: タイトル |
|
|
94
|
+
| `whyAreWeHere` | Slide 2: 我われはなぜここにいるのか |
|
|
95
|
+
| `elevatorPitch` | Slide 3: エレベーターピッチ |
|
|
96
|
+
| `values` | Slide 4: どんな価値をもたらすのか? |
|
|
97
|
+
| `scope` | Slide 5: やらないことリスト |
|
|
98
|
+
| `stakeholders` | Slide 6: プロジェクトコミュニティ |
|
|
99
|
+
| `technicalSolution` | Slide 7: 技術的な解決策の概要 |
|
|
100
|
+
| `risks` | Slide 8: 夜も眠れなくなるような問題 |
|
|
101
|
+
| `team` | Slide 9: 俺たちの "A チーム" |
|
|
102
|
+
| `timeline` | Slide 10: 期間を見極める |
|
|
103
|
+
| `tradeoffs` | Slide 11: トレードオフ・スライダー |
|
|
104
|
+
| `initialRelease` | Slide 12: 初回のリリースに必要なもの |
|
|
105
|
+
|
|
77
106
|
#### バージョン管理
|
|
78
107
|
|
|
79
|
-
-
|
|
80
|
-
-
|
|
108
|
+
- 出力ファイル名は `SLIDE_DATA.meta.outputFileName` で指定する(例: `PROJECT_v0.1.0.pptx`)
|
|
109
|
+
- `meta.title` と `meta.outputFileName` を同時に更新すること
|
|
81
110
|
|
|
82
111
|
### 6. 注意事項
|
|
83
112
|
|
|
@@ -91,13 +120,14 @@ inception-deck.md の内容が更新された場合、生成スクリプトの
|
|
|
91
120
|
|
|
92
121
|
1. `npm install pptxgenjs`(初回のみ)
|
|
93
122
|
2. @docs/analysis/inception-deck.md の内容を確認
|
|
94
|
-
3.
|
|
95
|
-
4.
|
|
123
|
+
3. @.claude/scripts/generate-inception-deck.mjs の `SLIDE_DATA` をプロジェクト固有の内容に書き換える
|
|
124
|
+
4. `node .claude/scripts/generate-inception-deck.mjs` を実行
|
|
125
|
+
5. @docs/analysis/slide/ に .pptx が生成されたことを確認
|
|
96
126
|
|
|
97
127
|
### インセプションデッキ更新後のスライド再生成
|
|
98
128
|
|
|
99
129
|
1. @docs/analysis/inception-deck.md の更新内容を確認
|
|
100
|
-
2. @.claude/scripts/generate-inception-deck.mjs
|
|
130
|
+
2. @.claude/scripts/generate-inception-deck.mjs の `SLIDE_DATA` を更新
|
|
101
131
|
3. `node .claude/scripts/generate-inception-deck.mjs` を実行
|
|
102
132
|
|
|
103
133
|
### 関連スキル
|