# -*- 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'<w:shd {} w:val="clear" w:fill="{}"/>'.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)
