Post

⚓ DATT 12 - Anchor 시스템 설계와 지역 기반 자동 큐레이션 구조

개요

현재 DATT는 다음 기능들을 지원한다.

1
2
3
4
5
장소 검색
Nearby Search
Place Detail API
JWT 인증
Bookmark 기능

하지만 이것만으로는 단순:

1
"장소 검색 서비스"

에 가깝다.

DATT가 진짜로 만들고 싶은 것은:

1
2
3
4
데이트
약속
여행
로컬 탐색

등의 경험을 빠르게 탐색할 수 있는 플랫폼이다.

따라서 이번 단계에서는:

1
Anchor 시스템

을 구축하였다.


Anchor란 무엇인가

DATT의 Anchor는 단순 저장 기능이 아니다.

Anchor는:

1
2
"특정 지역에 닻을 내리고
그 주변 경험을 자동 큐레이션하는 기능"

이다.

예를 들어 사용자가:

1
2
3
4
성수
을지로
강릉
홍대

등 특정 지역을 지정하고:

1
닻 버튼 클릭

만 하면:

1
2
3
4
5
맛집
카페
술집
숙소
놀거리

등을 자동 추천받는다.

즉 Anchor는:

1
지역 기반 경험 큐레이션

시스템이다.


왜 장소가 아닌 경험을 추천하는가

기존 장소 서비스 대부분은:

1
장소 단위 검색

에 집중한다.

예:

1
2
3
맛집 검색
카페 검색
술집 검색

하지만 실제 사용자는:

1
"어디 갈까?"

보다:

1
"오늘 어떻게 놀까?"

를 더 많이 고민한다.

즉 사용자가 원하는 것은:

1
장소 하나

가 아니라:

1
지역 기반 경험 흐름

이다.

예:

1
2
3
성수에서 데이트
강릉에서 1박2일
홍대에서 친구 모임

등.

Anchor는 바로 이 문제를 해결하기 위한 구조다.


Anchor 시스템 핵심 구조

Anchor는 다음 구조를 가진다.

1
2
3
4
5
Anchor
↕
AnchorPlace
↕
PlaceMaster

즉:

1
2
3
4
5
Anchor
= 기준 지역

AnchorPlace
= 기준 지역 주변 자동 추천 결과

이다.


Anchor Entity 설계

Anchor는:

1
"어디에 닻을 내렸는가"

를 표현한다.

최종 구조는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Entity
@Table(name = "anchor")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Anchor extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "member_id", nullable = false)
    private Member member;

    private String title;

    private String basePlaceName;
    private String baseAddress;

    private Double baseLon;
    private Double baseLat;

    private Double radiusKm;

    private boolean isPublic;

    private long viewCount;
}

핵심은:

1
기준 좌표

를 저장한다는 점이다.


왜 좌표 기반으로 설계했는가

처음에는:

1
장소 여러 개 저장

방식도 고려했다.

하지만 DATT의 핵심은:

1
"지역 기반 탐색"

이다.

따라서:

1
2
3
성수역
홍대입구역
강릉 중앙시장

같은:

1
기준 좌표

를 중심으로 자동 추천하는 구조가 더 자연스럽다.


AnchorPlace 설계

AnchorPlace는:

1
Anchor 생성 당시 추천된 장소 스냅샷

이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Entity
@Table(name = "anchor_place")
public class AnchorPlace extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private Anchor anchor;

    @ManyToOne(fetch = FetchType.LAZY)
    private PlaceMaster placeMaster;

    @Enumerated(EnumType.STRING)
    private AnchorPlaceCategory category;

    private Double distanceKm;

    private int recommendOrder;
}

왜 추천 결과를 스냅샷으로 저장했는가

중요한 이유가 있다.

만약 매번 실시간 Nearby Search만 수행하면:

1
시간이 지나면서 추천 결과가 계속 바뀐다.

예:

1
2
3
공공데이터 변경
폐업
신규 장소 추가

등.

하지만 공유된 Anchor는:

1
"그 당시의 경험"

을 유지해야 한다.

따라서:

1
Anchor 생성 당시 추천 결과

를 별도 저장하는 구조로 설계했다.


Nearby Search와의 연동

Anchor의 핵심은:

1
Nearby Search 재사용

이다.

Anchor 생성 시 다음 흐름이 수행된다.

1
2
3
4
5
Anchor 생성
→ 기준 좌표 설정
→ Nearby Search 수행
→ 카테고리별 추천
→ AnchorPlace 저장

즉 기존 Nearby Search를:

1
재사용 가능한 추천 엔진

처럼 활용한다.


카테고리별 추천 구조

Anchor는 다음 카테고리 기준으로 자동 추천한다.

1
2
3
4
5
FOOD
CAFE
BAR
STAY
PLAY

즉:

1
2
3
4
5
맛집
카페
술집
숙소
놀거리

기반이다.


업종 코드 기반 추천

추천은 공공데이터 업종 중분류 코드 기반으로 수행한다.

예:

1
2
3
4
5
6
FOOD("맛집", List.of(
    "I201",
    "I202",
    "I203",
    "I204"
))

즉:

1
2
3
업종 코드
→ 카테고리 매핑
→ Nearby Search 수행

구조다.


Anchor 추천 흐름

최종 흐름은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
사용자
→ 지역 지정
→ Anchor 생성

Anchor 생성
→ Nearby Search 수행

Nearby 결과
→ FOOD / CAFE / BAR / STAY / PLAY 분리

분리된 결과
→ AnchorPlace 저장

최종
→ AnchorDetailResponse 반환

왜 Anchor를 독립 도메인으로 봤는가

중요한 설계 포인트다.

처음에는 단순:

1
장소 저장 기능

처럼 보일 수 있다.

하지만 실제로는:

1
2
3
4
5
추천
공유
랭킹
개인화
큐레이션

등으로 확장된다.

즉 Anchor는 단순 기능이 아니라:

1
DATT 핵심 경험 도메인

이다.


Anchor 공유 구조

Anchor는:

1
공개/비공개

구조를 가진다.

1
private boolean isPublic;

즉:

1
2
3
4
5
공개 Anchor
→ 누구나 조회 가능

비공개 Anchor
→ 작성자만 조회 가능

이다.


Anchor 조회수 구조

Anchor는 공유 콘텐츠 성격을 가지기 때문에:

1
조회수

도 저장한다.

1
private long viewCount;

조회수는:

1
상세 조회 성공 시 증가

한다.

향후:

1
2
인기 Anchor
추천 랭킹

등으로 확장 가능하다.


Anchor 목록 조회 구조

Anchor는:

1
2
최신순
인기순

정렬을 지원한다.

1
2
3
4
5
public enum AnchorSortType {

    LATEST,
    POPULAR
}

즉:

1
2
createdAt DESC
viewCount DESC

기반 조회가 가능하다.


Anchor와 Bookmark의 관계

처음에는 Bookmark와 Anchor를 직접 연결할지 고민했다.

하지만 최종적으로는:

1
2
3
Bookmark
≠
Anchor

로 분리했다.

Bookmark는:

1
저장 행위

이고,

Anchor는:

1
지역 기반 경험 큐레이션

이다.

즉 역할이 다르다.


대신 어떻게 연동했는가

Bookmark는:

1
Anchor 생성 진입점

으로 사용한다.

예:

1
2
3
내가 저장한 장소
→ 기준점으로 선택
→ Anchor 생성

즉:

1
2
Bookmark는 입력 데이터
Anchor는 결과 콘텐츠

구조다.


경험 탐색 플랫폼 모델링

DATT는 단순:

1
장소 검색 플랫폼

이 아니다.

최종적으로는:

1
"어디서 무엇을 경험할 것인가"

를 탐색하는 플랫폼이다.

Anchor는 바로 이 철학을 기반으로 설계되었다.


현재 구조의 장점

현재 구조는 다음 장점을 가진다.

1
2
3
4
5
Nearby Search 재사용 가능
카테고리별 추천 가능
공유 가능
확장 가능
개인화 가능

특히:

1
2
Anchor
→ 경험 단위 콘텐츠

로 설계한 것이 핵심이다.


향후 확장 방향

현재는 MVP 수준이다.

하지만 이후 다음 기능들로 확장 가능하다.


1. AI 기반 추천

예:

1
사용자 취향 기반 장소 추천

2. 실시간 인기 지역

예:

1
현재 가장 인기 있는 Anchor

3. Gamification

예:

1
2
3
Anchor 생성 경험치
랭킹
칭호

4. 공유 기능 강화

예:

1
2
3
친구 공유
링크 공유
비공개 공유 링크

마무리

이번 단계에서는:

1
Anchor 시스템

을 구축하며:

1
지역 기반 자동 큐레이션 구조

를 완성하였다.

핵심은:

1
2
장소를 검색하는 것이 아니라
경험을 탐색하게 만드는 것

이다.

DATT는 앞으로:

1
2
3
4
데이트
여행
약속
로컬 탐색

등 실제 사용자 경험 중심 플랫폼으로 확장될 예정이다.

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