Post

⚓ DATT 18 - Anchor · 게이미피케이션 프론트엔드 구조 설계

⚓ 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는:

  • 탐색
  • 기록
  • 공유
  • 성장

이 연결되는 서비스로 확장될 수 있는 기반을 갖추게 되었다.

This post is licensed under CC BY 4.0 by the author.