style: [barobill] PPT 라이트 테마로 전환 (인쇄 친화적 흰색 배경)
This commit is contained in:
@@ -4,8 +4,8 @@ module.paths.unshift(path.join(require('os').homedir(), '.claude/skills/pptx-ski
|
||||
|
||||
const PptxGenJS = require('pptxgenjs');
|
||||
|
||||
// BI 로고를 base64로 변환
|
||||
const biLogoPath = '/home/aweso/sam/docs/assets/bi/sam_bi_white.png';
|
||||
// BI 로고 (밝은 배경용 검정 로고)
|
||||
const biLogoPath = '/home/aweso/sam/docs/assets/bi/sam_bi_black.png';
|
||||
const biLogoBase64 = fs.existsSync(biLogoPath)
|
||||
? 'image/png;base64,' + fs.readFileSync(biLogoPath).toString('base64')
|
||||
: null;
|
||||
@@ -14,95 +14,121 @@ async function main() {
|
||||
const pres = new PptxGenJS();
|
||||
pres.defineLayout({ name: 'CUSTOM_16x9', width: 10, height: 5.625 });
|
||||
pres.layout = 'CUSTOM_16x9';
|
||||
pres.author = '(주)코드브릿지엑스';
|
||||
pres.title = '바로빌 서비스 이관 완료 보고';
|
||||
|
||||
// ─── 색상 팔레트 ───
|
||||
// ─── 라이트 테마 색상 팔레트 (인쇄 친화) ───
|
||||
const C = {
|
||||
dark: '1a1a2e',
|
||||
darkBlue: '16213e',
|
||||
accent: '0f3460',
|
||||
blue: '2196F3',
|
||||
green: '4CAF50',
|
||||
greenBg: 'E8F5E9',
|
||||
greenDark: '2E7D32',
|
||||
orange: 'FF9800',
|
||||
orangeBg: 'FFF3E0',
|
||||
red: 'E53935',
|
||||
redBg: 'FFEBEE',
|
||||
purple: '7C4DFF',
|
||||
purpleBg: 'EDE7F6',
|
||||
// 배경
|
||||
white: 'FFFFFF',
|
||||
gray: '666666',
|
||||
grayLight: 'F5F5F5',
|
||||
grayBorder: 'E0E0E0',
|
||||
text: '333333',
|
||||
textLight: '999999',
|
||||
bg: 'F8FAFC', // 슬라이드 배경 (아주 밝은 회색)
|
||||
cardBg: 'FFFFFF',
|
||||
// 텍스트
|
||||
title: '0F172A', // 거의 검정
|
||||
text: '334155', // 슬레이트 700
|
||||
textLight: '94A3B8', // 슬레이트 400
|
||||
textMuted: '64748B', // 슬레이트 500
|
||||
// 포인트 컬러
|
||||
primary: '2563EB', // 블루 600
|
||||
primaryLight: 'DBEAFE', // 블루 100
|
||||
primaryDark: '1E40AF', // 블루 800
|
||||
green: '16A34A', // 그린 600
|
||||
greenLight: 'DCFCE7', // 그린 100
|
||||
greenDark: '15803D', // 그린 700
|
||||
orange: 'EA580C', // 오렌지 600
|
||||
orangeLight: 'FFEDD5', // 오렌지 100
|
||||
red: 'DC2626', // 레드 600
|
||||
redLight: 'FEE2E2', // 레드 100
|
||||
purple: '7C3AED', // 바이올렛 600
|
||||
purpleLight: 'EDE9FE', // 바이올렛 100
|
||||
teal: '0D9488', // 틸 600
|
||||
tealLight: 'CCFBF1', // 틸 100
|
||||
// 구조
|
||||
border: 'E2E8F0', // 슬레이트 200
|
||||
divider: 'CBD5E1', // 슬레이트 300
|
||||
headerBg: 'F1F5F9', // 슬레이트 100
|
||||
dark: '1E293B', // 슬레이트 800 (강조 배경)
|
||||
};
|
||||
|
||||
// ─── 공통 함수 ───
|
||||
function addFooter(slide, pageNum, totalPages) {
|
||||
slide.addShape(pres.ShapeType.rect, { x: 0, y: 5.25, w: 10, h: 0.375, fill: { color: C.dark } });
|
||||
slide.addText('SAM 바로빌 서비스 이관 보고 | (주)코드브릿지엑스', {
|
||||
x: 0.5, y: 5.25, w: 7, h: 0.375, fontSize: 7, color: '888888', fontFace: 'Arial'
|
||||
slide.addShape(pres.ShapeType.rect, { x: 0, y: 5.25, w: 10, h: 0.375, fill: { color: C.headerBg } });
|
||||
slide.addShape(pres.ShapeType.rect, { x: 0, y: 5.24, w: 10, h: 0.01, fill: { color: C.border } });
|
||||
slide.addText('SAM 바로빌 서비스 이관 보고 | (주)코드브릿지엑스', {
|
||||
x: 0.5, y: 5.25, w: 7, h: 0.375, fontSize: 7, color: C.textLight, fontFace: 'Arial'
|
||||
});
|
||||
slide.addText(`${pageNum} / ${totalPages}`, {
|
||||
x: 8.5, y: 5.25, w: 1, h: 0.375, fontSize: 7, color: '888888', align: 'right', fontFace: 'Arial'
|
||||
x: 8.5, y: 5.25, w: 1, h: 0.375, fontSize: 7, color: C.textLight, align: 'right', fontFace: 'Arial'
|
||||
});
|
||||
}
|
||||
|
||||
function addPageTitle(slide, title, subtitle) {
|
||||
slide.addShape(pres.ShapeType.rect, { x: 0.5, y: 0.35, w: 0.06, h: 0.35, fill: { color: C.blue } });
|
||||
slide.addText(title, { x: 0.7, y: 0.28, w: 6, h: 0.5, fontSize: 20, bold: true, color: C.dark, fontFace: 'Arial' });
|
||||
slide.addShape(pres.ShapeType.rect, { x: 0.5, y: 0.35, w: 0.06, h: 0.4, fill: { color: C.primary } });
|
||||
slide.addText(title, { x: 0.7, y: 0.28, w: 6, h: 0.55, fontSize: 22, bold: true, color: C.title, fontFace: 'Arial' });
|
||||
if (subtitle) {
|
||||
slide.addText(subtitle, { x: 0.7, y: 0.72, w: 6, h: 0.3, fontSize: 10, color: C.gray, fontFace: 'Arial' });
|
||||
slide.addText(subtitle, { x: 0.7, y: 0.78, w: 6, h: 0.25, fontSize: 10, color: C.textMuted, fontFace: 'Arial' });
|
||||
}
|
||||
}
|
||||
|
||||
function addBadge(slide, x, y, text, bgColor, textColor) {
|
||||
slide.addShape(pres.ShapeType.roundRect, { x, y, w: text.length * 0.12 + 0.4, h: 0.28, rectRadius: 0.04, fill: { color: bgColor } });
|
||||
slide.addText(text, { x, y, w: text.length * 0.12 + 0.4, h: 0.28, fontSize: 8, bold: true, color: textColor, align: 'center', fontFace: 'Arial' });
|
||||
}
|
||||
|
||||
const totalPages = 7;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// 슬라이드 1: 표지
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const slide1 = pres.addSlide();
|
||||
slide1.background = { fill: C.dark };
|
||||
slide1.background = { fill: C.white };
|
||||
|
||||
// 상단 장식 라인
|
||||
slide1.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 10, h: 0.06, fill: { color: C.blue } });
|
||||
// 상단 컬러 바
|
||||
slide1.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 10, h: 0.08, fill: { color: C.primary } });
|
||||
|
||||
// 좌측 세로 장식
|
||||
slide1.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: 0.08, h: 5.625, fill: { color: C.primary } });
|
||||
|
||||
// BI 로고
|
||||
if (biLogoBase64) {
|
||||
slide1.addImage({ data: biLogoBase64, x: 0.7, y: 0.5, w: 1.2, h: 1.2 });
|
||||
slide1.addImage({ data: biLogoBase64, x: 0.6, y: 0.4, w: 0.8, h: 0.8 });
|
||||
}
|
||||
|
||||
// 제목 영역
|
||||
slide1.addText('바로빌 서비스 이관 완료 보고', {
|
||||
x: 0.7, y: 1.8, w: 8.6, h: 0.8,
|
||||
fontSize: 32, bold: true, color: C.white, fontFace: 'Arial'
|
||||
// 제목
|
||||
slide1.addText('바로빌 서비스 이관', {
|
||||
x: 0.6, y: 1.8, w: 6, h: 0.7,
|
||||
fontSize: 36, bold: true, color: C.title, fontFace: 'Arial'
|
||||
});
|
||||
slide1.addText('MNG → API 전체 기능 이관 현황', {
|
||||
x: 0.7, y: 2.6, w: 8.6, h: 0.5,
|
||||
fontSize: 16, color: C.blue, fontFace: 'Arial'
|
||||
slide1.addText('완료 보고', {
|
||||
x: 0.6, y: 2.4, w: 6, h: 0.6,
|
||||
fontSize: 36, bold: true, color: C.primary, fontFace: 'Arial'
|
||||
});
|
||||
|
||||
// 구분선
|
||||
slide1.addShape(pres.ShapeType.rect, { x: 0.7, y: 3.3, w: 2, h: 0.03, fill: { color: C.blue } });
|
||||
// 부제목
|
||||
slide1.addShape(pres.ShapeType.rect, { x: 0.6, y: 3.2, w: 2.5, h: 0.03, fill: { color: C.primary } });
|
||||
slide1.addText('MNG → API 전체 기능 이관 현황', {
|
||||
x: 0.6, y: 3.4, w: 5, h: 0.35,
|
||||
fontSize: 14, color: C.textMuted, fontFace: 'Arial'
|
||||
});
|
||||
|
||||
// 메타 정보
|
||||
slide1.addText([
|
||||
{ text: '보고일: 2026-03-22', options: { fontSize: 11, color: '888888' } },
|
||||
{ text: '\n담당: R&D실', options: { fontSize: 11, color: '888888' } },
|
||||
{ text: '\n프로젝트: SAM (Smart Automation Management)', options: { fontSize: 11, color: '888888' } },
|
||||
], { x: 0.7, y: 3.6, w: 5, h: 1.2, fontFace: 'Arial', lineSpacingMultiple: 1.5 });
|
||||
{ text: '보고일 2026-03-22', options: { fontSize: 10, color: C.textLight } },
|
||||
{ text: '\n담당 R&D실', options: { fontSize: 10, color: C.textLight } },
|
||||
], { x: 0.6, y: 4.0, w: 4, h: 0.8, fontFace: 'Arial', lineSpacingMultiple: 1.6 });
|
||||
|
||||
// 우측 하이라이트 카드
|
||||
slide1.addShape(pres.ShapeType.roundRect, { x: 6.5, y: 3.5, w: 3, h: 1.4, rectRadius: 0.15, fill: { color: '222244' }, line: { color: C.blue, width: 1 } });
|
||||
slide1.addText('이관 완료', { x: 6.5, y: 3.6, w: 3, h: 0.3, fontSize: 10, color: C.blue, align: 'center', fontFace: 'Arial' });
|
||||
slide1.addText('12 / 12', { x: 6.5, y: 3.9, w: 3, h: 0.5, fontSize: 36, bold: true, color: C.green, align: 'center', fontFace: 'Arial' });
|
||||
slide1.addText('100% 완료', { x: 6.5, y: 4.4, w: 3, h: 0.3, fontSize: 12, bold: true, color: C.green, align: 'center', fontFace: 'Arial' });
|
||||
// 우측 완료 카드
|
||||
slide1.addShape(pres.ShapeType.roundRect, { x: 6.5, y: 1.5, w: 3, h: 2.8, rectRadius: 0.15, fill: { color: C.greenLight }, line: { color: C.green, width: 1.5 } });
|
||||
slide1.addText('이관 완료', { x: 6.5, y: 1.7, w: 3, h: 0.3, fontSize: 11, color: C.green, align: 'center', fontFace: 'Arial' });
|
||||
slide1.addText('12 / 12', { x: 6.5, y: 2.1, w: 3, h: 0.7, fontSize: 44, bold: true, color: C.greenDark, align: 'center', fontFace: 'Arial' });
|
||||
slide1.addText('100%', { x: 6.5, y: 2.8, w: 3, h: 0.4, fontSize: 20, bold: true, color: C.green, align: 'center', fontFace: 'Arial' });
|
||||
|
||||
// 핵심 수치 카드들
|
||||
const metrics = [
|
||||
{ label: 'API 엔드포인트', value: '87+', color: C.primary, bg: C.primaryLight },
|
||||
{ label: 'SOAP 메서드', value: '57', color: C.teal, bg: C.tealLight },
|
||||
];
|
||||
metrics.forEach((m, i) => {
|
||||
const mx = 6.5 + i * 1.55;
|
||||
slide1.addShape(pres.ShapeType.roundRect, { x: mx, y: 3.55, w: 1.4, h: 0.65, rectRadius: 0.08, fill: { color: m.bg } });
|
||||
slide1.addText(m.value, { x: mx, y: 3.52, w: 1.4, h: 0.4, fontSize: 18, bold: true, color: m.color, align: 'center', fontFace: 'Arial' });
|
||||
slide1.addText(m.label, { x: mx, y: 3.88, w: 1.4, h: 0.25, fontSize: 7, color: m.color, align: 'center', fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
addFooter(slide1, 1, totalPages);
|
||||
|
||||
@@ -110,14 +136,15 @@ async function main() {
|
||||
// 슬라이드 2: 이관 배경 및 목적
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const slide2 = pres.addSlide();
|
||||
slide2.background = { fill: C.white };
|
||||
slide2.background = { fill: C.bg };
|
||||
addPageTitle(slide2, '이관 배경 및 목적', 'MNG 백오피스 → API 서비스 전환');
|
||||
|
||||
// 아키텍처 다이어그램
|
||||
// Before 카드
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 1.3, w: 4.2, h: 3.5, rectRadius: 0.12, fill: { color: C.redBg }, line: { color: 'FFCDD2', width: 1 } });
|
||||
addBadge(slide2, 1.6, 1.45, 'AS-IS', C.red, C.white);
|
||||
slide2.addText('MNG 단독 운영', { x: 0.7, y: 1.9, w: 3.8, h: 0.35, fontSize: 14, bold: true, color: C.red, align: 'center', fontFace: 'Arial' });
|
||||
// AS-IS
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 1.3, w: 4.2, h: 3.6, rectRadius: 0.12, fill: { color: C.white }, line: { color: C.border, width: 1 } });
|
||||
// 헤더
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 1.3, w: 4.2, h: 0.5, rectRadius: 0.12, fill: { color: C.redLight } });
|
||||
slide2.addShape(pres.ShapeType.rect, { x: 0.5, y: 1.68, w: 4.2, h: 0.13, fill: { color: C.redLight } });
|
||||
slide2.addText('AS-IS | MNG 단독 운영', { x: 0.7, y: 1.35, w: 3.8, h: 0.4, fontSize: 12, bold: true, color: C.red, fontFace: 'Arial' });
|
||||
|
||||
const asIsItems = [
|
||||
'SOAP 연동이 MNG에만 존재',
|
||||
@@ -126,19 +153,21 @@ async function main() {
|
||||
'멀티테넌트 SaaS 제공 불가',
|
||||
];
|
||||
asIsItems.forEach((item, i) => {
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 0.7, y: 2.5 + i * 0.55, w: 3.8, h: 0.42, rectRadius: 0.06, fill: { color: C.white } });
|
||||
slide2.addShape(pres.ShapeType.ellipse, { x: 0.85, y: 2.58 + i * 0.55, w: 0.22, h: 0.22, fill: { color: C.red } });
|
||||
slide2.addText('x', { x: 0.85, y: 2.56 + i * 0.55, w: 0.22, h: 0.22, fontSize: 9, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide2.addText(item, { x: 1.2, y: 2.5 + i * 0.55, w: 3.2, h: 0.42, fontSize: 10, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
const iy = 2.05 + i * 0.6;
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 0.7, y: iy, w: 3.8, h: 0.45, rectRadius: 0.06, fill: { color: C.headerBg } });
|
||||
slide2.addShape(pres.ShapeType.ellipse, { x: 0.85, y: iy + 0.1, w: 0.25, h: 0.25, fill: { color: C.red } });
|
||||
slide2.addText('X', { x: 0.85, y: iy + 0.1, w: 0.25, h: 0.25, fontSize: 10, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide2.addText(item, { x: 1.25, y: iy, w: 3.1, h: 0.45, fontSize: 10, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
// 화살표
|
||||
slide2.addText('→', { x: 4.6, y: 2.7, w: 0.8, h: 0.5, fontSize: 28, bold: true, color: C.blue, align: 'center', fontFace: 'Arial' });
|
||||
slide2.addText('▶', { x: 4.6, y: 2.8, w: 0.8, h: 0.5, fontSize: 24, color: C.primary, align: 'center', fontFace: 'Arial' });
|
||||
|
||||
// After 카드
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 5.3, y: 1.3, w: 4.2, h: 3.5, rectRadius: 0.12, fill: { color: C.greenBg }, line: { color: 'C8E6C9', width: 1 } });
|
||||
addBadge(slide2, 6.4, 1.45, 'TO-BE', C.green, C.white);
|
||||
slide2.addText('API + React 서비스', { x: 5.5, y: 1.9, w: 3.8, h: 0.35, fontSize: 14, bold: true, color: C.greenDark, align: 'center', fontFace: 'Arial' });
|
||||
// TO-BE
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 5.3, y: 1.3, w: 4.2, h: 3.6, rectRadius: 0.12, fill: { color: C.white }, line: { color: C.border, width: 1 } });
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 5.3, y: 1.3, w: 4.2, h: 0.5, rectRadius: 0.12, fill: { color: C.greenLight } });
|
||||
slide2.addShape(pres.ShapeType.rect, { x: 5.3, y: 1.68, w: 4.2, h: 0.13, fill: { color: C.greenLight } });
|
||||
slide2.addText('TO-BE | API + React 서비스', { x: 5.5, y: 1.35, w: 3.8, h: 0.4, fontSize: 12, bold: true, color: C.greenDark, fontFace: 'Arial' });
|
||||
|
||||
const toBeItems = [
|
||||
'API에 독립 SOAP 서비스 구축',
|
||||
@@ -147,10 +176,11 @@ async function main() {
|
||||
'멀티테넌트 SaaS 과금 체계',
|
||||
];
|
||||
toBeItems.forEach((item, i) => {
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 5.5, y: 2.5 + i * 0.55, w: 3.8, h: 0.42, rectRadius: 0.06, fill: { color: C.white } });
|
||||
slide2.addShape(pres.ShapeType.ellipse, { x: 5.65, y: 2.58 + i * 0.55, w: 0.22, h: 0.22, fill: { color: C.green } });
|
||||
slide2.addText('✓', { x: 5.65, y: 2.56 + i * 0.55, w: 0.22, h: 0.22, fontSize: 9, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide2.addText(item, { x: 6.0, y: 2.5 + i * 0.55, w: 3.2, h: 0.42, fontSize: 10, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
const iy = 2.05 + i * 0.6;
|
||||
slide2.addShape(pres.ShapeType.roundRect, { x: 5.5, y: iy, w: 3.8, h: 0.45, rectRadius: 0.06, fill: { color: C.headerBg } });
|
||||
slide2.addShape(pres.ShapeType.ellipse, { x: 5.65, y: iy + 0.1, w: 0.25, h: 0.25, fill: { color: C.green } });
|
||||
slide2.addText('✓', { x: 5.65, y: iy + 0.08, w: 0.25, h: 0.25, fontSize: 11, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide2.addText(item, { x: 6.05, y: iy, w: 3.1, h: 0.45, fontSize: 10, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
addFooter(slide2, 2, totalPages);
|
||||
@@ -159,54 +189,64 @@ async function main() {
|
||||
// 슬라이드 3: 이관 현황 총괄
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const slide3 = pres.addSlide();
|
||||
slide3.background = { fill: C.white };
|
||||
slide3.background = { fill: C.bg };
|
||||
addPageTitle(slide3, '이관 현황 총괄', '12개 영역 전체 API 이관 완료');
|
||||
|
||||
// 프로그레스 바
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 1.15, w: 9, h: 0.35, rectRadius: 0.06, fill: { color: 'E0E0E0' } });
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 1.15, w: 9, h: 0.35, rectRadius: 0.06, fill: { color: C.border } });
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 1.15, w: 9, h: 0.35, rectRadius: 0.06, fill: { color: C.green } });
|
||||
slide3.addText('100% 완료 (12/12 영역)', { x: 0.5, y: 1.15, w: 9, h: 0.35, fontSize: 11, bold: true, color: C.white, align: 'center', fontFace: 'Arial' });
|
||||
|
||||
// 영역 테이블
|
||||
// 테이블
|
||||
const areas = [
|
||||
['SOAP 연동 서비스', '57개 메서드', C.green],
|
||||
['바로빌 설정/회원', '설정 + 회원 CRUD', C.green],
|
||||
['계좌 조회 (EAccount)', '13 EP + Sync', C.green],
|
||||
['카드 조회 (ECard)', '16 EP + Sync', C.green],
|
||||
['홈택스 매입/매출', '13 EP + Sync', C.green],
|
||||
['전자세금계산서 발행', '16 EP (SOAP)', C.green],
|
||||
['자동 동기화 스케줄러', 'Job (매일 06:00)', C.green],
|
||||
['카카오톡 발송', '12 EP', C.blue],
|
||||
['SMS 발송', '4 EP', C.blue],
|
||||
['구독/과금 관리', '9 EP', C.purple],
|
||||
['사용량 관리', '4 EP', C.purple],
|
||||
['SOAP 연동 서비스', '57개 메서드', 'green', '기존'],
|
||||
['바로빌 설정/회원 관리', '설정 + 회원 CRUD', 'green', '기존'],
|
||||
['계좌 조회 (EAccount)', '13 EP + Sync', 'green', '기존'],
|
||||
['카드 조회 (ECard)', '16 EP + Sync', 'green', '기존'],
|
||||
['홈택스 매입/매출', '13 EP + Sync', 'green', '기존'],
|
||||
['전자세금계산서 발행', '16 EP (SOAP)', 'green', '기존'],
|
||||
['자동 동기화 스케줄러', 'Job (매일 06:00)', 'green', '기존'],
|
||||
['카카오톡 발송', '12 EP', 'blue', '신규'],
|
||||
['SMS 발송', '4 EP', 'blue', '신규'],
|
||||
['구독/과금 관리', '9 EP', 'purple', '신규'],
|
||||
['사용량 관리', '4 EP', 'purple', '신규'],
|
||||
];
|
||||
|
||||
// 테이블 헤더
|
||||
const tblY = 1.7;
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 0.5, y: tblY, w: 9, h: 0.35, rectRadius: 0.04, fill: { color: C.dark } });
|
||||
slide3.addText('#', { x: 0.55, y: tblY, w: 0.4, h: 0.35, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('영역', { x: 1.0, y: tblY, w: 4, h: 0.35, fontSize: 8, bold: true, color: C.white, valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('API 규모', { x: 5.2, y: tblY, w: 2, h: 0.35, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('상태', { x: 7.5, y: tblY, w: 1.8, h: 0.35, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
// 헤더
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 0.5, y: tblY, w: 9, h: 0.35, rectRadius: 0.03, fill: { color: C.dark } });
|
||||
slide3.addText('#', { x: 0.6, y: tblY, w: 0.4, h: 0.35, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('영역', { x: 1.1, y: tblY, w: 3.5, h: 0.35, fontSize: 8, bold: true, color: C.white, valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('API 규모', { x: 4.8, y: tblY, w: 2, h: 0.35, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('구분', { x: 7.0, y: tblY, w: 0.8, h: 0.35, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('상태', { x: 8.0, y: tblY, w: 1.3, h: 0.35, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
areas.forEach((area, i) => {
|
||||
const rowY = tblY + 0.38 + i * 0.3;
|
||||
const rowBg = i % 2 === 0 ? C.grayLight : C.white;
|
||||
slide3.addShape(pres.ShapeType.rect, { x: 0.5, y: rowY, w: 9, h: 0.3, fill: { color: rowBg } });
|
||||
slide3.addText(`${i + 1}`, { x: 0.55, y: rowY, w: 0.4, h: 0.3, fontSize: 8, color: C.gray, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText(area[0], { x: 1.0, y: rowY, w: 4, h: 0.3, fontSize: 9, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText(area[1], { x: 5.2, y: rowY, w: 2, h: 0.3, fontSize: 8, color: C.gray, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
// 상태 배지
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 7.8, y: rowY + 0.04, w: 1.2, h: 0.22, rectRadius: 0.04, fill: { color: area[2] } });
|
||||
slide3.addText('완료', { x: 7.8, y: rowY + 0.04, w: 1.2, h: 0.22, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
const colorMap = { green: C.green, blue: C.primary, purple: C.purple };
|
||||
const bgMap = { green: C.greenLight, blue: C.primaryLight, purple: C.purpleLight };
|
||||
|
||||
areas.forEach((a, i) => {
|
||||
const ry = tblY + 0.38 + i * 0.29;
|
||||
const rowBg = i % 2 === 0 ? C.headerBg : C.white;
|
||||
slide3.addShape(pres.ShapeType.rect, { x: 0.5, y: ry, w: 9, h: 0.29, fill: { color: rowBg } });
|
||||
slide3.addText(`${i + 1}`, { x: 0.6, y: ry, w: 0.4, h: 0.29, fontSize: 8, color: C.textLight, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText(a[0], { x: 1.1, y: ry, w: 3.5, h: 0.29, fontSize: 9, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText(a[1], { x: 4.8, y: ry, w: 2, h: 0.29, fontSize: 8, color: C.textMuted, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
// 구분 배지
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 7.05, y: ry + 0.04, w: 0.7, h: 0.21, rectRadius: 0.03, fill: { color: bgMap[a[2]] } });
|
||||
slide3.addText(a[3], { x: 7.05, y: ry + 0.04, w: 0.7, h: 0.21, fontSize: 7, bold: true, color: colorMap[a[2]], align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
// 완료 배지
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 8.2, y: ry + 0.04, w: 0.9, h: 0.21, rectRadius: 0.03, fill: { color: C.green } });
|
||||
slide3.addText('완료', { x: 8.2, y: ry + 0.04, w: 0.9, h: 0.21, fontSize: 7, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
// 신규 이관 표시
|
||||
slide3.addShape(pres.ShapeType.ellipse, { x: 0.6, y: 4.85, w: 0.15, h: 0.15, fill: { color: C.blue } });
|
||||
slide3.addText('이번 세션 신규 이관 (카카오톡/SMS)', { x: 0.85, y: 4.82, w: 3, h: 0.2, fontSize: 7, color: C.blue, fontFace: 'Arial' });
|
||||
slide3.addShape(pres.ShapeType.ellipse, { x: 4.0, y: 4.85, w: 0.15, h: 0.15, fill: { color: C.purple } });
|
||||
slide3.addText('이번 세션 신규 이관 (과금/사용량)', { x: 4.25, y: 4.82, w: 3, h: 0.2, fontSize: 7, color: C.purple, fontFace: 'Arial' });
|
||||
// 범례
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 4.85, w: 0.5, h: 0.2, rectRadius: 0.03, fill: { color: C.primaryLight } });
|
||||
slide3.addText('신규', { x: 0.5, y: 4.85, w: 0.5, h: 0.2, fontSize: 7, bold: true, color: C.primary, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('이번 세션 카카오톡/SMS 이관', { x: 1.1, y: 4.83, w: 2.5, h: 0.22, fontSize: 8, color: C.textMuted, fontFace: 'Arial' });
|
||||
|
||||
slide3.addShape(pres.ShapeType.roundRect, { x: 3.8, y: 4.85, w: 0.5, h: 0.2, rectRadius: 0.03, fill: { color: C.purpleLight } });
|
||||
slide3.addText('신규', { x: 3.8, y: 4.85, w: 0.5, h: 0.2, fontSize: 7, bold: true, color: C.purple, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide3.addText('이번 세션 과금/사용량 이관', { x: 4.4, y: 4.83, w: 2.5, h: 0.22, fontSize: 8, color: C.textMuted, fontFace: 'Arial' });
|
||||
|
||||
addFooter(slide3, 3, totalPages);
|
||||
|
||||
@@ -214,27 +254,18 @@ async function main() {
|
||||
// 슬라이드 4: API 엔드포인트 상세
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const slide4 = pres.addSlide();
|
||||
slide4.background = { fill: C.white };
|
||||
slide4.background = { fill: C.bg };
|
||||
addPageTitle(slide4, 'API 엔드포인트 상세', '총 87+ REST API 엔드포인트 구축');
|
||||
|
||||
const epGroups = [
|
||||
{ title: '데이터 조회/관리', color: C.green, bg: C.greenBg, border: 'C8E6C9', items: [
|
||||
['카드 거래', '16 EP'],
|
||||
['은행 거래', '13 EP'],
|
||||
['홈택스', '13 EP'],
|
||||
['세금계산서', '16 EP'],
|
||||
{ title: '데이터 조회/관리', color: C.green, bg: C.greenLight, items: [
|
||||
['카드 거래', '16 EP'], ['은행 거래', '13 EP'], ['홈택스', '13 EP'], ['세금계산서', '16 EP'],
|
||||
]},
|
||||
{ title: '통신/발송', color: C.blue, bg: 'E3F2FD', border: 'BBDEFB', items: [
|
||||
['카카오톡', '12 EP'],
|
||||
['SMS', '4 EP'],
|
||||
['동기화', '3 EP'],
|
||||
['회원관리', '3 EP'],
|
||||
{ title: '통신/발송', color: C.primary, bg: C.primaryLight, items: [
|
||||
['카카오톡', '12 EP'], ['SMS', '4 EP'], ['동기화', '3 EP'], ['회원관리', '3 EP'],
|
||||
]},
|
||||
{ title: '관리/과금', color: C.purple, bg: C.purpleBg, border: 'D1C4E9', items: [
|
||||
['과금 관리', '9 EP'],
|
||||
['사용량', '4 EP'],
|
||||
['설정', '3 EP'],
|
||||
['스케줄러', 'Daily Job'],
|
||||
{ title: '관리/과금', color: C.purple, bg: C.purpleLight, items: [
|
||||
['과금 관리', '9 EP'], ['사용량', '4 EP'], ['설정', '3 EP'], ['스케줄러', 'Daily Job'],
|
||||
]},
|
||||
];
|
||||
|
||||
@@ -244,19 +275,16 @@ async function main() {
|
||||
const gy = 1.2;
|
||||
|
||||
// 카드 배경
|
||||
slide4.addShape(pres.ShapeType.roundRect, { x: gx, y: gy, w: cardW, h: 3.8, rectRadius: 0.12, fill: { color: group.bg }, line: { color: group.border, width: 1 } });
|
||||
|
||||
// 카드 헤더
|
||||
slide4.addShape(pres.ShapeType.roundRect, { x: gx, y: gy, w: cardW, h: 3.8, rectRadius: 0.12, fill: { color: C.white }, line: { color: C.border, width: 1 } });
|
||||
// 헤더
|
||||
slide4.addShape(pres.ShapeType.roundRect, { x: gx, y: gy, w: cardW, h: 0.5, rectRadius: 0.12, fill: { color: group.color } });
|
||||
// 하단 모서리 채우기
|
||||
slide4.addShape(pres.ShapeType.rect, { x: gx, y: gy + 0.38, w: cardW, h: 0.13, fill: { color: group.color } });
|
||||
slide4.addText(group.title, { x: gx, y: gy + 0.05, w: cardW, h: 0.4, fontSize: 13, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
// 카드 항목
|
||||
group.items.forEach((item, ii) => {
|
||||
const iy = gy + 0.7 + ii * 0.75;
|
||||
slide4.addShape(pres.ShapeType.roundRect, { x: gx + 0.15, y: iy, w: cardW - 0.3, h: 0.6, rectRadius: 0.08, fill: { color: C.white }, shadow: { type: 'outer', blur: 3, offset: 1, color: '00000010' } });
|
||||
slide4.addText(item[0], { x: gx + 0.3, y: iy + 0.05, w: cardW - 0.6, h: 0.22, fontSize: 10, bold: true, color: C.text, fontFace: 'Arial' });
|
||||
slide4.addShape(pres.ShapeType.roundRect, { x: gx + 0.15, y: iy, w: cardW - 0.3, h: 0.6, rectRadius: 0.08, fill: { color: C.headerBg }, line: { color: C.border, width: 0.5 } });
|
||||
slide4.addText(item[0], { x: gx + 0.3, y: iy + 0.05, w: cardW - 0.6, h: 0.22, fontSize: 10, color: C.text, fontFace: 'Arial' });
|
||||
slide4.addText(item[1], { x: gx + 0.3, y: iy + 0.3, w: cardW - 0.6, h: 0.22, fontSize: 16, bold: true, color: group.color, fontFace: 'Arial' });
|
||||
});
|
||||
});
|
||||
@@ -264,22 +292,21 @@ async function main() {
|
||||
addFooter(slide4, 4, totalPages);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// 슬라이드 5: SOAP 메서드 구현율
|
||||
// 슬라이드 5: SOAP 구현율
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const slide5 = pres.addSlide();
|
||||
slide5.background = { fill: C.white };
|
||||
slide5.background = { fill: C.bg };
|
||||
addPageTitle(slide5, 'SOAP 메서드 구현율', 'MNG 대비 API 100% 이상 구현');
|
||||
|
||||
const soapData = [
|
||||
{ name: 'CORPSTATE\n회원관리', mng: 3, api: 3, color: '26A69A' },
|
||||
{ name: 'BANKACCOUNT\n계좌조회', mng: 13, api: 14, color: '42A5F5' },
|
||||
{ name: 'CARD\n카드조회', mng: 11, api: 11, color: '5C6BC0' },
|
||||
{ name: 'TI\n세금계산서', mng: 3, api: 3, color: 'AB47BC' },
|
||||
{ name: 'KAKAOTALK\n카카오톡', mng: 15, api: 15, color: 'FFA726' },
|
||||
{ name: 'SMS\n문자전송', mng: 4, api: 4, color: 'EF5350' },
|
||||
{ name: 'CORPSTATE\n회원관리', mng: 3, api: 3, color: C.teal },
|
||||
{ name: 'BANK\nACCOUNT', mng: 13, api: 14, color: C.primary },
|
||||
{ name: 'CARD\n카드조회', mng: 11, api: 11, color: '6366F1' },
|
||||
{ name: 'TI\n세금계산서', mng: 3, api: 3, color: C.purple },
|
||||
{ name: 'KAKAOTALK\n카카오톡', mng: 15, api: 15, color: C.orange },
|
||||
{ name: 'SMS\n문자전송', mng: 4, api: 4, color: C.red },
|
||||
];
|
||||
|
||||
// 차트 영역
|
||||
const chartX = 0.5;
|
||||
const chartY = 1.3;
|
||||
const barW = 1.3;
|
||||
@@ -287,176 +314,151 @@ async function main() {
|
||||
const maxVal = 16;
|
||||
const chartH = 2.5;
|
||||
|
||||
// 차트 배경
|
||||
slide5.addShape(pres.ShapeType.roundRect, { x: 0.3, y: 1.1, w: 9.4, h: 3.1, rectRadius: 0.1, fill: { color: C.white }, line: { color: C.border, width: 0.5 } });
|
||||
|
||||
soapData.forEach((d, i) => {
|
||||
const bx = chartX + i * (barW + barGap);
|
||||
const bx = chartX + 0.15 + i * (barW + barGap);
|
||||
|
||||
// MNG 바
|
||||
const mngH = (d.mng / maxVal) * chartH;
|
||||
slide5.addShape(pres.ShapeType.roundRect, {
|
||||
x: bx, y: chartY + chartH - mngH, w: barW * 0.45, h: mngH,
|
||||
rectRadius: 0.04, fill: { color: 'BDBDBD' }
|
||||
x: bx, y: chartY + chartH - mngH, w: barW * 0.42, h: mngH,
|
||||
rectRadius: 0.04, fill: { color: C.border }
|
||||
});
|
||||
slide5.addText(`${d.mng}`, {
|
||||
x: bx, y: chartY + chartH - mngH - 0.22, w: barW * 0.45, h: 0.22,
|
||||
fontSize: 9, bold: true, color: C.gray, align: 'center', fontFace: 'Arial'
|
||||
x: bx, y: chartY + chartH - mngH - 0.2, w: barW * 0.42, h: 0.2,
|
||||
fontSize: 8, bold: true, color: C.textMuted, align: 'center', fontFace: 'Arial'
|
||||
});
|
||||
|
||||
// API 바
|
||||
const apiH = (d.api / maxVal) * chartH;
|
||||
slide5.addShape(pres.ShapeType.roundRect, {
|
||||
x: bx + barW * 0.5, y: chartY + chartH - apiH, w: barW * 0.45, h: apiH,
|
||||
x: bx + barW * 0.48, y: chartY + chartH - apiH, w: barW * 0.42, h: apiH,
|
||||
rectRadius: 0.04, fill: { color: d.color }
|
||||
});
|
||||
slide5.addText(`${d.api}`, {
|
||||
x: bx + barW * 0.5, y: chartY + chartH - apiH - 0.22, w: barW * 0.45, h: 0.22,
|
||||
fontSize: 9, bold: true, color: d.color, align: 'center', fontFace: 'Arial'
|
||||
x: bx + barW * 0.48, y: chartY + chartH - apiH - 0.2, w: barW * 0.42, h: 0.2,
|
||||
fontSize: 8, bold: true, color: d.color, align: 'center', fontFace: 'Arial'
|
||||
});
|
||||
|
||||
// 라벨
|
||||
slide5.addText(d.name, {
|
||||
x: bx, y: chartY + chartH + 0.08, w: barW, h: 0.45,
|
||||
fontSize: 8, color: C.text, align: 'center', valign: 'top', fontFace: 'Arial'
|
||||
x: bx - 0.05, y: chartY + chartH + 0.08, w: barW + 0.1, h: 0.4,
|
||||
fontSize: 7, color: C.text, align: 'center', valign: 'top', fontFace: 'Arial'
|
||||
});
|
||||
|
||||
// 구현율
|
||||
const rate = Math.round((d.api / d.mng) * 100);
|
||||
slide5.addShape(pres.ShapeType.roundRect, { x: bx + 0.2, y: chartY + chartH + 0.52, w: barW - 0.4, h: 0.22, rectRadius: 0.04, fill: { color: C.greenBg } });
|
||||
slide5.addText(`${rate}%`, { x: bx + 0.2, y: chartY + chartH + 0.52, w: barW - 0.4, h: 0.22, fontSize: 8, bold: true, color: C.greenDark, align: 'center', fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
// 범례
|
||||
slide5.addShape(pres.ShapeType.rect, { x: 7.5, y: 1.3, w: 0.3, h: 0.18, fill: { color: 'BDBDBD' } });
|
||||
slide5.addText('MNG', { x: 7.85, y: 1.28, w: 0.8, h: 0.22, fontSize: 9, color: C.gray, fontFace: 'Arial' });
|
||||
slide5.addShape(pres.ShapeType.rect, { x: 7.5, y: 1.55, w: 0.3, h: 0.18, fill: { color: C.blue } });
|
||||
slide5.addText('API', { x: 7.85, y: 1.53, w: 0.8, h: 0.22, fontSize: 9, color: C.blue, fontFace: 'Arial' });
|
||||
slide5.addShape(pres.ShapeType.rect, { x: 8.0, y: 1.25, w: 0.25, h: 0.15, fill: { color: C.border } });
|
||||
slide5.addText('MNG', { x: 8.3, y: 1.22, w: 0.6, h: 0.2, fontSize: 8, color: C.textMuted, fontFace: 'Arial' });
|
||||
slide5.addShape(pres.ShapeType.rect, { x: 8.0, y: 1.48, w: 0.25, h: 0.15, fill: { color: C.primary } });
|
||||
slide5.addText('API', { x: 8.3, y: 1.45, w: 0.6, h: 0.2, fontSize: 8, color: C.primary, fontFace: 'Arial' });
|
||||
|
||||
// 합계 박스
|
||||
// 합계 바
|
||||
slide5.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 4.55, w: 9, h: 0.5, rectRadius: 0.08, fill: { color: C.dark } });
|
||||
slide5.addText([
|
||||
{ text: 'SOAP 메서드 합계 ', options: { fontSize: 11, color: '888888' } },
|
||||
{ text: 'MNG 49개', options: { fontSize: 11, color: 'BDBDBD', bold: true } },
|
||||
{ text: ' → ', options: { fontSize: 11, color: '888888' } },
|
||||
{ text: 'API 50개', options: { fontSize: 11, color: C.green, bold: true } },
|
||||
{ text: ' (100%+)', options: { fontSize: 11, color: C.green } },
|
||||
{ text: 'SOAP 메서드 합계 ', options: { fontSize: 10, color: C.textLight } },
|
||||
{ text: 'MNG 49개', options: { fontSize: 10, color: C.divider, bold: true } },
|
||||
{ text: ' → ', options: { fontSize: 10, color: C.textLight } },
|
||||
{ text: 'API 50개', options: { fontSize: 10, color: C.green, bold: true } },
|
||||
{ text: ' (100%+)', options: { fontSize: 10, color: C.green } },
|
||||
], { x: 0.5, y: 4.55, w: 9, h: 0.5, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
addFooter(slide5, 5, totalPages);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// 슬라이드 6: 코드 매핑 요약
|
||||
// 슬라이드 6: 코드 매핑
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const slide6 = pres.addSlide();
|
||||
slide6.background = { fill: C.white };
|
||||
slide6.background = { fill: C.bg };
|
||||
addPageTitle(slide6, '코드 매핑 요약', 'MNG → API 파일 대응 관계');
|
||||
|
||||
const mappings = [
|
||||
{ cat: 'Service', mng: 6, api: 8, detail: 'SOAP, Sync, Billing, Usage, TaxInvoice' },
|
||||
{ cat: 'Controller', mng: 14, api: 11, detail: '카드/은행/홈택스/세금계산서/카카오톡/SMS/과금/사용량' },
|
||||
{ cat: 'Model', mng: 18, api: 17, detail: '거래, 분개, 구독, 과금, 정책 등' },
|
||||
{ cat: 'Migration', mng: '-', api: 30, detail: '바로빌 관련 테이블 생성/수정' },
|
||||
{ cat: 'Route', mng: 20, api: '87+', detail: 'finance.php 내 바로빌 라우트 그룹' },
|
||||
{ cat: 'Job', mng: 1, api: 1, detail: 'SyncBarobillDataJob (매일 자동 동기화)' },
|
||||
{ cat: 'Service', mng: '6개', api: '8개', detail: 'SOAP, Sync, Billing, Usage, TaxInvoice 등' },
|
||||
{ cat: 'Controller', mng: '14개', api: '11개', detail: '카드/은행/홈택스/세금계산서/카카오톡/SMS/과금/사용량' },
|
||||
{ cat: 'Model', mng: '18개', api: '17개', detail: '거래, 분개, 구독, 과금, 정책 등' },
|
||||
{ cat: 'Migration', mng: '-', api: '30개', detail: '바로빌 관련 테이블 생성/수정' },
|
||||
{ cat: 'Route', mng: '20개', api: '87+', detail: 'finance.php 내 바로빌 라우트 그룹' },
|
||||
{ cat: 'Job', mng: '1개', api: '1개', detail: 'SyncBarobillDataJob (매일 자동 동기화)' },
|
||||
];
|
||||
|
||||
// 테이블 헤더
|
||||
// 테이블
|
||||
const mY = 1.2;
|
||||
slide6.addShape(pres.ShapeType.roundRect, { x: 0.5, y: mY, w: 9, h: 0.4, rectRadius: 0.04, fill: { color: C.accent } });
|
||||
slide6.addText('유형', { x: 0.6, y: mY, w: 1.5, h: 0.4, fontSize: 9, bold: true, color: C.white, valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText('MNG', { x: 2.2, y: mY, w: 1, h: 0.4, fontSize: 9, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText('API', { x: 3.3, y: mY, w: 1, h: 0.4, fontSize: 9, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText('포함 내용', { x: 4.5, y: mY, w: 4.8, h: 0.4, fontSize: 9, bold: true, color: C.white, valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addShape(pres.ShapeType.roundRect, { x: 0.5, y: mY, w: 9, h: 0.4, rectRadius: 0.04, fill: { color: C.dark } });
|
||||
slide6.addText('유형', { x: 0.6, y: mY, w: 1.2, h: 0.4, fontSize: 9, bold: true, color: C.white, valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText('MNG', { x: 1.9, y: mY, w: 0.9, h: 0.4, fontSize: 9, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText('API', { x: 2.9, y: mY, w: 0.9, h: 0.4, fontSize: 9, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText('포함 내용', { x: 4.0, y: mY, w: 5.3, h: 0.4, fontSize: 9, bold: true, color: C.white, valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
mappings.forEach((m, i) => {
|
||||
const ry = mY + 0.44 + i * 0.55;
|
||||
const bg = i % 2 === 0 ? C.grayLight : C.white;
|
||||
slide6.addShape(pres.ShapeType.roundRect, { x: 0.5, y: ry, w: 9, h: 0.5, rectRadius: 0.04, fill: { color: bg } });
|
||||
|
||||
const ry = mY + 0.44 + i * 0.5;
|
||||
const bg = i % 2 === 0 ? C.white : C.headerBg;
|
||||
slide6.addShape(pres.ShapeType.rect, { x: 0.5, y: ry, w: 9, h: 0.5, fill: { color: bg } });
|
||||
// 카테고리 배지
|
||||
slide6.addShape(pres.ShapeType.roundRect, { x: 0.65, y: ry + 0.1, w: 1.3, h: 0.3, rectRadius: 0.04, fill: { color: C.accent } });
|
||||
slide6.addText(m.cat, { x: 0.65, y: ry + 0.1, w: 1.3, h: 0.3, fontSize: 9, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
slide6.addText(`${m.mng}`, { x: 2.2, y: ry, w: 1, h: 0.5, fontSize: 12, color: C.gray, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText(`${m.api}`, { x: 3.3, y: ry, w: 1, h: 0.5, fontSize: 12, bold: true, color: C.blue, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText(m.detail, { x: 4.5, y: ry, w: 4.8, h: 0.5, fontSize: 9, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addShape(pres.ShapeType.roundRect, { x: 0.65, y: ry + 0.1, w: 1, h: 0.3, rectRadius: 0.04, fill: { color: C.primary } });
|
||||
slide6.addText(m.cat, { x: 0.65, y: ry + 0.1, w: 1, h: 0.3, fontSize: 8, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText(m.mng, { x: 1.9, y: ry, w: 0.9, h: 0.5, fontSize: 11, color: C.textMuted, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText(m.api, { x: 2.9, y: ry, w: 0.9, h: 0.5, fontSize: 11, bold: true, color: C.primary, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
slide6.addText(m.detail, { x: 4.0, y: ry, w: 5.3, h: 0.5, fontSize: 9, color: C.text, valign: 'middle', fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
// 이관 원칙 박스
|
||||
slide6.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 4.2, w: 9, h: 0.8, rectRadius: 0.08, fill: { color: 'FFF8E1' }, line: { color: 'FFE082', width: 1 } });
|
||||
slide6.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 4.15, w: 9, h: 0.85, rectRadius: 0.08, fill: { color: C.orangeLight }, line: { color: C.orange, width: 0.5 } });
|
||||
slide6.addText([
|
||||
{ text: '이관 원칙: ', options: { fontSize: 10, bold: true, color: C.orange } },
|
||||
{ text: '이관 원칙\n', options: { fontSize: 10, bold: true, color: C.orange } },
|
||||
{ text: 'MNG 코드를 수정/삭제하지 않고, API에 독립적으로 새로 구현. 같은 DB(samdb)를 공유하되, 각각 독립 SOAP 호출. 멀티테넌트(tenant_id) 격리 필수.', options: { fontSize: 9, color: C.text } },
|
||||
], { x: 0.7, y: 4.25, w: 8.6, h: 0.7, valign: 'middle', fontFace: 'Arial' });
|
||||
], { x: 0.7, y: 4.2, w: 8.6, h: 0.75, valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
addFooter(slide6, 6, totalPages);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// 슬라이드 7: 향후 계획 (Next Steps)
|
||||
// 슬라이드 7: 향후 계획
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
const slide7 = pres.addSlide();
|
||||
slide7.background = { fill: C.white };
|
||||
slide7.background = { fill: C.bg };
|
||||
addPageTitle(slide7, '향후 계획', '출시까지의 로드맵');
|
||||
|
||||
// 타임라인
|
||||
const phases = [
|
||||
{ title: 'Phase 1', sub: 'SOAP 이관\n(API 개발)', status: '완료', color: C.green, statusBg: C.greenBg, statusColor: C.greenDark },
|
||||
{ title: 'Phase 2', sub: 'UI 구현\n(React 개발)', status: '다음', color: C.blue, statusBg: 'E3F2FD', statusColor: C.blue },
|
||||
{ title: 'Phase 3', sub: '베타테스트\n(내부→외부)', status: '예정', color: C.orange, statusBg: C.orangeBg, statusColor: C.orange },
|
||||
{ title: 'Phase 4', sub: '정식 출시\n(온보딩 가동)', status: '예정', color: C.purple, statusBg: C.purpleBg, statusColor: C.purple },
|
||||
{ title: 'Phase 1', sub: 'SOAP 이관\n(API 개발)', status: '완료', color: C.green, statusBg: C.greenLight },
|
||||
{ title: 'Phase 2', sub: 'UI 구현\n(React 개발)', status: '다음', color: C.primary, statusBg: C.primaryLight },
|
||||
{ title: 'Phase 3', sub: '베타테스트\n(내부→외부)', status: '예정', color: C.orange, statusBg: C.orangeLight },
|
||||
{ title: 'Phase 4', sub: '정식 출시\n(온보딩 가동)', status: '예정', color: C.purple, statusBg: C.purpleLight },
|
||||
];
|
||||
|
||||
phases.forEach((p, i) => {
|
||||
const px = 0.5 + i * 2.35;
|
||||
const py = 1.3;
|
||||
|
||||
const py = 1.2;
|
||||
// 카드
|
||||
slide7.addShape(pres.ShapeType.roundRect, { x: px, y: py, w: 2.15, h: 1.6, rectRadius: 0.1, fill: { color: C.white }, line: { color: p.color, width: 1.5 } });
|
||||
|
||||
slide7.addShape(pres.ShapeType.roundRect, { x: px, y: py, w: 2.15, h: 1.7, rectRadius: 0.1, fill: { color: C.white }, line: { color: p.color, width: 1.5 } });
|
||||
// 넘버 서클
|
||||
slide7.addShape(pres.ShapeType.ellipse, { x: px + 0.75, y: py + 0.15, w: 0.6, h: 0.6, fill: { color: p.color } });
|
||||
slide7.addText(`${i + 1}`, { x: px + 0.75, y: py + 0.15, w: 0.6, h: 0.6, fontSize: 18, bold: true, color: C.white, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
// Phase 제목
|
||||
slide7.addText(p.title, { x: px, y: py + 0.8, w: 2.15, h: 0.25, fontSize: 11, bold: true, color: p.color, align: 'center', fontFace: 'Arial' });
|
||||
slide7.addText(p.sub, { x: px, y: py + 1.0, w: 2.15, h: 0.35, fontSize: 8, color: C.gray, align: 'center', fontFace: 'Arial' });
|
||||
|
||||
slide7.addText(p.sub, { x: px, y: py + 1.05, w: 2.15, h: 0.35, fontSize: 8, color: C.textMuted, align: 'center', fontFace: 'Arial' });
|
||||
// 상태 배지
|
||||
slide7.addShape(pres.ShapeType.roundRect, { x: px + 0.55, y: py + 1.38, w: 1, h: 0.2, rectRadius: 0.04, fill: { color: p.statusBg } });
|
||||
slide7.addText(p.status, { x: px + 0.55, y: py + 1.38, w: 1, h: 0.2, fontSize: 8, bold: true, color: p.statusColor, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
|
||||
// 연결선
|
||||
slide7.addShape(pres.ShapeType.roundRect, { x: px + 0.55, y: py + 1.42, w: 1, h: 0.22, rectRadius: 0.04, fill: { color: p.statusBg } });
|
||||
slide7.addText(p.status, { x: px + 0.55, y: py + 1.42, w: 1, h: 0.22, fontSize: 8, bold: true, color: p.color, align: 'center', valign: 'middle', fontFace: 'Arial' });
|
||||
// 화살표
|
||||
if (i < 3) {
|
||||
slide7.addText('→', { x: px + 2.05, y: py + 0.55, w: 0.4, h: 0.4, fontSize: 16, color: C.grayBorder, align: 'center', fontFace: 'Arial' });
|
||||
slide7.addText('▶', { x: px + 2.1, y: py + 0.55, w: 0.3, h: 0.4, fontSize: 12, color: C.divider, align: 'center', fontFace: 'Arial' });
|
||||
}
|
||||
});
|
||||
|
||||
// 남은 과제 카드
|
||||
slide7.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 3.2, w: 4.3, h: 1.7, rectRadius: 0.1, fill: { color: C.white }, line: { color: C.blue, width: 1 } });
|
||||
slide7.addText('Phase 2 주요 작업 (React UI)', { x: 0.7, y: 3.3, w: 3.9, h: 0.3, fontSize: 11, bold: true, color: C.blue, fontFace: 'Arial' });
|
||||
|
||||
const phase2Tasks = [
|
||||
'계좌/카드/홈택스 조회 화면',
|
||||
'세금계산서 발행 화면',
|
||||
'바로빌 연동 설정 화면 보강',
|
||||
'카카오톡/SMS 발송 화면',
|
||||
];
|
||||
phase2Tasks.forEach((task, i) => {
|
||||
slide7.addShape(pres.ShapeType.ellipse, { x: 0.8, y: 3.7 + i * 0.28, w: 0.12, h: 0.12, fill: { color: C.blue } });
|
||||
slide7.addText(task, { x: 1.05, y: 3.65 + i * 0.28, w: 3.5, h: 0.22, fontSize: 9, color: C.text, fontFace: 'Arial' });
|
||||
// Phase 2 작업
|
||||
slide7.addShape(pres.ShapeType.roundRect, { x: 0.5, y: 3.2, w: 4.3, h: 1.7, rectRadius: 0.1, fill: { color: C.white }, line: { color: C.primary, width: 1 } });
|
||||
slide7.addText('Phase 2 주요 작업 (React UI)', { x: 0.7, y: 3.3, w: 3.9, h: 0.3, fontSize: 11, bold: true, color: C.primary, fontFace: 'Arial' });
|
||||
['계좌/카드/홈택스 조회 화면', '세금계산서 발행 화면', '바로빌 연동 설정 화면 보강', '카카오톡/SMS 발송 화면'].forEach((t, i) => {
|
||||
slide7.addShape(pres.ShapeType.ellipse, { x: 0.85, y: 3.72 + i * 0.28, w: 0.12, h: 0.12, fill: { color: C.primary } });
|
||||
slide7.addText(t, { x: 1.1, y: 3.66 + i * 0.28, w: 3.5, h: 0.22, fontSize: 9, color: C.text, fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
// 확인 필요 사항 카드
|
||||
// 확인 사항
|
||||
slide7.addShape(pres.ShapeType.roundRect, { x: 5.2, y: 3.2, w: 4.3, h: 1.7, rectRadius: 0.1, fill: { color: C.white }, line: { color: C.orange, width: 1 } });
|
||||
slide7.addText('출시 전 확인 필요 사항', { x: 5.4, y: 3.3, w: 3.9, h: 0.3, fontSize: 11, bold: true, color: C.orange, fontFace: 'Arial' });
|
||||
|
||||
const confirmTasks = [
|
||||
'멀티테넌트 CERTKEY 구조 확인 (바로빌 측)',
|
||||
'테스트→운영 모드 전환 프로세스',
|
||||
'공동인증서 등록 URL 제공 플로우',
|
||||
'충전잔액 모니터링 + 과금 정책 확정',
|
||||
];
|
||||
confirmTasks.forEach((task, i) => {
|
||||
slide7.addShape(pres.ShapeType.ellipse, { x: 5.5, y: 3.7 + i * 0.28, w: 0.12, h: 0.12, fill: { color: C.orange } });
|
||||
slide7.addText(task, { x: 5.75, y: 3.65 + i * 0.28, w: 3.5, h: 0.22, fontSize: 9, color: C.text, fontFace: 'Arial' });
|
||||
['멀티테넌트 CERTKEY 구조 확인 (바로빌)', '테스트→운영 모드 전환 프로세스', '공동인증서 등록 URL 제공 플로우', '충전잔액 모니터링 + 과금 정책 확정'].forEach((t, i) => {
|
||||
slide7.addShape(pres.ShapeType.ellipse, { x: 5.55, y: 3.72 + i * 0.28, w: 0.12, h: 0.12, fill: { color: C.orange } });
|
||||
slide7.addText(t, { x: 5.8, y: 3.66 + i * 0.28, w: 3.5, h: 0.22, fontSize: 9, color: C.text, fontFace: 'Arial' });
|
||||
});
|
||||
|
||||
addFooter(slide7, 7, totalPages);
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user