Skip to content

feat: places.category_group 분류 컬럼 추가 - #112

Open
labyrinth30 wants to merge 1 commit into
refactor/share-pin-card-query-helpersfrom
refactor/place-category-group
Open

feat: places.category_group 분류 컬럼 추가#112
labyrinth30 wants to merge 1 commit into
refactor/share-pin-card-query-helpersfrom
refactor/place-category-group

Conversation

@labyrinth30

Copy link
Copy Markdown
Contributor

Stacked PR — base가 main이 아니라 #111 브랜치입니다. #111이 머지되면 base가 자동으로 main으로 바뀝니다. 리뷰는 이 PR의 커밋 1개(d864377)만 보시면 됩니다.

스택: #111이 PR#107

개요

카테고리 필터를 조회 시점의 키워드 매칭에서 저장 시점의 분류로 옮깁니다.

#107은 category 문자열에 ilike를 14개 겁니다:

음식점 있거나 식당 있거나 restaurant 있거나 한식 있거나 ... (14개) 그런데 카페는 빼고

문제가 셋입니다.

  • 인덱스를 못 탑니다 — 부분 문자열 매칭이라 places 전체를 훑습니다.
  • 키워드 누락이 계속 생깁니다 — "커피", "브런치", "펍", "이자카야"는 지금 안 잡힙니다. 새 카테고리를 볼 때마다 조회 쿼리를 고쳐야 합니다.
  • 단위 테스트가 안 됩니다 — 분류 규칙이 SQL 안에 박혀 있어 DB를 띄워야만 확인됩니다.

작업 내용

1. places.category_group 컬럼

cafe / restaurant / other, varchar(16), NOT NULL DEFAULT 'other'.
PLACE_PROVIDERS와 같은 방식(varchar + $type<>())으로 맞췄습니다.

2. classifyPlaceCategory() — 저장 시점 1회 분류

place-result.repository.ts의 upsert에서 채웁니다. category가 갱신되면 category_group도 함께 갱신되도록 onConflictDoUpdateset에도 넣었습니다.

카페를 먼저 판정합니다. 카카오는 "음식점 > 카페 > 커피전문점"처럼 계층 전체를 한 문자열로 주기 때문에 카페도 "음식점"에 걸립니다. 판정 순서가 곧 우선순위이고, 이게 #107의 "restaurant에서 카페 제외" 조건과 결과가 같습니다.

키워드 목록(place.constant.ts)은 #107에 있던 것을 그대로 옮겼습니다. 분류 결과가 달라지지 않게 하려는 의도입니다. 누락 키워드 보강은 별도로 하는 게 리뷰하기 좋다고 봤습니다.

3. 기존 행 backfill

마이그레이션에 UPDATE를 넣었습니다. 규칙은 TS 쪽과 동일하게 유지해야 하고, 그 사실을 SQL 주석에 적어뒀습니다.

얻는 것

이전 이후
조회 ilike 14개 + 부정 조건 2개 category_group = ?
키워드 누락 시 조회 쿼리 수정 함수 하나 수정
테스트 E2E만 단위 테스트 6개
카테고리 추가 쿼리에 if 블록 enum + 함수 한 줄

검증

결과
bun run typecheck 통과
bun run check 통과
bun run test:unit 227 pass / 0 fail (신규 6개)
bun run test:e2e 103 pass / 0 fail

e2e는 drizzle/의 마이그레이션을 실제로 적용하므로 backfill UPDATE도 함께 검증됩니다.

리뷰 포인트

인덱스를 일부러 안 걸었습니다. 값이 3종뿐이라 선택도가 낮아 플래너가 잘 안 씁니다. 이 PR의 이득은 인덱스가 아니라 부분 문자열 매칭 14회를 등호 비교 하나로 바꾸는 데 있습니다. 필요해지면 그때 추가하는 게 낫다고 봤는데, 의견 주시면 넣겠습니다.

분류 규칙이 TS와 마이그레이션 SQL 두 곳에 있습니다. backfill이 일회성이라 감수했습니다. 규칙을 바꾸면 backfill 마이그레이션을 다시 만들어야 하고, 그 내용을 SQL 주석에 남겼습니다.

조회 쿼리는 안 건드렸습니다. 이 PR만 보면 아무도 안 읽는 컬럼이 생기는데, 실제 교체는 #107에서 합니다. 스택을 얇게 쪼개려는 의도입니다.

🤖 Generated with Claude Code

카테고리 필터를 조회 시점의 키워드 매칭이 아니라 저장 시점의 분류로 옮긴다.
#107은 조회할 때마다 category 문자열에 ilike 14개를 걸고 있는데, 인덱스를 못
타고 키워드 누락이 계속 생기며 분류 규칙을 단위 테스트할 수도 없다.

- places.category_group 컬럼(cafe/restaurant/other, default 'other') 추가
- classifyPlaceCategory()로 place upsert 시점에 1회 분류. 카카오는
  "음식점 > 카페 > 커피전문점"처럼 계층을 한 문자열로 주기 때문에 카페를 먼저
  판정한다 — #107의 "restaurant에서 카페 제외" 규칙과 결과가 같다.
- 키워드 목록은 #107에 있던 것을 그대로 옮겨 분류 결과가 달라지지 않게 했다.
- 기존 행은 마이그레이션의 UPDATE로 backfill한다.

조회 쿼리 교체는 #107에서 한다. 이 PR은 컬럼과 분류 로직까지만 넣는다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5519378c-83a2-492f-881a-1cb86e31446b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant