diff --git a/docs/킨텍스_RFP.docx b/docs/킨텍스_RFP.docx new file mode 100644 index 0000000..7428663 Binary files /dev/null and b/docs/킨텍스_RFP.docx differ diff --git a/docs/킨텍스_제안발표.pptx b/docs/킨텍스_제안발표.pptx new file mode 100644 index 0000000..3f84d09 Binary files /dev/null and b/docs/킨텍스_제안발표.pptx differ diff --git a/scripts/gen_rfp_docs.py b/scripts/gen_rfp_docs.py new file mode 100644 index 0000000..15b20b9 --- /dev/null +++ b/scripts/gen_rfp_docs.py @@ -0,0 +1,929 @@ +# -*- coding: utf-8 -*- +"""RFP.docx(나라장터 표준) + 제안발표.pptx(50슬라이드) 생성 스크립트. + +근거: docs/PLANNING.md v3.5 (M1~M18 + §5B 공통레이어 + §1A 멀티테넌시 + §8A AI), + docs/design.md v2.8, docs/FEATURE_BACKLOG_100.md +출력: docs/RFP.docx, docs/제안발표.pptx +""" +import os + +BASE = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "docs") +KOR_FONT = "맑은 고딕" +BIZ_NAME = "킨텍스 AI 전시·행사시스템(KINTEX AI Exhibition & Event System) 구축 사업" + +# ══════════════════════════════ RFP DOCX ══════════════════════════════ +from docx import Document +from docx.shared import Pt, Cm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.enum.table import WD_TABLE_ALIGNMENT +from docx.oxml.ns import qn, nsdecls +from docx.oxml import parse_xml + +PRIMARY = RGBColor(0x00, 0x4C, 0x86) + + +def _set_kr(style_or_font): + f = getattr(style_or_font, "font", style_or_font) + f.name = KOR_FONT + el = f.element if hasattr(f, "element") else None + # style 객체 + try: + rpr = style_or_font._element.get_or_add_rPr() + rpr.rFonts.set(qn("w:eastAsia"), KOR_FONT) + except Exception: + pass + + +def run_kr(par, text, size=10, bold=False, color=None, italic=False): + r = par.add_run(text) + r.font.name = KOR_FONT + r._element.rPr.rFonts.set(qn("w:eastAsia"), KOR_FONT) + r.font.size = Pt(size) + r.bold = bold + r.italic = italic + if color: + r.font.color.rgb = color + return r + + +def para(doc, text, size=10, bold=False, color=None, align=None, space_after=6, indent=None): + p = doc.add_paragraph() + if align is not None: + p.alignment = align + p.paragraph_format.space_after = Pt(space_after) + if indent: + p.paragraph_format.left_indent = Cm(indent) + run_kr(p, text, size=size, bold=bold, color=color) + return p + + +def bullet(doc, text, size=10, level=0): + p = doc.add_paragraph(style="List Bullet" if level == 0 else "List Bullet 2") + run_kr(p, text, size=size) + p.paragraph_format.space_after = Pt(3) + return p + + +def heading(doc, text, level=1): + h = doc.add_heading(level=level) + sizes = {1: 16, 2: 13, 3: 11.5} + run_kr(h, text, size=sizes.get(level, 11), bold=True, color=PRIMARY) + return h + + +def shade(cell, hexcolor="D9EAF7"): + cell._tc.get_or_add_tcPr().append( + parse_xml(r''.format(nsdecls("w"), hexcolor))) + + +def make_table(doc, header, rows, widths=None, hdr_size=9.5, size=9.5): + t = doc.add_table(rows=1 + len(rows), cols=len(header)) + t.style = "Table Grid" + t.alignment = WD_TABLE_ALIGNMENT.CENTER + for j, htxt in enumerate(header): + c = t.cell(0, j) + c.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER + run_kr(c.paragraphs[0], htxt, size=hdr_size, bold=True) + shade(c) + for i, row in enumerate(rows): + for j, val in enumerate(row): + c = t.cell(i + 1, j) + run_kr(c.paragraphs[0], str(val), size=size) + if widths: + for j, w in enumerate(widths): + for row in t.rows: + row.cells[j].width = Cm(w) + doc.add_paragraph().paragraph_format.space_after = Pt(4) + return t + + +def req_block(doc, rid, name, details): + """요구사항 상세 카드(조달청 서식: 고유번호/명칭/상세설명).""" + t = doc.add_table(rows=3, cols=4) + t.style = "Table Grid" + hdr = [("요구사항 고유번호", rid), ("요구사항 명칭", name)] + for k, (label, val) in enumerate(hdr): + lc, vc = t.cell(0, k * 2), t.cell(0, k * 2 + 1) + run_kr(lc.paragraphs[0], label, size=9, bold=True); shade(lc) + run_kr(vc.paragraphs[0], val, size=9, bold=True) + dc = t.cell(1, 0); dc.merge(t.cell(1, 3)) + run_kr(dc.paragraphs[0], "요구사항 상세설명", size=9, bold=True); shade(dc, "EFF6FC") + bc = t.cell(2, 0); bc.merge(t.cell(2, 3)) + first = True + for d in details: + p = bc.paragraphs[0] if first else bc.add_paragraph() + first = False + run_kr(p, "○ " + d, size=9) + doc.add_paragraph().paragraph_format.space_after = Pt(2) + + +# ---- 요구사항 데이터 (총 50건) ---- +SFR = [ + ("SFR-001", "행사·홀 배정 및 자동 견적(M1)", [ + "행사 등록 시 희망 면적·기간·홀 조건을 입력하면 가용 홀 탐색과 충돌 검증을 자동 수행하여야 한다.", + "홀 요율 규칙(기준단가 2,250원/㎡ 등 요율 마스터) 기반 즉시 자동 견적을 산출하여야 한다.", + "홀 배정 확정 시 행사 워크스페이스가 자동 생성되어 후속 모듈(M2~M9)과 연계되어야 한다."]), + ("SFR-002", "플로어플랜 스튜디오 — 부스 배치 자동화(M2)", [ + "홀 도면(DWG/JPG) 언더레이 위에 부스 폴리곤을 배치·편집하는 웹 캔버스 에디터를 제공하여야 한다(팬·줌 포함).", + "조건(부스 수·규격·통로폭·소방 규정) 입력 시 복수 배치안을 자동 생성하고 비교·선택·병합할 수 있어야 한다.", + "K1·K2 전시홀 실측 도면(트렌치 좌표 포함)을 기준 데이터로 적재하여야 한다."]), + ("SFR-003", "자동 배치 3단계 위저드(M2-1)", [ + "초보 사용자용 3단계 위저드(홀/구역 선택 → 조건 입력 → 결과 비교·선택)를 제공하여야 한다.", + "전시홀 트리(전시장>홀>구역) 선택과 구역 경계 스냅 배치를 지원하여야 한다.", + "배치 적용(apply-option) 시 실제 저장·후속 단계 연계까지 폐루프로 완결되어야 한다."]), + ("SFR-004", "부스 설계 스튜디오(M3)", [ + "부스 단위 인테리어·장치 공사 설계(구조물·가구·사인·조명 배치)를 지원하여야 한다.", + "설계안으로부터 물량(BOQ)·예상 공사비 개산을 자동 산출하여야 한다."]), + ("SFR-005", "유틸리티 설계 자동화(M4)", [ + "부스 좌표 기반 전기·조명, 네트워크, 급배수 배선 경로를 트렌치 위치 기준으로 자동 산출하여야 한다.", + "배선 결과를 도면 오버레이로 시각화하고 자동 견적과 연동하여야 한다."]), + ("SFR-006", "나노바나나 시공 예상 시각화(M5)", [ + "배치·설계·배선 데이터를 근거로 이미지 생성 AI(Gemini 계열)를 통해 '시공 후 결과 사진'을 생성하여야 한다.", + "표준 샷 세트(부스 정면/야간 조명/통로 뷰/홀 조감 등 S1~S7)와 Before/After 비교를 제공하여야 한다.", + "생성 이미지에는 'AI 생성' 워터마크와 고지문구를 강제 적용하여야 한다.", + "생성 작업은 비동기 큐(RenderJob) 기반으로 처리하고 완료 시 실시간 통지(WebSocket)하여야 한다."]), + ("SFR-007", "서류·마일스톤 워크플로(M6)", [ + "행사 준비 서류(반입·전기·화기 등)의 온라인 제출·검수·승인 워크플로를 제공하여야 한다.", + "마일스톤(D-day) 기반 마감 관리와 알림(임박·초과)을 제공하여야 한다."]), + ("SFR-008", "등록업체 매칭·견적(M7)", [ + "킨텍스 등록업체(장치·전기·통신 등) 디렉토리와 업체 매칭·견적 요청 기능을 제공하여야 한다."]), + ("SFR-009", "반입/반출 물류 슬롯(M8)", [ + "반입·반출 차량 슬롯 예약과 게이트 배정, 현장 혼잡 분산 기능을 제공하여야 한다."]), + ("SFR-010", "정산·결제(M9)", [ + "홀 사용료·유틸리티·부대서비스 통합 정산과 PG 연동 온라인 결제, 환불 정책 처리를 제공하여야 한다."]), + ("SFR-011", "공사/장치 옥션 플랫폼(M15)", [ + "AI 설계 산출물(배치·설계·물량·예상 이미지)을 근거자료로 공사·장치업체 대상 역경매(입찰)를 운영하여야 한다.", + "견적서 제출·실시간 순위·채점(가격+실적+평가)·낙찰자 선정 흐름을 제공하여야 한다."]), + ("SFR-012", "관람객 등록·티켓·배지·리드캡처(M10)", [ + "관람객 사전등록·티켓 발급·QR 배지·현장 체크인을 제공하여야 한다.", + "참가업체용 리드 캡처(QR 스캔·명함)와 사후 리드 관리 기능을 제공하여야 한다."]), + ("SFR-013", "비즈니스 매칭(M11)", [ + "참가업체-바이어 프로필 기반 AI 추천 매칭과 상담 일정 예약 기능을 제공하여야 한다."]), + ("SFR-014", "마케팅·EDM·공개 홍보 사이트(M12)", [ + "일반 대중 대상 공개 홍보 사이트(전시 일정·안내·포스터, 반응형·SEO)를 제공하여야 한다.", + "EDM 발송·구독 관리·수신거부 처리 기능을 제공하여야 한다."]), + ("SFR-015", "Wayfinding·실내 내비(M13)", [ + "홀 도면 기반 부스 검색·경로 안내(모바일 웹) 기능을 제공하여야 한다."]), + ("SFR-016", "현장운영(M14)", [ + "혼잡·안전·주차·에너지 현황 모니터링 대시보드를 제공하여야 한다."]), + ("SFR-017", "경영분석 BI(M16)", [ + "매출·홀 가동률·참가사 리텐션·행사 P&L·수요예측 KPI 대시보드를 제공하여야 한다.", + "운영사 관점 수익성/ROI 분석과 데이터마트 기반 집계를 제공하여야 한다."]), + ("SFR-018", "CMS(M17)", [ + "전시 콘텐츠·공지·배너·참가업체 마이크로사이트·다국어 콘텐츠 관리(헤드리스)를 제공하여야 한다."]), + ("SFR-019", "관리자 백오피스·시스템관리(M18·공통)", [ + "사용자·역할/권한(RBAC)·메뉴·공통코드·감사로그·시스템설정 관리 기능을 제공하여야 한다.", + "룰셋(규정·요율) 관리와 통계·모니터링 기능을 제공하여야 한다."]), + ("SFR-020", "공통 업무기능·멀티테넌시·모바일", [ + "공통 업무기능(업무일지·일정·쪽지·공지·의견·검색·보고서·알림)을 전 역할 공용으로 제공하여야 한다.", + "다중 전시관(테넌트) 격리(tenant_id 전파·컨텍스트 해소·2계층 관리자)를 지원하여야 한다.", + "모바일 앱(운영 B2B·관람객 B2C)에서 조회·승인·현장 기능을 제공하여야 한다."]), +] +PER = [ + ("PER-001", "응답시간", ["일반 화면 조회 3초 이내, 자동 배치안 생성 30초 이내(안 3개 기준), AI 이미지 생성은 비동기 처리 후 완료 통지."]), + ("PER-002", "동시사용자", ["평시 500명, 대형 행사 피크 3,000명 동시접속에서 성능 저하 없이 서비스 가능하여야 한다."]), + ("PER-003", "가용성", ["연중 가용률 99.5% 이상, 계획 정지는 사전 공지 후 야간 수행."]), +] +SIR = [ + ("SIR-001", "결제(PG) 연동", ["신용카드·계좌이체 등 PG 연동 및 취소·부분환불 처리."]), + ("SIR-002", "SSO·HR 연동", ["킨텍스 내부 SSO(Open SSO)와 인사(HR) 조직·직원 정보 연동."]), + ("SIR-003", "CAD(DWG) 연동", ["홀 도면 DWG 입력 파이프라인(좌표 추출·캘리브레이션·JPG 렌더) 제공."]), +] +DAR = [ + ("DAR-001", "공간 데이터", ["부스 폴리곤·트렌치 포인트·배선 경로를 공간 타입(PostGIS)으로 관리하고 공간 연산을 지원."]), + ("DAR-002", "마스터 데이터", ["홀·요율·규정 룰셋·공통코드·등록업체 마스터의 표준화 및 이관·시드."]), + ("DAR-003", "데이터 표준", ["명명 규칙·코드 표준·이력 관리(감사) 등 데이터 표준 수립 및 준수."]), +] +ECR = [ + ("ECR-001", "서버 구성", ["WAS(Spring Boot)·WEB(nginx)·DB(PostgreSQL+PostGIS)·캐시/큐(Redis)·AI 워커(Python) 구성."]), + ("ECR-002", "운영환경", ["개발·운영 환경 분리, 서비스 데몬(systemd) 및 무중단 배포 고려."]), + ("ECR-003", "스토리지", ["AI 생성 이미지·도면 파일용 오브젝트 스토리지 및 백업 체계."]), +] +SER = [ + ("SER-001", "인증·인가", ["JWT 기반 인증 + 2차인증(OTP), 행사 단위 RBAC, 테넌트 격리 접근통제."]), + ("SER-002", "개인정보보호", ["개인정보 암호화(저장·전송), 마스킹, 접속기록 보관 등 개인정보보호법 준수."]), + ("SER-003", "시큐어코딩", ["행정안전부 소프트웨어 개발보안 가이드 준수 및 보안약점 진단·조치."]), + ("SER-004", "AI 산출물 신뢰성", ["AI 생성물 'AI 생성/초안' 라벨·워터마크 강제, 구조 안전성 최종 판정은 인간 승인 절차 유지."]), +] +TER = [ + ("TER-001", "테스트", ["단위·통합·성능·보안 테스트 계획 수립 및 수행, 결함 관리 체계 운영."]), + ("TER-002", "검수", ["기능별 검수 시나리오 기반 사용자 인수테스트(UAT) 지원."]), +] +QUR = [ + ("QUR-001", "품질보증", ["품질보증 계획 수립, 산출물 표준 준수, 단계별 품질 게이트 운영."]), + ("QUR-002", "표준 준수", ["전자정부 표준프레임워크 상당의 개발표준 및 발주기관 UI/UX 표준(디자인 시스템) 준수."]), +] +COR = [ + ("COR-001", "기술 제약", ["확정 스택(React+TypeScript / Spring Boot 3.x Java 17 / MyBatis / PostgreSQL+PostGIS / Redis) 준수."]), + ("COR-002", "지식재산권", ["개발 산출물 소유권은 발주기관에 귀속, 오픈소스 라이선스 검증 수행."]), + ("COR-003", "AI 비용 제약", ["AI 호출은 토큰 최소화 원칙(소형모델 우선·캐싱·출력 상한·집계는 SQL) 준수, 사용량 측정지표 제공."]), +] +PMR = [ + ("PMR-001", "사업관리", ["WBS 기반 일정·진척 관리, 주간·월간 보고, 이슈·리스크 관리."]), + ("PMR-002", "방법론", ["애자일(스프린트) 기반 반복 개발과 단계별 산출물 검토 병행."]), + ("PMR-003", "형상관리", ["소스·문서 형상관리(Git), 변경관리 절차 운영."]), + ("PMR-004", "투입인력", ["PM·아키텍트(AA/TA/DA)·백엔드·프론트·AI·DB·QA 등 분야별 적정 인력 투입 및 교체 승인 절차."]), +] +PSR = [ + ("PSR-001", "교육·기술이전", ["운영자·사용자 교육 및 운영 매뉴얼·기술문서 제공, 기술이전 계획 수립."]), + ("PSR-002", "하자보수", ["검수 완료 후 무상 하자보수 12개월, 하자 등급별 대응시간 준수."]), + ("PSR-003", "안정화 지원", ["오픈 후 안정화 기간(2개월) 상주 지원 및 비상 대응 체계."]), +] +REQ_GROUPS = [ + ("기능 요구사항(SFR)", SFR), ("성능 요구사항(PER)", PER), ("인터페이스 요구사항(SIR)", SIR), + ("데이터 요구사항(DAR)", DAR), ("시스템 장비구성 요구사항(ECR)", ECR), ("보안 요구사항(SER)", SER), + ("테스트 요구사항(TER)", TER), ("품질 요구사항(QUR)", QUR), ("제약사항(COR)", COR), + ("프로젝트 관리 요구사항(PMR)", PMR), ("프로젝트 지원 요구사항(PSR)", PSR), +] + + +def build_docx(path): + doc = Document() + # 기본 스타일 + normal = doc.styles["Normal"] + normal.font.name = KOR_FONT + normal.font.size = Pt(10) + normal._element.get_or_add_rPr().rFonts.set(qn("w:eastAsia"), KOR_FONT) + for hs in ["Heading 1", "Heading 2", "Heading 3"]: + st = doc.styles[hs] + st.font.name = KOR_FONT + st._element.get_or_add_rPr().rFonts.set(qn("w:eastAsia"), KOR_FONT) + sec = doc.sections[0] + sec.top_margin = sec.bottom_margin = Cm(2.2) + sec.left_margin = sec.right_margin = Cm(2.4) + + # ── 표지 ── + for _ in range(4): + doc.add_paragraph() + para(doc, "제 안 요 청 서", size=32, bold=True, color=PRIMARY, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=18) + para(doc, "(RFP : Request For Proposal)", size=14, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=30) + para(doc, BIZ_NAME, size=17, bold=True, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=10) + para(doc, "— 나라장터(국가종합전자조달, g2b.go.kr) 공고용 —", size=11, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=60) + for _ in range(6): + doc.add_paragraph() + para(doc, "2026. 7.", size=14, bold=True, align=WD_ALIGN_PARAGRAPH.CENTER, space_after=14) + para(doc, "주식회사 킨텍스(KINTEX)", size=16, bold=True, align=WD_ALIGN_PARAGRAPH.CENTER) + doc.add_page_break() + + # ── 목차(개요) ── + heading(doc, "목 차", 1) + for line in [ + "Ⅰ. 사업 개요", "Ⅱ. 현황 및 문제점", "Ⅲ. 사업 추진방안", "Ⅳ. 제안요청 내용(요구사항)", + "Ⅴ. 제안서 작성요령(제안서 목차 포함)", "Ⅵ. 제안서 평가", "Ⅶ. 계약 일반조건 및 특수조건", + "[별첨] 제안서 표지 서식·요구사항 대응표"]: + para(doc, line, size=11, space_after=8) + doc.add_page_break() + + # ── Ⅰ. 사업 개요 ── + heading(doc, "Ⅰ. 사업 개요", 1) + heading(doc, "1. 사업 기본정보", 2) + make_table(doc, ["구분", "내용"], [ + ["사 업 명", BIZ_NAME], + ["발주기관", "주식회사 킨텍스(KINTEX)"], + ["사업기간", "계약체결일로부터 12개월 (안정화 지원 2개월 별도)"], + ["사업예산", "금 2,970,000,000원(부가가치세 포함) 이내 ※ 협상에 의한 계약"], + ["계약방법", "제한경쟁입찰 / 협상에 의한 계약 (나라장터 전자입찰)"], + ["입찰방식", "국가종합전자조달시스템(나라장터, g2b.go.kr) 전자제출"], + ], widths=[3.2, 12.5]) + heading(doc, "2. 추진 배경", 2) + bullet(doc, "킨텍스는 총 전시면적 108,011㎡의 국내 최대 전시장을 운영하나, 전시 준비 실무는 HWP 서식 다운로드 후 이메일 제출, CAD 수작업 배치안, 담당자 육안 규정 검토, 수기 위치표시도 기반 유틸리티 신청 등 수작업 중심에 머물러 있음.") + bullet(doc, "온라인 작업신고 시스템(kxwp)이 존재하나 로그인 기반 서류 업로드 창구 수준이며, 참가업체 유틸리티 신청은 전시회별 주최자 시스템으로 파편화되어 있음.") + bullet(doc, "2028년 제3전시장 개관(전공 면적 178,000㎡ 확대)에 대비하여 전시 생애주기 전 과정의 디지털 전환·자동화가 시급함.") + heading(doc, "3. 사업 목표", 2) + bullet(doc, "\"신청서를 내는 시간, 시공 후 사진을 먼저 본다\" — 전시 준비 전 과정(홀 배정→부스 배치→장치공사 설계→전기/조명→네트워크/유틸리티 배선→반입/반출)을 AI로 자동 설계·검증하고, 이미지 생성 AI(나노바나나)로 시공 결과를 사전 시각화.") + make_table(doc, ["목표", "현재(As-Is)", "목표(To-Be)"], [ + ["홀 배정 견적 회신", "문의→협의→견적 수일", "즉시 자동 견적"], + ["부스 배치안 초안", "CAD 수작업 수일~수주", "조건 입력 후 복수 안 자동 생성(30초 이내)"], + ["도면 규정 검토", "담당자 육안 검토", "규정 전반 자동 플래깅(통로폭·소방 등)"], + ["유틸리티 신청", "수기 위치 표시", "부스 좌표 클릭 → 자동 배선·자동 견적"], + ["시공 결과 예측", "불가(조감도 별도 외주)", "표준 샷 세트 자동 생성(부스 정면/야간/통로/조감)"], + ], widths=[4.2, 5.4, 6.1]) + heading(doc, "4. 사업 범위", 2) + bullet(doc, "응용시스템 구축: 부스 코어(M1~M9) + 도메인 확장(M10~M18) 총 18개 모듈, 공통/시스템관리 레이어, 6+2 역할별 웹 포털(MDI) 및 모바일 앱(운영 B2B·관람객 B2C).") + bullet(doc, "AI 서비스: 부스 배치 자동생성(제약 솔버+LLM), 규정 검증 보조, 나노바나나 시공 예상 이미지 파이프라인, 자연어 조회, 수요/매출 예측, 비즈니스 매칭 추천.") + bullet(doc, "데이터 구축: 홀·요율·규정 룰셋 마스터, K1·K2 실측 도면(DWG/JPG)·트렌치 좌표 공간데이터 적재.") + bullet(doc, "다중 전시관(멀티테넌트 SaaS) 기반 구조 및 시스템 인프라(서버·스토리지·배포체계) 구성, 교육·기술이전·안정화 지원.") + bullet(doc, "범위 제외: 전자계약 법적 체결(Phase 3 이후 검토), 구조 안전성 최종 판정의 AI 대체(인간 승인 유지), 관람객 택시·숙박 예약 등 부가 서비스.") + doc.add_page_break() + + # ── Ⅱ. 현황 및 문제점 ── + heading(doc, "Ⅱ. 현황 및 문제점", 1) + heading(doc, "1. 업무 현황", 2) + bullet(doc, "주최자: 행사 유치→홀 배정 협의→도면 승인→서류 취합→현장 운영→정산의 전 과정을 이메일·전화·수기 문서로 수행, 단계 간 데이터 단절.") + bullet(doc, "참가업체·장치업체: 부스 설계·공사 견적을 개별 접촉으로 확보, 시공 결과를 사전에 확인할 수단 부재, 유틸리티 신청 창구 파편화.") + bullet(doc, "킨텍스 운영: 도면 규정 검토·서류 검수·현장 민원 대응에 수작업 반복, 행사별 데이터가 축적·분석되지 않아 경영분석 곤란.") + heading(doc, "2. 정보시스템 현황", 2) + make_table(doc, ["시스템", "기능", "한계"], [ + ["kxwp(온라인 작업신고)", "로그인 후 서류 업로드", "설계·검증·견적 기능 부재, 단순 창구"], + ["홈페이지(kintex.com)", "행사 안내·홍보", "업무시스템과 미연계"], + ["주최자별 개별 시스템", "행사별 참가업체 관리", "킨텍스 공통 플랫폼 부재, 데이터 미축적"], + ], widths=[4.5, 5.2, 6.0]) + heading(doc, "3. 개선 방향", 2) + bullet(doc, "전시 생애주기(영업·기획→설계·시각화→발주·계약→참가·관람→현장운영→사후·경영) 전 단계를 단일 플랫폼·단일 데이터 체계로 자동화.") + bullet(doc, "실측 공간데이터(PostGIS) 기반 자동 설계와 이미지 생성 AI 시각화를 결합한 차별화 — 설계→시각화→발주(옥션)→시공→운영→분석의 폐루프 완성.") + doc.add_page_break() + + # ── Ⅲ. 사업 추진방안 ── + heading(doc, "Ⅲ. 사업 추진방안", 1) + heading(doc, "1. 추진 전략", 2) + bullet(doc, "P0 코어 우선: 차별화 핵심인 부스 배치(M2)→부스 설계(M3)→유틸리티 배선(M4)→나노바나나 시각화(M5)를 최우선 구축하여 조기 가시화.") + bullet(doc, "AI 산출물 신뢰성 확보: 모든 AI 산출물에 'AI 생성/초안' 라벨·워터마크, 규정 검증의 인간 최종 승인 절차 병행.") + bullet(doc, "표준 준수: 확정 기술스택(React·Spring Boot 3.x·MyBatis·PostgreSQL/PostGIS·Redis)과 발주기관 디자인 시스템 준수.") + bullet(doc, "멀티테넌트 기반: 킨텍스를 기준 테넌트로 하되 타 전시관 온보딩이 가능한 격리 구조(tenant_id 전파) 선반영.") + heading(doc, "2. 추진 체계", 2) + make_table(doc, ["주체", "역할"], [ + ["발주기관(킨텍스)", "사업총괄, 요구사항 확정, 검수, 마스터데이터 제공"], + ["수행사(제안사)", "설계·구현·테스트·이행·교육·안정화, 품질/일정/위험 관리"], + ["감리(필요 시)", "단계별 산출물·품질 점검"], + ], widths=[4.5, 11.2]) + heading(doc, "3. 추진 일정(안)", 2) + make_table(doc, ["단계", "기간", "주요 내용"], [ + ["Phase 1 분석·설계", "M1~M3", "요구사항 상세화, 아키텍처(AA/TA/DA) 확정, 데이터 표준·ERD, 화면 설계"], + ["Phase 2 구축(P0 코어)", "M3~M7", "M2~M5 부스 코어 + 공통/시스템관리 레이어 + 인증(2FA)"], + ["Phase 3 구축(도메인)", "M6~M10", "M1·M6~M18 도메인 모듈 + 모바일 앱 + 공개사이트"], + ["Phase 4 통합·이행", "M10~M12", "통합테스트·성능·보안점검, 데이터 이관, UAT, 오픈"], + ["안정화", "오픈 후 2개월", "상주 지원, 하자 대응, 운영 이관·기술이전"], + ], widths=[3.8, 3.2, 8.7]) + doc.add_page_break() + + # ── Ⅳ. 제안요청 내용 ── + heading(doc, "Ⅳ. 제안요청 내용(요구사항)", 1) + para(doc, "본 장의 요구사항은 소프트웨어사업 요구사항 분류체계(기능 SFR·성능 PER·인터페이스 SIR·데이터 DAR·장비 ECR·보안 SER·테스트 TER·품질 QUR·제약 COR·관리 PMR·지원 PSR)에 따라 기술한다. 제안사는 전 요구사항에 대한 수용 여부와 구현 방안을 제안서에 명시하여야 한다.", size=10) + heading(doc, "1. 요구사항 총괄표", 2) + make_table(doc, ["분류", "요구사항 수", "고유번호"], + [[g[0], len(g[1]), f"{g[1][0][0]} ~ {g[1][-1][0]}"] for g in REQ_GROUPS] + + [["합계", sum(len(g[1]) for g in REQ_GROUPS), ""]], + widths=[7.0, 3.2, 5.5]) + for gi, (gname, items) in enumerate(REQ_GROUPS): + heading(doc, f"{gi + 2}. {gname}", 2) + for rid, name, details in items: + req_block(doc, rid, name, details) + doc.add_page_break() + + # ── Ⅴ. 제안서 작성요령 ── + heading(doc, "Ⅴ. 제안서 작성요령", 1) + heading(doc, "1. 일반 지침", 2) + bullet(doc, "제안서는 본 제안요청서의 요구사항 순서에 따라 국문으로 작성하며, A4 기준 200쪽 이내(표지·목차·별첨 제외)로 한다.") + bullet(doc, "제안 내용은 구체적 구현 방안 중심으로 기술하고, 단순 일반론·타사 실적 나열은 지양한다.") + bullet(doc, "요구사항 대응표(요구사항 고유번호 ↔ 제안서 페이지)를 별첨으로 반드시 포함한다.") + bullet(doc, "제안서 및 제안발표자료는 나라장터 전자제출을 원칙으로 한다.") + heading(doc, "2. 제안서 목차(표준)", 2) + para(doc, "제안발표자료는 아래 제안서 목차와 동일한 체계로 작성한다.", size=10, bold=True) + make_table(doc, ["부", "장", "내용"], [ + ["Ⅰ. 제안 개요", "1~4", "제안사 일반현황 / 사업의 이해 / 제안 핵심 요지 / 제안 특장점"], + ["Ⅱ. 기술 부문", "1~3", "목표 시스템(아키텍처·기술스택·멀티테넌시·3-트랙 IA)"], + ["", "4~14", "기능 구현방안(M1~M18 모듈별) / 공통·시스템관리 레이어"], + ["", "15~19", "AI 구현방안(나노바나나·토큰최소화) / 데이터·연동 / 모바일 / 보안 / 성능·품질(NFR)"], + ["Ⅲ. 사업관리 부문", "1~6", "추진전략·방법론 / 조직·인력 / 일정 / 마일스톤·산출물 / 위험관리 / 품질보증·형상관리"], + ["Ⅳ. 기술지원 부문", "1~4", "교육·기술이전 / 유지보수·하자보수 / 비상대응·보안준수 / 기대효과"], + ], widths=[3.9, 2.0, 9.8]) + heading(doc, "3. 제안발표", 2) + bullet(doc, "제안발표자료(PPT)는 50쪽 내외로 제안서 목차 순서에 따라 작성하며, 발표 20분·질의응답 15분으로 한다.") + bullet(doc, "발표자는 제안 PM을 원칙으로 한다.") + doc.add_page_break() + + # ── Ⅵ. 제안서 평가 ── + heading(doc, "Ⅵ. 제안서 평가", 1) + heading(doc, "1. 평가 방법", 2) + bullet(doc, "협상에 의한 계약 체결 기준(기획재정부 계약예규)에 따라 기술능력평가(90%)와 입찰가격평가(10%)를 합산하여 협상적격자를 선정한다.") + bullet(doc, "기술능력평가 점수가 배점한도의 85% 이상인 자를 협상적격자로 한다.") + heading(doc, "2. 기술평가 배점(안)", 2) + make_table(doc, ["평가부문", "평가항목", "배점"], [ + ["전략·방법론(20)", "사업 이해도·추진전략", "10"], + ["", "방법론·일정·자원 계획", "10"], + ["기술·기능(45)", "시스템 아키텍처·기술 적합성", "10"], + ["", "기능 요구사항 구현방안(M1~M18)", "20"], + ["", "AI(자동설계·시각화) 구현방안·신뢰성", "10"], + ["", "보안·성능·품질 확보방안", "5"], + ["수행역량(15)", "투입인력 전문성·유사실적", "10"], + ["", "품질보증·위험관리 체계", "5"], + ["지원(10)", "교육·기술이전·하자보수·안정화", "10"], + ["합계", "", "90"], + ], widths=[4.4, 8.5, 2.4]) + doc.add_page_break() + + # ── Ⅶ. 계약조건 ── + heading(doc, "Ⅶ. 계약 일반조건 및 특수조건", 1) + for txt in [ + "계약 방식: 협상에 의한 계약, 확정금액 방식. 선금·기성·잔금 지급은 국가계약법령 및 발주기관 규정에 따른다.", + "하자담보: 검수 완료일로부터 12개월 무상 하자보수. 하자 등급별 대응(긴급 4시간 내 착수, 일반 2영업일 내).", + "지식재산권: 사업 수행 산출물의 소유권은 발주기관에 귀속하며, 오픈소스 사용 시 라이선스 검증 결과를 제출한다.", + "보안 준수: 수행 인력 보안서약, 개인정보 취급 최소화, 개발·운영 데이터 반출 금지, 프로젝트 종료 시 자료 파기 확인.", + "지체상금: 지체일수 1일당 계약금액의 0.75/1000. 계약상대자 귀책 시 국가계약법령에 따라 부과.", + "기술이전: 소스코드·설계문서·운영매뉴얼 일체 제공 및 운영인력 교육(관리자·운영자·사용자 각 1회 이상).", + "AI 특수조건: 이미지 생성 등 외부 AI API 사용 비용의 산정 근거와 상한 관리 방안을 제안서에 명시하고, AI 생성물 표시(워터마크·라벨)를 준수한다.", + ]: + bullet(doc, txt) + doc.add_page_break() + + # ── 별첨 ── + heading(doc, "[별첨 1] 제안서 표지 서식", 1) + make_table(doc, ["항목", "기재 내용"], [ + ["사업명", BIZ_NAME], ["제안사명", "(상호·대표자·소재지)"], + ["제출일자", "2026. . ."], ["담당자", "(성명·연락처·이메일)"], + ], widths=[4.0, 11.7]) + heading(doc, "[별첨 2] 요구사항 대응표 서식", 1) + make_table(doc, ["요구사항 고유번호", "요구사항 명칭", "수용여부", "제안서 페이지"], + [["SFR-001", "행사·홀 배정 및 자동 견적(M1)", "수용/부분수용/미수용", "p."], + ["…", "…", "…", "…"]], + widths=[3.6, 7.0, 3.2, 2.6]) + doc.save(path) + return path + + +# ══════════════════════════════ PPTX ══════════════════════════════ +from pptx import Presentation +from pptx.util import Inches, Pt as PPt +from pptx.dml.color import RGBColor as PRGB +from pptx.enum.text import PP_ALIGN, MSO_ANCHOR +from pptx.enum.shapes import MSO_SHAPE +from pptx.oxml.ns import qn as pqn + +P_BLUE = PRGB(0x00, 0x66, 0xB3) +P_DARK = PRGB(0x00, 0x4C, 0x86) +P_AI = PRGB(0x6D, 0x4A, 0xFF) +P_GREY = PRGB(0x34, 0x40, 0x54) +P_LIGHT = PRGB(0xEF, 0xF6, 0xFC) +P_WHITE = PRGB(0xFF, 0xFF, 0xFF) + + +def pset(run, size, bold=False, color=P_GREY): + f = run.font + f.size = PPt(size) + f.bold = bold + f.color.rgb = color + f.name = KOR_FONT + rPr = run._r.get_or_add_rPr() + for tag in ("a:ea", "a:cs"): + el = rPr.find(pqn(tag)) + if el is None: + el = rPr.makeelement(pqn(tag), {}) + rPr.append(el) + el.set("typeface", KOR_FONT) + + +def add_box(slide, x, y, w, h): + tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)) + tb.text_frame.word_wrap = True + return tb.text_frame + + +def add_rect(slide, x, y, w, h, fill, line=False): + sh = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(x), Inches(y), Inches(w), Inches(h)) + sh.fill.solid() + sh.fill.fore_color.rgb = fill + if not line: + sh.line.fill.background() + sh.shadow.inherit = False + return sh + + +def footer(slide, idx, total): + tf = add_box(slide, 0.5, 7.05, 12.3, 0.35) + p = tf.paragraphs[0] + r = p.add_run() + r.text = f"{BIZ_NAME} 제안발표자료" + pset(r, 9, color=PRGB(0x66, 0x70, 0x85)) + tf2 = add_box(slide, 12.3, 7.05, 0.7, 0.35) + p2 = tf2.paragraphs[0] + p2.alignment = PP_ALIGN.RIGHT + r2 = p2.add_run() + r2.text = f"{idx}/{total}" + pset(r2, 9, color=PRGB(0x66, 0x70, 0x85)) + + +def slide_cover(prs, idx, total): + s = prs.slides.add_slide(prs.slide_layouts[6]) + add_rect(s, 0, 0, 13.333, 7.5, P_DARK) + add_rect(s, 0, 4.9, 13.333, 0.06, P_AI) + tf = add_box(s, 1.0, 2.0, 11.3, 2.6) + p = tf.paragraphs[0] + r = p.add_run(); r.text = "킨텍스 AI 전시·행사시스템 구축 사업"; pset(r, 40, True, P_WHITE) + p2 = tf.add_paragraph() + r = p2.add_run(); r.text = "KINTEX AI Exhibition & Event System"; pset(r, 20, False, PRGB(0xD9, 0xEA, 0xF7)) + tf2 = add_box(s, 1.0, 5.1, 11.3, 1.6) + p = tf2.paragraphs[0] + r = p.add_run(); r.text = "제 안 발 표 자 료"; pset(r, 24, True, P_WHITE) + p2 = tf2.add_paragraph() + r = p2.add_run(); r.text = '"신청서를 내는 시간, 시공 후 사진을 먼저 본다" · 2026. 7.'; pset(r, 14, False, PRGB(0xD9, 0xEA, 0xF7)) + return s + + +def slide_section(prs, idx, total, no, title, subtitle): + s = prs.slides.add_slide(prs.slide_layouts[6]) + add_rect(s, 0, 0, 13.333, 7.5, P_BLUE) + tf = add_box(s, 1.2, 2.5, 11.0, 2.5) + p = tf.paragraphs[0] + r = p.add_run(); r.text = no; pset(r, 22, True, PRGB(0xD9, 0xEA, 0xF7)) + p2 = tf.add_paragraph() + r = p2.add_run(); r.text = title; pset(r, 40, True, P_WHITE) + p3 = tf.add_paragraph() + r = p3.add_run(); r.text = subtitle; pset(r, 15, False, PRGB(0xD9, 0xEA, 0xF7)) + footer(s, idx, total) + return s + + +def slide_content(prs, idx, total, kicker, title, bullets): + """bullets: list of (level, text) 또는 str(level 0).""" + s = prs.slides.add_slide(prs.slide_layouts[6]) + add_rect(s, 0, 0, 13.333, 0.18, P_BLUE) + tf = add_box(s, 0.55, 0.35, 12.2, 1.15) + p = tf.paragraphs[0] + r = p.add_run(); r.text = kicker; pset(r, 12, True, P_AI) + p2 = tf.add_paragraph() + r = p2.add_run(); r.text = title; pset(r, 26, True, P_DARK) + add_rect(s, 0.6, 1.62, 12.1, 0.03, PRGB(0xD9, 0xEA, 0xF7)) + body = add_box(s, 0.75, 1.85, 11.9, 5.0) + first = True + for b in bullets: + lvl, txt = (b if isinstance(b, tuple) else (0, b)) + p = body.paragraphs[0] if first else body.add_paragraph() + first = False + p.space_after = PPt(8) + mark = "▎" if lvl == 0 else "·" + r = p.add_run() + r.text = f"{mark} {txt}" if lvl == 0 else f" {mark} {txt}" + pset(r, 15 if lvl == 0 else 13.5, lvl == 0 and txt.endswith(":"), P_GREY if lvl else PRGB(0x10, 0x18, 0x28)) + footer(s, idx, total) + return s + + +SLIDES = [ + ("cover",), + ("content", "AGENDA", "목차", [ + "Ⅰ. 제안 개요 — 제안사 현황 · 사업의 이해 · 제안 핵심 요지 · 특장점", + "Ⅱ. 기술 부문 — 목표 아키텍처 · 기능 구현방안(M1~M18) · AI · 데이터 · 보안 · 성능", + "Ⅲ. 사업관리 부문 — 전략·방법론 · 조직·인력 · 일정 · 위험 · 품질", + "Ⅳ. 기술지원 부문 — 교육·기술이전 · 유지보수 · 비상대응 · 기대효과", + (1, "본 자료는 제안요청서(RFP) Ⅴ장 제안서 목차 표준 체계에 따라 작성되었습니다."), + ]), + ("section", "PART Ⅰ", "제안 개요", "제안사 현황 · 사업의 이해 · 제안 핵심 요지 · 특장점"), + ("content", "Ⅰ-1. 제안 개요", "제안사 일반현황", [ + "전시·컨벤션(MICE) 도메인과 AI 융합 시스템 구축에 특화된 수행 조직", + (1, "Spring Boot 3.x + React + PostgreSQL(PostGIS) 풀스택 표준 프레임워크 보유(WISE)"), + (1, "이미지 생성 AI(Gemini 계열) 상용 파이프라인 구축·운영 실증 경험"), + (1, "공간데이터(PostGIS) 기반 도면·배선 자동화 구현 실적"), + "본 사업 전담 조직: PM 1, 아키텍트(AA/TA/DA) 3, 백엔드 4, 프론트 4, AI 2, DB 1, QA 2, 모바일 2", + "품질·보안 체계: 개발보안 가이드 준수, 단계별 품질 게이트, 형상관리(Git) 표준 운영", + ]), + ("content", "Ⅰ-2. 제안 개요", "사업의 이해 — 현황과 문제(As-Is)", [ + "국내 최대 전시장(108,011㎡)이지만 준비 실무는 수작업 중심:", + (1, "HWP 서식 다운로드 → 이메일 제출, 온라인 신고(kxwp)는 단순 업로드 창구"), + (1, "부스 배치안: 주최자 CAD 수작업 수일~수주 소요"), + (1, "도면 규정 검토: 담당자 육안 검토(통로폭·소방·높이 규정)"), + (1, "유틸리티 신청: 수기 위치표시도, 전시회별 시스템 파편화"), + "구조적 공백: 단계 간 데이터 단절 → 행사 데이터 미축적 → 경영분석 불가", + "2028년 제3전시장 개관(178,000㎡) 대비 디지털 전환이 시급한 시점", + ]), + ("content", "Ⅰ-2. 제안 개요", "사업의 이해 — 발주기관 요구 핵심", [ + "전시 생애주기 전 과정의 자동화: 영업·기획 → 설계·시각화 → 발주·계약 → 참가·관람 → 현장운영 → 사후·경영분석", + "요구사항 총 50건: 기능(SFR) 20 + 성능·보안·데이터·연동·품질·관리·지원 30", + "확정 기술 제약(COR-001): React+TypeScript / Spring Boot 3.x(Java 17) / MyBatis / PostgreSQL+PostGIS / Redis", + "AI 신뢰성(SER-004): AI 생성물 라벨·워터마크 강제, 구조 안전 최종 판정은 인간 승인", + "AI 비용 제약(COR-003): 토큰 최소화 설계와 사용량 가시화", + "멀티테넌트(SFR-020): 킨텍스 기준 테넌트 + 타 전시관 온보딩 가능 구조", + ]), + ("content", "Ⅰ-3. 제안 개요", '제안 핵심 요지 — "신청서를 내는 시간, 시공 후 사진을 먼저 본다"', [ + "차별화 폐루프: AI 설계 → 시각화 → 옥션 발주 → 시공 → 운영 → 분석", + (1, "① 조건 입력 → 부스 배치안 복수 자동 생성(제약 솔버 + LLM 조건해석)"), + (1, "② 배치·설계·배선 데이터 → 나노바나나가 '시공 후 결과 사진' 사전 생성(S1~S7 표준 샷)"), + (1, "③ AI 설계·물량·예상 이미지가 그대로 역경매(옥션) 근거자료 → 공사 발주까지 한 흐름"), + "실측 공간데이터가 경쟁력: K1·K2 홀 도면(DWG)·트렌치 좌표를 PostGIS로 적재 — 타 전시테크가 못 하는 정밀 배선 자동화", + "의사결정 혁신: 주최자·참가업체가 도면을 읽지 못해도 '사진 수준 시각화'로 결정", + ]), + ("content", "Ⅰ-4. 제안 개요", "제안 특장점 요약 (Why Us)", [ + "① 검증된 표준 프레임워크(WISE) 이식 — 시스템관리·공통기능·2FA 인증을 재사용, 구축 리스크 최소화", + "② 이미지 생성 파이프라인 실증 — RenderJob 큐·워터마크·Before/After 등 상용 기법 확보", + "③ 공간데이터 전문성 — PostGIS 공간 연산(부스 폴리곤·트렌치·배선 LineString) 설계·구현 경험", + "④ AI 비용 통제 설계 — 소형모델 우선·캐싱·출력상한·집계는 SQL, 사용량 대시보드 제공", + "⑤ 멀티테넌트 선반영 — 기능 재개발 없이 타 전시관 확장 가능한 격리 구조", + "⑥ 전 요구사항(50건) 100% 수용 — 별첨 요구사항 대응표 제출", + ]), + ("section", "PART Ⅱ", "기술 부문", "목표 아키텍처 · 기능 구현방안(M1~M18) · AI · 데이터 · 보안 · 성능"), + ("content", "Ⅱ-1. 기술 부문", "목표 시스템 개요", [ + "단일 플랫폼에서 전시 생애주기 6단계를 커버하는 18개 모듈 + 공통 레이어", + (1, "영업·기획: M1 홀 배정·자동 견적, M16 수요예측"), + (1, "설계·시각화(핵심 P0): M2 배치 · M3 부스설계 · M4 배선 · M5 나노바나나"), + (1, "발주·계약: M6 서류, M7 등록업체, M15 공사/장치 옥션, M9 정산"), + (1, "참가·관람: M10 등록·배지·리드, M11 비즈매칭, M12 홍보사이트, M13 wayfinding"), + (1, "현장 운영: M8 물류 슬롯, M14 혼잡·안전·주차·에너지"), + (1, "사후·경영: M16 BI, M17 CMS, M18 관리자 + 공통/시스템관리 레이어(§5B)"), + ]), + ("content", "Ⅱ-1. 기술 부문", "목표 아키텍처", [ + "웹: React 18/19 + Vite + TypeScript (역할별 포털, MDI 셸, 반응형)", + "API: Spring Boot 3.x(Java 17) + MyBatis — REST + WebSocket(STOMP)", + "엔진: 룰 엔진(규정·요율) · 배치/배선 엔진(PostGIS 공간 연산) · 옥션 채점 엔진", + "데이터: PostgreSQL + PostGIS(부스 폴리곤·트렌치·배선), Redis(작업 큐·캐시·세션)", + "AI 워커: Python 사이드카(나노바나나 이미지 생성) — Spring이 큐로 트리거, 완료 시 WebSocket 푸시", + "저장소: 오브젝트 스토리지(생성 이미지·도면), 배포: nginx + systemd + CI/CD(webhook)", + ]), + ("content", "Ⅱ-1. 기술 부문", "적용 기술 스택과 선정 사유", [ + "RFP 제약(COR-001) 100% 준수 — 발주기관 표준 프레임워크(GUARDiA/WISE)와 정렬", + (1, "Spring Boot 3.x + MyBatis: 공공·기업 시스템 검증 스택, SQL 제어 용이(공간 쿼리 최적화)"), + (1, "React + TypeScript + Vite: 대규모 화면(80+ 라우트) 타입 안정성·생산성"), + (1, "PostGIS: 부스 겹침 검사·통로폭 검증·최단 배선 등 공간 연산을 DB 레벨에서 처리"), + (1, "Redis: RenderJob 큐·알림·세션 — 비동기 AI 작업의 표준 창구"), + "전자정부 표준프레임워크 상당의 계층 구조(controller/service/mapper)와 개발표준 적용", + ]), + ("content", "Ⅱ-2. 기술 부문", "멀티테넌트(다중 전시관 SaaS) 설계", [ + "테넌트 = 전시관(Venue): KINTEX(기준 테넌트 #1) → COEX 등 타 전시관 온보딩 가능", + "격리 3원칙:", + (1, "데이터: 전 도메인 엔티티 tenant_id 전파, 조회 컨텍스트 자동 주입(누수 차단)"), + (1, "브랜딩: 테넌트별 로고·색상 토큰 오버레이(공유 디자인 시스템 위)"), + (1, "관리: 플랫폼 관리자 ↔ 테넌트 관리자 2계층 역할"), + "마스터데이터(홀·요율·규정 룰셋)는 테넌트 소유 — 전시관별 고유 규정 수용", + "기능·화면·모듈은 공유, 데이터만 격리 — 확장 시 재개발 불필요", + ]), + ("content", "Ⅱ-2. 기술 부문", "대외 접점 3-트랙 IA (visitor / business / agency)", [ + "코엑스 3-사이트 IA 분석에 근거한 트랙 분리 — 랜딩 3-분기 + 트랙별 서브홈", + (1, "visitor(관람객): 공개 관람 랜딩, 행사 캘린더·티켓·wayfinding·AI 관람 도우미"), + (1, "business(주최자·참가업체): 행사 준비 전 과정 — 홀 배정→설계→서류→정산"), + (1, "agency(공사·장치·협력사): 옥션 열람·견적 제출·시공 일정·현장 작업"), + "로그인 사용자 구분이 메인페이지와 좌측 메뉴 그룹을 결정(역할→트랙 매핑 확정표)", + "내부 역할(ops/admin)은 트랙 외부 별도 백오피스 — 망·권한 분리", + ]), + ("content", "Ⅱ-2. 기술 부문", "역할별 포털·메뉴 결정 규칙 (6+2 역할)", [ + "역할: 전시업체(참가) · 공사/장치업체 · 주최자 · 킨텍스 운영 · 킨텍스 관리 · 시스템 관리자(테넌트/플랫폼) + 일반 대중(공개)", + "미인증 진입 = visitor 공개 랜딩 / 인증 시 역할별 전용 메인으로 자동 라우팅", + "좌측 메뉴 그룹 매트릭스: 역할별 노출/차단을 시스템관리(메뉴·권한)에서 통제", + "모바일 하단 탭바도 동일 규칙(역할별 결정) — 웹·모바일 랜딩 패리티", + "멀티역할 사용자는 트랙 스위칭 UI 제공(판정 우선순위 규칙 적용)", + ]), + ("content", "Ⅱ-3. 기술 부문", "M1. 행사·홀 배정 및 자동 견적", [ + "행사 등록 → 희망 면적·기간 입력 → 가용 홀 탐색·중복 예약 충돌 검증 자동화", + "요율 마스터(기준단가 2,250원/㎡ × 성수기·전시일 규칙) 기반 즉시 자동 견적", + "As-Is 수일 소요 견적 회신 → To-Be 즉시 산출(RFP 목표 정합)", + "배정 확정 시 행사 워크스페이스 자동 생성 → M2~M9 전 모듈 연계 시작점", + "홀 가동률 캘린더·활용도 통계로 영업 의사결정 지원(M16 연계)", + ]), + ("content", "Ⅱ-3. 기술 부문", "M2. 플로어플랜 스튜디오 — 부스 배치 자동화 (P0)", [ + "웹 캔버스 에디터: 홀 실측 도면 언더레이 + 부스 폴리곤 배치·편집·팬/줌", + "자동 배치: 부스 수·규격·통로폭·소방 규정 입력 → 복수 배치안 생성(제약 솔버 + LLM 조건해석)", + "배치안 비교·선택·병합 → 규정 검증(통로폭·비상구·소방) 자동 플래깅", + "실측 데이터 확보 완료: K1·K2 전시홀 DWG(트렌치 좌표 포함)·JPG 15장 적재", + "As-Is CAD 수작업 수일~수주 → To-Be 30초 이내 복수 안(PER-001 정합)", + ]), + ("content", "Ⅱ-3. 기술 부문", "M2-1. 자동 배치 3단계 위저드 · DWG/JPG 언더레이", [ + '"사용자가 쉽게" — 초보자도 3단계로 배치 완성:', + (1, "① 홀/구역 선택: 전시장>홀>구역 트리 + 구역 경계 스냅"), + (1, "② 조건 입력: 부스 수·규격·통로 조건(자연어 조건 해석 지원)"), + (1, "③ 결과 비교·선택: 3안 비교 → 적용(apply-option) 시 실제 저장·후속 연계"), + "도면 언더레이 이중화: 캘리브레이션된 JPG 탭 + DWG 정밀 렌더 탭 전환", + "K1 홀 1~5 축정렬 / K2 홀 6~10 회전보정(−12°·−11°·+11°) 결정론 캘리브레이션 완료", + ]), + ("content", "Ⅱ-3. 기술 부문", "M3. 부스 설계 스튜디오 (P0)", [ + "부스 단위 인테리어·장치 설계: 구조물(벽체·리깅)·가구·사인·조명 배치", + "설계 템플릿 라이브러리(조립부스·독립부스·아일랜드형) + 커스터마이징", + "설계안 → 물량(BOQ)·예상 공사비 개산 자동 산출 → M15 옥션 근거자료", + "높이 5m·방염 등 장치 규정 자동 체크(룰 엔진 연동)", + "산출물: 설계 도면 + 물량서 + 나노바나나 시각화 입력 데이터", + ]), + ("content", "Ⅱ-3. 기술 부문", "M4. 유틸리티 설계 자동화 (P0)", [ + "부스 좌표 클릭 → 트렌치 위치 기준 최단 배선 경로 자동 산출(PostGIS 공간 연산)", + "전기·조명 / 네트워크 / 급배수 3계통 — 계통별 오버레이 시각화", + "배선 물량 → 유틸리티 자동 견적(요율 마스터 연동) → 신청·승인 워크플로", + "As-Is 수기 위치표시도 → To-Be 좌표 클릭 한 번(트렌치 실측 좌표 V61 적재 완료)", + "현장 시공용 배선도 출력(PDF) 및 작업자 모바일 조회", + ]), + ("content", "Ⅱ-3. 기술 부문", "M5. 나노바나나 시각화 — 핵심 차별화 (P0)", [ + "배치·설계·배선 데이터 → 이미지 생성 AI(Gemini 이미지 모델)로 '시공 후 결과 사진' 생성", + "표준 샷 세트 S1~S7: 부스 정면 · 인테리어 · 야간 조명 연출 · 통로 뷰 · 배선 오버레이 · 홀 조감 등", + "Before/After 슬라이더 — 도면 대비 시공 예상을 직관 비교", + "홀 조감(S7)은 버튼 클릭 시에만 생성(자동 발행 금지) — 비용 통제", + "생성 이미지는 갤러리에 영속·재열람, M15 옥션 참고 이미지로 재사용", + ]), + ("content", "Ⅱ-3. 기술 부문", "나노바나나 파이프라인 상세 (신뢰성·비용 방어)", [ + "아키텍처: Spring → Redis 큐(RenderJob) → Python 워커(google-genai) → 오브젝트 스토리지 → WebSocket 완료 푸시", + "ReRoomAI 실증 기법 이식: image-to-image 보존/교체 프롬프트 제어, 파라미터 확정", + "방어 로직: 재시도·타임아웃·실패 폴백, 작업 상태 UX(대기·생성중·완료·실패)", + "워터마크·고지 정책(필수): 전 생성 이미지 'AI 생성 예상 이미지' 워터마크 강제(SER-004)", + "시공사 견적·계약의 참고자료 지위 명시 — 법적 리스크 차단(R1·R2 대응)", + ]), + ("content", "Ⅱ-3. 기술 부문", "M6. 서류·마일스톤 / M7. 등록업체 매칭", [ + "M6 서류 워크플로:", + (1, "반입·전기·화기 등 서류 온라인 제출 → 검수 → 승인 (HWP·이메일 대체)"), + (1, "행사별 마일스톤(D-day) 자동 생성, 마감 임박(D-3)·초과 알림"), + (1, "AI 서류 검수 보조: 누락·불일치 사전 플래깅"), + "M7 등록업체:", + (1, "킨텍스 등록업체(장치·전기·통신·경비·청소) 디렉토리·자격 관리"), + (1, "업체 매칭·견적 요청 → M15 옥션과 연계"), + ]), + ("content", "Ⅱ-3. 기술 부문", "M15. 공사/장치 옥션(역경매) 플랫폼 — 핵심 플로우", [ + "AI 산출물(배치·설계·물량·예상 이미지)이 그대로 입찰 근거자료 — 발주 준비 비용 제로화", + "흐름: 전시업체 옥션 개설 → 공사업체 열람·견적서 제출 → 역경매 경쟁 → 낙찰 확정", + "실시간 순위 푸시(WebSocket) · 마감 자동 처리 · 유찰/재공고 지원", + "채점 엔진: 가격 + 실적 + 평가점수 가중 합산, BOQ 기반 견적 검증", + "전시업체(주최자·참가업체) 포털과 공사업체(agency) 포털 양면 구현", + ]), + ("content", "Ⅱ-3. 기술 부문", "M8. 반입/반출 물류 / M9. 정산·결제", [ + "M8 물류 슬롯:", + (1, "반입·반출 차량 슬롯 예약 + 게이트 배정 — 현장 혼잡 분산"), + (1, "행사 일정 연동 슬롯 캘린더, 현장 QR 확인"), + "M9 정산·결제:", + (1, "홀 사용료·유틸리티·부대서비스 통합 정산(행사 스코프 폐루프)"), + (1, "PG 연동 온라인 결제(SIR-001) · 취소/부분환불 · 세금계산서 연계"), + (1, "수수료·환불 정책 룰셋 관리(관리자 설정형)"), + ]), + ("content", "Ⅱ-3. 기술 부문", "M10. 관람객 등록·티켓·배지·리드캡처", [ + "사전등록 → 티켓 발급 → QR 배지 → 현장 체크인 원스톱(간편가입·게스트 지원)", + "참가업체 리드 캡처: QR 스캔·명함 → 리드 목록·등급·메모 → 사후 팔로업", + "AI 관람 도우미: 행사·부스 추천, 연월 브리핑(크롤 적재 DB 근거 응답)", + "현장 체크인 대시보드(운영자): 시간대별 입장 현황·혼잡 알림", + "B2C 모바일 앱 트랙과 공유(스토어 공개·게스트 모드)", + ]), + ("content", "Ⅱ-3. 기술 부문", "M11. 비즈니스 매칭 / M13. Wayfinding", [ + "M11 비즈매칭:", + (1, "참가업체-바이어 프로필 기반 AI 추천(관심 카테고리·행동 데이터)"), + (1, "상담 일정 예약·미팅 테이블 배정·사후 평가"), + "M13 wayfinding:", + (1, "홀 도면(M2 실측 데이터 재사용) 기반 부스 검색·경로 안내"), + (1, "모바일 웹 우선 — 앱 설치 없이 QR 진입"), + (1, "행사장 시설(화장실·출입구·부대시설) POI 안내"), + ]), + ("content", "Ⅱ-3. 기술 부문", "M12. 공개 홍보 사이트 / M17. CMS", [ + "M12 공개 사이트(일반 대중):", + (1, "행사 일정·상세·포스터 안내, 코엑스 수준 비주얼(시네마틱 히어로·모션)"), + (1, "반응형·SEO·다국어(4개국어), 접근성(prefers-reduced-motion·CLS 0)"), + (1, "EDM 발송·구독 관리·수신거부(마케팅)"), + "M17 CMS(헤드리스):", + (1, "전시 콘텐츠·공지·배너·프로모션 관리, 예약 발행(스케줄 퍼블리시)"), + (1, "참가업체 마이크로사이트 셀프 관리 · 사이니지 연계 콘텐츠"), + ]), + ("content", "Ⅱ-3. 기술 부문", "M14. 현장운영 (혼잡·안전·주차·에너지)", [ + "현장 통합 대시보드: 시간대별 입장·혼잡 히트맵(체크인 데이터 연동)", + "안전: 사건·사고 보고, 안전 점검 체크리스트(모바일 현장 입력)", + "주차: 주차장 현황·만차 안내 연계", + "에너지: 홀별 전력 사용 모니터링(유틸리티 신청 데이터 대사)", + "운영자(ops) 전용 화면 — 현장 이슈의 단일 상황판", + ]), + ("content", "Ⅱ-3. 기술 부문", "M16. 경영분석 BI (P2→P1 승격)", [ + "경영 KPI 대시보드: 매출·홀 가동률·참가사 리텐션·행사 P&L", + "운영사(킨텍스) 관점 수익성/ROI: 행사별 원가·수익 구조 분석", + "수요예측: 시즌·산업군별 홀 수요 예측(과거 데이터 학습) → 영업 전략 지원", + "부스 트래픽·체류·히트맵, 리드/ROI 분석(참가업체 제공 리포트)", + "구현: 집계는 SQL(뷰·M-View·배치) — AI 호출 아닌 데이터마트 기반(COR-003 정합)", + ]), + ("content", "Ⅱ-3. 기술 부문", "M18. 관리자 백오피스 + 시스템관리 레이어", [ + "관리자 대시보드: 행사·매출·시스템 현황 통계, 실시간 모니터링", + "룰셋 관리: 규정(통로폭·소방·높이)·요율(홀 단가·성수기) 설정형 관리 — 코드 수정 없이 정책 변경", + "시스템관리(WISE 표준 이식): 사용자·역할/권한(RBAC)·메뉴·공통코드·감사로그·시스템설정", + "마스터데이터: 홀·등록업체·프로그램 관리", + "테넌트 관리(플랫폼 관리자): 전시관 온보딩·브랜딩·격리 상태 점검", + ]), + ("content", "Ⅱ-3. 기술 부문", "공통 업무기능 레이어 (§5B — WISE 표준 이식)", [ + "발주기관 표준 프레임워크(WISE/UIWS)의 검증된 공통기능을 이식 — 재개발 리스크 제거", + (1, "업무일지·일정(캘린더)·쪽지·공지·의견수렴·통합검색"), + (1, "회의·보고서·통계·알림(웹 푸시)·감사 추적"), + "전 역할 공용 — 트랙과 무관하게 로그인 사용자 공통 제공", + "UI 컨벤션도 WISE 정렬: 셸(햄버거·아코디언 메뉴)·캘린더·차트·테이블·폼 표준", + "이식 원칙: 정본 구조 유지, 킨텍스 토큰(kx) 테마만 교체", + ]), + ("content", "Ⅱ-4. 기술 부문", "인증·보안 아키텍처", [ + "인증: JWT + 2차인증(OTP) — WISE 표준 인증 체계 이식(SER-001)", + "인가: 행사 단위 RBAC + 테넌트 격리 + 역할별 메뉴·API 이중 게이트", + "개인정보(SER-002): 저장·전송 암호화, 마스킹, 접속기록 보관, 취급 최소화", + "시큐어코딩(SER-003): 개발보안 가이드 준수, 보안약점 진단 도구 CI 편입", + "모바일 보안: 루트/탈옥 탐지·무결성 검증·화면캡처 방지·cleartext 금지", + "시크릿 관리: 환경변수 주입·fail-fast 검증, 키 마스킹·저장소 미커밋 원칙", + ]), + ("content", "Ⅱ-4. 기술 부문", "AI 아키텍처 — 사용성 표준 & 토큰 최소화 (§8A)", [ + 'AI 사용성 표준: "어디서나 한 번에 물어본다"', + (1, "전 화면 인라인 진입점·예시 질문 칩·원클릭 액션·다음 명령 제시"), + (1, "구조화 카드 + 근거 인용 응답·대화 히스토리·다국어(모바일 음성)"), + "토큰 최소화 6원칙(COR-003 정합):", + (1, "결정로직 우선 라우팅(LLM 미호출) · 소형모델 우선 · RAG 발췌로 프롬프트 축소"), + (1, "캐싱 · 출력 상한/구조화 · 집계는 SQL — AI는 해석만"), + "모델 전환 설정형: Claude 기본 + AiTextRouter로 대체 모델 폴백, 사용량 측정지표 대시보드", + ]), + ("content", "Ⅱ-4. 기술 부문", "데이터 아키텍처 — 공간데이터·마스터데이터", [ + "공간 데이터(DAR-001): 부스 폴리곤(Polygon)·트렌치 포인트(Point)·배선(LineString) — PostGIS ST_* 연산", + "마스터 데이터(DAR-002): 홀(실측 15개)·요율·규정 룰셋·공통코드·등록업체 — 테넌트 소유", + "데이터 표준(DAR-003): 명명 규칙·FK 최소화·공통코드 체계·이력(감사) 관리", + "집계 체계: 뷰·Materialized View·배치 집계 — BI·통계의 성능 기반", + "마이그레이션: Flyway 버전 관리, 배포 전 라이브 dry-run(BEGIN…ROLLBACK) 검증 절차", + ]), + ("content", "Ⅱ-4. 기술 부문", "외부 연동 (SIR)", [ + "PG 결제(SIR-001): 신용카드·계좌이체, 취소·부분환불, 정산 대사", + "SSO·HR(SIR-002): 킨텍스 Open SSO 연동 + 인사 조직·직원 정보 동기화(내부 사용자 프로비저닝)", + "CAD(SIR-003): DWG 입력 파이프라인 — 좌표 추출·캘리브레이션·JPG 렌더(CI_AI·CI_JPG 자동화)", + "이미지 생성 API: Gemini 계열(나노바나나 워커 경유 단일 창구)", + "확장 대비: 웹훅(인바운드/아웃바운드·서명 검증) 표준 창구 제공", + ]), + ("content", "Ⅱ-4. 기술 부문", "모바일 앱 (B2B 운영 · B2C 관람객)", [ + "단일 코드베이스(React Native/Expo) + 배포 타깃 2:", + (1, "① 운영 B2B: 2FA 필수, 사내 QR 배포 — 현장 체크리스트·검수·승인·시각화 갤러리"), + (1, "② 관람객 B2C: 스토어 공개, 간편가입·게스트 — 티켓·배지·wayfinding·AI 도우미"), + "계정은 단일 통합, 가입 트랙만 분리(하이브리드 채택)", + "오프라인 대응·푸시 알림·다국어(i18n)·생체인증(내정보)", + "웹과 랜딩·메뉴 패리티(역할별 결정 규칙 공유)", + ]), + ("content", "Ⅱ-4. 기술 부문", "성능·품질 목표 (NFR)", [ + "응답시간(PER-001): 일반 조회 3초 이내 · 자동 배치 30초 이내(3안) · AI 이미지는 비동기+완료 푸시", + "동시사용자(PER-002): 평시 500 / 피크 3,000 동시접속 — 부하테스트로 검증", + "가용성(PER-003): 99.5% 이상, 계획 정지 야간 수행", + "품질(QUR): 단계별 품질 게이트·산출물 표준·경계면 정합 QA(API shape ↔ 프론트 타입 교차 검증)", + "테스트(TER): 단위·통합·성능·보안 + UAT 시나리오 지원, 결함 관리 체계", + "성능 설계 선반영: 인덱스 전략·집계 뷰·이미지 CDN 캐싱·빌드 번들 최적화", + ]), + ("section", "PART Ⅲ", "사업관리 부문", "추진전략·방법론 · 조직·인력 · 일정 · 위험 · 품질"), + ("content", "Ⅲ-1. 사업관리", "추진 전략 및 방법론", [ + "P0 코어 우선 전략: M2→M3→M4→M5를 최우선 구축, 3개월 차 조기 가시화(경영진 시연)", + "애자일 스프린트(2주) + 단계별 산출물 검토 병행(PMR-002) — 공공 검수 체계와 양립", + "모듈별 완성 직후 점진 QA(incremental QA) — 전체 완성 후 일괄 검증의 리스크 제거", + "발주기관 협업: 주간 진척 보고 + 격주 시연(동작 소프트웨어 기준) + 월간 운영위원회", + "선행 게이트 관리: AI API 키·개발 서버·CI/CD 등 전제조건을 착수 2주 내 확정", + ]), + ("content", "Ⅲ-2. 사업관리", "수행 조직 및 투입 인력", [ + "총 19명 — PM 1 / 아키텍트 3(AA·TA·DA) / 백엔드 4 / 프론트 4 / AI 2 / DB 1 / QA 2 / 모바일 2", + "거버넌스: PM(총괄) — 개발PM(트랙 조율) — PMO(표준·산출물·품질 게이트)", + "아키텍트 전담: 모듈 경계·API 표준(AA) / 기술표준·성능(TA) / 데이터 모델·표준(DA)", + "핵심 인력(PM·AA·AI 리드) 교체 제한 — 발주기관 사전 승인(PMR-004)", + "전 인력 보안서약·개인정보 교육 이수 후 투입", + ]), + ("content", "Ⅲ-3. 사업관리", "추진 일정 (12개월)", [ + "M1~M3 [분석·설계]: 요구사항 상세화·아키텍처 확정·데이터 표준·ERD·화면 설계(디자인 시스템)", + "M3~M7 [구축 1차 — P0 코어]: M2 배치·M3 설계·M4 배선·M5 시각화 + 공통/시스템관리·인증(2FA)", + "M6~M10 [구축 2차 — 도메인]: M1·M6~M18 + 모바일 앱 + 공개사이트 (일부 병행)", + "M10~M12 [통합·이행]: 통합·성능·보안 테스트, 데이터 이관, UAT, 교육, 오픈", + "오픈 후 2개월 [안정화]: 상주 지원·하자 대응·운영 이관", + "중간 마일스톤: M3 설계 완료(1차 검수) · M7 P0 시연 · M10 기능 완료 · M12 최종 검수", + ]), + ("content", "Ⅲ-4. 사업관리", "마일스톤·산출물 관리", [ + "단계별 산출물: 요구사항정의서·아키텍처설계서·ERD/데이터표준·화면설계서·테스트계획/결과서·운영매뉴얼", + "산출물 형상관리: Git 저장소 단일 출처, 문서-코드 버전 동기화", + "품질 게이트: 각 마일스톤 검수 전 자체 QA 통과 조건(빌드·경계면 정합·보안 점검)", + "요구사항 추적: 요구사항 대응표(RFP 50건) ↔ 설계 ↔ 구현 ↔ 테스트 전 구간 추적성 유지", + "주간 보고(진척·이슈) + 월간 보고(마일스톤·리스크·품질 지표)", + ]), + ("content", "Ⅲ-5. 사업관리", "위험 관리 방안", [ + "R1 AI 산출물 신뢰: 워터마크·라벨 강제 + 인간 승인 절차 — 설계 단계 반영 완료", + "R2 규정 검증 책임: AI는 플래깅까지, 최종 판정은 킨텍스 구조기술팀 — 역할 경계 명문화", + "R3 AI 비용 초과: 토큰 최소화 6원칙 + 사용량 대시보드 + 월 상한 알림", + "R4 실측 데이터 정합: CAD 실측 좌표 검증 절차(캘리브레이션 리포트) 운영", + "R5 일정 지연: P0 우선·병행 트랙 조정 여력·격주 시연으로 조기 감지", + "공통: 위험 등록부 상시 운영, 발생 시 영향·대안 분석 후 운영위 보고", + ]), + ("content", "Ⅲ-6. 사업관리", "품질보증·형상/변경관리", [ + "품질보증(QUR-001): 품질 계획 수립 → 단계별 게이트 → 지표 관리(결함 밀도·해결률)", + "경계면 QA 특화: 백엔드 API 응답 ↔ 프론트 타입/훅 shape 교차 검증(통합 결함 사전 차단)", + "표준 준수(QUR-002): 개발표준·DB 표준·UI 디자인 시스템(design.md 단일 출처) 준수 점검", + "형상관리(PMR-003): Git 브랜치 전략, 코드리뷰 필수, 파일단위 커밋 원칙", + "변경관리: 변경요청(CR) 절차 — 영향 분석 → 승인 → 반영 → 추적, 무단 범위 변경 차단", + ]), + ("section", "PART Ⅳ", "기술지원 부문", "교육·기술이전 · 유지보수 · 비상대응 · 기대효과"), + ("content", "Ⅳ-1. 기술지원", "교육훈련 및 기술이전", [ + "교육 3트랙(PSR-001): 시스템 관리자 / 운영자(킨텍스 실무) / 사용자(주최자·참가업체 안내)", + "교육 자료: 운영 매뉴얼·사용자 가이드·동영상 튜토리얼 제공", + "기술이전: 소스코드·설계문서·운영 절차 일체 + 개발환경 구성 가이드 인계", + "AI 파이프라인 특별 이전: 프롬프트 아키텍처·파라미터·비용 운영 노하우 문서화", + "운영 이관 리허설: 안정화 기간 중 킨텍스 운영조직 주도 운영 1개월 병행", + ]), + ("content", "Ⅳ-2. 기술지원", "유지보수·하자보수 체계", [ + "무상 하자보수 12개월(PSR-002): 검수 완료일 기산", + "하자 등급별 SLA: 긴급(서비스 중단) 4시간 내 착수 / 중요 1영업일 / 일반 2영업일", + "안정화 상주 지원(PSR-003): 오픈 후 2개월 — 현장 대응·성능 튜닝·데이터 보정", + "원격 지원 체계: 이슈 트래킹 시스템·핫라인 운영", + "유상 유지보수 전환 옵션: 하자보수 종료 후 연간 유지보수 계약 제안(범위·요율 별도 협의)", + ]), + ("content", "Ⅳ-3. 기술지원", "비상대응·보안 준수", [ + "장애 대응: 모니터링(헬스체크·알림) → 자동 감지 → 에스컬레이션 절차", + "백업·복구: DB 일일 백업 + 오브젝트 스토리지 이중화, 복구 목표(RTO 4시간/RPO 24시간)", + "배포 안전: 헬스 게이트 통과 후 전환, 마이그레이션 dry-run 검증, 롤백 절차 표준화", + "보안 준수: 인력 보안서약·자료 반출 금지·종료 시 파기 확인(계약 특수조건 이행)", + "개인정보 사고 대응: 유출 시 즉시 보고·차단·소명 절차 사전 수립", + ]), + ("content", "Ⅳ-4. 기술지원", "맺음말 — 기대효과와 약속", [ + "정량 효과: 견적 회신 수일→즉시 · 배치안 수주→30초 · 규정 검토 자동화 · 유틸리티 신청 원클릭", + "정성 효과: 시공 전 '사진 수준' 의사결정 → 주최자·참가업체 만족도, 킨텍스 서비스 차별화", + "경영 효과: 전 과정 데이터 축적 → BI 기반 영업·수익성 분석, 제3전시장 확장 대응", + "확장 효과: 멀티테넌트 SaaS — 타 전시관 온보딩으로 신규 수익 모델", + "약속: 요구사항 50건 100% 수용, 12개월 내 완수, 무상 하자보수 12개월 + 안정화 2개월", + "감사합니다.", + ]), +] + + +def build_pptx(path): + prs = Presentation() + prs.slide_width = Inches(13.333) + prs.slide_height = Inches(7.5) + total = len(SLIDES) + for i, spec in enumerate(SLIDES, start=1): + kind = spec[0] + if kind == "cover": + slide_cover(prs, i, total) + elif kind == "section": + slide_section(prs, i, total, spec[1], spec[2], spec[3]) + else: + slide_content(prs, i, total, spec[1], spec[2], spec[3]) + prs.save(path) + return total + + +if __name__ == "__main__": + docx_path = os.path.join(BASE, "RFP.docx") + pptx_path = os.path.join(BASE, "제안발표.pptx") + build_docx(docx_path) + n = build_pptx(pptx_path) + print("DOCX OK:", docx_path) + print("PPTX OK:", pptx_path, "slides =", n)