IT의 IT 블로그
사이드 프로젝트 소개 | 셀프 인테리어 가이드 본문
안녕하세요.
이번 글에서는 제가 진행한 사이드 프로젝트인
self-interior-guide를 소개해보려고 합니다.
이 프로젝트는
셀프 인테리어를 처음 시작하는 사용자를 위한
“가이드 + 견적” 웹 서비스입니다.
단순히 인테리어 정보를 나열하는 것이 아니라,
실제로 사용자가 참고하면서 진행할 수 있도록
체크리스트형 UX로 설계한 것이 핵심입니다.
아래 링크에서 실제 서비스와 코드를 함께 확인하실 수 있습니다.

🔗 서비스 바로가기
https://self-interior-guide.vercel.app
🔗 GitHub
https://github.com/Ryuintae/self-interior-guide
1. 왜 이 프로젝트를 만들었는가
셀프 인테리어를 처음 시작하면 대부분 이런 문제를 겪습니다.
- 무엇부터 해야 할지 모르겠음
- 순서를 몰라 시행착오가 많음
- 정보가 많지만 오히려 더 혼란스러움
기존 콘텐츠는 대부분 “정보 제공”에 집중되어 있고,
실제로 따라가면서 사용할 수 있는 구조는 부족하다고 느꼈습니다.
그래서 단순한 정보 전달이 아니라,
💡 **“실제로 참고하면서 진행할 수 있는 구조”**를 만들고자 했습니다.
2. 기존 방식의 한계
일반적인 인테리어 가이드는 대부분 다음과 같은 구조를 가지고 있습니다.
❌ 단계형 튜토리얼
- 1 → 2 → 3 → 4 순서 강제
- 모든 단계를 완료해야 한다는 부담
- 필요한 정보만 선택적으로 보기 어려움
하지만 실제 사용자는 모든 단계를 그대로 따르지 않습니다.
상황에 따라 필요한 부분만 참고하고
순서도 유동적으로 바뀌는 경우가 많습니다.
3. 해결 방식: 체크리스트형 UX

이 프로젝트의 핵심은 하나입니다.
✅ “완료”가 아니라 “확인”
- 단계 완료 ❌
- 체크 기반 확인 ✅
즉,
- “다음 단계로 진행하세요” → ❌
- “이 항목은 확인했나요?” → ✅
이 기준으로 UX 전체를 설계했습니다.
4. UX 설계 핵심
이 프로젝트에서 가장 중요하게 본 것은
사용자의 부담을 줄이는 구조입니다.
4.1 진행률 제거
일반적으로 많이 사용하는 진행률(%), 단계 완료 개념을 제거했습니다.
진행률은 사용자에게 “끝까지 해야 한다”는 압박을 주기 때문입니다.
4.2 체크 UI 위치 변경


초기에는 체크 UI를 상단에 배치했지만,
현재는 하단으로 이동시켰습니다.
- 상단: 바로 행동 유도 → 부담
- 하단: 내용 확인 → 체크
💡 “읽기 → 이해 → 체크” 흐름으로 변경했습니다.
4.3 ResultPage 재정의

보통 ResultPage는 “완료 화면”입니다.
하지만 이 프로젝트에서는
💡 전체 체크리스트를 다시 확인하는 화면으로 설계했습니다.
- 내가 확인한 항목
- 아직 보지 않은 항목
- 다시 보고 싶은 항목
을 정리하고,
자연스럽게 견적 페이지로 이동하도록 구성했습니다.
4.4 EstimatePage UX (행동으로 연결)

가이드에서 끝나는 것이 아니라,
사용자가 실제로 다음 행동을 할 수 있도록
견적 페이지로 흐름을 연결했습니다.
EstimatePage는 단순 입력폼이 아니라,
선택한 옵션을 시각적으로 확인하면서 견적을 비교할 수 있는 구조입니다.
- 공간 타입 선택
- 벽 / 바닥 / 가구 색상 변경
- 선택값에 따른 예상 견적 범위 표시
특히 중요한 포인트는
상태 변경 → 3D 화면 즉시 반영
이라는 흐름입니다.
사용자는 단순히 값을 입력하는 것이 아니라,
- 직접 보고
- 비교하고
- 선택할 수 있습니다
즉,
💡 정보 확인 → 상태 정리 → 실제 행동(견적)
으로 이어지는 UX 흐름을 만들고자 했습니다.
5. 페이지 구조
전체 흐름은 다음과 같습니다.
Home
→ GuideStart
→ GuideStep
→ GuideResult
→ Estimate
각 페이지의 역할은 다음과 같습니다.
- HomePage: 서비스 소개 및 진입
- GuideStartPage: 사용자 조건 선택
- GuideStepPage: 가이드 내용 확인
- GuideResultPage: 전체 체크 상태 정리
- EstimatePage: 3D 기반 견적 확인
이 구조의 핵심은
강제 흐름이 아니라 자유 탐색 구조라는 점입니다.
6. 프로젝트 구조
이 프로젝트는 단순히 페이지를 나열하는 구조가 아니라,
역할과 도메인 기준으로 분리된 구조로 설계했습니다.
실제 src 구조는 다음과 같습니다.
src
├─ index.css
├─ main.tsx
├─ vite-env.d.ts
│
├─ app
│ ├─ RootLayout.tsx
│ └─ router.tsx
│
├─ assets
│ ├─ hero.png
│ ├─ react.svg
│ └─ vite.svg
│
├─ features
│ ├─ configurator
│ │ ├─ components
│ │ │ ├─ RoomCanvas.tsx
│ │ │ └─ RoomScene.tsx
│ │ └─ store
│ │ └─ useConfiguratorStore.ts
│ │
│ ├─ estimate
│ │ ├─ data
│ │ │ └─ estimateData.ts
│ │ └─ types
│ │ └─ estimate.ts
│ │
│ └─ guide
│ ├─ data
│ │ ├─ guideData.ts
│ │ └─ guideRecommendations.ts
│ ├─ store
│ │ └─ useGuideStore.ts
│ └─ types
│ └─ guide.ts
│
├─ pages
│ ├─ HomePage.tsx
│ ├─ GuideStartPage.tsx
│ ├─ GuideStepPage.tsx
│ ├─ GuideResultPage.tsx
│ └─ EstimatePage.tsx
│
└─ shared
└─ ui
├─ PageShell.tsx
├─ ProgressBar.tsx
├─ ScrollToTop.tsx
└─ SectionCard.tsx
6.1 구조 설계 기준
이 프로젝트 구조는 다음 기준으로 나눴습니다.
- app → 앱 전체 구조 (라우팅, 레이아웃)
- features → 기능/도메인 단위
- pages → 실제 화면 단위
- shared/ui → 공통 UI 컴포넌트
즉,
“화면”이 아니라 “역할” 기준으로 분리한 구조입니다.
6.2 app: 앱 진입 구조
- router.tsx: 전체 라우팅 정의
- RootLayout.tsx: 공통 레이아웃
이 영역은 앱의 흐름을 담당합니다.
이 프로젝트는
- 가이드
- 결과
- 견적
처럼 페이지 간 이동이 많기 때문에,
라우팅 구조 자체가 UX 흐름과 연결되는 구조입니다.
6.3 features: 도메인 중심 구조
이 프로젝트에서 가장 중요한 설계 포인트입니다.
왜 features로 나눴는가?
처음에는 pages 중심으로도 구현할 수 있지만,
기능이 커질수록 아래 문제가 발생합니다.
- 상태와 UI가 섞임
- 데이터와 로직이 뒤엉킴
- 유지보수 어려움
그래서 다음 기준으로 분리했습니다.
“기능 단위로 묶는다”
6.3.1 guide (핵심 도메인)
guide
├─ data
├─ store
└─ types
이 프로젝트의 핵심 기능입니다.
- guideData.ts → 가이드 콘텐츠
- guideRecommendations.ts → 추천 로직
- useGuideStore.ts → 상태 관리
- guide.ts → 타입 정의
UI / 상태 / 데이터 / 타입을 분리한 구조
이 구조 덕분에
- 데이터 수정
- 상태 변경
- UI 변경
이 서로 영향을 덜 받도록 만들 수 있습니다.
6.3.2 estimate (견적 계산 영역)
estimate
├─ data
└─ types
이 영역은
견적 계산 기준을 담당합니다.
- 옵션별 가격
- 공간별 비용
- 계산 로직 기준
UI와 분리했기 때문에
나중에 계산 방식이 바뀌어도 영향 범위를 줄일 수 있습니다.
6.3.3 configurator (3D 영역)
configurator
├─ components
└─ store
이 영역은
3D 시각화 + 사용자 인터랙션을 담당합니다.
- RoomCanvas → 렌더링 영역
- RoomScene → 실제 공간 구성
- useConfiguratorStore → 상태 관리
특히
Canvas와 Scene을 분리한 구조
는 중요한 포인트입니다.
- Canvas → 렌더링 환경
- Scene → 오브젝트 구성
6.4 pages: 사용자 화면 단위
pages
├─ HomePage
├─ GuideStartPage
├─ GuideStepPage
├─ GuideResultPage
└─ EstimatePage
이 폴더는 단순 화면 모음이 아니라,
사용자 흐름을 구성하는 레이어입니다.
- Home → 진입
- Guide → 정보 탐색
- Result → 상태 확인
- Estimate → 행동
즉,
페이지 = UX 흐름 단위
6.5 shared/ui: 공통 UI
shared/ui
├─ PageShell
├─ SectionCard
├─ ScrollToTop
└─ ProgressBar
이 영역은 UI 일관성을 담당합니다.
주요 역할
- PageShell → 페이지 구조 통일
- SectionCard → 카드 UI 통일
- ScrollToTop → UX 개선
- ProgressBar → 초기 UX 실험 흔적
특히 SectionCard는
가이드, 옵션, 설명을 같은 톤으로 묶어주는 핵심 컴포넌트입니다.
6.6 구조 설계에서 중요했던 포인트
이 구조에서 중요하게 본 것은 다음입니다.
1) 역할 분리
- UI / 상태 / 데이터 / 타입 분리
2) 도메인 중심 설계
- guide / estimate / configurator
3) 확장성
- API 연동 가능 구조
- 기능 추가 시 영향 최소화
6.7 정리
이 프로젝트 구조는 단순한 파일 분리가 아니라,
가이드 UX, 상태 관리, 3D 견적 기능을 명확히 분리하여
확장성과 유지보수를 고려한 구조로 설계한 것입니다.
결국 느낀 점은,
작은 프로젝트라도 구조를 어떻게 잡느냐에 따라
이후의 확장성과 유지보수 난이도가 크게 달라진다는 것입니다.
7. 기술 스택과 선택 이유
이 프로젝트는 단순 UI 구현이 아니라
UX 흐름, 상태 관리, 3D 인터랙션까지 포함되어 있기 때문에
각 역할에 맞게 기술을 선택했습니다.
7.1 React + TypeScript
- React
- TypeScript
이 프로젝트는 페이지 흐름이 많고, 상태 변화도 다양한 구조입니다.
단순 정적인 페이지가 아니라
가이드 → 체크 상태 → 견적 → 3D 반영까지 이어지는 구조이기 때문에
컴포넌트 기반 구조와 상태 흐름 관리가 중요한 프로젝트였습니다.
React를 선택한 이유는 다음과 같습니다.
- 컴포넌트 단위로 UI를 분리하기 용이
- 상태 기반 렌더링 구조
- 생태계가 풍부
TypeScript를 사용한 이유는
- 가이드 데이터 구조 관리
- 상태 구조 안정성 확보
- 확장 시 오류 방지
특히 이 프로젝트는
guideData, estimateData, 상태 구조 등이 명확해야 하기 때문에
타입 안정성이 중요했습니다.
7.2 Vite
이 프로젝트는 Vite를 사용해 개발 환경을 구성했습니다.
이유는 단순합니다.
개발 속도와 DX(개발 경험)
- 빠른 dev server 실행
- 즉각적인 HMR
- 설정이 단순함
이 프로젝트는 UI를 계속 수정하고 실험하는 과정이 많기 때문에
빌드 속도보다 개발 반복 속도가 더 중요했습니다.
또한 Vite는
▶ 개발 환경에서는 ESM 기반
▶ 빌드 시에는 Rollup 사용
이라는 구조이기 때문에
최근 프론트엔드 환경에도 잘 맞는 선택이라고 판단했습니다.
7.3 Zustand (상태 관리)
이 프로젝트에서는 Redux 대신 Zustand를 사용했습니다.
이유는 다음과 같습니다.
- 보일러플레이트가 적음
- 직관적인 상태 관리
- 작은 프로젝트에서도 과하지 않음
특히 이 프로젝트의 핵심 상태는 다음과 같습니다.
- 가이드 선택 값
- 체크 상태
- 시나리오별 상태 분리
- 견적 옵션 상태
이 구조는 전역 상태가 필요하지만,
Redux처럼 복잡한 구조까지는 필요하지 않았습니다.
그래서
▶ 가볍지만 확장 가능한 상태 관리 도구
로 Zustand를 선택했습니다.
7.4 React Router
이 프로젝트는 사용자 흐름이 중요한 구조입니다.
- Home → Guide → Step → Result → Estimate
단순 페이지 이동이 아니라
UX 흐름 자체가 중요한 프로젝트이기 때문에
라우팅 구조가 명확해야 했습니다.
React Router를 사용한 이유는
- 선언적인 라우팅
- 동적 라우트 지원 (/step/:stepId)
- SPA 구조에 적합
7.5 Tailwind CSS
스타일링은 Tailwind CSS를 사용했습니다.
이유는 다음과 같습니다.
- 빠른 UI 구현
- 일관된 디자인 시스템 유지
- 커스터마이징 용이
이 프로젝트는 카드 UI, 체크리스트 UI, 옵션 UI 등
비슷한 패턴이 반복되는 구조입니다.
Tailwind를 사용하면
✅ 클래스 기반으로 빠르게 UI를 조합할 수 있고
✅ 디자인 일관성을 유지하기 쉽습니다.
7.6 Three.js + React Three Fiber
이 프로젝트에서 가장 특징적인 부분은
3D 기반 견적 UI입니다.
이를 위해 다음을 사용했습니다.
- Three.js
- React Three Fiber
- @react-three/drei
왜 3D를 사용했는가
단순 견적 입력폼이 아니라,
사용자가 공간을 “보면서” 선택할 수 있도록 하기 위해서입니다.
- 벽 색상 변경
- 바닥 색상 변경
- 가구 색상 변경
이러한 선택을 숫자가 아니라
시각적으로 확인할 수 있도록 설계했습니다.
React Three Fiber를 선택한 이유
- React 방식으로 3D 구성 가능
- 상태와 3D를 자연스럽게 연결
- 컴포넌트 단위로 Scene 구성 가능
예를 들어:
- 상태 변경 → 3D 반영
- 선택 값 → 즉시 시각화
이 흐름을 자연스럽게 구현할 수 있습니다.
7.7 정리
이 프로젝트의 기술 스택은 단순히 최신 기술을 사용한 것이 아니라,
각 역할에 맞게 선택했습니다.
- React → UI 구조
- Zustand → 상태 관리
- Vite → 개발 경험
- Tailwind → UI 생산성
- Three.js → 시각적 인터랙션
결과적으로 이 조합은
UX 중심 프로젝트를 빠르게 구현하기 위한 구조
라고 볼 수 있습니다.
8. 구현에서 중요했던 포인트
8.1 시나리오 기반 상태 분리
const scenarioKey = `${spaceType}-${scope}`;
8.2 체크 상태 구조
stepStatusByScenario[scenarioKey][stepId]
8.3 가이드 → 견적 연결
“읽고 끝”이 아니라
행동으로 이어지는 구조
10. 정리하며
복잡한 정보를 최대한 쉽게 전달하려고 했지만,
사용자 입장에서는 여전히 어렵게 느껴지는 부분이 있을 수 있다고 생각합니다.
이번 프로젝트를 통해
기능을 구현하는 것보다
사용자가 어떻게 이해하고 받아들이는지가 더 중요하다는 것을 느꼈습니다.
앞으로는 화면 설계와 기획을 통해
사용자가 더 자연스럽게 이해하고 사용할 수 있도록 개선해 나가고자 합니다.
이 프로젝트는 복잡한 인테리어 과정을
체크리스트 UX로 단순화하고
3D 견적까지 연결한 서비스입니다.
핵심은 기술보다
사용자의 부담을 줄이는 구조였으며,
이 방향으로 계속 개선해 나갈 예정입니다.
읽어주셔서 감사합니다.
'프로젝트 회고록' 카테고리의 다른 글
| 사이드 프로젝트 | NBA Game Picker (4) - Matchup Score 설명 페이지 구성 (0) | 2026.05.18 |
|---|---|
| 사이드 프로젝트 | NBA Game Picker (2) - 홈 화면 구조와 컴포넌트 분리 (0) | 2026.05.04 |
| 사이드 프로젝트 | NBA Game Picker (1) - 프로젝트 기획과 서비스 방향 (0) | 2026.05.01 |
| 사내 공통 로그인 템플릿 개발 (Security Starter) (1) | 2025.12.31 |
| LOD1 건물 시각화: 공공데이터 기반 3D 빌딩 구축 튜토리얼 (0) | 2025.12.16 |