harness/plugins/zio-harness/knowledge/kintex/docs/analysis/reroomai-source.md
DESKTOP-TKLFCPR\ython 1ef2235939 feat(zio-harness): v1.1.0 — auto source analysis + GUARDiA/KINTEX knowledge base
- SessionStart hook (scripts/graphify_setup.py): auto-install graphifyy[sql],
  build knowledge graph on first run (graphify extract --code-only, local AST),
  incremental graphify update thereafter — install-only smartness
- knowledge/kintex/: all 183 KINTEX md docs bundled (planning/design/analysis)
- knowledge/guardia/: distilled GUARDiA-wide knowledge from 2,483 md files
  (solutions-catalog, standard-framework, operations-cicd, lessons-learned;
  credentials/IP-free curated)
- SKILL.md: graph-first codebase query rules + knowledge base loading guide

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 23:15:35 +09:00

180 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ReRoomAI 소스코드 분석
> 분석일: 2026-07-11 · 대상: `C:\GUARDiA\workspace\ReRoomAI` — AI 공간 인테리어 리디자인 웹 서비스
> 목적: 킨텍스 전시 부스 "시공 후 결과 사진 생성 AI" 시스템(PLANNING §6 나노바나나 파이프라인)의 구조보존 제어 파라미터 확정
> 연계: PLANNING.md R11 / BACKLOG B-11 해소 근거 문서
---
## 1. 프로젝트 개요
**ReRoom AI**는 방 사진 한 장을 업로드하고 공간 유형·인테리어 스타일을 선택하면 약 10초 만에 새로운 분위기의 방으로 재렌더링하는 AI 인테리어 리디자인 웹 서비스다.
핵심 설계 철학은 **"건축학적 뼈대 보존 + 표면 요소 교체"**. 원본 방의 벽·창문·문·천장·**카메라 시야 구도(perspective)**는 그대로 유지하고 가구·조명·색감·장식만 선택한 테마로 바꾼다. 이것이 킨텍스 부스 시스템에 이식할 가장 중요한 개념 — "빈 부스 공간 골격은 유지하고 그 안에 배치·인테리어·조명·배선만 시공된 결과를 합성"과 동일한 문제 구조다.
주요 기능:
- 6가지 공간 유형(거실/침실/주방/욕실/서재/원룸) × 8가지 스타일(모던/미니멀/북유럽/인더스트리얼/재팬디/미드센추리/한옥/호텔라운지)
- **이중 API 모드**: 데모 모드(서버 키, 브라우저 로컬 2회 + IP당 하루 10회 제한) / BYOK 모드(사용자 개인 키, 무제한)
- **Before/After 드래그 비교 슬라이더**(마우스·터치·키보드 지원)
- 결과 PNG 다운로드 + "다른 스타일로 다시 디자인"(원본 재업로드 없이 연속 실험)
- 클라이언트 Canvas 전처리(긴 쪽 1024px 다운스케일)
---
## 2. 기술 스택
| 레이어 | 기술 |
|--------|------|
| 프레임워크 | **Next.js 16.2.10** (App Router, Node runtime) — 단일 리포 서버리스, Vercel 배포 지향 |
| 언어 | TypeScript 5 |
| UI | React 19.2.4 |
| 스타일 | Tailwind CSS v4 (`@theme` 커스텀 토큰), Pretendard + Noto Serif KR (`next/font`) |
| **AI SDK** | **`@google/genai` ^2.10.0** (Google 공식 SDK) |
| **모델** | **`gemini-3.1-flash-image-preview`** (= 나노바나나 2 / Nano Banana 2) |
| 의존성 | 극히 단순 — `@google/genai`, `next`, `react`, `react-dom` **4개뿐** |
> 주목: `AGENTS.md`에 "이 Next.js는 학습 데이터와 다르다, 코드 작성 전 `node_modules/next/dist/docs/` 가이드를 읽으라"는 경고. Next 16 신버전이라 관례가 다를 수 있음.
---
## 3. 디렉터리 구조
```
ReRoomAI/
├── app/
│ ├── layout.tsx # 폰트·메타데이터·OG
│ ├── page.tsx # 섹션 조립: Header→Hero→StyleGallery→HowItWorks→Studio→Faq→Footer
│ ├── globals.css # 디자인 토큰(@theme)·그레인/리빌
│ └── api/generate/route.ts # ★ Gemini 이미지 생성 라우트(IP 레이트리밋 포함) — 시스템의 심장
├── components/
│ ├── Studio.tsx # ★ 메인 인터랙션(업로드·옵션·생성·결과) — 클라이언트 플로우 전체
│ ├── CompareSlider.tsx # ★ Before/After 슬라이더(clip-path + 포인터캡처)
│ ├── Header/Hero/StyleGallery/StyleCards/HowItWorks/Faq/Footer.tsx # 랜딩 섹션
│ └── Reveal.tsx # 스크롤 리빌 래퍼
├── lib/
│ ├── constants.ts # ★ 공간유형·스타일 정의 (UI와 서버 프롬프트 단일 출처)
│ └── useLocalStorage.ts # SSR 안전 localStorage 훅
├── .env.example # GEMINI_API_KEY
└── package.json
```
핵심 파일 4개: `app/api/generate/route.ts`(백엔드 생성), `lib/constants.ts`(프롬프트 사전), `components/Studio.tsx`(클라이언트 플로우), `components/CompareSlider.tsx`(결과 비교 UI).
---
## 4. AI / 이미지 생성 파이프라인 ★
### 사용 모델·API
- **Google Gemini `gemini-3.1-flash-image-preview`(나노바나나 2)** 를 `@google/genai` 공식 SDK의 `ai.models.generateContent()`로 호출.
- **입력 이미지 + 텍스트 지시문을 함께 전달**하는 멀티모달 image-to-image(인페인팅형 편집). Stable Diffusion·ControlNet 등 미사용 — 순수 Gemini 이미지 모델 단일 호출로 원본 구조를 참조·보존.
### 이미지 흐름 (입력 → 변환 → 결과)
```
[클라이언트 Studio.tsx]
1. 파일 업로드(드래그앤드롭/클릭) — image/* 검증, 10MB 상한
2. Canvas 전처리: 긴 쪽 1024px 다운스케일 → canvas.toDataURL('image/jpeg', 0.85) → base64 data URL (전송량·비용 절감 핵심)
3. POST /api/generate { image(base64), roomTypeId, styleId, byokKey }
[서버 route.ts — runtime='nodejs', maxDuration=60]
4. content-length 8MB 가드 → JSON 파싱 → roomType/style 유효성 검증
5. API 키 결정: BYOK 우선, 없으면 process.env.GEMINI_API_KEY
6. 데모 모드면 IP당 일일 제한(Map 인메모리) 체크
7. data URL에서 mimeType + base64 분리(정규식), 8MB*1.33 재검증
8. 프롬프트 조립 → Gemini generateContent 호출
9. 응답 candidate에서 inlineData(생성 이미지 base64) 추출
- finishReason==='SAFETY' → 차단 에러
- 성공 시에만 IP 카운트 차감(실패는 횟수 소모 안 함)
10. { image: base64 } 반환
[클라이언트]
11. `data:image/png;base64,${data.image}`로 resultImage 세팅
12. CompareSlider에 before(업로드)·after(결과) 주입
```
### 프롬프트 구성 방식 (★ 가장 차용 가치 높음)
**구조화된 사전(dictionary) 조각을 템플릿에 조립**. `lib/constants.ts`가 UI 라벨(한글)과 프롬프트 조각(영문)을 한 객체에 묶어 **UI 선택과 서버 프롬프트가 단일 출처 공유**:
```ts
// 공간 유형: { id, label(한글), prompt(영문) }
{ id: "living_room", label: "거실", prompt: "living room" }
// 스타일: { id, label, desc, swatch(색3종), prompt(상세 지시문) }
{ id: "modern", label: "모던", swatch:["#2b2b2e",...],
prompt: "sleek modern style: clean lines, neutral palette with charcoal and greige,
low-profile furniture, matte finishes, statement lighting" }
```
최종 지시문 템플릿(route.ts:106):
```
Redesign this {roomType.prompt} interior in {style.prompt}.
Keep the room architecture — walls, windows, doors, ceiling and camera perspective — exactly the same.
Replace furniture, lighting, color palette and decor to match the target style.
Photorealistic interior photography, natural lighting, high detail.
```
프롬프트 4단 구성: **① 대상+스타일 지정 → ② "보존할 것" 명시적 잠금(architecture/perspective) → ③ "교체할 것" 명시 → ④ 사진 품질 지시(photorealistic/natural lighting/high detail)**. 이 "보존/교체 명시적 분리" 패턴이 부스 시스템의 핵심.
---
## 5. 킨텍스 부스 시스템 차용 패턴 ★★★
(전시 부스 배치·인테리어·전기·조명·네트워크 배선 자동화 → 나노바나나 시공 후 결과 사진)
**(A) 모델·SDK 선택 — 검증된 정답 그대로 채택**
- `@google/genai` + `gemini-3.1-flash-image-preview`, `generateContent``{ inlineData:{mimeType,data} }`(입력 이미지) + `{ text: instruction }`(지시문)을 `parts` 배열로 전달하는 호출 형태 복제. `nanobanana-visualize` 스킬이 이 호출 패턴을 표준화.
**(B) "보존/교체 명시적 분리" 프롬프트 아키텍처 — 부스 도메인 치환**
- ReRoom "walls·windows·ceiling·camera perspective exactly same" → 부스 **"부스 외곽 치수·기둥·바닥 트렌치 그리드·천장 트러스·통로 방향·카메라 앵글 유지"**.
- ReRoom "furniture·lighting·color·decor 교체" → 부스 **"집기(데스크·선반·배너·사이니지)·조명 기구·전기 콘센트·네트워크 AP·카펫/부스 벽면 그래픽 배치"**.
- **구조화 사전 재사용**: `ROOM_TYPES`/`STYLES` → 부스 도메인 사전
- `BOOTH_TYPES`(독립/조립/코너/아일랜드, 3×3·6×3…)
- `BOOTH_STYLES`(럭셔리/테크/친환경/미니멀…)
- `FIXTURE_LAYERS`(조명 레이어·전기 배선 레이어·네트워크 배선 레이어) — **레이어별 프롬프트 조각** 조립로 "조명만 야간 연출"(S2)·"배선 오버레이"(S6) 변형 렌더.
- 각 객체가 `{ id, label(한글), prompt(영문), swatch }`를 갖고 **UI 선택 ↔ 서버 프롬프트 단일 출처 공유** 유지 시 유지보수 비용 급감.
**(C) Before/After 비교 슬라이더(`CompareSlider.tsx`) — 거의 무수정 재사용**
- `clip-path: inset(0 {100-pos}% 0 0)`로 After 레이어 클립 → 리사이즈에도 픽셀 정렬 유지. 포인터 캡처 + 키보드(방향키·Shift 큰 스텝) + ARIA slider 접근성 완비 자립 컴포넌트. design.md S5(시공 전 빈 부스 ↔ 시공 후 렌더)에 그대로 투입. React/Next 스택이면 파일 복사 수준.
**(D) 클라이언트 Canvas 전처리(`Studio.handleImageFile`)**
- 긴 쪽 1024px 다운스케일 + JPEG 0.85 → base64. 전송량·모델 비용·응답시간 동시 절감 필수 전처리. 부스 도면/현장 사진 동일 적용.
**(E) API 라우트 방어 로직 — 프로덕션 안정성 템플릿**
- 다층 크기 가드(content-length 8MB → base64 ×1.33 재검증), `finishReason==='SAFETY'` 처리, **에러 분기**(API_KEY_INVALID / RESOURCE_EXHAUSTED·quota·429 / SAFETY)로 친화적 한글 메시지. **성공 시에만 사용량 차감**. 부스 API(RenderJob 워커)의 골격으로 복제.
**(F) 이중 키 모드(데모/BYOK) + IP 레이트리밋**
- 서버 인메모리 `Map<ip,{count,resetAt}>` 24h 윈도우. 전시회 현장 태블릿 데모 노출에 유용. **인메모리라 재시작·다중 인스턴스 취약** → 우리 시스템은 PostgreSQL/Redis 기반 RenderJob 쿼터로 대체(PLANNING §6-4 비용 제어와 통합).
**(G) 단계별 로딩 UX**
- `LOADING_STATUSES`("공간 구조 분석 → 스타일 요소 배치 → 조명·색상 튜닝 → 최종 고화질 렌더링") 2.5초 순환. 부스용 "부스 골격 인식 → 집기 배치 → 전기·조명 배선 → 최종 렌더링"으로 치환. design.md 진행 배지("생성 중… 평균 40초")와 연결.
---
## 6. UI / 화면 구성
단일 페이지(랜딩) 서비스. `page.tsx` 세로 조립: Header → Hero(CompareSlider LCP priority) → StyleGallery(카드 클릭 시 `window` 커스텀이벤트 `reroom:style`로 Studio 전달) → HowItWorks → **Studio ★** → Faq → Footer.
**Studio 흐름**(단일 컴포넌트가 입력→로딩→결과 3상태 조건부 렌더):
1. **입력** — 좌: `01 원본 업로드`(드래그존+미리보기), 우: `02 공간 유형`(pill), `03 스타일`(스와치 카드). 하단: BYOK 토글+키, 에러 alert, "생성하기".
2. **로딩** — 바운스 도트 + 순환 상태 텍스트(`aria-live`) + "약 10초".
3. **결과** — "Redesign Complete" 배지 + CompareSlider + [PNG 다운로드]/[다른 스타일]/[다른 사진].
상태 전부 로컬 `useState` + `useLocalStorage`(무료횟수·BYOK·키 영속). 전역 스토어·라우팅 없음 — 극경량 단일화면 SPA. 부스 초기 PoC도 이 패턴으로 빠르게 구현 후 확장 가능.
---
## 7. 설계 착수 3대 차용 결론
1. **호출 스택 그대로**: `@google/genai``gemini-3.1-flash-image-preview`, 입력이미지(inlineData)+지시문(text) parts 전달 image-to-image 편집. `route.ts`가 프로덕션 API 골격 템플릿.
2. **프롬프트 = 구조화 사전 조립 + 보존/교체 명시 분리**: `constants.ts` `{id,label,prompt}`를 부스 도메인(부스타입·스타일·조명/전기/네트워크 레이어)으로 치환, "골격·앵글 유지 / 집기·배선·조명 배치" 명시 잠금 템플릿.
3. **CompareSlider·Canvas 전처리·단계별 로딩 UX** 파일 복사 수준 재사용(React/Next 전제).
---
## 8. ★ 보안 결정 필요 사항 (선행)
나노바나나(Gemini) 이미지 생성은 **외부 API 호출**이다. GUARDiA 보안 제약(루트 CLAUDE.md)상 외부 API는 원칙 금지이며 현재 승인된 예외는 `api.anthropic.com`뿐 — **Gemini(generativelanguage.googleapis.com)는 미승인**. 단, 본 kintex 프로젝트는 GUARDiA ITSM(관공서 인프라 관제)과 별개 도메인의 독립 저장소(`zio/kintex`)이며, PLANNING v1.0과 사용자 요구가 명시적으로 나노바나나를 채택하고 있다.
**조치**: 부스 M5 파이프라인 구현 착수 전 소유자에게 **Gemini 외부 호출 승인 여부**를 확정한다. 승인 시 `GEMINI_API_KEY`를 서버 env로만 로드(코드·DB·커밋·로그·응답 기록 금지, ReRoomAI (E) 방어 패턴 준수). 미승인 시 대안 — 온프레미스 이미지 생성(SDXL 등) 어댑터로 폴백하되 image-to-image 구조보존 품질은 재평가 필요.