# KINTEX AI 전시·행사시스템 — 설계서 > - 문서 종류: 설계서(System Design Document) > - 프로젝트: **KINTEX AI 전시·행사시스템** (KINTEX AI Exhibition & Event System) > - 작성일: 2026-07-12 · 버전: v1.0 > - 근거 문서: `docs/PLANNING.md`(v3.4) · `docs/design.md`(v2.4) · `docs/architecture/{app,system,tech,data,network,sso-hr-integration}.md` · `docs/COMMON_CODES.md` · **실제 구현 스키마(Flyway `V1~V49`)** · 실제 컨트롤러(REST 계약) > - 보안: 본 문서에는 자격증명·비밀번호·SSH·내부 IP·시크릿을 기재하지 않는다. > - 비고: 본 설계서는 구현된 스키마·API 계약을 정본으로 삼고, 계획(설계 완료·미구현) 항목은 그 취지를 명시한다. --- ## 목차 1. 시스템 아키텍처 2. 애플리케이션 아키텍처(레이어·모듈·의존성) 3. 데이터 설계 4. API 설계 5. 화면 설계 6. AI 설계(§8A) 7. 인증·인가 설계 8. 네트워크·보안영역 설계 9. 비기능 요구사항(NFR) --- ## 1. 시스템 아키텍처 ### 1-1. 전체 구성 **6개 역할별 분리 프론트(React·Vite·TS) + 단일 공유 Spring Boot 백엔드 + 나노바나나 Python 워커 사이드카**를 SSO·역할 RBAC 위에 얹고, PostGIS·Redis 큐·오브젝트 스토리지를 공유한다. ``` [엣지/DMZ] CDN · WAF/nginx(TLS 종단) │ [역할별 프론트] organizer · exhibitor · contractor · ops · admin(내부) · public/visitor │ (SSO · 역할 RBAC 게이트) [공유 Spring Boot 백엔드] REST + WebSocket(STOMP) │ 룰 엔진(요율/규정) · 배치·배선 엔진(PostGIS) · 옥션 엔진(M15) · BI 집계(M16) · CMS(M17) · 공개 API │ [비동기] Redis 큐 → 나노바나나 워커(google-genai) · 서류/PDF/EDM 워커 → 오브젝트 스토리지 │ (완료 시 WebSocket 푸시) [데이터] PostgreSQL + PostGIS (프라이머리 + 읽기 복제) · 오브젝트 스토리지 ``` ### 1-2. 대원칙(5) 1. **단일 공간 데이터 모델** — 부스 폴리곤·트렌치 포인트·배선 경로를 PostGIS로 일원화(설계·시각화·검증·정산·wayfinding·BI가 동일 원천 재사용). 2. **이미지 생성 전면 비동기** — Spring이 RenderJob을 Redis 큐에 발행 → Python 워커가 Gemini로 생성 → 오브젝트 스토리지 적재 → WebSocket 완료 푸시. `GEMINI_API_KEY`는 워커 전유(백엔드 미취급). 3. **역할별 프론트 분리** — 최소권한·공격면 축소, 공유 디자인 시스템·컴포넌트·API 계약 상속. 4. **룰셋 = 버전 관리 데이터** — 규정(높이·방염·하중)·요율을 코드가 아닌 `rulesets/*.json` + master_data로 관리(연 단위 개정 무중단 반영). 5. **공개 vs 내부 백오피스 보안영역 분리**(§8). ### 1-3. 배포 토폴로지(존) - **공개 존(DMZ)**: Reverse Proxy/WAF·nginx·TLS, CDN, 공개 프론트 SSR/SSG, 공개 API GW(화이트리스트 엔드포인트만), PG 콜백. - **애플리케이션 존(내부망)**: 인증 프론트 정적 서빙(organizer·exhibitor·contractor·ops), 공유 백엔드 jar × N(systemd, 무상태 수평 확장), 워커 데몬 × M. - **관리 존(내부 전용)**: admin 백오피스(웹 전용, VPN/허용 IP + 2FA 강제). - **데이터 존(최내곽)**: PostgreSQL+PostGIS(프라이머리+스탠바이)·읽기 복제·Redis HA·오브젝트 스토리지. **아웃바운드 없음(유출 경로 제거)**. > 물리 서버·도메인·포트는 G2 게이트 확정 후 Phase E에서 실체화(개발 도메인은 `kintex.zioinfo.co.kr`, 포트 8021). 근거: architecture/system.md·network.md. --- ## 2. 애플리케이션 아키텍처(레이어·모듈·의존성) ### 2-1. 패키지 구조 루트 `com.zioinfo.kintex`. 횡단 계층 + 도메인 모듈: - `common`(응답봉투·페이징·에러·감사 AOP·공통코드 캐시 — **무의존**), `config`(Security·WebSocket·Redis·MyBatis), `auth`(JWT·RBAC·2FA/OTP·가드), `rules`(규정·요율 룰셋 로딩·평가), `system`(시스템관리), `work`(공통 업무), `module`(도메인 m2~m5 등). - 리소스: `application.yml`(env 플레이스홀더), `mybatis/mapper/**/*.xml`(공간 SQL `ST_*`), `rulesets/`(compliance·rates JSON = 데이터). ### 2-2. 레이어링 표준 | 계층 | 책임 | 금지 | |---|---|---| | Controller | HTTP 바인딩·`@Valid`·RBAC 가드 호출·서비스 위임·`ApiResponse` 래핑 | 비즈니스 로직·SQL·트랜잭션·매퍼 직접 호출 | | Service(interface+Impl) | 비즈니스 규칙·`@Transactional` 경계·룰 엔진 호출·매퍼 오케스트레이션·DTO 조립 | HTTP 타입 참조 | | Mapper(MyBatis) | DB 접근·공간 SQL(ST_*) 바인딩 | 비즈니스 분기·DTO 조립 | | DTO(record) / domain | 불변 전송 객체 / 순수 값객체(프레임워크 무의존) | — | - 공간 연산은 매퍼 XML의 PostGIS SQL로 수행(서비스는 스칼라/GeoJSON 결과만 사용). 조회 `readOnly=true`, 버전 리소스는 낙관적 잠금(불일치=409). ### 2-3. 의존성 규칙(단방향·순환 금지) - `module.mN` → `rules·auth·common`(횡단 허용). `common`은 **무의존**. - **모듈 간 명시 방향만**: M3→M2, M4→M2, M5→M2·M3·M4, M15→M2·M3·M4·M5·M7, M9→M1·M4·M15, M13→M2, M14→M4·M10, M16→전 모듈(읽기), M12→M10·M17. - 역방향 필요 시 직접 참조 금지 → **도메인 이벤트·공유 식별자로 디커플**(예: M15 낙찰→M9는 발주 링크). 모듈 간 결합은 서비스 인터페이스로만. 검증 = ArchUnit 빌드타임 아키텍처 테스트(역참조·순환 CI 차단). - 백엔드는 **단일 공유 모듈러 모놀리스**(역할별로 쪼개지 않음) — 모듈 경계 + 의존 규칙으로 코드 레벨 강제, 노출 표면은 경로 접두 + RBAC로 분리. > 근거: architecture/app.md. --- ## 3. 데이터 설계 ### 3-1. 데이터 표준(명명·타입) - 테이블/컬럼: PostgreSQL 무인용 소문자 `snake_case`, PK `<엔티티>_id`(도메인은 UUID), WISE 이식 테이블은 정본 PK 유지. - 지오메트리 `geom`/`<용도>_geom`, 암호화 PII `<필드>_enc`, 코드 컬럼 `status`/`<의미>_code`, 시각 `*_at`(timestamptz, UTC 저장/Asia/Seoul 표시), 금액 `numeric`(KRW). - **DTO(camelCase) ↔ 컬럼(snake_case)**: MyBatis `map-underscore-to-camel-case=true`. - **응답 제외(불변)**: `*_enc`·`password_hash`·`otp_secret`·내부 IP/SSH·내부 식별자는 API 응답 완전 제외. ### 3-2. FK 최소화 원칙 (소유자 지시 2026-07-12) - **원칙: "FK는 최소화, 공통코드로 관리."** 신규 도메인/테넌트 테이블은 물리 `FOREIGN KEY`를 두지 않고, 참조무결성은 **애플리케이션 레이어 검증 + `*_id` 소프트 참조 명명**으로 보장. - **근거**: ① 멀티테넌트 복합 PK(`(tenant_id, id)`) 전환 시 단일 id FK가 `UNIQUE(id)` 보조제약을 강제하는 마찰 ② MyBatis가 조인·삭제 순서 제어 ③ 멱등 `ON CONFLICT` 시드 순서 자유 ④ 부스 재배치(replaceBooths) 시 자식 재지정 빈번(V3 `utility_order`·`render_job`이 이미 소프트 참조 = 정본 사례). - **물리 FK 예외 화이트리스트(그 외 신규 FK 신설 금지)**: (W1) `common_code.grp_code`, (W2) `sys_menu.parent_id`(self), (W3) `sys_role_permission`, (W4) `sys_role_menu` — 전역 시스템/RBAC 무결성 필수분만. - **소프트 참조 보완**: 임계 트랜잭션(낙찰·정산) 명시적 부모 존재 검증, 삭제는 서비스가 자식 선처리(soft-delete `use_yn='N'` 우선), 논리참조 인덱스 `(tenant_id, _id)`, 야간 고아 스캔(DQ 게이트). ### 3-3. 공통코드 표준 - 범주형 컬럼(상태·유형·심각도 등 열거 가능 소수값)은 자유문자열/DB enum이 아닌 `common_code_group`/`common_code`로 관리. 컬럼엔 **코드값(영문 상수)만 저장**, 표시명(한글)은 조인/캐시. **DB `ENUM` 물리타입 지양**. - **코드 vs 마스터 경계**: 열거 가능 소수값=공통코드(BOOTH_TYPE·RENDER_STATUS·SHOT_PRESET 등), 다건·CRUD·버전 대상=마스터/룰셋(홀·요율·규정 룰셋·등록업체). 정본 = `docs/COMMON_CODES.md`. - 확정 코드그룹 예: `EVENT_ROLE`(ORGANIZER·EXHIBITOR·CONTRACTOR·HALL_MANAGER), `PORTAL_ROLE`, `BOOTH_TYPE`(independent·assembled), `COMPLIANCE_SEVERITY`(block·warn·pass), `RENDER_STATUS`(QUEUED·RUNNING·DONE·FAILED), `SHOT_PRESET`(S1~S7), `VERIFY_METHOD`(EMAIL·OTP). ### 3-4. 공간 데이터 표준 - **SRID `0`**(홀 로컬 평면 데카르트 좌표, 단위 미터). 지리좌표(4326) 아님, `geometry`(geography 아님). - 부스 = `Polygon`, 트렌치 = `Point`(+ 배선 run은 LineString), 배선 = `LineString`/`MultiLineString`. 전 `geom` **GiST 인덱스 필수**. - 저장 전 `ST_IsValid`·닫힌 링·홀 내포 검증(실패 시 400). 미실측 트렌치는 `is_assumed=true` 플래그(PLANNING R4). - 파생 연산: 최단 배선(라우팅), 통로 폭 검증(버퍼), 면적 정산(ST_Area)이 모두 SQL 수준에서 수행. ### 3-5. 핵심 엔티티(구현 스키마 기준) **신원·마스터(V2)** - `app_user`(id·email·display_name·`password_hash`(BCrypt, 응답 제외)·hall_manager·`otp_secret`(응답 제외)·failed_login_count·locked_until·status) — V7에서 otp_enabled·verify_method·role_code·dept_id·last_login_at 순증, V26에서 tenant_id 순증. - `company`(id·registration_no(사업자번호, 초대 검증 키)·name·category(14분류)·region·**registered**(미등록 응찰 차단)). - `event`·`hall`(exhibition_center·label·width/depth/height_m·area_m2·floor_load_t_per_m2·floor_type·booth_capacity·has_gas·is_assumed_trench)·`hall_assignment`. - `event_member`(event_id·user_id·**role_code**(ORGANIZER·EXHIBITOR·CONTRACTOR·HALL_MANAGER)·booth_id·company_id) — 행사 단위 RBAC 멤버십. - `booth_standard`(assembled·premium spec jsonb)·`master_data`(RATE·UTILITY_FEE·COMPLIANCE + ruleset_version). **공간 코어(V3, P0)** - `trench`(hall_id·geom(Point)·supply_power/water/air/network/gas·is_assumed). - `hall_exit`(geom(Point)·clearance_m — 비상구 이격 버퍼). - `layout`(event_id·hall_id·version·status, UNIQUE(event_id,hall_id,version)). - `booth`(layout_id·booth_no·booth_type·geom(Polygon)·size_w/d_m·height_m·floor_load_t_per_m2·premium). - `design_plan`(booth_id·version·status·spec jsonb, UNIQUE(booth_id,version)). - `utility_order`(event_id·booth_id(소프트 참조)·quote jsonb·wiring(MultiLineString)·location_diagram_url). - `render_job`(event_id·booth_id(소프트)·shot_preset(S1~S7)·status·image_url·schema_hash·model_version·error_message(요약만)). **옥션 M15(V16)** - `auction`(event_id·category·auction_type(reverse/rfq)·award_criteria(lowest/comprehensive)·weight_price/reputation/delivery·round·deadline·material_package_id·materials). - `auction_invite`(등록업체만, UNIQUE(auction_id,company_id) — 미등록 원천 차단). - `bid`(=Quotation: subtotal·vat·total·lead_days·valid_until·terms·`lines` jsonb·version·status, UNIQUE(auction_id,company_id) — 재응찰 시 버전 증가). - `award`(옥션당 1건, bid_id·reason·awarded_by — 감사 추적)·`company_reputation`(rating·jobs_done·claim_rate). - 봉인 입찰: 마감 전 경쟁 견적 비공개(서비스 레이어 강제 마스킹), 마감 후 발주자 전체 공개. **관람·발주·정산·콘텐츠(V14~V24 등)** - M6: `event_milestone`·`required_document`·`document_review_issue`(V14). M8: `dock`·`dock_reservation`(V15), `logistics_*`(V33). - M10: `visitor_registration`·`lead`(V17). M12: `edm_campaign`·`sponsorship_package`·`sponsorship_sponsor`(V18). 공개: `exhibit_inquiry`(V20)·`visitor_guide`·`transport_info`(V43). - M17 CMS: `cms_content`·`cms_translation`·`microsite`(V19), `cms_content_version`·`cms_media`(V21). - M9: `invoice`·`invoice_payment`(V24), `invoice_refund`·`tax_invoice`(V34). M1 판매: `booth_sale`(V27). 결재: `approval`·`approval_line`·`approval_history`(V29). **공통·시스템관리(V7·V8·V37)** - `common_code_group`/`common_code`·`sys_menu`·`sys_role`/`sys_permission`/`sys_role_permission`·`sys_setting`·`audit_log`(actor·action·target·summary·ruleset_version·result·ip_hint)(V7). - 공통 업무(V8): `worklog`·`schedule`·`message`/`message_recipient`·`notice`·`opinion`/`opinion_comment`·`meeting`/`meeting_action`·`report`·`notification`. - 시스템 기초(V37): `dept`·`sys_program`·`sys_role_menu`·`sys_auth_policy`·`login_history`·`error_log`. 기타: `login_slide`(V11)·`holiday`(V41)·`sys_message`(V48)·`mail_log`(V36)·`webhook_*`(V35)·`ai_config`(V30). **멀티테넌시(V26·V31)** - `tenant`(id(slug: kintex·coex)·name·domain·status). KINTEX = 테넌트 #1 시드. - 핵심 테이블 `tenant_id` 순증(`NOT NULL DEFAULT 'kintex'` 백필, 회귀 0) + `(tenant_id, …)` 선두 복합 인덱스. V31에서 테넌트 루트(event·hall·app_user)를 `PRIMARY KEY (tenant_id, id)` 복합 PK로 전환. ### 3-6. 마이그레이션 요약(Flyway V1~V49) | 버전 | 주제 | 주요 산출 | |---|---|---| | V1 | 확장 | PostGIS·pgcrypto 등 extension | | V2 | 신원·마스터 | app_user·company·event·hall·hall_assignment·event_member·booth_standard·master_data | | V3 | 공간 코어(P0) | trench·hall_exit·layout·booth·design_plan·utility_order·render_job(+GiST) | | V4·V5·V6 | 마스터 시드 | 홀 마스터·트렌치 그리드·마스터/데모 시드 | | V7 | 시스템관리·보안 | common_code(_group)·sys_menu·sys_role/permission·sys_setting·audit_log | | V8 | 공통 업무 | worklog·schedule·message·notice·opinion·meeting·report·notification | | V9 | 공개 인증 | password_reset | | V10 | 시드 | 10년치 행사 시드 | | V11·V12·V13 | 부가 | login_slide·TOTP 2FA·카탈로그/대시보드 인덱스 | | V14 | M6 | event_milestone·required_document·document_review_issue | | V15 | M8 | dock·dock_reservation | | V16 | M15 옥션 | auction·auction_invite·bid·award·company_reputation(+시드) | | V17 | M10 | visitor_registration·lead | | V18 | M12 | edm_campaign·sponsorship_package·sponsorship_sponsor | | V19 | M17 CMS | cms_content·cms_translation·microsite | | V20 | 공개 사이트 | exhibit_inquiry | | V21 | 확장 | cms_content_version·cms_media(체크인·리드·CMS 확장) | | V23 | 일정 보강 | schedule 확장 | | V24 | M9 정산 | invoice·invoice_payment | | V25 | M1 | 홀 배정 확장 | | V26 | 멀티테넌시 1단계 | tenant + 핵심 테이블 tenant_id 순증·복합 인덱스 | | V27 | 부스 판매 | booth_sale | | V28 | 옥션 부가 | BOQ·옥션 수수료 | | V29 | 결재 | approval·approval_line·approval_history | | V30 | AI | ai_config | | V31 | 테넌트 표준 | 테넌트 루트 복합 PK((tenant_id, id)) 전환 | | V32 | 시드 | 2026 하반기 킨텍스 행사 | | V33 | M8 확장 | logistics_equipment/request·rental_item/order·inbound | | V34 | M9 확장 | invoice_refund·tax_invoice | | V35 | 자동화 | webhook_subscription·delivery·inbound·edm_followup_log | | V36 | 메일 | mail_log | | V37 | 시스템 기초 | dept·sys_program·sys_role_menu·sys_auth_policy·login_history·error_log | | V38·V39 | 데모 | full·realism 데모 시드 | | V41·V42 | 마스터/데모 | holiday(2050)·대량 데모 시드 | | V43 | 관람 가이드 | visitor_guide·transport_info + `v_event_calendar`·`v_event_monthly_summary`(뷰) | | V44 | 성능 | 성능 인덱스 | | V45·V46·V47 | 부가/데모 | 프로필 사진·포스터 로컬 에셋·라이브 행사 폐루프 시드 | | V48 | 메시지 | sys_message(템플릿) | | V49 | 데모 | 빈 테이블 데모 시드 | > 멱등(`IF NOT EXISTS`·`ON CONFLICT`) + 비파괴 순증 원칙. V22·V40은 결번. ### 3-7. VIEW/MVIEW/배치 전략 - **`v_*` VIEW**: 실시간 파생·경량 조인·상태 산출(예 `v_event_calendar` — 날짜→UPCOMING/ONGOING/ENDED 산출로 별도 상태 컬럼 불필요). tenant_id 필터·민감 컬럼 미노출. - **`mv_*` MATERIALIZED VIEW**: 무겁고 실시간성 낮은 집계(BI KPI·가동률·리드/ROI). 새로고침 전략 명시(야간 배치·`REFRESH ... CONCURRENTLY`·mview 인덱스). - **BI 데이터마트(M16)**: 스타 스키마 `FACT_BOOKING/SETTLEMENT/UTILITY/AUCTION/VISITOR` + `DIM_DATE/HALL/EVENT/EXHIBITOR` + `KPI_SNAPSHOT`(built_at 각인). 별도 `mart` 스키마, 야간 ETL 또는 읽기 복제. **운영 DB 직조회 금지**. - **배치 카탈로그(J1~J9)**: mview 새로고침·KPI 스냅샷·마감 알림/할일·EDM/옥션 통지·세션 만료 정리·고아 검출(DQ)·PII 보존/파기(행사종료+1년)·행사 crawl·정산 롤업. 공통 요건: 멱등·분산락·실패 격리·감사·테넌트 스코프. > 근거: architecture/data.md. --- ## 4. API 설계 ### 4-1. 표준 - 베이스 `/api`. 공개=`/api/public/**`, 워커=`/api/internal/**`, 행사 스코프=`/api/events/{eventId}/…`, 플랫폼 관리=`/api/admin/**`(hasRole ADMIN), 인증=`/api/auth/**`. 비-CRUD 액션은 하위 동사 세그먼트(POST). - 응답 봉투 `ApiResponse`{success·data·error{code,message}}, 목록 `PageResponse`{items·page·size·total}. - **ErrorCode→HTTP**: VALIDATION 400 · UNAUTHORIZED 401 · FORBIDDEN 403 · NOT_FOUND 404 · CONFLICT 409 · **COMPLIANCE_BLOCKED 422** · **RENDER_QUOTA_EXCEEDED 429** · **NOT_REGISTERED_COMPANY 403** · NOT_IMPLEMENTED 501 · INTERNAL 500. ### 4-2. 도메인별 주요 엔드포인트(실제 컨트롤러 기준) | 도메인 | 베이스 경로 | 컨트롤러 | |---|---|---| | 인증(로그인·2FA·비번찾기·프로필사진·앱무결성) | `/api/auth`, `/api/auth/app-integrity` | AuthController·PublicAuthController·TwoFactorController·ProfilePhotoController·AppIntegrityController | | M2 플로어플랜 | `/api/events/{eventId}/halls/{hallId}/layout` | FloorplanController | | M3 부스 설계 | `/api/events/{eventId}/booths/{boothId}/design` | DesignController | | M4 유틸리티 | `/api/events/{eventId}/booths/{boothId}/utility` | UtilityController | | M5 렌더잡 | `/api/events/{eventId}`(render), `/api/internal/render`(워커 콜백) | RenderJobController·RenderWorkerCallbackController | | M15 옥션 | `/api/auctions`, `/api/contractor` | AuctionController·ContractorController | | M1 홀 배정·부스 판매 | `/api/halls`, `/api/booth-sales`, `/api/events`(catalog) | HallAssignController·BoothSalesController·EventCatalogController | | M6 서류·마일스톤 | `/api/events/{eventId}`(document) | DocumentController | | M8 물류 | `/api/events/{eventId}`, `/api/events/{eventId}/logistics` | LogisticsController·LogisticsExtController | | M9 정산 | `/api/settlement` | SettlementController | | M10 관람객·리드 | `/api/visitors` 등(VisitorController) | VisitorController | | M12 마케팅 | `/api/events/{eventId}`(marketing) | MarketingController | | M16 BI·분석 | `/api/analytics`, `/api/events/{eventId}/analytics`, `/api/events/{eventId}/dashboard`, `/api/admin/dashboard` | AnalyticsController·AnalyticsOverviewController·DashboardController·AdminDashboardController | | M17 CMS·마이크로사이트 | `/api/cms/contents`, `/api/cms/media`, `/api/exhibitors/{exhibitorId}/microsite` | CmsContentController·CmsMediaController·MicrositeController | | 공개 사이트·가이드·AI 도우미 | `/api/public`, `/api/public/cms`, `/api/public/microsites`, `/api/public/ai` | PublicSiteController·PublicGuideController·PublicCmsController·PublicMicrositeController·VisitorAssistantController | | 현장 운영 | `/api/events/{eventId}/ops` | OpsController | | 공통 업무(§5B) | `/api/work/{worklogs,schedules,messages,notices,opinions,search,meetings,reports,stats,approvals,notifications}` | Worklog·Schedule·Message·Notice·Opinion·Search·Meeting·Report·Stats·Approval·Notification Controller | | 시스템관리(M18) | `/api/admin/{users,roles,roles/{role}/menus,programs,depts,companies,settings,audit,login-history,error-log,mail-config,notify-config,system-health,rulesets,auth-policy}` | SysUser·Role·RoleMenu·Program·Dept·Company·Setting·AuditLog·LoginHistory·ErrorLog·MailConfig·NotifyConfig·SystemHealth·AdminRuleset·AuthPolicy Controller | | 테넌트 | `/api/admin/tenants` | TenantAdminController | | AI 설정·NL 질의 | `/api/admin/ai`, `/api/ai` | AiConfigController·NlQueryController | | 웹훅 | `/api/webhooks/in`, `/api/admin/webhooks` | WebhookInbound·WebhookAdmin Controller | | 헬스 | `/health`, `/api/home` | HealthController·HomeController | ### 4-3. WebSocket(STOMP)·큐 계약 - `GET /ws`(SockJS), prefix `/topic`(서버→클라)·`/app`(클라→서버). 토픽 `/topic/render/{jobId}`·`/topic/auction/{auctionId}`·`/topic/events/{eventId}/notifications`·checkin. 페이로드는 REST DTO 재사용. - Redis 큐: RenderJob 큐 `kintex:renderjob:queue`, 상태 `...:job:{jobId}`, 쿼터 `...:quota:{eventId}`. **성공 시에만 쿼터 차감**. G1 미승인 시에도 큐잉/상태는 동작(목/degraded). > 근거: architecture/app.md, 실제 controller 매핑. --- ## 5. 화면 설계 ### 5-1. 화면 총괄 design.md v2.4 집계 **총 89화면** — 웹 코어·도메인 52(SCR-01~51, SCR-HOME) + 관리자 10(SCR-A1~A10) + 공개사이트 8(SCR-P1~P8) + 3-트랙 관문 4(SCR-T0~T3) + 모바일 15(SCR-M1~M15). 역할 약칭: 주=주최자·참=참가업체·장=장치/공사업체·홀=킨텍스 직원·관=관리자·대=일반 대중/관람객. ### 5-2. 웹 코어·도메인(대표) | SCR | 화면 | 모듈 | 역할 | |---|---|---|---| | SCR-01 | 로그인 & 행사 워크스페이스 선택 | 공통 | 전 | | SCR-HOME | 로그인 후 메인 홈(랜딩 대시보드) | 공통·§5B·M1·M12 | 전 | | SCR-02 | 주최자 대시보드(D-데이 마일스톤 타임라인) | M1·M6 | 주 | | SCR-03 | 부스 배치 에디터(DnD+AI 자동배치+규정 오버레이) | M2 | 주 | | SCR-04 | 배치안 비교(S7 홀 전경 조감) | M2·M5 | 주 | | SCR-05 | 참가업체 부스 홈 | M3·M6 | 참 | | SCR-06 | 부스 설계 스튜디오(스펙→나노바나나 4샷+before/after) | M3·M5 | 참·장 | | SCR-07 | 유틸리티 배선 뷰(트렌치 오버레이+자동 견적) | M4 | 참·장 | | SCR-08 | 유틸리티 신청 요약·위치표시도 | M4b | 참 | | SCR-09 | 장치업체 규정 검증 리포트 | M3 | 장 | | SCR-10/11 | 홀매니저 승인 큐 / 검수 상세 | M2·M3·M6 | 홀 | | SCR-12 | 시각화 갤러리(S1~S7) | M5 | 전 | | SCR-13 | 경영분석 대시보드 | M16 | 주·홀·관 | | SCR-18~29 | 홀배정·부스판매·정산·서류·매칭·물류·옥션(개설·응찰·견적서·낙찰) | M1·M6·M7·M8·M9·M15 | 역할별 | | SCR-30~37 | 관람객 등록·체크인·리드·EDM·스폰서십·CMS·마이크로사이트·다국어 | M10·M12·M17 | 역할별 | | SCR-38 | 업체 수주 부스 대시보드 | 업체포털 | 장 | | SCR-39~48 | §5B 공통 업무(업무일지·일정·쪽지·공지·의견·검색·회의록·업무보고·알림·마이페이지) | §5B | 전 | | SCR-49~51 | 회원가입·비밀번호 재설정·2차 인증(OTP) 설정 | §5B-3 | 전 | ### 5-3. 관리자 백오피스(SCR-A*, M18·§5B-1, MDI 적용) SCR-A1 사용자 · A2 역할·권한(RBAC) · A3 공통코드 · A4 메뉴 · A5 감사로그 · A6 시스템설정 · A7 마스터데이터(홀·요율·요금·부스표준·등록업체) · A8 규정 룰셋 버전 · A9 테넌트 온보딩(플랫폼 슈퍼관리자) · A10 AI 플랫폼 설정(AiConfig). ### 5-4. 공개 홍보 사이트(SCR-P*, MDI 비적용·SEO/다국어) SCR-P1 홈 · P2 행사 상세 · P3 공개 인터랙티브 플로어플랜 · P4 관람객 사전등록 · P5 마이크로사이트 공개 뷰 · P6 참가/부스 문의 · P7 입장권 예매(티켓팅) · P8 예매 확인·취소. ### 5-5. 3-트랙 IA(§3C, SCR-T*) 코엑스 3-사이트 IA를 킨텍스 단일 도메인 위에 **visitor / business / agency** 3-트랙 얕은 진입 레이어로 정형화. 신규 라우트 4개(`/`=SCR-T0 관문, `/visitor`=T1, `/business`=T2, `/agency`=T3)만 추가하고 기존 딥라우트·MDI·티켓 공개 라우트는 불변(회귀 0). - **SCR-T0 관문**(`/`, 미인증): 제품 히어로 + 3-트랙 대형 분기 카드(관람 1순위) + 행사 하이라이트 레일. - **SCR-T1 visitor**: 세련된 마케팅 홈페이지로 격상, 중심 = 대화형 AI 관람 도우미(히어로 정중앙 자연어 입력창 + 예시 질문칩). 라이트/다크 토글(공개 예외). - **SCR-T2 business**: B2B 실무 톤, 주최자(홀 임대)/참가업체(부스 신청) 2-분기 가치 제안 + 임대 절차 스텝 → 로그인 CTA. - **SCR-T3 agency**: 옥션/역경매 차별점 강조, 등록업체 안내(739개사·14분류·미등록 시공 엄금) + 진행 중 공사 옥션 공고 리스트 → 등록업체 로그인 CTA. - **공개 셸**: PublicShell + 상단 3-트랙 전환 탭(TrackSwitcher), 좌측 "KINTEX AI 전시·행사시스템" 워드마크, 우측 언어(한/영/중/일)·로그인. 서브도메인 테넌트 컨텍스트 하 해당 테넌트 콘텐츠만 노출. ### 5-6. 역할 → 랜딩·메뉴 결정 규칙(웹·모바일 공통) - 미인증 기본 진입 = visitor 공개 관람 랜딩(SCR-T0). 인증 후 역할 매핑 트랙의 전용 메인으로 랜딩: - primaryTrack 우선순위: 내부-admin > 내부-ops > business > agency > visitor. - 랜딩: ADMIN→관리 메인(SCR-16) / MANAGER·HALL_MANAGER→운영 메인 / ORGANIZER·EXHIBITOR→비즈니스 메인(SCR-T2) / CONTRACTOR→에이전시 메인(SCR-T3) / VISITOR→관람객 메인(SCR-T1). - 좌측 메뉴 그룹(GROUPS: ops·design·visitor·finance·work·system)은 트랙 필터로 노출/숨김. `system` 그룹은 ADMIN만. - 모바일 하단 탭바는 역할별 4~5탭 구성. ### 5-7. 디자인 시스템(요약) - **브랜드**: 킨텍스 CI 블루 계열 B2B 실무 톤. AI 생성물은 항상 "AI 생성/초안" 라벨. - **컬러 토큰(kx)**: `primary-600 #0066B3`(주 브랜드), `primary-700 #004C86`, `ai-accent #6D4AFF`(AI 전용), success `#0E8A5F`·warning `#B45309`·error `#D92D20`, `canvas-bg #1C2536`(에디터 다크 서피스), 배선 전기 `#EF4444`/네트워크 `#3B82F6`/급배수 `#22C55E`. WCAG AA 이상. - **타이포**: Pretendard(숫자·좌표 tabular), Display 28 / H1 24 / Body 14, 테이블 행 44px(모바일 48). - **컴포넌트**: StatusBadge(작성중→제출→AI검토→승인→반려→시공→검수), DdayChip(D-3 warning), ViolationFlag(차단 빨강/경고 주황 + 도면 위 번호 핀 1:1), AI 라벨(보라 외곽선), 생성 이미지 상시 고지문(제거 불가). 라운드 버튼 4px/카드 8px(상한)/칩 pill. 12컬럼·컨테이너 max 1440px. - **MDI 셸**: 좌측 사이드바(240px)+상단 문서 탭바+DocumentHost, ShellFooter 36px. 메뉴 클릭=탭 열기(라우트 이동 아님), 비활성 탭 상태 보존, 최대 12탭, 세션 `localStorage`(`kintex.mdi.{role}.{eventId}`). MDI 적용=관리자·주최자·참가·장치·홀매니저 / 비적용=공개(P·T)·모바일. - **캘린더**: WISE(UIWS `CalendarView`) 패턴 문자 그대로 — 월 6주×7열, 기간 이벤트=가로 spanning bar, "+N" 팝업, 전시장 세그먼트 필터는 홀 마스터 센터 distinct 동적 옵션(하드코딩 금지). - **반응형·다크모드**: 웹 1440px(설계·에디터·대시보드)/모바일 390px(조회·승인·현장). 다크모드 Phase 1 미지원(에디터 캔버스만 다크), 공개 마케팅 T1은 예외적 토글. 전 화면 풀블리드·공백 없는 반응형(전역 NFR). ### 5-8. 모바일(SCR-M*, Expo/RN 390px) 조회·승인·현장 전용(캔버스 편집 미제공, 뷰어+승인 액션만). 하단 탭 4개. SCR-M1 시공업체 현장 체크리스트 · M2 홀매니저 현장 검수 · M3 역할별 홈 · M4 리드캡처(배지 스캔) · M5 관람객 홈·배지/QR · M6 wayfinding · M7 플로어플랜·부스 검색 · M8 비즈매칭 · M9 세션·아젠다 · M10 반입 통행증·안전 · M11 알림센터 · M12 서류·승인 조회 · M13 옥션 순위 · M14 티켓 예매 · M15 내 티켓 지갑. ### 5-9. Stitch 연동 전 화면 Stitch 경유(프로젝트 `9385904003821333054`, 디자인 시스템 "Precision Enterprise AI"). 생성 화면 = `stitch_kintex_ai_system_architect/`(각 디렉터리 `code.html`·`screen.png`). design.md가 토큰·컴포넌트 권위(상충 시 design.md 우선). 신규 정의 SCR-HOME·SCR-T0~T3는 미생성(designer Stitch 의뢰 대상). > 근거: design.md v2.4 §1~§4, PLANNING §2-3. --- ## 6. AI 설계(§8A — 사용성 & 토큰 최소화) ### 6-1. 사용성 표준(U1~U7) 전 화면 공통 인라인 AI 진입점(`AiAssistant`) + 예시 질문 칩 + 원탭 액션 + 다음 명령 제시(규칙 기반 우선) + **구조화 카드 + 근거 인용**(출처 레코드 링크, 근거 없으면 "모름" 폴백) + 대화 히스토리(요약 압축) + 접근성/다국어/모바일/음성. 관람객·업무 사용자가 단일 `AiAssistant` + 단일 `/ai/ask` 계약 공유, 노출 위치·칩·허용 액션만 역할/트랙으로 스코프. ### 6-2. 토큰 최소화 6원칙(P1~P6) - **P1 결정론 우선 라우팅**: 사실 조회형(일정·교통·주차·마감일·요금·부스 위치·통계)은 DB/뷰가 직접 응답(LLM 미호출). LLM은 요약·추천·자연어 종합에만. - **P2 소형모델 우선 티어링**: 온프레미스 소형(Ollama qwen3:1.7b/llama3.2:1b) → 난도·실패 시 Claude 승급(AiTextRouter). - **P3 RAG 발췌**: top_k 제한·컬럼 프로젝션으로 짧은 컨텍스트만(전체 문서/테이블 주입 금지). - **P4 캐싱**: 응답 캐시(의도+파라미터+tenant+locale, TTL)·프롬프트 프리픽스·기간 요약 재사용. - **P5 출력 상한·구조화**: max_tokens 상한 + JSON/카드 구조화. - **P6 집계는 SQL로**: 통계·랭킹·추이는 데이터마트 SQL이 산출, LLM은 설명·해석만. ### 6-3. 계약·측정 - **단일 계약** `POST /ai/ask`: 입력 `{question, contextRef, locale, history}`, 출력 `{answerCard, citations[], followups[], route(direct|small|escalated), usage(tokens·cached)}`. - IntentRouter는 규칙 테이블(공통코드)로 관리, 사실조회 의도는 DB 리졸버 매핑, 미매핑만 LLM 경로. 캐시 키 `hash(intent+params+tenant_id+locale)`. - AI 프로바이더: Claude 기본(`api.anthropic.com`, 키 env only) + AiTextRouter(실패 시 Ollama 폴백) + AiConfig 설정 화면(하드코딩 금지). 나노바나나(Gemini)는 별도 이미지 파이프라인(본 절 토큰 원칙 대상 아님, G1 게이트). - **측정지표**(`ai_usage_log` 적재, tenant/모듈 비용 귀속): LLM 우회율 ≥40%·소형모델 처리율 ≥70%·캐시 적중률 ≥30%·평균 입력 ≤1500/출력 ≤400·근거 인용률 ≥95%(초기 가설). > 근거: PLANNING §8A. 현행 visitor-assistant DB 근거 응답·AiTextRouter 폴백과 정합(표준화). --- ## 7. 인증·인가 설계 ### 7-1. 현행(구현) — JWT + RBAC + 2FA - **JWT(HS256)**: 클레임 sub·name·roles(eventId→역할)·hm(홀매니저)·plat(플랫폼 역할)·otp. STATELESS·CSRF disable. 공개(permitAll): `GET /health`·`POST /api/auth/login`·`/ws/**`·`/api/internal/render/callback`·(Phase D)`/api/public/**`. - **이중 RBAC**: 플랫폼 역할(JWT `plat`+`hasRole`) × 행사 역할(JWT `roles`/`hm`+`EventAccessGuard.requireRole`). 열람=행사 멤버 or 홀매니저, 편집·액션=역할별. **등록업체 게이트(불변)**: CONTRACTOR 응찰은 등록업체 검증 필수(미등록=NOT_REGISTERED_COMPANY 403). - **2차 인증(TOTP RFC6238)**: SHA1·30s·6자리·±1 윈도우. 최초 QR 등록, 마이페이지 재설정/해제, 관리자 OTP 초기화. 대상 = 업무 사용자 필수, 일반 관람객 미강제(승격 시 필수 전환). - **로그인 실패 잠금**(failed_login_count·locked_until) + 관리자 해제. **admin 비밀번호** = env `ADMIN_PASSWORD_ENC`(AES-256-GCM) + 별도 키파일 주입, 기동 시 BCrypt 재시드(`admin123` 하드코딩 금지). - 민감 컬럼(`password_hash`·`otp_secret`)은 API 응답에서 완전 제외. ### 7-2. 계정 체계(단일 통합 + 가입 트랙 분리) - 계정/RBAC는 단일 통합, 가입 트랙만 분리: 업무 트랙(B2B, 승인/초대+2FA 필수) vs 관람객 트랙(B2C, 간편가입/게스트 예매·2FA 미강제). 관람객→바이어/참가 승격은 단일 계정 등급 상향(리드·비즈매칭·재방문 이력 연속성 유지). ### 7-3. Open SSO / HR 연동 (계획 — 설계 완료·미구현) - **프로토콜**: OIDC(Authorization Code + PKCE) 우선 + SAML 2.0 옵션. **IdP = Keycloak 자체 호스팅(온프레미스, 내부망 IdP — 외부 API 금지 비해당)**. - **기존 JWT+2FA와 공존(교체 아님)**: SSO는 로그인 게이트웨이만 교체, 성공 후 백엔드가 기존 `JwtService.issue()`로 동일 형태 앱 JWT를 브로커 발급 → 전 화면·RBAC·행사 스코프 불변. `/api/auth/oidc/callback`만 신설, 로컬 로그인 폴백 유지(IdP 장애 대비). - **2FA**: IdP realm이 OTP 제공 시 위임(이중 2FA 방지), 미구성·로컬 폴백은 기존 TotpService 유지. - **HR 연동**: 어댑터 `HrDirectoryClient`(+Mock)로 외부 HR API를 정본 조달 + 로컬 읽기 캐시 스냅샷(미가용 시 degraded). PII 최소(주민번호·연락처·급여 미수집), 삭제는 소프트. 전역 역할·hall_manager는 IdP 그룹/클레임 매핑, **행사 역할(event_member)은 로컬 권위 유지**. - **3자 매핑**: SSO subject(`sub`) ↔ HR 사번(`empNo`) ↔ 로컬 `app_user.id`(연결 테이블 `user_identity`). 이메일 단독 매칭 금지, 충돌 시 자동 병합 금지·관리자 수동 링크. JIT 프로비저닝(첫 SSO 로그인 시 password_hash 없이 생성). - **이행**: 피처플래그(`sso.enabled`) 4단계(준비→coexist→pilot→cutover→정착), 각 단계 롤백 게이트. 신설 모델(`user_identity`·`hr_dept_snapshot`·`hr_emp_snapshot`·`hr_sync_log`·`dept.source`)은 DA/backend 인계 백로그(미구현). > 근거: architecture/sso-hr-integration.md, PLANNING §5B-3, 실제 스키마. --- ## 8. 네트워크·보안영역 설계 ### 8-1. 존 모델(4계층 + 관리 존) | 존 | 구성 | 인바운드 | 아웃바운드 | |---|---|---|---| | 엣지(무신뢰) | CDN·WAF/DDoS | 인터넷 80/443 | DMZ LB | | DMZ(공개) | 공개 LB(TLS 종단)·public SSR·visitor 게이트웨이·공개 API GW·PG 콜백 | 엣지에서만 | 내부망 API GW(제한), **데이터 존 직결 금지** | | 내부망(인증·운영) | 내부 LB·SSO 게이트·내부 API GW·공유 백엔드 | DMZ(허용 API)·관리 존(IP/VPN) | 데이터 존·AI 워커·승인 아웃바운드 | | AI 워커 존 | Redis 큐·나노바나나 워커·Ollama | 내부망(큐 소비만) | 데이터 존(OBJ), Gemini egress 단일 경로만 | | 데이터 존(최내곽) | PostgreSQL+PostGIS·오브젝트 스토리지·BI 읽기 복제 | 내부망·AI 워커(서비스 계정만) | **없음(전면 차단)** | | 관리 존 | 배스천·관측성·백업 | 운영자 VPN/허용 IP | 대상 존 SSH·수집 | - **핵심 규칙**: DMZ → 데이터 존 직접 접근 절대 금지(내부망 백엔드 API 경유). 데이터 존 아웃바운드 없음. ### 8-2. 공개 vs 내부 백오피스 분리 - DMZ: 공개 홍보 사이트(`www.`/`expo.`, SSR·CDN·SEO·다국어·비인증·쓰기 없음), 관람객 앱(`visitor.`·쓰기 제한). - 내부망(인증): `organizer.`·`exhibitor.`·`contractor.`(등록업체 검증). 내부망(운영): `ops.`(IP/VPN 제한). 관리: `admin.`(M18) = VPN/허용 IP allowlist + 2FA 강제 + 감사로그 전량 + 웹 전용. - 공개(DMZ) 3원칙: 쓰기 없음 · 데이터 존 직결 불가 · 캐시/CDN 적극. ### 8-3. 방화벽·LB·TLS·아웃바운드 - 기본 정책 = DROP(default-deny). DB 포트(5432)·Redis·OBJ 인터넷 미노출. DMZ↔내부망은 HTTPS/API만. - WAF: OWASP Top10, 업로드 확장자·MIME·크기 이중 검증, PG 콜백 IP allowlist+서명 검증, admin·옥션 레이트리밋 강화. - LB: 공개 LB(DMZ) / 내부 LB(백엔드, 무상태 JWT 라운드로빈+헬스체크) / WebSocket 스티키. TLS는 LB 종단(HSTS·TLS1.2+), 존 간 mTLS 옵션. - **아웃바운드 게이트(승인 4목적지)**: `api.anthropic.com`(승인, 실패 시 Ollama 폴백)·`generativelanguage.googleapis.com`(G1 미승인, 워커에서만)·PG 결제·SMTP. 그 외 전량 차단. 키 격리=네트워크 격리(Gemini 키=워커 존, Claude/PG 키=백엔드, 데이터 존 무아웃바운드). ### 8-4. 보안 불변(위반 = QA 반려) ① 스택트레이스 미노출(요약만) ② 민감정보(자격증명·PII) 응답 완전 제외 ③ `GEMINI_API_KEY` 백엔드 미취급(M5는 큐 발행까지만) ④ AI 이미지 항상 워터마크·고지 강제 ⑤ admin 비번 env 주입 ⑥ 크로스-테넌트 접근은 플랫폼 슈퍼관리자 전용 API(감사). > 근거: architecture/network.md·app.md, CLAUDE.md 보안 제약. --- ## 9. 비기능 요구사항(NFR) ### 9-1. 성능·용량 - 플로어플랜 3안 생성 수 분 내, 배치·배선 상호작용 P95 < 2s, 부스 목록 P95 < 500ms, 이미지 단건 평균 ~40s(비동기·SLA 대상 아님), 공개 캐시 히트 P95 < 200ms, 옥션 순위 갱신 < 1s. - 대형 행사 3,000~5,000부스(홀당 200~600). **Hikari max = `${DB_POOL_MAX:3}` + PgBouncer 권고**(공유 PG 포화 방지). ### 9-2. 가용성 - 코어 인증·설계·조회 경로 HA SLO 99.5%(성수기 99.9% 지향). 백엔드 무상태 수평 확장(세션·순위·타이머·쿼터·캐시 Redis 외부화), Redis HA(Sentinel/Cluster+AOF), PG 프라이머리+읽기 복제(BI·공개조회 오프로드). ### 9-3. 기술 표준(핀 버전) - 백엔드: Java 17 · Spring Boot 3.2.5 · Gradle · **MyBatis 3.0.3**(JPA 금지, `@MapperScan(annotationClass=Mapper.class)`) · jjwt 0.12.5 · UTF-8 강제. - 프론트: React 18.3.1 · Vite 5.4.8 · TypeScript 5.6.2(strict) · react-router-dom 6 · @tanstack/react-query 5 · zustand 4(Redux 금지). 빌드 `tsc -b && vite build`(타입 에러=빌드 실패). - 워커: Python 3.11+ · google-genai · `gemini-3.1-flash-image-preview`. 실 호출은 `NANOBANANA_LIVE=1`+`GEMINI_API_KEY` 동시 충족 시만(기본 목/degraded). - 데이터: PostgreSQL+PostGIS(`kintex_db`)·Redis·오브젝트 스토리지·Flyway. - 관측성: Actuator+Micrometer 권고(`/actuator/health` 배포 게이트·`/metrics`). 로그 보안 불변(자격증명·IP·PII·스택트레이스 금지, `include-stacktrace:never`). ### 9-4. 접근성·국제화 - WCAG AA 이상, 차트 색 외 패턴/라벨 병기, KPI·표 aria-label, 키보드 포커스 링 `primary-600` 2px, 전 아이콘 선(stroke) SVG(이모지 금지), i18n 키 분리(한/영/중/일 로케일 숫자/통화/날짜 포맷), `prefers-reduced-motion` 준수. > 근거: architecture/system.md·tech.md, design.md 전역 NFR. --- > **후속 산출 명시**: 본 설계서와 개발계획서(`01_개발계획서.md`)는 개발 착수 시점 산출물이다. **사용자지침서·운영자지침서는 UI 정렬 안정화 이후 별도 산출**한다(deliverables 갱신 정책상 완성+QA 통과 후 최신 메뉴를 반영해야 하므로 이번 범위에서 제외).