Compare commits

..

4 Commits

Author SHA1 Message Date
zio
41503f7bb6 docs(audit): GAP_AUDIT re-adjudication 2026-07-14 — code gaps 0 remaining
- G-01~G-09 all verified resolved against live code/endpoints/Flyway V50~V56
- remaining items are roadmap-only: document HWP render, AppQr iOS (EAS G3)
- UNDEVELOPED_BACKLOG: lead AI rescore + CMS AI translation marked shipped

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:06:45 +09:00
zio
1c4edb0cd8 feat(m2): floorplan canvas wheel zoom + left-drag pan (owner directive 07-14)
- non-passive wheel listener zooms 0.3x~4x, synced to page zoom state via
  new onZoomChange prop (wired in BoothLayoutEditorPage)
- pointer-capture left-drag pans the canvas; 3px threshold and click-capture
  suppression so a drag never mis-fires booth select/deselect
- grab/grabbing cursor, transition off while panning, touch-action none

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:06:45 +09:00
zio
3f479a93cb fix(ui): resolve reviewer backlog R13-01, R15-02, R17-01, R17-02 + stale comments
- R13-01: SCR-13 revenue trend now renders AI forecast as dashed area —
  client-side least-squares linear regression, 2-month horizon, bridge point,
  AiLabel + note; skipped gracefully under 3 data points
- R15-02: SCR-15 category default is now visible — categoryDefaulted flag
  renders a '기본값' badge with tooltip instead of silent 'exhibition'
- R17-01: SCR-17 adds §8 system icon library — auto-enumerates icons.tsx
  line-SVG set (namespace import, self-syncing)
- R17-02: CHART.warning renamed CHART.violationWarn (value unchanged),
  ReportPage usage updated
- hygiene: MeetingPage/MultilingualCmsPage header comments updated to reflect
  shipped STT + AI-translation wiring (stale '미배선' removed)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:06:23 +09:00
zio
d548044f34 docs(design): design.md v2.5 — resolve designer backlog B-01, B-04~B-08, B-10
- B-01: SCR-06 assembled-booth mode (signage/furniture/lighting option panels,
  option quote, deadline lock states, dedicated Stitch prompt) + SCR-05 branch
- B-04: screen count re-audit — P0 core 15, total 89 screens (SCR-T0~T3 included)
- B-05: organizer sitemap gains 정산·결제 [M9] entry, SCR-02 IA memo
- B-06: SCR-01 prompt adds email-verification login tertiary button
- B-07: SCR-03 share button in prompt + violation pins aligned 1:1 with summary
- B-08: SCR-04 sales area corrected 4,420 -> 4,590㎡ (510 booths x 9㎡)
- B-10: Phase 2/3 labels on SCR-10/11, SCR-M1/M2; M4a lighting UI review memo

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:06:05 +09:00
18 changed files with 375 additions and 64 deletions

View File

@ -4,16 +4,16 @@
| ID | 심각도 | 내용 | 담당 에이전트 | 상태 | | ID | 심각도 | 내용 | 담당 에이전트 | 상태 |
|---|---|---|---|---| |---|---|---|---|---|
| B-01 | Major | 조립부스 옵션(간판·가구·조명 선택) 신청 UI 부재 — PLANNING M3 Phase 1 범위인데 design.md에 화면 없음. SCR-05/06에 조립부스 모드 추가 필요 | designer | open | | B-01 | Major | 조립부스 옵션(간판·가구·조명 선택) 신청 UI 부재 — PLANNING M3 Phase 1 범위인데 design.md에 화면 없음. SCR-05/06에 조립부스 모드 추가 필요 | designer | **done** (design.md v2.5, 2026-07-14) — SCR-06에 **조립부스 모드** 신설(옵션 패널 3그룹: 간판 문구·서체·색 / 가구 표준 자재 카탈로그 그리드(스테퍼+기본·추가₩ 칩) / 조명 스포트·주간야간, 프리뷰 즉시 갱신·옵션 견적·CTA "옵션 신청 제출"(주최측 시공, 컨펌 미적용)·마감 잠금 등 상태 + 전용 영어 Stitch 프롬프트). SCR-05에 조립부스 분기(헤더·옵션 마감 할 일·장치업체 초대 미노출·모드 진입) 순증 |
| B-02 | Major | S6 배선 오버레이의 시공 검증용 산출은 생성형이 아닌 백엔드 래스터 합성 렌더러로 구현 필요 (client.py에는 주의 주석만 반영됨) | developer | **done** (v1.2) — `render_wiring_overlay_raster()` 신설(로컬 PIL, 좌표 정합, power=적/network=청/plumbing=녹, 트렌치 마커·범례, base_image 합성). 생성형 `generate_wiring_overlay`는 발표 보조용으로 분리 | | B-02 | Major | S6 배선 오버레이의 시공 검증용 산출은 생성형이 아닌 백엔드 래스터 합성 렌더러로 구현 필요 (client.py에는 주의 주석만 반영됨) | developer | **done** (v1.2) — `render_wiring_overlay_raster()` 신설(로컬 PIL, 좌표 정합, power=적/network=청/plumbing=녹, 트렌치 마커·범례, base_image 합성). 생성형 `generate_wiring_overlay`는 발표 보조용으로 분리 |
| B-03 | Major | 나노바나나 입력 스키마를 PLANNING §6-2 정식 스키마(booth polygon, zones, shot preset, render_hints)로 확장 + GeneratedImage에 메타데이터(생성일·스키마 해시·모델 버전) 임베드 | visualizer/developer | **done** (v1.2) — `build_booth_prompt(scene)`가 §6-2 scene(hall/booth/design/lighting/wiring/shot/render_hints) 수용, `GeneratedImage.save()`가 사이드카 `.meta.json`+PNG tEXt 청크로 생성일·스키마 해시(SHA-256)·모델 버전·seed 결정적 임베드 | | B-03 | Major | 나노바나나 입력 스키마를 PLANNING §6-2 정식 스키마(booth polygon, zones, shot preset, render_hints)로 확장 + GeneratedImage에 메타데이터(생성일·스키마 해시·모델 버전) 임베드 | visualizer/developer | **done** (v1.2) — `build_booth_prompt(scene)`가 §6-2 scene(hall/booth/design/lighting/wiring/shot/render_hints) 수용, `GeneratedImage.save()`가 사이드카 `.meta.json`+PNG tEXt 청크로 생성일·스키마 해시(SHA-256)·모델 버전·seed 결정적 임베드 |
| B-04 | Minor | design.md 화면 수 표기(13) → 실제 웹 12+모바일 2=14 정정 | designer | open | | B-04 | Minor | design.md 화면 수 표기(13) → 실제 웹 12+모바일 2=14 정정 | designer | **done** (design.md v2.5, 2026-07-14) — 13→14는 v1.0.1에서 기정정. v2.5에서 현행 기준 재정정: §3 헤더 P0 코어 14→**15개**(SCR-HOME 포함, 웹 13+모바일 2) + §2.8-2 집계의 SCR-T0~T3 누락 정정 85→**총 89화면**(✅Stitch 83·미생성 6) |
| B-05 | Minor | SCR-02 프롬프트 사이드바 "정산" 메뉴 — IA와 불일치 정리 | designer | open | | B-05 | Minor | SCR-02 프롬프트 사이드바 "정산" 메뉴 — IA와 불일치 정리 | designer | **done** (design.md v2.5, 2026-07-14) — v2.0에서 SCR-21 정산·결제(M9)가 정식 화면이 됨에 따라 §2-1 주최자 사이트맵에 "정산·결제 [M9, P1] — Phase 2 (SCR-21)" 추가 + SCR-02에 정합 메모(프롬프트 메뉴 문구 "정산" 유지) |
| B-06 | Minor | SCR-01 이메일 인증 로그인 프롬프트 누락 | designer | open | | B-06 | Minor | SCR-01 이메일 인증 로그인 프롬프트 누락 | designer | **done** (design.md v2.5, 2026-07-14) — Stitch 프롬프트에 tertiary 버튼 "이메일 인증으로 로그인" 추가(스펙↔프롬프트 정합) |
| B-07 | Minor | SCR-03 "공유" 버튼 프롬프트 누락 + 위반 요약(2/3)과 캔버스 핀 샘플(적2·주1) 불일치 | designer | open | | B-07 | Minor | SCR-03 "공유" 버튼 프롬프트 누락 + 위반 요약(2/3)과 캔버스 핀 샘플(적2·주1) 불일치 | designer | **done** (design.md v2.5, 2026-07-14) — 프롬프트 툴바에 "공유" 아이콘 버튼 추가 + 캔버스를 요약(차단2·경고3)에 정렬: 주황 빗금 부스 1→3개(핀 3·4·5), 스펙 레이아웃 ③에 핀 번호·건수 명시로 1:1 고정 |
| B-08 | Minor | SCR-04 샘플 지표 산술 오류(510부스 ↔ 판매면적 4,420㎡) | designer | open | | B-08 | Minor | SCR-04 샘플 지표 산술 오류(510부스 ↔ 판매면적 4,420㎡) | designer | **done** (design.md v2.5, 2026-07-14) — 4,420→**4,590㎡**(510부스×기본 9㎡, SCR-03의 486부스=4,374㎡와 동일 산식) + 산식 기준을 스펙에 명문화 |
| B-09 | Minor | analysis 문서 내 D-15/D-25 표기 혼재 정리 | planner | **done** (v1.1) — kintex-website.md §5 마일스톤을 D-150/D-30/D-25/D-7로 통일(유틸리티=D-25), D-15 오기 제거 | | B-09 | Minor | analysis 문서 내 D-15/D-25 표기 혼재 정리 | planner | **done** (v1.1) — kintex-website.md §5 마일스톤을 D-150/D-30/D-25/D-7로 통일(유틸리티=D-25), D-15 오기 제거 |
| B-10 | Minor | 홀매니저(SCR-10/11)·현장 모바일(SCR-M1/M2) 화면에 Phase 2/3 라벨 부착, 조명 배치안 제안(M4a) 전용 UI 검토 | designer | open | | B-10 | Minor | 홀매니저(SCR-10/11)·현장 모바일(SCR-M1/M2) 화면에 Phase 2/3 라벨 부착, 조명 배치안 제안(M4a) 전용 UI 검토 | designer | **done** (design.md v2.5, 2026-07-14) — SCR-10/11 헤딩·메모에 **Phase 2**(PLANNING §9 홀매니저 대시보드), SCR-M1/M2에 **Phase 3**(현장 모바일 운영 도구) 라벨 부착(화면·구현 선행 확보 명시). 조명 배치안 제안(M4a) 전용 UI는 SCR-06에 검토 메모 신설 — Phase 1은 조명 프리셋+S2 야간 컷으로 흡수, 조도 히트맵·기구 배치 캔버스 전용 SCR은 정밀 조도 시뮬레이션(P2)과 함께 분리 검토(현 시점 신규 화면 없음) |
| B-11 | Major | ReRoomAI 소스 분석(docs/analysis/reroomai-source.md) — 소스 폴더 연결 대기 중. 완료 후 PLANNING §6 ReRoomAI 연계 절 보강 | planner/visualizer | **done** (v1.1) — 소스 분석 완료·PLANNING §6-4/6-5 확정(모델·SDK·구조화 사전·보존/교체 프롬프트 템플릿·RenderJob 방어·UX), §10 R11 해소·R12 추가 | | B-11 | Major | ReRoomAI 소스 분석(docs/analysis/reroomai-source.md) — 소스 폴더 연결 대기 중. 완료 후 PLANNING §6 ReRoomAI 연계 절 보강 | planner/visualizer | **done** (v1.1) — 소스 분석 완료·PLANNING §6-4/6-5 확정(모델·SDK·구조화 사전·보존/교체 프롬프트 템플릿·RenderJob 방어·UX), §10 R11 해소·R12 추가 |
| B-12 | Minor | client.py에 동일 시드/일관성 파라미터(PLANNING §6-3) 지원 검토 (Gemini API 시드 지원 범위 확인 필요) | visualizer | **done** (v1.2) — `render_shot(..., seed=)` 지원. `GenerateContentConfig(seed=)`로 전달 시도하되 SDK/모델 미지원(TypeError)이면 자동으로 참조체인 기반 일관성(첫 컷을 다음 샷 reference_image로 재사용)으로 폴백. SKILL.md에 명시. ★실호출 검증은 소유자 승인 후 | | B-12 | Minor | client.py에 동일 시드/일관성 파라미터(PLANNING §6-3) 지원 검토 (Gemini API 시드 지원 범위 확인 필요) | visualizer | **done** (v1.2) — `render_shot(..., seed=)` 지원. `GenerateContentConfig(seed=)`로 전달 시도하되 SDK/모델 미지원(TypeError)이면 자동으로 참조체인 기반 일관성(첫 컷을 다음 샷 reference_image로 재사용)으로 폴백. SKILL.md에 명시. ★실호출 검증은 소유자 승인 후 |
@ -21,9 +21,9 @@
| ID | 심각도 | 내용 | 담당 | 상태 | | ID | 심각도 | 내용 | 담당 | 상태 |
|---|---|---|---|---| |---|---|---|---|---|
| R13-01 | Minor | SCR-13 추세 차트 "AI 예측 점선 구간"이 스펙·힌트 문구엔 있으나 AreaChart가 점선 예측 구간을 미렌더 — 힌트가 없는 요소를 지칭(오도 소지). 점선 렌더 구현 또는 힌트 정정 | developer(designer 확인) | open | | R13-01 | Minor | SCR-13 추세 차트 "AI 예측 점선 구간"이 스펙·힌트 문구엔 있으나 AreaChart가 점선 예측 구간을 미렌더 — 힌트가 없는 요소를 지칭(오도 소지). 점선 렌더 구현 또는 힌트 정정 | developer(designer 확인) | **done** (2026-07-14) — 매출 시리즈에 클라이언트 최소제곱 선형회귀(`buildTrendForecast`, overview 엔드포인트와 동일 기법) 적용, 향후 2개월을 `revenueForecast` 점선 Area(strokeDasharray "5 4", ai-accent, 마지막 실측점 브릿지)로 렌더. AiLabel "AI 수요예측" + 안내 노트 노출. 점 3개 미만이면 예측 생략(graceful). 힌트 정정 아닌 실렌더로 해소 |
| R15-01 | Minor | SCR-15 홀 셀렉트가 필터 로직에 미배선(선택 무효과) | developer | **done** (2026-07-11) — `matchesHall()` 배선("홀" 뒤 번호만 파싱, "제N전시장" N 오매칭 방지), tsc 재통과 | | R15-01 | Minor | SCR-15 홀 셀렉트가 필터 로직에 미배선(선택 무효과) | developer | **done** (2026-07-11) — `matchesHall()` 배선("홀" 뒤 번호만 파싱, "제N전시장" N 오매칭 방지), tsc 재통과 |
| R15-02 | Minor | SCR-15 실 워크스페이스 모드에서 category를 'exhibition' 하드코딩 — 샘플/기본값 시각 표기 없음(estVisitors는 "집계 대기" 표기됨) | developer | open | | R15-02 | Minor | SCR-15 실 워크스페이스 모드에서 category를 'exhibition' 하드코딩 — 샘플/기본값 시각 표기 없음(estVisitors는 "집계 대기" 표기됨) | developer | **done** (2026-07-14) — 실 category는 known 값이면 그대로 사용, 미지정/미지값만 'exhibition'으로 대체하고 `categoryDefaulted` 플래그로 카드에 "기본값" 배지(title 툴팁 안내) 표기. `ScheduleEvent.categoryDefaulted` 추가, i18n은 defaultValue 인라인 |
| R17-01 | Minor | SCR-17 스타일가이드에 "시스템 아이콘 라이브러리" 섹션 누락(스펙 9항목 중 1) — 아이콘 세트 교체(UNDEVELOPED_BACKLOG §1)와 함께 처리 권장 | developer(designer) | open | | R17-01 | Minor | SCR-17 스타일가이드에 "시스템 아이콘 라이브러리" 섹션 누락(스펙 9항목 중 1) — 아이콘 세트 교체(UNDEVELOPED_BACKLOG §1)와 함께 처리 권장 | developer(designer) | **done** (2026-07-14) — ComponentGuidePage §8 "시스템 아이콘 라이브러리" 추가. `icons.tsx` 네임스페이스 import 로 기존 선 SVG 세트(56종) 자동 열거·그리드 나열(신규 아이콘 제작 아님). 아이콘 추가/제거 시 자동 동기화 |
| R17-02 | Minor | `chartColors.ts``CHART.warning` 키가 §1-2 warning(#B45309)이 아닌 §1-4 violation-warn(#F79009) 값 — 값은 토큰 정합, 키 이름만 오용 위험 → `violationWarn` 등으로 개명 권장 | developer | open | | R17-02 | Minor | `chartColors.ts``CHART.warning` 키가 §1-2 warning(#B45309)이 아닌 §1-4 violation-warn(#F79009) 값 — 값은 토큰 정합, 키 이름만 오용 위험 → `violationWarn` 등으로 개명 권장 | developer | **done** (2026-07-14) — `CHART.warning``CHART.violationWarn` 개명(값 #F79009 불변), 사용처 `ReportPage.tsx:35` 갱신. `occupancyTone`의 'warning' 반환은 시맨틱 톤 라벨(별개)이라 무영향 |
| R00-01 | 정보 | AppShell 단일 셸에 전 역할 네비 무차별 노출 — 역할별 포털+MDI 분리는 미착수 대형 트랙으로 기추적(UNDEVELOPED_BACKLOG §1·§4) | FE·DES | tracked | | R00-01 | 정보 | AppShell 단일 셸에 전 역할 네비 무차별 노출 — 역할별 포털+MDI 분리는 미착수 대형 트랙으로 기추적(UNDEVELOPED_BACKLOG §1·§4) | FE·DES | tracked |

View File

@ -8,14 +8,16 @@
## ① 요약 ## ① 요약
| 구분 | 건수 | | 구분 | 건수(최초 감사 2026-07-12) | 재판정(2026-07-14) |
|------|------| |------|------|------|
| **미개발 총계(코드)** | **9건** | | **미개발 총계(코드)** | **9건** | **0건**(전량 해소) |
| P0 (핵심 흐름 차단) | 0 | | P0 (핵심 흐름 차단) | 0 | 0 |
| P1 (주요 화면 미배선/백엔드 전무) | 2 | | P1 (주요 화면 미배선/백엔드 전무) | 2 | 0 (G-01·G-02 해소, 2026-07-13) |
| P2 (부분·degraded·planned) | 7 | | P2 (부분·degraded·planned) | 7 | 0 (G-03~G-09 전량 해소, 2026-07-13~14) |
| 데이터 이슈(별도, 코드 정상) | 행사스코프 시드 정렬 계열(전수 아님) | | 데이터 이슈(별도, 코드 정상) | 행사스코프 시드 정렬 계열(전수 아님) | 동일 |
| 문서 위생(별도, 미개발 아님) | 4 (stale "미구현" 주석) | | 문서 위생(별도, 미개발 아님) | 4 (stale "미구현" 주석) | 해소 + MeetingPage 헤더 주석 1건 추가 정정(2026-07-14) |
> **재판정 총평(2026-07-14):** 최초 감사의 P1 2건은 2026-07-13에, P2 7건(G-03~G-09)은 이후 세션에서 전량 실구현으로 해소됨을 코드/엔드포인트/Flyway(V50~V56) 기준으로 재확인했다. **현재 GAP_AUDIT 상 코드 미개발 잔여는 0건.** 진짜 잔여는 (a) 서류 **HWP** 렌더(G-05 후속, 명시적 스코프 밖), (b) AppQr **iOS**(EAS G3 게이트, 계획됨) — 둘 다 로드맵성 항목이며 "미개발 결함"이 아니다.
**총평:** 앱 완성도는 매우 높다. 데드 메뉴 0, 빈 onClick/데드링크 0, 최상위 `return null` 라우트 0. 도메인 백엔드(auction·visitor·cms·marketing·logistics·settlement·hallassign·boothsales)는 전부 실구현. **가장 중요한 발견은 "미개발이 많다"가 아니라 "프론트 `sample` 헤더 주석이 Phase D 백엔드 배포 이후 갱신되지 않아 STALE 하다"는 점** — 실제 미개발은 아래 2건(P1)뿐이며 나머지는 graceful degraded/planned. **총평:** 앱 완성도는 매우 높다. 데드 메뉴 0, 빈 onClick/데드링크 0, 최상위 `return null` 라우트 0. 도메인 백엔드(auction·visitor·cms·marketing·logistics·settlement·hallassign·boothsales)는 전부 실구현. **가장 중요한 발견은 "미개발이 많다"가 아니라 "프론트 `sample` 헤더 주석이 Phase D 백엔드 배포 이후 갱신되지 않아 STALE 하다"는 점** — 실제 미개발은 아래 2건(P1)뿐이며 나머지는 graceful degraded/planned.
@ -64,16 +66,17 @@
| ID | 항목 | 근거(파일:라인) | 유형 | 비고 | | ID | 항목 | 근거(파일:라인) | 유형 | 비고 |
|----|------|-----------------|------|------| |----|------|-----------------|------|------|
| G-03 | CMS AI 자동번역 | `cms/MultilingualCmsPage.tsx:127` · `cmsApi.ts:150` | 백엔드 501 → degraded "준비 중" | 초벌 번역 AI 미배선 | | ~~G-03~~ ✅ | CMS AI 자동번역 | `cms/CmsService.aiTranslate` · `cmsApi.ts:aiTranslate` | 실배선 완료(2026-07-13) — POST `/api/cms/contents/{id}/translations/ai?lang=` (AiTextRouter Claude→Ollama 폴백) | 초벌 번역 ko→en/zh/ja 실동작, degraded 정직 폴백 |
| G-04 | 마케팅 캠페인 실발송 | `marketing/MarketingController.java:49` | send 엔드포인트 존재하나 실 이메일 발송 미구현(status 전이만) | SMTP 연동 후속 | | ~~G-04~~ ✅ | 마케팅 캠페인 실발송 | `marketing/MarketingService.sendCampaign` · `mail/MailService`·`MailProperties` | 실배선 완료 — **운영 실발송 검증(2026-07-14)** | `sendCampaign`이 SMTP(MailService) 실디스패치 — cap/rate/testMode/live 강제, 수신동의+unsub 토큰, V53 `marketing_consent_send_history`, mail_log 정본(비동기 성공/실패). 힌트 "status 전이만"은 STALE |
| G-05 | 서류 HWP/PDF 생성 | `docs/ReportAuthoringPage.tsx:476-479` · `docs/DocsMilestonePage.tsx:34` | 버튼 `disabled` "준비중" | 파일 큐 연동 후속 | | ~~G-05~~ ✅ | 서류 PDF 생성 | `document/DocumentController.java:83` · `DocumentPdfService` | 실배선 완료(2026-07-13) — POST `/documents/{docType}/pdf`(생성·저장·다운로드 메타) | 안전관리 계획서 PDF 실동작. **HWP** 렌더만 스코프 밖(후속·엔드포인트 미노출) |
| G-06 | 회의 녹음/STT 전사 | `work/MeetingPage.tsx:161` | "준비 중" 표기 | 녹음·STT AI 미배선 | | ~~G-06~~ ✅ | 회의 녹음/STT 전사 | `work/MeetingPage.tsx:174`(MeetingAiPanel) · `work/meeting/MeetingSttClient`·`MeetingMinutesGenerator` | 실배선 완료 — 업로드→STT→AI 회의록 자동작성, V52 `meeting_transcript` | 헤더 주석(구 `:5`) 정정(2026-07-14). Jasper PDF만 후속 |
| G-07 | 통합검색 자연어(AI) | `work/SearchPage.tsx:132,144` | "준비 중", 키워드 검색은 동작 | AI 검색 미배선 | | ~~G-07~~ ✅ | 통합검색 자연어(AI) | `work/search/SearchController.java:36`(POST `/api/work/search/ai`) · `SearchAiService` | 실배선 완료 — 자연어 AI 검색 + 키워드 검색 병존 | AiTextRouter 경유 |
| G-08 | 마이페이지 프로필 수정·알림 서버동기화 | `work/MyPage.tsx:127,192` | "준비 중"(로컬 저장) | 프로필 PUT·알림설정 API 미배선 | | ~~G-08~~ ✅ | 마이페이지 프로필·알림 서버동기화 | `auth/AccountSettingsController.java`(PUT `/api/auth/me` · GET·PUT `/notification-prefs`) · V55 `user_notification_pref`·`NotificationPrefMapper` | 실배선 완료(2026-07-13~14) — 프로필 PUT + 알림설정 멱등 저장 | 로컬 저장→서버 동기화 전환 |
| G-09 | 부스설계 렌더 이력 저장 | `design/BoothDesignStudioPage.tsx:135` | 501 → "큐잉만 동작" | 렌더 이력 영속 후속 | | ~~G-09~~ ✅ | 부스설계 렌더 이력 저장 | `module/m5/RenderJobController.java:60`(GET `/booths/{boothId}/render-history`) · V54 `render_history_index` · `renderHistoryApi.list` | 실배선 완료 — DONE 렌더 최신순 영속 이력 갤러리 | 초기 spec 501 폴백은 이력이 아닌 "기본 스펙 시연"용(정상) |
### 계획됨(미개발 아님) ### 계획됨(미개발 아님) — 로드맵 잔여
- AppQr **iOS**`appqr/AppQrCodePage.tsx`: Android APK 배포, iOS는 EAS G3 게이트 명시적 로드맵. - **서류 HWP 렌더**(G-05 후속) — PDF는 실동작, HWP 포맷 렌더만 명시적 스코프 밖.
- **AppQr iOS**`appqr/AppQrCodePage.tsx`: Android APK 배포, iOS는 EAS G3 게이트 명시적 로드맵.
--- ---
@ -88,6 +91,7 @@
- ~~`screens/marketing/sampleMarketing.ts:3` "M12 백엔드 미구현"~~ → 실구현 반영 주석 갱신(G-04 실발송 후속 명시) - ~~`screens/marketing/sampleMarketing.ts:3` "M12 백엔드 미구현"~~ → 실구현 반영 주석 갱신(G-04 실발송 후속 명시)
- ~~`screens/cms/cms.css:4` "M17 백엔드 미구현 → 전 화면 로컬 샘플"~~ → cmsApi 실배선 반영 주석 갱신 - ~~`screens/cms/cms.css:4` "M17 백엔드 미구현 → 전 화면 로컬 샘플"~~ → cmsApi 실배선 반영 주석 갱신
→ 4건 모두 "실구현 완료 + 샘플은 강등 폴백" 문구로 정정. 재감사 오탐 방지. → 4건 모두 "실구현 완료 + 샘플은 강등 폴백" 문구로 정정. 재감사 오탐 방지.
- ~~`screens/work/MeetingPage.tsx:5` "녹음·STT·AI 요약·Jasper PDF 엔드포인트 부재 → disabled+툴팁"~~**STT·AI 회의록 실배선(G-06) 반영 주석 갱신(2026-07-14)**. Jasper PDF만 후속으로 명시.
--- ---
@ -97,13 +101,16 @@
|------|-----|------|------| |------|-----|------|------|
| 1 | ~~G-01~~ ✅ | TenantAdminPage → `/api/admin/tenants` GET/POST 배선(하드코딩·disabled 제거) — 2026-07-13 해소 | **kintex-frontend-dev** | | 1 | ~~G-01~~ ✅ | TenantAdminPage → `/api/admin/tenants` GET/POST 배선(하드코딩·disabled 제거) — 2026-07-13 해소 | **kintex-frontend-dev** |
| 2 | ~~G-02~~ ✅ | 티켓 도메인 백엔드(티켓·재고·예매·조회) + PG 어댑터 + 프론트 배선 — 2026-07-13 해소 | **kintex-backend-dev**(+visitor-dev) → frontend-dev | | 2 | ~~G-02~~ ✅ | 티켓 도메인 백엔드(티켓·재고·예매·조회) + PG 어댑터 + 프론트 배선 — 2026-07-13 해소 | **kintex-backend-dev**(+visitor-dev) → frontend-dev |
| 3 | G-04 | 캠페인 실발송(SMTP, 수신동의·상한) | kintex-backend-dev(marketing) | | 3 | ~~G-04~~ ✅ | 캠페인 실발송(SMTP, 수신동의·상한) — 운영 실발송 검증 2026-07-14 | kintex-backend-dev(marketing) |
| 4 | G-03 | CMS AI 자동번역 배선(AiTextRouter) | kintex-ai-dev | | 4 | ~~G-03~~ ✅ | CMS AI 자동번역 배선(AiTextRouter) — 2026-07-13 해소 | kintex-ai-dev |
| 5 | G-06/G-07 | 회의 STT·통합검색 자연어 AI | kintex-ai-dev | | 5 | ~~G-06/G-07~~ ✅ | 회의 STT·통합검색 자연어 AI — MeetingAiPanel·SearchAiService 실배선 | kintex-ai-dev |
| 6 | G-05/G-09 | 서류 HWP/PDF 생성·렌더 이력 영속(파일/렌더 큐) | kintex-backend-dev | | 6 | ~~G-05/G-09~~ ✅ | 서류 PDF 생성·렌더 이력 영속 — DocumentPdfService·render-history(V54). HWP만 후속 | kintex-backend-dev |
| 7 | G-08 | 마이페이지 프로필 PUT·알림설정 API | kintex-backend-dev + frontend-dev | | 7 | ~~G-08~~ ✅ | 마이페이지 프로필 PUT·알림설정 API — AccountSettingsController·V55 | kintex-backend-dev + frontend-dev |
| 8 | ~~(위생)~~ ✅ | STALE "미구현" 주석 4건 정리 — 2026-07-13 해소 | kintex-frontend-dev | | 8 | ~~(위생)~~ ✅ | STALE "미구현" 주석 정리(4건 + MeetingPage 헤더 2026-07-14) | kintex-frontend-dev |
| — | (데이터) | 행사스코프 시드 정렬(빈 화면 폴백 해소) | kintex-testdata-dev | | — | (데이터) | 행사스코프 시드 정렬(빈 화면 폴백 해소) | kintex-testdata-dev |
| — | (로드맵) | 서류 HWP 렌더 · AppQr iOS(EAS G3) — 미개발 결함 아님 | 후속 |
> **재판정 결론(2026-07-14):** ⑤ 백로그의 코드 수정 항목(G-01~G-09) **전량 ✅해소**. 남은 것은 데이터 시드 정렬(별도 트랙)과 로드맵성 2건(HWP·iOS)뿐. **GAP_AUDIT 상 코드 미개발 잔여 0.**
--- ---
*P0/P1 지적은 kintex-qa가 실동작(라우트 렌더·경계면)으로 재검증 후 kintex-impl-orchestrator로 인계.* *P0/P1 지적은 kintex-qa가 실동작(라우트 렌더·경계면)으로 재검증 후 kintex-impl-orchestrator로 인계.*

View File

@ -31,8 +31,8 @@
|---|---|---|---| |---|---|---|---|
| ✅ | M6/M8 백엔드 | **완료(2026-07-12, V14/V15)** — impl_m6m8.md 참조 | 완료 | | ✅ | M6/M8 백엔드 | **완료(2026-07-12, V14/V15)** — impl_m6m8.md 참조 | 완료 |
| 🔶 | M15 옥션 백엔드 | **개설·봉인 응찰·낙찰·수주 대시보드 완료(V16 + 2차 웨이브 스코어링)**. 잔여: WebSocket 실시간 순위(현 폴링) | D-M15 | | 🔶 | M15 옥션 백엔드 | **개설·봉인 응찰·낙찰·수주 대시보드 완료(V16 + 2차 웨이브 스코어링)**. 잔여: WebSocket 실시간 순위(현 폴링) | D-M15 |
| 🔶 | M10/M12 백엔드 | **사전등록·리드·체크인·배지·CSV·캠페인·스폰서십 완료(V17/V18/V21)**. 잔여: EDM 실 발송 게이트웨이·리드 AI 재계산(AiTextRouter) | D-M10/12 | | 🔶 | M10/M12 백엔드 | **사전등록·리드·체크인·배지·CSV·캠페인·스폰서십 완료(V17/V18/V21)** + **리드 AI 재계산(AiTextRouter, 비-PII·규칙 폴백) 실배선 완료(2026-07-13)**. 잔여: EDM 실 발송 게이트웨이 | D-M10/12 |
| 🔶 | M17 CMS 백엔드 | **콘텐츠·전이·번역·마이크로사이트·버전·미디어·공개API 완료(V19 + 2차 웨이브)**. 잔여: AI 자동번역 배선·예약게시 Redis 트리거 | D-M17 | | 🔶 | M17 CMS 백엔드 | **콘텐츠·전이·번역·마이크로사이트·버전·미디어·공개API 완료(V19 + 2차 웨이브)** + **AI 자동번역(AiTextRouter Claude→Ollama 폴백) 실배선 완료(2026-07-13)**. 잔여: 예약게시 Redis 트리거 | D-M17 |
| ✅ | 공개 카탈로그 API | **완료(2026-07-12, V20 public_site)** — /api/public/events 등 라이브 검증 | 완료 | | ✅ | 공개 카탈로그 API | **완료(2026-07-12, V20 public_site)** — /api/public/events 등 라이브 검증 | 완료 |
| ✅ | 프론트 admin RBAC 가드 | **완료(2026-07-12)** — AdminGuard + 전 /admin/* 라우트 배선(hallManager 기준·백엔드가 최종 권위) | 완료 | | ✅ | 프론트 admin RBAC 가드 | **완료(2026-07-12)** — AdminGuard + 전 /admin/* 라우트 배선(hallManager 기준·백엔드가 최종 권위) | 완료 |
| ✅ | QA minor 2 | **완료(2026-07-12)** — kx-field 스코프 격리·★ SVG는 기왕 해소, ✓(OrganizerDashboardPage) IconCheck 교체 | 완료 | | ✅ | QA minor 2 | **완료(2026-07-12)** — kx-field 스코프 격리·★ SVG는 기왕 해소, ✓(OrganizerDashboardPage) IconCheck 교체 | 완료 |

View File

@ -1,6 +1,6 @@
# 킨텍스 AI 전시관리 시스템 — UI 디자인 스펙 (design.md) # 킨텍스 AI 전시관리 시스템 — UI 디자인 스펙 (design.md)
> 작성: 디자인 에이전트(designer) · 작성일: 2026-07-12 · 버전: **v2.4** > 작성: 디자인 에이전트(designer) · 작성일: 2026-07-14 · 버전: **v2.5**
> 근거 문서: `docs/PLANNING.md` **v3.0**(모듈 맵 M1~M18 + §5B 공통/시스템관리 레이어 + §1A 멀티테넌시, 6+2 역할, 나노바나나 표준 샷 세트 S1~S7) · `docs/FEATURE_BACKLOG_100.md`(100대 기능 F001~F100·NFR 4축) · Stitch 산출물 `stitch_kintex_ai_system_architect/`(18화면 + DESIGN.md 3변형) 학습·정합 > 근거 문서: `docs/PLANNING.md` **v3.0**(모듈 맵 M1~M18 + §5B 공통/시스템관리 레이어 + §1A 멀티테넌시, 6+2 역할, 나노바나나 표준 샷 세트 S1~S7) · `docs/FEATURE_BACKLOG_100.md`(100대 기능 F001~F100·NFR 4축) · Stitch 산출물 `stitch_kintex_ai_system_architect/`(18화면 + DESIGN.md 3변형) 학습·정합
> **단일 출처(Single Source of Truth)**: 프론트 구현 토큰·컴포넌트 계약은 본 문서가 권위다. Stitch 화면(code.html/screen.png)은 시각 참조로만 사용하며, 상충 시 본 문서를 따른다. > **단일 출처(Single Source of Truth)**: 프론트 구현 토큰·컴포넌트 계약은 본 문서가 권위다. Stitch 화면(code.html/screen.png)은 시각 참조로만 사용하며, 상충 시 본 문서를 따른다.
> 용도: **각 화면의 "Stitch 프롬프트" 코드블록을 Google Stitch(stitch.withgoogle.com)에 그대로 붙여넣어 화면을 생성**한다. 문서는 한국어, Stitch 프롬프트만 영어. > 용도: **각 화면의 "Stitch 프롬프트" 코드블록을 Google Stitch(stitch.withgoogle.com)에 그대로 붙여넣어 화면을 생성**한다. 문서는 한국어, Stitch 프롬프트만 영어.
@ -92,7 +92,8 @@
│ └─ 배치안 비교 (S7 조감) (SCR-04) │ └─ 배치안 비교 (S7 조감) (SCR-04)
├─ 참가업체 관리 (초대 링크·신청 현황) — SCR-02 내 탭 ├─ 참가업체 관리 (초대 링크·신청 현황) — SCR-02 내 탭
├─ 서류·마일스톤 [M6, P1] — Phase 2 ├─ 서류·마일스톤 [M6, P1] — Phase 2
└─ 홀 배정·견적 [M1, P1] — Phase 2 ├─ 홀 배정·견적 [M1, P1] — Phase 2
└─ 정산·결제 [M9, P1] — Phase 2 (SCR-21) ※ SCR-02 사이드바 "정산" 메뉴와 정합 (v2.5 B-05)
참가업체 (Exhibitor) 참가업체 (Exhibitor)
├─ 내 부스 홈 — 진행 상태·마감 리마인더 (SCR-05) ├─ 내 부스 홈 — 진행 상태·마감 리마인더 (SCR-05)
@ -442,13 +443,13 @@ An enterprise MDI (multiple document interface) application shell for "KINTEX AI
| SCR-M14 | 모바일 티켓 예매 | M10·M9 | 대 | ✅Stitch | | SCR-M14 | 모바일 티켓 예매 | M10·M9 | 대 | ✅Stitch |
| SCR-M15 | 내 티켓 지갑 | M10·M9 | 대 | ✅Stitch | | SCR-M15 | 내 티켓 지갑 | M10·M9 | 대 | ✅Stitch |
**집계**: 웹 코어·도메인 52 (기존 17 + 신규 34 + **SCR-HOME 신규 1**) · 관리자 10 (신규) · 공개사이트 8 (기존 6 + 신규 2 티켓) · 모바일 15 (기존 3 + 신규 12) = **총 85화면**(기존 유지 20 + 신규 65). 상태: ✅Stitch 83 · ✅구현 20 · 🔲미생성 2 (SCR-HOME 신규 정의(Stitch 착수 전) + SCR-M3(✅구현(부분))). 2026-07-12 수확으로 SCR-HOME을 제외한 신규 화면은 전량 Stitch 확보됨. **집계(v2.5 정정 — B-04)**: 웹 코어·도메인 52 (기존 17 + 신규 34 + **SCR-HOME 신규 1**) · 관리자 10 (신규) · 공개사이트 8 (기존 6 + 신규 2 티켓) · **3-트랙 관문·서브홈 4 (SCR-T0~T3 — v2.2 신설, 이전 집계 문장에 누락되어 있던 것을 정정)** · 모바일 15 (기존 3 + 신규 12) = **총 89화면**. 상태: ✅Stitch 83 · ✅구현 20 · 🔲미생성 6 (SCR-HOME + SCR-T0~T3 4화면 + SCR-M3(✅구현(부분)·Stitch 미확보)). 2026-07-12 수확으로 위 6화면을 제외한 화면은 전량 Stitch 확보됨.
--- ---
## 3. 화면별 스펙 ## 3. 화면별 스펙
> P0 모듈(M2·M3·M4·M5) 중심 총 14개 화면(웹 12 + 모바일 2) + **v2.0 확장 SCR-13~17(경영분석 M16·홀운영 M14·전시일정 M1·M6·관리자 M18·컴포넌트 가이드)** + **v2.0 도메인 확장 SCR-18~51(M1·M6·M7·M8·M9·M15·M10·M12·M17·§5B 공통레이어)** + 관리자 §3A·공개사이트 §3B·모바일 §4. 각 Stitch 프롬프트는 화면 1개를 1회 생성하는 기준으로 작성했다. **디자인 토큰은 전부 §1을 따르고 신규 토큰은 추가하지 않는다.** > P0 코어 총 15개 화면(웹 13 = SCR-01·SCR-HOME·SCR-02~12, 모바일 2 = SCR-M1·M2 — v2.5 B-04 정정: SCR-HOME(v2.1.2 신설) 포함 재집계) + **v2.0 확장 SCR-13~17(경영분석 M16·홀운영 M14·전시일정 M1·M6·관리자 M18·컴포넌트 가이드)** + **v2.0 도메인 확장 SCR-18~51(M1·M6·M7·M8·M9·M15·M10·M12·M17·§5B 공통레이어)** + 관리자 §3A·공개사이트 §3B·3-트랙 §3C·모바일 §4. 전 화면 집계는 **§2.8-2(총 89화면)**를 권위로 한다. 각 Stitch 프롬프트는 화면 1개를 1회 생성하는 기준으로 작성했다. **디자인 토큰은 전부 §1을 따르고 신규 토큰은 추가하지 않는다.**
--- ---
@ -463,7 +464,7 @@ An enterprise MDI (multiple document interface) application shell for "KINTEX AI
- **Stitch 프롬프트**: - **Stitch 프롬프트**:
``` ```
A B2B SaaS login page for "KINTEX AI 전시관리", a Korean exhibition management platform. Desktop web, 1440px, light theme. All UI text in Korean. Split layout: left 55% is a brand panel with a photorealistic AI-rendered exhibition booth photo as background, dark blue gradient overlay (#004C86), large white headline "신청서를 내는 순간, 시공 후 사진을 먼저 봅니다" and a small caption "AI 생성 예상 이미지". Right 45% is a white card on #F9FAFB background: KINTEX wordmark logo in blue #0066B3, title "로그인", email and password inputs with Korean labels "이메일", "비밀번호", a primary blue #0066B3 button "로그인", divider, and a secondary outlined button "킨텍스 내부 계정으로 로그인". Below the card, small text link "초대 코드로 참여하기". Font is a clean Korean sans-serif (Pretendard style). Professional, trustworthy, enterprise tone. A B2B SaaS login page for "KINTEX AI 전시관리", a Korean exhibition management platform. Desktop web, 1440px, light theme. All UI text in Korean. Split layout: left 55% is a brand panel with a photorealistic AI-rendered exhibition booth photo as background, dark blue gradient overlay (#004C86), large white headline "신청서를 내는 순간, 시공 후 사진을 먼저 봅니다" and a small caption "AI 생성 예상 이미지". Right 45% is a white card on #F9FAFB background: KINTEX wordmark logo in blue #0066B3, title "로그인", email and password inputs with Korean labels "이메일", "비밀번호", a primary blue #0066B3 button "로그인", a tertiary text button "이메일 인증으로 로그인" right below it, divider, and a secondary outlined button "킨텍스 내부 계정으로 로그인". Below the card, small text link "초대 코드로 참여하기". Font is a clean Korean sans-serif (Pretendard style). Professional, trustworthy, enterprise tone.
``` ```
--- ---
@ -511,6 +512,7 @@ A post-login landing home dashboard for "KINTEX AI 전시관리", a Korean B2B e
### SCR-02 주최자 대시보드 (히어로: D-데이 마일스톤 타임라인) ### SCR-02 주최자 대시보드 (히어로: D-데이 마일스톤 타임라인)
- **대상**: 주최자 · **진입 경로**: 로그인 → 행사 선택 (주최자 기본 홈) - **대상**: 주최자 · **진입 경로**: 로그인 → 행사 선택 (주최자 기본 홈)
- **IA 정합 메모(v2.5 — B-05 해소)**: Stitch 프롬프트의 사이드바 메뉴 "정산"은 v2.0에서 정식 화면이 된 **SCR-21 정산·결제 대시보드(M9 · Phase 2)** 진입 메뉴다. §2-1 주최자 사이트맵에 "정산·결제 [M9]"를 추가해 IA↔프롬프트 불일치를 해소했다(메뉴 표기 문구는 "정산" 유지).
- **레이아웃**: - **레이아웃**:
1. 상단 행사 헤더: 행사명 "2026 스마트팩토리 코리아", 기간·홀(홀7), 대형 카운트다운 "개장까지 D-31" 1. 상단 행사 헤더: 행사명 "2026 스마트팩토리 코리아", 기간·홀(홀7), 대형 카운트다운 "개장까지 D-31"
2. **히어로 — 마일스톤 타임라인 (가로 전폭)**: D-150 홀 배정 → D-30 사전업무협의 → D-25 유틸리티 신청 마감 → D-7 신고서류 제출 → D-0 개장. 완료 노드는 녹색 체크, 현재 구간은 파란 진행 바, 임박 노드는 주황 펄스. 각 노드 아래 카드에 잔여 항목 수("신고서류 3/7 완료") 2. **히어로 — 마일스톤 타임라인 (가로 전폭)**: D-150 홀 배정 → D-30 사전업무협의 → D-25 유틸리티 신청 마감 → D-7 신고서류 제출 → D-0 개장. 완료 노드는 녹색 체크, 현재 구간은 파란 진행 바, 임박 노드는 주황 펄스. 각 노드 아래 카드에 잔여 항목 수("신고서류 3/7 완료")
@ -531,14 +533,14 @@ An enterprise dashboard for an exhibition organizer, part of "KINTEX AI 전시
- **레이아웃**: - **레이아웃**:
1. 상단 툴바: 배치안 버전 드롭다운("배치안 B v3"), 저장 상태, **보라색 AI 버튼 "AI 자동배치"**, "규정 검증 실행", "홀 전경 생성(S7)", 공유 1. 상단 툴바: 배치안 버전 드롭다운("배치안 B v3"), 저장 상태, **보라색 AI 버튼 "AI 자동배치"**, "규정 검증 실행", "홀 전경 생성(S7)", 공유
2. 좌측 도구 패널(240px): 부스 팔레트(기본 3×3m / 프리미엄 6×3m / 아일랜드), 시설 요소(무대·라운지·주출입구), 레이어 토글(트렌치 그리드 / 기둥·셔터·비상구 / 위반 오버레이) 2. 좌측 도구 패널(240px): 부스 팔레트(기본 3×3m / 프리미엄 6×3m / 아일랜드), 시설 요소(무대·라운지·주출입구), 레이어 토글(트렌치 그리드 / 기둥·셔터·비상구 / 위반 오버레이)
3. **중앙 캔버스(다크 `#1C2536`)**: 홀7 도면(126×90m, 축척 표시) 위 부스 폴리곤 드래그앤드롭. 부스는 파란 채움+부스번호, 선택 시 핸들. 트렌치 그리드는 점선, 비상구는 녹색 아이콘. **위반 오버레이**: 통로 폭 미달 구간 빨간 반투명 밴드 + 번호 핀, 바닥하중 초과 부스 주황 빗금 3. **중앙 캔버스(다크 `#1C2536`)**: 홀7 도면(126×90m, 축척 표시) 위 부스 폴리곤 드래그앤드롭. 부스는 파란 채움+부스번호, 선택 시 핸들. 트렌치 그리드는 점선, 비상구는 녹색 아이콘. **위반 오버레이**: 통로 폭 미달 구간 빨간 반투명 밴드 + 번호 핀(차단 2건 — 핀 1·2), 바닥하중 초과 부스 주황 빗금(경고 3건 — 핀 3·4·5) — 우측 [검증] 탭 요약 "차단 2 · 경고 3"과 핀이 1:1 일치(v2.5 B-07 정정)
4. 우측 패널(360px) 탭 2개: [속성] 선택 부스 좌표·크기·타입·배정 업체 / [검증] 위반 목록 카드(핀 번호, 규정 근거 "피난 통로 3m 미만", 심각도, "위치 보기") + 요약 "차단 2 · 경고 3" 4. 우측 패널(360px) 탭 2개: [속성] 선택 부스 좌표·크기·타입·배정 업체 / [검증] 위반 목록 카드(핀 번호, 규정 근거 "피난 통로 3m 미만", 심각도, "위치 보기") + 요약 "차단 2 · 경고 3"
5. 하단 상태 바: 부스 수 486/510 · 판매 면적 · 줌 컨트롤 5. 하단 상태 바: 부스 수 486/510 · 판매 면적 · 줌 컨트롤
- **상태**: AI 자동배치 실행 중 — 캔버스 위 진행 오버레이("제약조건 풀이 중… 복수 안 생성") · 검증 통과 시 녹색 배너 "위반 0건 — 제출 가능" · 빈 캔버스 — "조건을 입력하고 AI 자동배치로 시작하세요" CTA. - **상태**: AI 자동배치 실행 중 — 캔버스 위 진행 오버레이("제약조건 풀이 중… 복수 안 생성") · 검증 통과 시 녹색 배너 "위반 0건 — 제출 가능" · 빈 캔버스 — "조건을 입력하고 AI 자동배치로 시작하세요" CTA.
- **Stitch 프롬프트**: - **Stitch 프롬프트**:
``` ```
A professional floor plan editor screen for exhibition booth layout, in a Korean B2B web app "KINTEX AI 전시관리". Desktop 1440px. All UI text in Korean. Three-column editor layout. Top toolbar: version dropdown "배치안 B · v3", autosave label "저장됨", a distinctive purple #6D4AFF button with sparkle icon "AI 자동배치", outlined buttons "규정 검증 실행" and "홀 전경 생성". Left tool panel 240px on white: booth palette items with small square previews ("기본 부스 3×3m", "프리미엄 6×3m", "아일랜드 부스"), facility items ("무대", "라운지", "주출입구"), and layer toggles with switches ("트렌치 그리드", "기둥·비상구", "위반 오버레이" turned on). Center: large dark navy canvas #1C2536 showing a top-down exhibition hall floor plan (hall outline 126×90m with scale ruler), dozens of small blue booth rectangles arranged in rows with white booth numbers like "A-101", dashed grid lines for floor trenches, green emergency-exit icons on walls; overlay violations: two semi-transparent red bands across an aisle with numbered red pins "1", "2", and one booth hatched in orange with pin "3". Right panel 360px with two tabs "속성 | 검증", showing the 검증 tab: summary chips "차단 2 · 경고 3", a list of violation cards each with pin number, red or orange severity dot, Korean text like "피난 통로 폭 3m 미만 (규정 §4.2)" and a small link "위치 보기". Bottom status bar: "부스 486 / 510 · 판매면적 4,374㎡ · 100%" with zoom controls. Dense engineering-tool aesthetic, light UI chrome around a dark canvas. A professional floor plan editor screen for exhibition booth layout, in a Korean B2B web app "KINTEX AI 전시관리". Desktop 1440px. All UI text in Korean. Three-column editor layout. Top toolbar: version dropdown "배치안 B · v3", autosave label "저장됨", a distinctive purple #6D4AFF button with sparkle icon "AI 자동배치", outlined buttons "규정 검증 실행" and "홀 전경 생성", and an icon button with a share icon labeled "공유" at the right end of the toolbar. Left tool panel 240px on white: booth palette items with small square previews ("기본 부스 3×3m", "프리미엄 6×3m", "아일랜드 부스"), facility items ("무대", "라운지", "주출입구"), and layer toggles with switches ("트렌치 그리드", "기둥·비상구", "위반 오버레이" turned on). Center: large dark navy canvas #1C2536 showing a top-down exhibition hall floor plan (hall outline 126×90m with scale ruler), dozens of small blue booth rectangles arranged in rows with white booth numbers like "A-101", dashed grid lines for floor trenches, green emergency-exit icons on walls; overlay violations: two semi-transparent red bands across an aisle with numbered red pins "1", "2", and three booths hatched in orange with numbered orange pins "3", "4", "5". Right panel 360px with two tabs "속성 | 검증", showing the 검증 tab: summary chips "차단 2 · 경고 3", a list of violation cards each with pin number, red or orange severity dot, Korean text like "피난 통로 폭 3m 미만 (규정 §4.2)" and a small link "위치 보기". Bottom status bar: "부스 486 / 510 · 판매면적 4,374㎡ · 100%" with zoom controls. Dense engineering-tool aesthetic, light UI chrome around a dark canvas.
``` ```
--- ---
@ -550,11 +552,12 @@ A professional floor plan editor screen for exhibition booth layout, in a Korean
1. 헤더: "AI 생성 배치안 3건 — 조건: 목표 510부스, 프리미엄 15%, 무대 1" + 조건 수정 버튼 1. 헤더: "AI 생성 배치안 3건 — 조건: 목표 510부스, 프리미엄 15%, 무대 1" + 조건 수정 버튼
2. 배치안 카드 3열 그리드: 각 카드에 **S7 아이소메트릭 조감 이미지(AI 생성 라벨+워터마크)**, 지표(부스 수·판매면적·통로 폭 최소값·위반 수), 라디오 선택 2. 배치안 카드 3열 그리드: 각 카드에 **S7 아이소메트릭 조감 이미지(AI 생성 라벨+워터마크)**, 지표(부스 수·판매면적·통로 폭 최소값·위반 수), 라디오 선택
3. 하단 비교 테이블(지표 나란히) + 우측 고정 CTA "이 안으로 편집 시작" 3. 하단 비교 테이블(지표 나란히) + 우측 고정 CTA "이 안으로 편집 시작"
- **샘플 지표 산술 정합(v2.5 — B-08 정정)**: 판매면적 샘플은 부스 수 × 기본 3×3m(9㎡) 기준으로 통일 — **510부스 = 4,590㎡**(SCR-03 하단 상태 바의 486부스 = 4,374㎡와 동일 산식). 기존 4,420㎡ 표기는 산술 오류로 폐기.
- **상태**: S7 생성 중 — 카드 이미지 영역 스켈레톤+"조감 생성 중…" · 실패 — 도면 탑뷰 래스터로 대체 표시 + 재시도. - **상태**: S7 생성 중 — 카드 이미지 영역 스켈레톤+"조감 생성 중…" · 실패 — 도면 탑뷰 래스터로 대체 표시 + 재시도.
- **Stitch 프롬프트**: - **Stitch 프롬프트**:
``` ```
A comparison screen showing 3 AI-generated exhibition floor layout options, Korean B2B web app, desktop 1440px, light theme, blue #0066B3 primary, purple #6D4AFF for AI labels. All UI text in Korean. Header: title "AI 배치안 비교", subtitle "조건: 목표 510부스 · 프리미엄 15% · 무대 1개소", outlined button "조건 수정". Three large cards in a row, each card contains: an isometric 3D-style rendering of an exhibition hall filled with rows of white booths (bird's-eye view), a small purple chip "AI 생성" and a faint diagonal watermark "AI 생성 예상 이미지" on the image, card title "배치안 A/B/C", metric rows "부스 510개 · 판매면적 4,420㎡ · 최소 통로폭 3.2m · 위반 0건" (option C shows "위반 2건" in red), and a radio button "선택". Below the cards: a compact comparison table with the same metrics side by side. Bottom right: primary blue button "이 안으로 편집 시작". Clean, decision-focused layout. A comparison screen showing 3 AI-generated exhibition floor layout options, Korean B2B web app, desktop 1440px, light theme, blue #0066B3 primary, purple #6D4AFF for AI labels. All UI text in Korean. Header: title "AI 배치안 비교", subtitle "조건: 목표 510부스 · 프리미엄 15% · 무대 1개소", outlined button "조건 수정". Three large cards in a row, each card contains: an isometric 3D-style rendering of an exhibition hall filled with rows of white booths (bird's-eye view), a small purple chip "AI 생성" and a faint diagonal watermark "AI 생성 예상 이미지" on the image, card title "배치안 A/B/C", metric rows "부스 510개 · 판매면적 4,590㎡ · 최소 통로폭 3.2m · 위반 0건" (option C shows "위반 2건" in red), and a radio button "선택". Below the cards: a compact comparison table with the same metrics side by side. Bottom right: primary blue button "이 안으로 편집 시작". Clean, decision-focused layout.
``` ```
--- ---
@ -568,6 +571,7 @@ A comparison screen showing 3 AI-generated exhibition floor layout options, Kore
3. 할 일 카드 리스트(D-데이 칩): "유틸리티 신청 마감 D-6 — 인터넷은 현장 추가신청 불가" (warning 강조) / "장치업체 초대" / "설계 컨펌 대기 1건" 3. 할 일 카드 리스트(D-데이 칩): "유틸리티 신청 마감 D-6 — 인터넷은 현장 추가신청 불가" (warning 강조) / "장치업체 초대" / "설계 컨펌 대기 1건"
4. 내 부스 예상 사진 카드(S1 최신본, AI 고지) + "설계 스튜디오 열기" / "유틸리티 신청" 두 CTA 4. 내 부스 예상 사진 카드(S1 최신본, AI 고지) + "설계 스튜디오 열기" / "유틸리티 신청" 두 CTA
5. 신청·견적 요약: 전기 5kW ₩275,000 · 인터넷 1회선 ₩150,000 · 상태 배지 5. 신청·견적 요약: 전기 5kW ₩275,000 · 인터넷 1회선 ₩150,000 · 상태 배지
- **조립부스 분기(v2.5 신설 — B-01)**: 부스 유형이 **조립부스(기본형)**인 참가업체는 ① 헤더가 "부스 B-201 · 조립부스 3×3m(기본형) · 홀7"로 표기되고 ② 할 일 카드에 "조립부스 옵션 신청 마감 D-n"(warning)이 추가되며 ③ "장치업체 초대하기" 카드는 미노출(조립부스는 주최측 일괄 시공 — PLANNING M3) ④ CTA "부스 설계 스튜디오"는 SCR-06 **조립부스 모드**(간판·가구·조명 옵션 선택)로 진입한다. 예상 사진 카드·진행 스테퍼(신청→승인→시공→검수)는 동일.
- **상태**: 설계 전 빈 상태 — S1 자리 일러스트+"설계를 시작하면 시공 예상 사진이 생성됩니다" · 마감 초과 — 할 일 카드 빨강 잠금("마감 경과 — 주최자 문의"). - **상태**: 설계 전 빈 상태 — S1 자리 일러스트+"설계를 시작하면 시공 예상 사진이 생성됩니다" · 마감 초과 — 할 일 카드 빨강 잠금("마감 경과 — 주최자 문의").
- **Stitch 프롬프트**: - **Stitch 프롬프트**:
@ -593,6 +597,23 @@ A home screen for an exhibitor company in a Korean exhibition management web app
A "booth design studio" screen in a Korean exhibition-tech web app where users input booth specs and see AI-generated construction preview photos. Desktop 1440px, light theme, blue #0066B3 primary, purple #6D4AFF for AI actions. All UI text in Korean. Top bar: context text "부스 A-102 · 독립부스 6×3m · 높이 제한 5m", version dropdown "설계 v2", and a prominent purple button with sparkle icon "예상 사진 생성". Left panel 360px: accordion form sections in Korean — "기본 정보" (업종 select showing "로봇/제조", 예산 input), "공간 구성" (toggle chips 안내데스크/시연존/상담존/창고 with percentage sliders), "구조" (벽체 높이 slider at 4.2m with max mark "5m 제한", text input "간판 문구" filled with "한빛로보틱스", a toggle "리깅 사용" ON with an inline orange warning "구조계산서 D-7 제출 필요"), "자재" (finish swatches, a required checkbox "방염 자재 사용 확인"), "조명" (segmented control 주간/야간). Center hero: a 2×2 grid of large photorealistic booth preview images labeled with small chips "S1 부스 정면", "S2 야간 점등", "S3 통로 뷰", "S4 부스 내부" — S2 shows a dramatic night-lit booth; each image has a faint watermark "AI 생성 예상 이미지"; the S4 tile is an empty placeholder with a button "클릭해 생성". Below the grid: a wide before/after comparison slider — left half shows an empty concrete exhibition hall floor, right half the finished booth photo, with a draggable vertical handle in the middle and labels "시공 전 / 시공 후". Bottom right sticky bar: validation summary chips "통과 11 · 경고 1" and a primary button "장치업체에 컨펌 요청". Visual-first, image-dominant layout. A "booth design studio" screen in a Korean exhibition-tech web app where users input booth specs and see AI-generated construction preview photos. Desktop 1440px, light theme, blue #0066B3 primary, purple #6D4AFF for AI actions. All UI text in Korean. Top bar: context text "부스 A-102 · 독립부스 6×3m · 높이 제한 5m", version dropdown "설계 v2", and a prominent purple button with sparkle icon "예상 사진 생성". Left panel 360px: accordion form sections in Korean — "기본 정보" (업종 select showing "로봇/제조", 예산 input), "공간 구성" (toggle chips 안내데스크/시연존/상담존/창고 with percentage sliders), "구조" (벽체 높이 slider at 4.2m with max mark "5m 제한", text input "간판 문구" filled with "한빛로보틱스", a toggle "리깅 사용" ON with an inline orange warning "구조계산서 D-7 제출 필요"), "자재" (finish swatches, a required checkbox "방염 자재 사용 확인"), "조명" (segmented control 주간/야간). Center hero: a 2×2 grid of large photorealistic booth preview images labeled with small chips "S1 부스 정면", "S2 야간 점등", "S3 통로 뷰", "S4 부스 내부" — S2 shows a dramatic night-lit booth; each image has a faint watermark "AI 생성 예상 이미지"; the S4 tile is an empty placeholder with a button "클릭해 생성". Below the grid: a wide before/after comparison slider — left half shows an empty concrete exhibition hall floor, right half the finished booth photo, with a draggable vertical handle in the middle and labels "시공 전 / 시공 후". Bottom right sticky bar: validation summary chips "통과 11 · 경고 1" and a primary button "장치업체에 컨펌 요청". Visual-first, image-dominant layout.
``` ```
- **조립부스 모드 (v2.5 신설 — B-01 해소 · PLANNING M3 Phase 1 범위)**: 부스 유형이 **조립부스(assembled — 주최측 기본 구조, 옥타놈 셸 스킴)**이면 본 화면은 자유 설계 대신 **옵션 선택 모드**로 렌더된다(신규 SCR 부여 없이 SCR-06의 모드 분기 — 진입 분기는 SCR-05 "조립부스 분기" 참조).
- **상단 컨텍스트**: "부스 B-201 · 조립부스 3×3m(기본형)" + 회색 칩 "조립부스" + 마감 칩 "옵션 신청 마감 D-6"(warning). 보라 버튼 "예상 사진 생성"은 동일.
- **좌측 옵션 패널(360px, 아코디언 3그룹 — 독립부스 스펙 패널 대체)**:
1. **간판** — 간판 문구 입력(국문·영문), 서체 프리셋 3종 라디오 카드, 간판 색상 스와치. 한글 오탈자 자동 검수 연동(실패 시 주황 배지 — 독립부스와 동일 규칙).
2. **가구****조립부스 표준 자재 카탈로그(마스터 데이터)** 기반 카탈로그 그리드. 항목 카드 = 썸네일 + 명칭 + 수량 스테퍼 + "기본 제공"/"추가 ₩" 칩: 안내데스크(기본)·상담 테이블(추가)·의자(기본 4)·유리 쇼케이스(추가)·브로슈어 랙(추가)·파이텍스(바닥) 색상 스와치.
3. **조명** — 스포트라이트 수량 스테퍼(기본 3등 포함, 초과분 추가 요금)·형광등 토글·주간/야간 세그먼트(M4a 연동).
- **중앙 히어로**: 옵션 반영 프리뷰 — 옵션 변경 시 3D 프리뷰/예상 사진(S1) 즉시 갱신(PLANNING M3 "옵션 선택 → 3D 프리뷰 + M5 예상 사진 즉시 생성"), AI 워터마크 상시. 하단 Before/After 슬라이더는 "기본형 ↔ 옵션 적용" 비교로 대체.
- **우측 하단 고정 바**: 옵션 견적 요약("기본 제공 ₩0 + 추가 옵션 ₩155,000 = 합계 ₩155,000") + CTA **"옵션 신청 제출"**. 장치업체 컨펌 플로 미적용(조립부스는 주최자/킨텍스 접수·주최측 시공) — 제출 모달에 "옵션 마감 후 변경 불가" 확인 체크(필수).
- **상태**: 간판 문구 미입력 시 제출 비활성 · 마감 경과 시 옵션 편집 잠금 + "마감 경과 — 주최자 문의"(SCR-05 규칙 동일) · 프리뷰 생성 중 타일 스켈레톤+진행 배지 · 오탈자 검수 실패 시 주황 배지 "간판 문구 확인 필요".
- **Stitch 프롬프트 (조립부스 모드)**:
```
A "shell scheme booth options" variant of the booth design studio in a Korean exhibition-tech web app, where an exhibitor with a standard assembled booth (octanorm shell scheme) picks signage, furniture and lighting options instead of free-form design. Desktop 1440px, light theme, blue #0066B3 primary, purple #6D4AFF for AI actions, Korean sans-serif (Pretendard style). All UI text in Korean. Top bar: context text "부스 B-201 · 조립부스 3×3m (기본형)" with a gray chip "조립부스", an amber deadline chip "옵션 신청 마감 D-6", and a prominent purple button with sparkle icon "예상 사진 생성". Left panel 360px: accordion option groups in Korean — "간판" (a text input "간판 문구" filled with "한빛로보틱스", an English name input, 3 font preset radio cards, a row of signage color swatches), "가구" (a catalog grid of furniture option cards, each with a small thumbnail, name, quantity stepper and a price chip: "안내데스크 · 기본 제공 · 1", "상담 테이블 · ₩30,000 · 1", "의자 · 기본 제공 · 4", "유리 쇼케이스 · ₩70,000 · 1", "브로슈어 랙 · ₩15,000 · 1", and a "파이텍스 색상" swatch row), "조명" (a stepper row "스포트라이트 · 기본 3등 포함 → 5등 (+₩40,000)", a toggle "형광등", a segmented control "주간 | 야간"). Center hero: one large photorealistic preview image of a standard aluminium-frame shell scheme booth with a fascia signboard reading "한빛로보틱스", the selected furniture and spotlights visible, a faint watermark "AI 생성 예상 이미지" and a small caption chip "옵션 반영 즉시 갱신". Below the preview: a wide before/after comparison slider with a draggable vertical handle and labels "기본형 / 옵션 적용". Bottom right sticky bar: a compact quote summary "기본 제공 ₩0 + 추가 옵션 ₩155,000 = 합계 ₩155,000" and a primary blue button "옵션 신청 제출". Catalog-shopping-like option picking, but professional B2B tone.
```
- **조명 배치안 제안(M4a) 전용 UI 검토 메모(v2.5 — B-10)**: PLANNING M4a의 "조도 목표(전시품 강조/상담존)별 조명 배치안 제안"은 Phase 1에서는 본 화면 좌패널 ⑤조명 프리셋(주간/야간) + S2 야간 점등 컷(SCR-12 갤러리)으로 흡수한다. 조도 히트맵·조명 기구 배치 캔버스 등 **전용 화면 신설은 정밀 조도 시뮬레이션(P2 — PLANNING §9 Phase 3)과 함께 별도 SCR로 분리 검토**하며, 현 시점 신규 화면은 없다(신설 시 designer 경유·Stitch 의뢰 원칙 준수).
--- ---
### SCR-07 유틸리티 배선 뷰 (히어로: 트렌치 오버레이 + 자동 견적 패널) [M4a+M4b] ### SCR-07 유틸리티 배선 뷰 (히어로: 트렌치 오버레이 + 자동 견적 패널) [M4a+M4b]
@ -647,9 +668,10 @@ A compliance validation report screen for exhibition booth construction drawings
--- ---
### SCR-10 홀매니저 승인 큐 (히어로: AI 사전심사 플래그) [M2+M3+M6] ### SCR-10 홀매니저 승인 큐 (히어로: AI 사전심사 플래그) [M2+M3+M6 · Phase 2]
- **대상**: 홀매니저 · **진입 경로**: 킨텍스 내부 계정 로그인 → 기본 홈 - **대상**: 홀매니저 · **진입 경로**: 킨텍스 내부 계정 로그인 → 기본 홈
- **로드맵 라벨(v2.5 — B-10)**: PLANNING §9 로드맵 기준 홀매니저 대시보드는 **Phase 2** 범위다. 화면·Stitch·구현은 선행 확보(§2.8-2 ✅) — 라벨은 운영 투입(전 홀 확장·워크플로 통합) 시점 표기.
- **레이아웃**: - **레이아웃**:
1. 헤더: 담당 홀 필터 칩(홀6·홀7·홀8) + 검색 + 요약 KPI(대기 23 · 오늘 마감 5 · AI 차단 플래그 4) 1. 헤더: 담당 홀 필터 칩(홀6·홀7·홀8) + 검색 + 요약 KPI(대기 23 · 오늘 마감 5 · AI 차단 플래그 4)
2. **히어로 — 승인 큐 테이블(전폭)**: 열 = 행사/부스, 유형(부스 배치도·장치 도면·유틸리티·신고서류), 제출자, 제출일, D-데이, **AI 사전심사 열**(칩: "통과" 녹 / "경고 2" 주황 / "차단 1" 빨강 — 호버 시 위반 요약 툴팁), 상태, [검수] 버튼. AI 차단 행은 좌측 빨간 엣지 바. 정렬 기본: 차단→마감 임박순 2. **히어로 — 승인 큐 테이블(전폭)**: 열 = 행사/부스, 유형(부스 배치도·장치 도면·유틸리티·신고서류), 제출자, 제출일, D-데이, **AI 사전심사 열**(칩: "통과" 녹 / "경고 2" 주황 / "차단 1" 빨강 — 호버 시 위반 요약 툴팁), 상태, [검수] 버튼. AI 차단 행은 좌측 빨간 엣지 바. 정렬 기본: 차단→마감 임박순
@ -663,9 +685,10 @@ An approval queue dashboard for a venue hall manager at KINTEX exhibition center
--- ---
### SCR-11 홀매니저 검수 상세 (도면 + 위반 오버레이 + 승인/반려) ### SCR-11 홀매니저 검수 상세 (도면 + 위반 오버레이 + 승인/반려) [M2+M3 · Phase 2]
- **대상**: 홀매니저 · **진입 경로**: SCR-10 → [검수] - **대상**: 홀매니저 · **진입 경로**: SCR-10 → [검수]
- **로드맵 라벨(v2.5 — B-10)**: SCR-10과 동일 — **Phase 2**(홀매니저 대시보드) 범위(화면·구현은 선행 확보).
- **레이아웃**: - **레이아웃**:
1. 헤더: 제출물 컨텍스트(행사·부스·유형·버전·제출자) + 이전/다음 큐 이동 화살표 1. 헤더: 제출물 컨텍스트(행사·부스·유형·버전·제출자) + 이전/다음 큐 이동 화살표
2. 좌측 70% — 도면 뷰어(다크 캔버스): 제출 도면 + AI 위반 오버레이 토글, 위반 핀 클릭 ↔ 우측 목록 동기 하이라이트. 상단 보조 탭: [도면] [예상 사진(참고용 — 심사 근거 아님 라벨)] [이전 버전 비교] 2. 좌측 70% — 도면 뷰어(다크 캔버스): 제출 도면 + AI 위반 오버레이 토글, 위반 핀 클릭 ↔ 우측 목록 동기 하이라이트. 상단 보조 탭: [도면] [예상 사진(참고용 — 심사 근거 아님 라벨)] [이전 버전 비교]
@ -1704,9 +1727,10 @@ A public agency (contractor / booth-construction partner) sub-home page for the
--- ---
### SCR-M1 [모바일] 시공업체 현장 체크리스트 [M3 규정 + 현장 공정] ### SCR-M1 [모바일] 시공업체 현장 체크리스트 [M3 규정 + 현장 공정 · Phase 3]
- **대상**: 장치업체 현장 인력 · **진입 경로**: 모바일 로그인 → 수주 부스 → "현장 체크리스트" (장치 기간 중 기본 홈) - **대상**: 장치업체 현장 인력 · **진입 경로**: 모바일 로그인 → 수주 부스 → "현장 체크리스트" (장치 기간 중 기본 홈)
- **로드맵 라벨(v2.5 — B-10)**: PLANNING §9 기준 현장 모바일 운영 도구는 **Phase 3** 범위다(화면·Stitch·구현은 선행 확보 — 라벨은 현장 운영 투입 시점 표기).
- **레이아웃**: - **레이아웃**:
1. 상단 고정: 부스 A-102 · 홀7 · "장치 1일차" + 도면/예상사진(S1) 토글 썸네일(참고용 라벨) 1. 상단 고정: 부스 A-102 · 홀7 · "장치 1일차" + 도면/예상사진(S1) 토글 썸네일(참고용 라벨)
2. 체크리스트 그룹(아코디언): ① 반입 전(방염 확인서 지참, 안전모) ② 시공 중 — 금지작업 경고 카드 상시 노출("전기톱·용접·페인트 작업 장내 금지", 소음 70~75dB 한도) ③ 구조(높이 실측 5m 이하 확인 — 수치 입력, 리깅 구조계산서 제출 확인) ④ 완료(사진 업로드 → 홀매니저 검수 요청) 2. 체크리스트 그룹(아코디언): ① 반입 전(방염 확인서 지참, 안전모) ② 시공 중 — 금지작업 경고 카드 상시 노출("전기톱·용접·페인트 작업 장내 금지", 소음 70~75dB 한도) ③ 구조(높이 실측 5m 이하 확인 — 수치 입력, 리깅 구조계산서 제출 확인) ④ 완료(사진 업로드 → 홀매니저 검수 요청)
@ -1721,9 +1745,10 @@ A mobile on-site checklist app screen for a booth construction crew at KINTEX ex
--- ---
### SCR-M2 [모바일] 홀매니저 현장 검수 ### SCR-M2 [모바일] 홀매니저 현장 검수 [M2+M3 · Phase 3]
- **대상**: 홀매니저 · **진입 경로**: 모바일 홈(승인 큐 카드 리스트) → 검수 요청 알림 탭 - **대상**: 홀매니저 · **진입 경로**: 모바일 홈(승인 큐 카드 리스트) → 검수 요청 알림 탭
- **로드맵 라벨(v2.5 — B-10)**: SCR-M1과 동일 — **Phase 3**(현장 모바일 운영 도구) 범위(화면·구현은 선행 확보).
- **레이아웃**: - **레이아웃**:
1. 상단: 부스 컨텍스트 + 승인 도면 썸네일(탭 시 전체 화면 뷰어, 핀치 줌) 1. 상단: 부스 컨텍스트 + 승인 도면 썸네일(탭 시 전체 화면 뷰어, 핀치 줌)
2. **비교 카드**: 승인 도면 vs 현장 사진(시공업체 업로드) 좌우 스와이프 비교, "AI 사전심사 플래그 3건" 요약 칩 — 탭 시 바텀시트로 플래그 목록(각 "현장 확인함" 체크) 2. **비교 카드**: 승인 도면 vs 현장 사진(시공업체 업로드) 좌우 스와이프 비교, "AI 사전심사 플래그 3건" 요약 칩 — 탭 시 바텀시트로 플래그 목록(각 "현장 확인함" 체크)
@ -1908,6 +1933,7 @@ A mobile "my ticket wallet" screen for an exhibition visitor, 390px width, light
| 버전 | 일자 | 작성자 | 내용 | | 버전 | 일자 | 작성자 | 내용 |
|---|---|---|---| |---|---|---|---|
| **v2.5** | 2026-07-14 | designer | **BACKLOG designer 잔여 티켓 일괄 해소(B-01·B-04~B-08·B-10) — 소유자 지시 "백로그 미진행 사항 진행".** 기존 구조·번호 체계·토큰 불변(신규 토큰 0), 스펙 정정·순증만. ①**B-01(Major)**: SCR-06에 **조립부스 모드** 신설(PLANNING M3 Phase 1 범위 — 신규 SCR 없이 모드 분기) — 좌측 옵션 패널 3그룹(간판 문구·서체·색/가구 표준 자재 카탈로그 그리드(수량 스테퍼+기본 제공·추가 ₩ 칩)/조명 스포트 스테퍼·주간야간), 옵션 변경 시 3D 프리뷰·S1 예상 사진 즉시 갱신, Before/After "기본형↔옵션 적용", 옵션 견적 요약+CTA "옵션 신청 제출"(장치업체 컨펌 미적용 — 주최측 시공), 상태(마감 잠금·문구 미입력 비활성·오탈자 배지) + **전용 영어 Stitch 프롬프트 1종**(견적 산술 정합 30,000+70,000+15,000+40,000=155,000). SCR-05에 조립부스 분기(헤더 표기·옵션 마감 할 일 카드·장치업체 초대 미노출·스튜디오 진입 분기) 순증 ②**B-04**: 화면 수 표기 정정 — §3 헤더 "총 14개(웹12+모바일2)"→**P0 코어 15개(웹 13 = SCR-01·HOME·02~12 + 모바일 2)**(SCR-HOME 신설 반영), §2.8-2 집계 문장의 SCR-T0~T3 4화면 누락 정정 **85→총 89화면**(✅Stitch 83·미생성 6 상태 정합 — v2.2 변경이력과 일치화) ③**B-05**: SCR-02 사이드바 "정산" 메뉴 IA 불일치 해소 — §2-1 주최자 사이트맵에 "정산·결제 [M9, P1] — Phase 2 (SCR-21)" 추가 + SCR-02에 정합 메모(프롬프트 메뉴 문구 유지) ④**B-06**: SCR-01 Stitch 프롬프트에 스펙에만 있던 "이메일 인증으로 로그인" 버튼 추가 ⑤**B-07**: SCR-03 프롬프트에 툴바 "공유" 버튼 추가 + 위반 요약(차단2·경고3)↔캔버스 핀 불일치 정정(주황 빗금 부스 1→3개, 핀 3·4·5 — 스펙 레이아웃 ③에 핀·건수 명시로 1:1 고정) ⑥**B-08**: SCR-04 샘플 지표 산술 오류 정정 — 판매면적 4,420㎡→**4,590㎡**(510부스×9㎡, SCR-03 486부스=4,374㎡와 동일 산식 명문화) ⑦**B-10**: SCR-10/11 헤딩·메모에 **Phase 2**(PLANNING §9 홀매니저 대시보드), SCR-M1/M2에 **Phase 3**(현장 모바일 운영 도구) 로드맵 라벨 부착(화면·구현 선행 확보 명시 — P0 우선순위 컬럼과 구분) + **조명 배치안 제안(M4a) 전용 UI 검토 메모**를 SCR-06에 신설(Phase 1은 조명 프리셋+S2 야간 컷으로 흡수, 조도 히트맵·기구 배치 캔버스 전용 SCR은 정밀 조도 시뮬레이션(P2)과 함께 분리 검토 — 현 시점 신규 화면 없음). PLANNING.md·src 무수정 |
| **v2.4** | 2026-07-12 | designer | **공개 사이트 비주얼·모션 전면 리뉴얼 스펙 신설(소유자 확정: "코엑스처럼 세련되게 — 히어로 배경·애니메이션·비주얼, 지금 착수").** §3C에 **3C-V 공개 사이트 비주얼·모션 스펙** 절 순증 — 기존 SCR-T0~T3·SCR-P* **구조는 불변**, 그 위에 비주얼/모션 레이어만 격상(구조 재설계 아님). ①**비주얼 폴리시(V-1)** 풀블리드·공백 없음·섹션 리듬(밴드↔카드 교대·96/64/40px)·여백·라운드 8px·소프트 앰비언트 그림자·타이포 위계 강화·선 SVG·이모지 금지·다크/라이트·2:3 포스터 카드. ②**모션 토큰(V-2)** duration(`--motion-fast 150`/`base 240`/`slow 400`/`hero 600`/`countup 1200`)·easing(`--ease-emphasized/standard/decelerate`) 신설(컬러 신규 토큰 0). ③**섹션별 배경·애니메이션 트리거 매핑(V-3)** 풀블리드 히어로(라이트 파랄랙스+인트로 리빌)·통계 카운트업·AI 타일 스태거·쇼케이스 hover 리프트/이미지 줌·행사 레일 오토스크롤·기획 브리핑 grow·공통 스크롤 리빌(IO threshold 0.15·once). ④**이미지 소스 매핑(V-4)** build 내장 `/media/`(hero·bands·poster·patterns 계약)·부재 시 그라디언트+패턴 폴백(레이아웃 시프트 0)·preload/lazy/webp/srcset. ⑤**접근성(V-5)** `prefers-reduced-motion` 필수 — 파랄랙스/오토스크롤 정지·카운트업 즉시·리빌 instant·모션은 전부 장식(정보 비의존)·양 테마 WCAG AA. ⑥**성능(V-6)** CSS 우선·`transform`/`opacity`만·`will-change` 절제·60fps·강등 순서. ⑦**프론트 계약(V-7)** `.pub-reveal`/`--stagger`·`.pub-hero__bg[data-parallax]`·`.pub-card--lift`·`.pub-card__media img` 줌·`.pub-countup`·`.pub-rail--auto`·폴백 유틸, **PublicShell 하위만 스코프**(AppShell/MDI·SCR-A*·모바일 미주입). ⑧**영어 Stitch 프롬프트 2종(V-8·V-9)** — 프리미엄 전시장 홈페이지(SCR-T1 시네마틱 히어로·스크롤 리빌·카운트업·hover 줌·오토스크롤·폴백·reduced-motion, 제품명 정확·NO emoji·선 SVG·라이트/다크) + 3-트랙 관문(SCR-T0 동일 톤 격상). **경계 준수**: visitor(T1)만 풀 시네마틱, business/agency는 B2B 톤 유지+공통 모션 절제 적용. 신규 컬러 토큰 0·PLANNING.md·src 무수정. | | **v2.4** | 2026-07-12 | designer | **공개 사이트 비주얼·모션 전면 리뉴얼 스펙 신설(소유자 확정: "코엑스처럼 세련되게 — 히어로 배경·애니메이션·비주얼, 지금 착수").** §3C에 **3C-V 공개 사이트 비주얼·모션 스펙** 절 순증 — 기존 SCR-T0~T3·SCR-P* **구조는 불변**, 그 위에 비주얼/모션 레이어만 격상(구조 재설계 아님). ①**비주얼 폴리시(V-1)** 풀블리드·공백 없음·섹션 리듬(밴드↔카드 교대·96/64/40px)·여백·라운드 8px·소프트 앰비언트 그림자·타이포 위계 강화·선 SVG·이모지 금지·다크/라이트·2:3 포스터 카드. ②**모션 토큰(V-2)** duration(`--motion-fast 150`/`base 240`/`slow 400`/`hero 600`/`countup 1200`)·easing(`--ease-emphasized/standard/decelerate`) 신설(컬러 신규 토큰 0). ③**섹션별 배경·애니메이션 트리거 매핑(V-3)** 풀블리드 히어로(라이트 파랄랙스+인트로 리빌)·통계 카운트업·AI 타일 스태거·쇼케이스 hover 리프트/이미지 줌·행사 레일 오토스크롤·기획 브리핑 grow·공통 스크롤 리빌(IO threshold 0.15·once). ④**이미지 소스 매핑(V-4)** build 내장 `/media/`(hero·bands·poster·patterns 계약)·부재 시 그라디언트+패턴 폴백(레이아웃 시프트 0)·preload/lazy/webp/srcset. ⑤**접근성(V-5)** `prefers-reduced-motion` 필수 — 파랄랙스/오토스크롤 정지·카운트업 즉시·리빌 instant·모션은 전부 장식(정보 비의존)·양 테마 WCAG AA. ⑥**성능(V-6)** CSS 우선·`transform`/`opacity`만·`will-change` 절제·60fps·강등 순서. ⑦**프론트 계약(V-7)** `.pub-reveal`/`--stagger`·`.pub-hero__bg[data-parallax]`·`.pub-card--lift`·`.pub-card__media img` 줌·`.pub-countup`·`.pub-rail--auto`·폴백 유틸, **PublicShell 하위만 스코프**(AppShell/MDI·SCR-A*·모바일 미주입). ⑧**영어 Stitch 프롬프트 2종(V-8·V-9)** — 프리미엄 전시장 홈페이지(SCR-T1 시네마틱 히어로·스크롤 리빌·카운트업·hover 줌·오토스크롤·폴백·reduced-motion, 제품명 정확·NO emoji·선 SVG·라이트/다크) + 3-트랙 관문(SCR-T0 동일 톤 격상). **경계 준수**: visitor(T1)만 풀 시네마틱, business/agency는 B2B 톤 유지+공통 모션 절제 적용. 신규 컬러 토큰 0·PLANNING.md·src 무수정. |
| **v2.3.2** | 2026-07-12 | designer | **SCR-T1 — AI 전시·행사 기획 브리핑(연간·월간 선제 제시) 추가(소유자 추가 지시 2026-07-12).** 단발 질의응답을 넘어 **AI가 개최 예정 전시·행사를 먼저 큐레이션**하는 섹션을 히어로 AI 능력 타일 직하(레이아웃 4번)에 신설 — **연/월 관점 토글**(① 연간=12개월 타임라인+분기 하이라이트+AiLabel "AI 요약" 헤드라인, ② 월간=선택 월 캘린더/리스트+AI 월간 요약), 연/월 전환 시 AI가 해당 기간 데이터 근거로 요약·추천 갱신. **중복 회피**: 하단 "진행 중/이번 달/다음 달" 쇼케이스(레이아웃 5)와 달리 본 섹션은 **연간 기획 관점**이 차별점, 월간은 동일 event 소스로 정합. 구성요소 `AiPlanningBriefing` 추가, 이하 레이아웃 5~11 재번호. **데이터 원천** — 신규 공개 엔드포인트 제안 `GET /api/public/events/planning?view=year|month&year&month`(크롤 적재 `exhibition`/`event`를 개최연·월 그룹 조회, AI 기간 요약은 AiTextRouter Claude→Ollama 폴백이 해당 기간 DB만 근거·근거 인용·캐시, DB 서빙·외부 실시간 호출 없음, 계약 제안). 상태(로딩·성공·**degraded(요약 미가용→데이터만 노출)**·빈·에러·기간 전환 부분 로딩) 정의. **Stitch 프롬프트 갱신** — 연간 타임라인+"AI 요약" 헤드라인("2026년은 상반기 스마트팩토리·로봇, 하반기 헬스케어·친환경…")+월간 요약("이번 달은 로봇·헬스케어 전시가 집중됩니다") 문단 추가, 쇼케이스와 구별 명시. 세련된 홈페이지 톤·풀블리드·반응형·라이트/다크·크롤 적재 DB 근거 원칙은 유지. 신규 토큰 0·PLANNING.md·src 무수정 | | **v2.3.2** | 2026-07-12 | designer | **SCR-T1 — AI 전시·행사 기획 브리핑(연간·월간 선제 제시) 추가(소유자 추가 지시 2026-07-12).** 단발 질의응답을 넘어 **AI가 개최 예정 전시·행사를 먼저 큐레이션**하는 섹션을 히어로 AI 능력 타일 직하(레이아웃 4번)에 신설 — **연/월 관점 토글**(① 연간=12개월 타임라인+분기 하이라이트+AiLabel "AI 요약" 헤드라인, ② 월간=선택 월 캘린더/리스트+AI 월간 요약), 연/월 전환 시 AI가 해당 기간 데이터 근거로 요약·추천 갱신. **중복 회피**: 하단 "진행 중/이번 달/다음 달" 쇼케이스(레이아웃 5)와 달리 본 섹션은 **연간 기획 관점**이 차별점, 월간은 동일 event 소스로 정합. 구성요소 `AiPlanningBriefing` 추가, 이하 레이아웃 5~11 재번호. **데이터 원천** — 신규 공개 엔드포인트 제안 `GET /api/public/events/planning?view=year|month&year&month`(크롤 적재 `exhibition`/`event`를 개최연·월 그룹 조회, AI 기간 요약은 AiTextRouter Claude→Ollama 폴백이 해당 기간 DB만 근거·근거 인용·캐시, DB 서빙·외부 실시간 호출 없음, 계약 제안). 상태(로딩·성공·**degraded(요약 미가용→데이터만 노출)**·빈·에러·기간 전환 부분 로딩) 정의. **Stitch 프롬프트 갱신** — 연간 타임라인+"AI 요약" 헤드라인("2026년은 상반기 스마트팩토리·로봇, 하반기 헬스케어·친환경…")+월간 요약("이번 달은 로봇·헬스케어 전시가 집중됩니다") 문단 추가, 쇼케이스와 구별 명시. 세련된 홈페이지 톤·풀블리드·반응형·라이트/다크·크롤 적재 DB 근거 원칙은 유지. 신규 토큰 0·PLANNING.md·src 무수정 |
| **v2.3.1** | 2026-07-12 | designer | **SCR-T1 마무리 — AI 전면 노출 + AI 답변 근거=크롤 적재 DB 명시(소유자 추가 지시 2건 2026-07-12).** ①**AI 기능 쇼케이스 타일 신설**(히어로 직하 레이아웃 3번): "AI 시스템인데 AI가 어디 있는지 모르겠다" 지적 반영 — AI 관람 도우미·AI 전시 추천·AI 길찾기·AI 일정 도우미·AI 혼잡/대기 안내·AI 시공 예상 이미지 6능력을 AiLabel 카드로 전면 홍보(구성요소 AiCapabilityTiles·상태(정적 상시·미가용 "준비 중")·이하 레이아웃 4~10 재번호). ②**데이터 원천 = 사전 크롤 적재 온프레미스 DB 명시**: AI 관람 도우미(`POST /api/public/ai/visitor-assistant`)가 **실시간 외부 크롤이 아니라 미리 크롤해 DB에 적재한 공개 데이터만을 RAG 근거로 답하고 참조 레코드를 인용**(범위 밖=degraded)함을 명문화 — 근거 테이블 계약 예시(`exhibition`/`event`·`transport_info`·`parking_info`·`ticket_policy`·`amenity_info`·`visitor_guide`·`floorplan`), 각 섹션 출처를 크롤 적재 DB로 매핑, degraded 폴백을 "크롤 적재 데이터 검색"으로 갱신, 백엔드 계약을 "공개 조회 API가 크롤 적재 DB에서 서빙(외부 실시간 호출 없음·온프레미스·근거 인용)" 전제로 기술. ③**Stitch 프롬프트 갱신** — AI 능력 쇼케이스 카드 6종 문구 + "served from a pre-crawled on-premise database, AI answers ONLY from stored data and cites its source" 추가. 세련된 홈페이지 톤·풀블리드·반응형·라이트/다크는 v2.3 그대로 유지. 신규 토큰 0·PLANNING.md·src 무수정 | | **v2.3.1** | 2026-07-12 | designer | **SCR-T1 마무리 — AI 전면 노출 + AI 답변 근거=크롤 적재 DB 명시(소유자 추가 지시 2건 2026-07-12).** ①**AI 기능 쇼케이스 타일 신설**(히어로 직하 레이아웃 3번): "AI 시스템인데 AI가 어디 있는지 모르겠다" 지적 반영 — AI 관람 도우미·AI 전시 추천·AI 길찾기·AI 일정 도우미·AI 혼잡/대기 안내·AI 시공 예상 이미지 6능력을 AiLabel 카드로 전면 홍보(구성요소 AiCapabilityTiles·상태(정적 상시·미가용 "준비 중")·이하 레이아웃 4~10 재번호). ②**데이터 원천 = 사전 크롤 적재 온프레미스 DB 명시**: AI 관람 도우미(`POST /api/public/ai/visitor-assistant`)가 **실시간 외부 크롤이 아니라 미리 크롤해 DB에 적재한 공개 데이터만을 RAG 근거로 답하고 참조 레코드를 인용**(범위 밖=degraded)함을 명문화 — 근거 테이블 계약 예시(`exhibition`/`event`·`transport_info`·`parking_info`·`ticket_policy`·`amenity_info`·`visitor_guide`·`floorplan`), 각 섹션 출처를 크롤 적재 DB로 매핑, degraded 폴백을 "크롤 적재 데이터 검색"으로 갱신, 백엔드 계약을 "공개 조회 API가 크롤 적재 DB에서 서빙(외부 실시간 호출 없음·온프레미스·근거 인용)" 전제로 기술. ③**Stitch 프롬프트 갱신** — AI 능력 쇼케이스 카드 6종 문구 + "served from a pre-crawled on-premise database, AI answers ONLY from stored data and cites its source" 추가. 세련된 홈페이지 톤·풀블리드·반응형·라이트/다크는 v2.3 그대로 유지. 신규 토큰 0·PLANNING.md·src 무수정 |

View File

@ -139,14 +139,29 @@ export function AnalyticsDashboardPage() {
<div className="kx-bi__chart"> <div className="kx-bi__chart">
{data.trend.length === 0 ? ( {data.trend.length === 0 ? (
<EmptyState title={t('analytics.trendEmptyTitle')} description={t('analytics.trendEmptyDesc')} /> <EmptyState title={t('analytics.trendEmptyTitle')} description={t('analytics.trendEmptyDesc')} />
) : ( ) : (() => {
const { rows, hasForecast } = buildTrendForecast(data.trend);
return (
<>
{hasForecast && (
<div className="kx-bi__forecast-legend">
<AiLabel>{t('analytics.forecastLabel', { defaultValue: 'AI 수요예측' })}</AiLabel>
<span className="kx-bi__forecast-note">
{t('analytics.forecastNote', { defaultValue: '선형회귀 기반 향후 2개월 예측(점선)' })}
</span>
</div>
)}
<ResponsiveContainer width="100%" height={320}> <ResponsiveContainer width="100%" height={320}>
<AreaChart data={data.trend} margin={{ top: 8, right: 12, bottom: 0, left: -8 }}> <AreaChart data={rows} margin={{ top: 8, right: 12, bottom: 0, left: -8 }}>
<defs> <defs>
<linearGradient id="gRevenue" x1="0" y1="0" x2="0" y2="1"> <linearGradient id="gRevenue" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor={CHART.primary600} stopOpacity={0.35} /> <stop offset="0%" stopColor={CHART.primary600} stopOpacity={0.35} />
<stop offset="100%" stopColor={CHART.primary600} stopOpacity={0.02} /> <stop offset="100%" stopColor={CHART.primary600} stopOpacity={0.02} />
</linearGradient> </linearGradient>
<linearGradient id="gRevenueForecast" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor={CHART.aiAccent} stopOpacity={0.22} />
<stop offset="100%" stopColor={CHART.aiAccent} stopOpacity={0.02} />
</linearGradient>
</defs> </defs>
<CartesianGrid stroke={CHART.neutral200} strokeDasharray="3 3" vertical={false} /> <CartesianGrid stroke={CHART.neutral200} strokeDasharray="3 3" vertical={false} />
<XAxis dataKey="period" tick={{ fontSize: 12, fill: CHART.slate }} tickLine={false} axisLine={{ stroke: CHART.neutral200 }} /> <XAxis dataKey="period" tick={{ fontSize: 12, fill: CHART.slate }} tickLine={false} axisLine={{ stroke: CHART.neutral200 }} />
@ -155,14 +170,34 @@ export function AnalyticsDashboardPage() {
<Tooltip <Tooltip
contentStyle={TOOLTIP_STYLE} contentStyle={TOOLTIP_STYLE}
formatter={(value, _name, item) => formatter={(value, _name, item) =>
item?.dataKey === 'revenue' ? formatWon(value as number) : t('analytics.boothsUnit', { n: (value as number).toLocaleString() }) item?.dataKey === 'booths'
? t('analytics.boothsUnit', { n: (value as number).toLocaleString() })
: item?.dataKey === 'revenueForecast'
? `${formatWon(value as number)} · ${t('analytics.forecastLabel', { defaultValue: 'AI 수요예측' })}`
: formatWon(value as number)
} }
/> />
<Area yAxisId="rev" type="monotone" dataKey="revenue" name={t('analytics.revenue')} stroke={CHART.primary600} fill="url(#gRevenue)" strokeWidth={2} /> <Area yAxisId="rev" type="monotone" dataKey="revenue" name={t('analytics.revenue')} stroke={CHART.primary600} fill="url(#gRevenue)" strokeWidth={2} connectNulls={false} />
<Area yAxisId="booth" type="monotone" dataKey="booths" name={t('analytics.booth')} stroke={CHART.aiAccent} fill={CHART.aiAccent} fillOpacity={0.08} strokeWidth={2} /> {hasForecast && (
<Area
yAxisId="rev"
type="monotone"
dataKey="revenueForecast"
name={t('analytics.forecastLabel', { defaultValue: 'AI 수요예측' })}
stroke={CHART.aiAccent}
fill="url(#gRevenueForecast)"
strokeWidth={2}
strokeDasharray="5 4"
dot={{ r: 2 }}
connectNulls
/>
)}
<Area yAxisId="booth" type="monotone" dataKey="booths" name={t('analytics.booth')} stroke={CHART.aiAccent} fill={CHART.aiAccent} fillOpacity={0.08} strokeWidth={2} connectNulls={false} />
</AreaChart> </AreaChart>
</ResponsiveContainer> </ResponsiveContainer>
)} </>
);
})()}
</div> </div>
</section> </section>
@ -318,6 +353,70 @@ function shortWon(v: number): string {
return String(v); return String(v);
} }
/**
* () (R13-01 · design.md SCR-13 "AI 예측 점선").
* AnalyticsTrendPoint revenue
* 2 (overview ).
* - 실측점: revenue , revenueForecast=null ( 릿 ).
* - 예측점: revenue=null, revenueForecast=( 0 ).
* (3) (hasForecast=false).
*/
interface TrendRow {
period: string;
revenue: number | null;
revenueForecast: number | null;
booths: number | null;
}
function buildTrendForecast(
trend: AnalyticsData['trend'],
horizon = 2,
): { rows: TrendRow[]; hasForecast: boolean } {
const base: TrendRow[] = trend.map((p) => ({
period: p.period,
revenue: p.revenue,
revenueForecast: null,
booths: p.booths,
}));
if (trend.length < 3) return { rows: base, hasForecast: false };
// 최소제곱 회귀: x=인덱스(0..n-1), y=revenue.
const n = trend.length;
let sx = 0, sy = 0, sxx = 0, sxy = 0;
trend.forEach((p, i) => {
sx += i; sy += p.revenue; sxx += i * i; sxy += i * p.revenue;
});
const denom = n * sxx - sx * sx;
if (denom === 0) return { rows: base, hasForecast: false };
const slope = (n * sxy - sx * sy) / denom;
const intercept = (sy - slope * sx) / n;
// 브릿지: 마지막 실측점을 예측선 시작점으로 복제(두 시리즈 연결).
base[base.length - 1].revenueForecast = base[base.length - 1].revenue;
const rows = [...base];
for (let k = 1; k <= horizon; k++) {
const idx = n - 1 + k;
const yhat = Math.max(0, Math.round(intercept + slope * idx));
rows.push({
period: addMonths(trend[n - 1].period, k),
revenue: null,
revenueForecast: yhat,
booths: null,
});
}
return { rows, hasForecast: true };
}
/** "YYYY-MM" 에 개월 가산. 파싱 실패 시 원본에 접미사(비회귀 폴백). */
function addMonths(period: string, add: number): string {
const m = /^(\d{4})-(\d{2})$/.exec(period);
if (!m) return `${period}+${add}`;
let y = Number(m[1]);
let mo = Number(m[2]) + add;
y += Math.floor((mo - 1) / 12);
mo = ((mo - 1) % 12) + 1;
return `${y}-${String(mo).padStart(2, '0')}`;
}
function isDegradable(error: unknown): boolean { function isDegradable(error: unknown): boolean {
return ( return (
error instanceof ApiRequestError && error instanceof ApiRequestError &&

View File

@ -61,6 +61,16 @@
.kx-bi__chart { .kx-bi__chart {
width: 100%; width: 100%;
} }
.kx-bi__forecast-legend {
display: flex;
align-items: center;
gap: var(--space-2);
margin-bottom: var(--space-2);
}
.kx-bi__forecast-note {
font-size: var(--fs-micro);
color: var(--color-neutral-500);
}
.kx-bi__sectors { .kx-bi__sectors {
align-self: stretch; align-self: stretch;
} }

View File

@ -11,7 +11,8 @@ export const CHART = {
aiAccent: '#6D4AFF', // AI 전용(수요예측 등) aiAccent: '#6D4AFF', // AI 전용(수요예측 등)
aiSurface: '#F5F3FF', aiSurface: '#F5F3FF',
success: '#0E8A5F', success: '#0E8A5F',
warning: '#F79009', // 오버레이/차트용 앰버(§1 violation-warn) violationWarn: '#F79009', // 오버레이/차트용 앰버(§1 violation-warn) — 키명은 실제 값(violation-warn) 기준
error: '#D92D20', error: '#D92D20',
slate: '#667085', // 보조 계열 slate: '#667085', // 보조 계열
neutral200: '#E4E7EC', neutral200: '#E4E7EC',

View File

@ -2,7 +2,8 @@
* SCR-37 [M17 / F069]. 참조: design.md §3 SCR-37. * SCR-37 [M17 / F069]. 참조: design.md §3 SCR-37.
* 상단: 언어 (///) · : 번역 ( × ) · : 병렬 ( KO ) + . * 상단: 언어 (///) · : 번역 ( × ) · : 병렬 ( KO ) + .
* API 전환: GET /api/cms/contents + GET/PUT /api/cms/contents/{id}/translations. upsert· . * API 전환: GET /api/cms/contents + GET/PUT /api/cms/contents/{id}/translations. upsert· .
* AI / (AiTextRouter ) disabled + . * AI /재생성: POST /api/cms/contents/{id}/translations/ai?lang= (AiTextRouter ClaudeOllama )
* trans_status='ai' , degraded(AI ) ( ).
*/ */
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { Button } from '../../components/ui/Button'; import { Button } from '../../components/ui/Button';

View File

@ -179,6 +179,7 @@ export function BoothLayoutEditorPage() {
selectedBoothId={selectedBoothId} selectedBoothId={selectedBoothId}
onSelectBooth={setSelectedBoothId} onSelectBooth={setSelectedBoothId}
zoom={zoom} zoom={zoom}
onZoomChange={setZoom}
floorplanUrl={hallFloorplanUrl(hallId)} floorplanUrl={hallFloorplanUrl(hallId)}
/> />
) )

View File

@ -1,7 +1,12 @@
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import type { BoothDto } from '../../api/types'; import type { BoothDto } from '../../api/types';
import './canvas.css'; import './canvas.css';
const ZOOM_MIN = 0.3;
const ZOOM_MAX = 4;
const WHEEL_STEP = 1.1;
const DRAG_THRESHOLD_PX = 3;
/* /*
* SVG (SCR-03 ). * SVG (SCR-03 ).
* - (#1C2536) + + . * - (#1C2536) + + .
@ -24,6 +29,8 @@ interface FloorplanCanvasProps {
zoom: number; zoom: number;
/** 실측 홀 도면(크롤 JPG) 언더레이 URL — 없거나 로드 실패 시 기존 다크 서피스만. */ /** 실측 홀 도면(크롤 JPG) 언더레이 URL — 없거나 로드 실패 시 기존 다크 서피스만. */
floorplanUrl?: string | null; floorplanUrl?: string | null;
/** 마우스휠 확대/축소 시 페이지 zoom 상태 동기화(소유자 지시 2026-07-14). 미지정 시 휠 줌 비활성. */
onZoomChange?: (zoom: number) => void;
} }
const TRENCH_SPACING_M = 9; // 가정 트렌치 그리드 간격(실측 대체 — R4) const TRENCH_SPACING_M = 9; // 가정 트렌치 그리드 간격(실측 대체 — R4)
@ -48,11 +55,72 @@ export function FloorplanCanvas({
onSelectBooth, onSelectBooth,
zoom, zoom,
floorplanUrl, floorplanUrl,
onZoomChange,
}: FloorplanCanvasProps) { }: FloorplanCanvasProps) {
const [hw, hh] = hallDims; const [hw, hh] = hallDims;
const [drawingOk, setDrawingOk] = useState(true); const [drawingOk, setDrawingOk] = useState(true);
useEffect(() => setDrawingOk(true), [floorplanUrl]); useEffect(() => setDrawingOk(true), [floorplanUrl]);
// ── 뷰어 조작(소유자 지시 2026-07-14): 마우스휠 확대/축소 + 왼쪽 드래그 이동 ──
const rootRef = useRef<HTMLDivElement | null>(null);
const [pan, setPan] = useState({ x: 0, y: 0 });
const [panning, setPanning] = useState(false);
const dragRef = useRef<{ startX: number; startY: number; baseX: number; baseY: number; moved: boolean } | null>(null);
const zoomRef = useRef(zoom);
zoomRef.current = zoom;
// 휠 줌 — 페이지 스크롤 억제를 위해 non-passive 리스너로 직접 부착.
useEffect(() => {
const el = rootRef.current;
if (!el || !onZoomChange) return;
const onWheel = (e: WheelEvent) => {
e.preventDefault();
const factor = e.deltaY < 0 ? WHEEL_STEP : 1 / WHEEL_STEP;
const next = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, zoomRef.current * factor));
onZoomChange(Math.round(next * 100) / 100);
};
el.addEventListener('wheel', onWheel, { passive: false });
return () => el.removeEventListener('wheel', onWheel);
}, [onZoomChange]);
const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
if (e.button !== 0) return; // 왼쪽 버튼만 이동
dragRef.current = { startX: e.clientX, startY: e.clientY, baseX: pan.x, baseY: pan.y, moved: false };
(e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);
};
const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
const d = dragRef.current;
if (!d) return;
const dx = e.clientX - d.startX;
const dy = e.clientY - d.startY;
if (!d.moved && Math.abs(dx) + Math.abs(dy) > DRAG_THRESHOLD_PX) {
d.moved = true;
setPanning(true);
}
if (d.moved) {
setPan({ x: d.baseX + dx, y: d.baseY + dy });
}
};
const endDrag = (e: React.PointerEvent<HTMLDivElement>) => {
if (dragRef.current) {
try {
(e.currentTarget as HTMLDivElement).releasePointerCapture(e.pointerId);
} catch {
/* 캡처 미보유 무시 */
}
}
setPanning(false);
// moved 플래그는 클릭 억제 판정(onClickCapture)까지 유지 — 클릭 이벤트가 뒤따라 온다.
};
// 드래그 직후 따라오는 click이 부스 선택/해제를 오발하지 않게 캡처 단계에서 차단.
const onClickCapture = (e: React.MouseEvent<HTMLDivElement>) => {
if (dragRef.current?.moved) {
e.preventDefault();
e.stopPropagation();
}
dragRef.current = null;
};
const trenchLines = useMemo(() => { const trenchLines = useMemo(() => {
const lines: { x1: number; y1: number; x2: number; y2: number }[] = []; const lines: { x1: number; y1: number; x2: number; y2: number }[] = [];
for (let x = TRENCH_SPACING_M; x < hw; x += TRENCH_SPACING_M) { for (let x = TRENCH_SPACING_M; x < hw; x += TRENCH_SPACING_M) {
@ -65,7 +133,16 @@ export function FloorplanCanvas({
}, [hw, hh]); }, [hw, hh]);
return ( return (
<div className="kx-canvas" style={{ transform: `scale(${zoom})` }}> <div
ref={rootRef}
className={`kx-canvas ${panning ? 'is-panning' : ''}`}
style={{ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` }}
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
onPointerUp={endDrag}
onPointerCancel={endDrag}
onClickCapture={onClickCapture}
>
<svg <svg
className="kx-canvas__svg" className="kx-canvas__svg"
viewBox={`${-PAD} ${-PAD} ${hw + PAD * 2} ${hh + PAD * 2}`} viewBox={`${-PAD} ${-PAD} ${hw + PAD * 2} ${hh + PAD * 2}`}

View File

@ -3,6 +3,12 @@
transition: transform 0.12s ease; transition: transform 0.12s ease;
max-width: 100%; max-width: 100%;
max-height: 100%; max-height: 100%;
cursor: grab;
touch-action: none; /* 포인터 드래그 이동 — 브라우저 제스처 가로채기 방지 */
}
.kx-canvas.is-panning {
transition: none; /* 드래그 중 지연 제거 */
cursor: grabbing;
} }
.kx-canvas__svg { .kx-canvas__svg {
width: min(900px, 100%); width: min(900px, 100%);

View File

@ -81,13 +81,13 @@ function periodLabel(start: string, end: string): string {
/** 실 API ExhibitionDto → 화면 ScheduleEvent 매핑. DB 미포함 필드(카테고리·홀·인원)는 기본값. */ /** 실 API ExhibitionDto → 화면 ScheduleEvent 매핑. DB 미포함 필드(카테고리·홀·인원)는 기본값. */
function toScheduleEvent(e: ExhibitionDto, i: number): ScheduleEvent { function toScheduleEvent(e: ExhibitionDto, i: number): ScheduleEvent {
const category = (KNOWN_CATEGORIES.has(e.category as EventCategory) const known = KNOWN_CATEGORIES.has(e.category as EventCategory);
? (e.category as EventCategory) const category = (known ? (e.category as EventCategory) : 'exhibition') as EventCategory;
: 'exhibition') as EventCategory;
return { return {
id: e.id, id: e.id,
title: e.name, title: e.name,
category, category,
categoryDefaulted: !known,
status: statusFromDates(e.startDate, e.endDate), status: statusFromDates(e.startDate, e.endDate),
period: periodLabel(e.startDate, e.endDate), period: periodLabel(e.startDate, e.endDate),
start: e.startDate, start: e.startDate,
@ -278,7 +278,17 @@ export function ExhibitionSchedulePage() {
<h2 className="kx-evcard__title">{e.title}</h2> <h2 className="kx-evcard__title">{e.title}</h2>
<span className={`kx-evstatus is-${e.status}`}>{t(`schedule.status.${e.status}`)}</span> <span className={`kx-evstatus is-${e.status}`}>{t(`schedule.status.${e.status}`)}</span>
</div> </div>
<p className="kx-evcard__cat">{t('schedule.catExhibit', { cat: t(`schedule.cat.${e.category}`) })}</p> <p className="kx-evcard__cat">
{t('schedule.catExhibit', { cat: t(`schedule.cat.${e.category}`) })}
{e.categoryDefaulted && (
<span
className="kx-evcard__cat-default"
title={t('schedule.catDefaultedTip', { defaultValue: '행사 분류 미지정 — 기본값(전시)으로 표시' })}
>
{t('schedule.catDefaulted', { defaultValue: '기본값' })}
</span>
)}
</p>
<ul className="kx-evcard__meta"> <ul className="kx-evcard__meta">
<li aria-label={t('schedule.period')}><IconCalendar size={14} /> <span className="tnum">{e.period}</span></li> <li aria-label={t('schedule.period')}><IconCalendar size={14} /> <span className="tnum">{e.period}</span></li>
<li aria-label={t('schedule.assignedHall')}><IconGrid size={14} /> {e.halls}</li> <li aria-label={t('schedule.assignedHall')}><IconGrid size={14} /> {e.halls}</li>

View File

@ -16,6 +16,8 @@ export interface ScheduleEvent {
id: string; id: string;
title: string; title: string;
category: EventCategory; category: EventCategory;
/** category 가 DB 실값이 아니라 기본값('exhibition')으로 대체됐는지(R15-02 시각 표기용). */
categoryDefaulted?: boolean;
status: EventStatus; status: EventStatus;
period: string; // "2026.09.0509.08" period: string; // "2026.09.0509.08"
start: string; // "2026-09-05" start: string; // "2026-09-05"

View File

@ -101,6 +101,18 @@
font-size: var(--fs-caption); font-size: var(--fs-caption);
color: var(--color-neutral-500); color: var(--color-neutral-500);
} }
.kx-evcard__cat-default {
display: inline-block;
margin-left: var(--space-1);
padding: 0 6px;
border-radius: 999px;
font-size: var(--fs-micro);
line-height: 1.6;
color: var(--color-neutral-500);
background: var(--color-neutral-100);
border: 1px solid var(--color-neutral-200);
vertical-align: middle;
}
.kx-evcard__meta { .kx-evcard__meta {
list-style: none; list-style: none;
margin: var(--space-1) 0; margin: var(--space-1) 0;

View File

@ -1,9 +1,21 @@
import type { ComponentType } from 'react';
import { AiImage } from '../../components/ui/AiImage'; import { AiImage } from '../../components/ui/AiImage';
import { AiLabel, DdayChip, RoleBadge, StatusBadge, type FlowStatus } from '../../components/ui/Badge'; import { AiLabel, DdayChip, RoleBadge, StatusBadge, type FlowStatus } from '../../components/ui/Badge';
import { Button } from '../../components/ui/Button'; import { Button } from '../../components/ui/Button';
import { EmptyState, ErrorState, Skeleton } from '../../components/ui/States'; import { EmptyState, ErrorState, Skeleton } from '../../components/ui/States';
import * as Icons from '../../components/ui/icons';
import type { IconProps } from '../../components/ui/icons';
import './styleguide.css'; import './styleguide.css';
/*
* SCR-17 §9 "시스템 아이콘 라이브러리" components/ui/icons.tsx SVG .
* import / ( ).
*/
const ICON_ENTRIES = (Object.entries(Icons) as [string, unknown][])
.filter(([name, val]) => name.startsWith('Icon') && typeof val === 'function')
.sort((a, b) => a[0].localeCompare(b[0]))
.map(([name, comp]) => [name.replace(/^Icon/, ''), comp as ComponentType<IconProps>] as const);
/* /*
* SCR-17 (§1 / ). * SCR-17 (§1 / ).
* (/_styleguide) . · design.md §1(tokens.css). * (/_styleguide) . · design.md §1(tokens.css).
@ -192,6 +204,22 @@ export function ComponentGuidePage() {
</div> </div>
</div> </div>
</section> </section>
{/* 8. 시스템 아이콘 라이브러리 (R17-01 · SCR-17 스펙 9항목) */}
<section className="kx-sg-card kx-sg-card--wide" data-accent="primary">
<h2 className="kx-sg-card__title"> </h2>
<p className="kx-sg-card__note">
components/ui/icons.tsx SVG · fill:none / stroke:currentColor · size . {ICON_ENTRIES.length}.
</p>
<ul className="kx-sg__icons">
{ICON_ENTRIES.map(([name, Comp]) => (
<li key={name} className="kx-sg__icon-cell">
<Comp size={22} aria-hidden="true" />
<span className="kx-sg__icon-name">{name}</span>
</li>
))}
</ul>
</section>
</div> </div>
</div> </div>
); );

View File

@ -276,6 +276,36 @@
justify-content: center; justify-content: center;
} }
/* 8. 시스템 아이콘 라이브러리 */
.kx-sg-card--wide {
grid-column: 1 / -1;
}
.kx-sg__icons {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
gap: var(--space-3);
}
.kx-sg__icon-cell {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-2);
border: var(--border-card);
border-radius: var(--radius-md);
color: var(--color-neutral-700, var(--color-neutral-900));
background: var(--color-neutral-50, #fff);
}
.kx-sg__icon-name {
font-size: var(--fs-micro);
color: var(--color-neutral-500);
text-align: center;
word-break: break-word;
}
@media (max-width: 1000px) { @media (max-width: 1000px) {
.kx-sg__grid, .kx-sg__grid,
.kx-sg__form, .kx-sg__form,

View File

@ -2,7 +2,8 @@
* SCR-45 (meeting). 참조: UIWS meeting/MeetingDetailPage. * SCR-45 (meeting). 참조: UIWS meeting/MeetingDetailPage.
* : 회의 / : 상세(· ·). * : 회의 / : 상세(· ·).
* : /api/work/meetings (get·create·minutes·actions·action status). * : /api/work/meetings (get·create·minutes·actions·action status).
* : 녹음 ·STT ·AI ·Jasper PDF UI는 disabled+. 07_work_api_gaps.md . * STT ·AI (G-06 , 2026-07-14) MeetingAiPanel(STT)
* MeetingController/MeetingSttClient/MeetingMinutesGenerator + V52 meeting_transcript. Jasper PDF는 .
*/ */
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';

View File

@ -32,7 +32,7 @@ const PERIODS: { v: Period; l: string }[] = [
{ v: 'QUARTERLY', l: '분기' }, { v: 'QUARTERLY', l: '분기' },
{ v: 'YEARLY', l: '연간' }, { v: 'YEARLY', l: '연간' },
]; ];
const BAR_COLORS = [CHART.primary600, CHART.primary700, CHART.aiAccent, CHART.success, CHART.warning, CHART.slate]; const BAR_COLORS = [CHART.primary600, CHART.primary700, CHART.aiAccent, CHART.success, CHART.violationWarn, CHART.slate];
function iso(d: Date): string { function iso(d: Date): string {
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;