⚓ DATT 18 - Anchor · 게이미피케이션 프론트엔드 구조 설계
개요
DATT는 단순한 장소 조회 서비스가 아니다.
핵심은:
1
"사용자 경험을 기록하고 연결하는 플랫폼"
이다.
따라서:
- 리뷰
- Anchor
- 저장
- 활동 로그
등의 사용자 활동이 매우 중요하다.
이번 단계에서는:
- 리뷰 시스템 프론트엔드 구조
- Anchor 생성 UX
- Place 상세 기반 활동 흐름
- Form Validation 전략
- 게이미피케이션 UX
- TanStack Query 기반 상태 관리
를 중심으로 사용자 활동 구조를 설계했다.
리뷰 시스템 프론트엔드 구조 설계
리뷰 시스템의 핵심 목적
리뷰는 단순한 텍스트 데이터가 아니다.
DATT에서는 리뷰가:
- 장소 신뢰도
- 사용자 활동 기록
- 경험 공유
- 게이미피케이션 경험치
와 연결된다.
즉:
1
"사용자 행동 데이터"
에 가깝다.
리뷰 조회 구조
리뷰는 Place 상세 페이지 내부에서 조회한다.
구조는 다음과 같다.
1
2
3
4
Place 상세
├─ 장소 정보
├─ 리뷰 작성
└─ 리뷰 목록
리뷰 목록은:
1
usePlaceReviews(placeId)
Hook 기반으로 관리했다.
리뷰 UI 컴포넌트 분리
리뷰 UI는 다음 구조로 분리했다.
1
2
3
ReviewCard
ReviewListSection
ReviewCreateForm
이 구조의 장점은:
- 재사용성 증가
- 관심사 분리
- 유지보수성 향상
이다.
Anchor 생성 UX 설계
Anchor란 무엇인가
Anchor는:
1
2
"기준 장소를 중심으로
경험 흐름을 묶는 구조"
다.
예를 들어:
1
2
3
4
의정부역
→ 카페
→ 식당
→ 산책 코스
를 하나의 경험 단위로 묶을 수 있다.
Place 상세와 Anchor 연결
초기에는 Anchor 생성 페이지를 독립적으로 만들었다.
하지만 UX 흐름상:
1
2
Place 상세
→ Anchor 생성
흐름이 더 자연스러웠다.
따라서:
1
2
3
Place 상세
→ "Anchor 만들기"
→ 기준 장소 자동 입력
구조로 개선했다.
Query Parameter 기반 초기값 전달
Place 상세에서:
1
2
3
/anchors/create?
basePlaceId=1
&basePlaceName=의정부역
형태로 정보를 전달한다.
Anchor 생성 페이지에서는:
1
useSearchParams()
를 통해 초기값을 자동 세팅한다.
이 방식의 장점은:
- 사용자 입력 감소
- UX 흐름 자연스러움
- 장소 맥락 유지
이다.
Place 상세 사용자 활동 흐름 설계
왜 Place 상세가 중요한가
Place 상세는 단순 정보 페이지가 아니다.
실제로는:
1
"사용자 활동 허브"
에 가깝다.
최종 흐름
최종적으로는:
1
2
3
4
5
6
Place 상세
├─ Bookmark
├─ 리뷰 작성
├─ 리뷰 조회
├─ Anchor 생성
└─ 사용자 활동 피드백
구조를 목표로 했다.
즉:
1
2
3
장소 정보 소비
→
사용자 활동 생성
흐름으로 연결한 것이다.
Form Validation 전략
왜 Validation이 중요한가
초기 MVP에서는:
- 빈 값 제출
- 잘못된 숫자 입력
- 중복 제출
등이 쉽게 발생했다.
특히 사용자 활동 기능은:
1
"입력 UX"
가 매우 중요하다.
Validation 공통화
Validation 유틸을 분리했다.
1
2
3
isBlank()
isNumberValue()
isInRange()
이렇게 공통 함수로 분리하면서:
- 코드 중복 감소
- Validation 일관성 확보
- 유지보수성 향상
효과를 얻었다.
버튼 상태 처리
중복 제출 방지를 위해:
1
disabled={mutation.isPending}
구조를 적용했다.
즉:
1
2
요청 중
→ 버튼 비활성화
UX를 제공한다.
활동 기반 게이미피케이션 UX 설계
왜 게이미피케이션을 붙였는가
DATT는:
1
"탐색 활동 자체"
를 재미있게 만드는 것이 중요했다.
따라서:
- 리뷰 작성
- Anchor 생성
- 저장 활동
등에 경험치 흐름을 연결했다.
현재 MVP 단계 UX
현재는 간단한:
1
2
리뷰 작성 완료!
경험치 +15 획득
수준의 피드백만 제공한다.
하지만 이것만으로도:
- 행동 보상감
- 사용자 몰입감
- 성장 느낌
이 크게 증가했다.
ActivityFeedback 컴포넌트
활동 성공 메시지는:
1
<ActivityFeedback />
컴포넌트로 분리했다.
이를 통해:
- 리뷰
- Anchor
- Bookmark
등 다양한 활동에 재사용 가능하도록 구성했다.
TanStack Query 기반 사용자 활동 상태 관리
왜 Query 기반으로 처리했는가
리뷰와 Anchor는:
1
서버 상태
다.
즉:
- 작성 후 갱신
- 상세 재조회
- 목록 invalidate
등이 중요하다.
invalidate 전략
리뷰 작성 성공 시:
1
2
3
queryClient.invalidateQueries({
queryKey: ["place-reviews", placeId],
});
구조를 사용했다.
또한:
1
["place", placeId]
도 함께 invalidate하여:
- 리뷰 수
- 평균 평점
등도 최신 상태로 갱신한다.
서버 상태와 UI 상태 분리
현재 구조는:
1
2
3
4
5
서버 상태
→ TanStack Query
UI 상태
→ useState
로 명확히 분리했다.
예를 들어:
1
2
3
4
5
리뷰 데이터
→ Query
입력창 상태
→ useState
다.
이 구조는 이후 기능 확장 시 매우 중요해진다.
앞으로의 개선 방향
현재는 MVP 수준이다.
추후에는:
- 별점 UI 개선
- 리뷰 이미지 업로드
- 활동 로그 Timeline
- 레벨업 애니메이션
- 업적 Unlock UI
- 실시간 경험치 반영
- 낙관적 업데이트
- Form Schema Validation
등을 추가할 예정이다.
마무리
이번 단계에서 가장 중요하게 생각한 것은:
1
2
"사용자 행동을
자연스럽게 연결하는 흐름"
이었다.
특히:
- Place 상세
- 리뷰
- Anchor
- 게이미피케이션
을 하나의 흐름으로 연결하면서:
1
단순 장소 조회 서비스
가 아니라:
1
"사용자 경험 플랫폼"
에 가까운 구조를 만들 수 있었다.
이제 DATT는:
- 탐색
- 기록
- 공유
- 성장
이 연결되는 서비스로 확장될 수 있는 기반을 갖추게 되었다.