Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions src/main/java/eatda/client/map/MapClientStoreSearchResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import eatda.domain.store.Store;
import eatda.domain.store.District;
import eatda.domain.store.StoreCategory;
import eatda.domain.store.StoreSearchResult;
import java.util.Map;
Expand All @@ -29,6 +29,7 @@ public record MapClientStoreSearchResult(
"음식점 > 카페", StoreCategory.CAFE,
"음식점 > 간식 > 제과,베이커리", StoreCategory.CAFE
);
private static final District DEFAULT_DISTRICT = District.ETC;

public boolean isFoodStore() {
return "FD6".equals(categoryGroupCode);
Expand All @@ -54,18 +55,15 @@ public StoreCategory getStoreCategory() {
.orElse(StoreCategory.OTHER);
}

public Store toStore() {
return Store.builder()
.kakaoId(kakaoId)
.category(getStoreCategory())
.phoneNumber(phoneNumber)
.name(name)
.placeUrl(placeUrl)
.roadAddress(roadAddress)
.lotNumberAddress(lotNumberAddress)
.latitude(latitude)
.longitude(longitude)
.build();
public District getDistrict() {
if (lotNumberAddress == null || lotNumberAddress.isBlank()) {
return DEFAULT_DISTRICT;
}
String[] addressParts = lotNumberAddress.split(" ");
if (addressParts.length < 2) {
return DEFAULT_DISTRICT;
}
return District.fromName(addressParts[1]);
}

public StoreSearchResult toDomain() {
Expand All @@ -77,6 +75,7 @@ public StoreSearchResult toDomain() {
placeUrl,
lotNumberAddress,
roadAddress,
getDistrict(),
latitude,
longitude
);
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/eatda/domain/store/District.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package eatda.domain.store;

import java.util.Arrays;
import lombok.Getter;

@Getter
public enum District {

GANGNAM("강남구"),
GANGDONG("강동구"),
GANGBUK("강북구"),
GANGSEO("강서구"),
GWANAK("관악구"),
GWANGJIN("광진구"),
GURO("구로구"),
GEUMCHEON("금천구"),
NOWON("노원구"),
DOBONG("도봉구"),
DONGDAEMUN("동대문구"),
DONGJAK("동작구"),
MAPO("마포구"),
SEODAEMUN("서대문구"),
SEOCHO("서초구"),
SEONGDONG("성동구"),
SEONGBUK("성북구"),
SONGPA("송파구"),
YANGCHEON("양천구"),
YEONGDEUNGPO("영등포구"),
YONGSAN("용산구"),
EUNPYEONG("은평구"),
JONGNO("종로구"),
JUNG("중구"),
JUNGNANG("중랑구"),
ETC("기타"),
;

private final String name;

District(String name) {
this.name = name;
}

public static District fromName(String name) {
return Arrays.stream(District.values())
.filter(district -> district.name.equals(name))
.findFirst()
.orElse(ETC);
}
}
12 changes: 7 additions & 5 deletions src/main/java/eatda/domain/store/Store.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ public class Store extends AuditingEntity {
@Column(name = "lot_number_address", nullable = false)
private String lotNumberAddress;

@Enumerated(EnumType.STRING)
@Column(name = "district", nullable = false, length = 31)
private District district;

@Embedded
private Coordinates coordinates;

Expand All @@ -58,6 +62,7 @@ private Store(String kakaoId,
String placeUrl,
String roadAddress,
String lotNumberAddress,
District district,
Double latitude,
Double longitude) {
this.kakaoId = kakaoId;
Expand All @@ -66,16 +71,13 @@ private Store(String kakaoId,
this.name = name;
this.placeUrl = placeUrl;
this.roadAddress = roadAddress;
this.district = district;
this.lotNumberAddress = lotNumberAddress;
this.coordinates = new Coordinates(latitude, longitude);
}

public String getAddressDistrict() {
String[] addressParts = lotNumberAddress.split(" ");
if (addressParts.length < 2) {
return "";
}
return addressParts[1];
return district.getName();
}

public String getAddressNeighborhood() {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/eatda/domain/store/StoreSearchResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public record StoreSearchResult(
String placeUrl,
String lotNumberAddress,
String roadAddress,
District district,
double latitude,
double longitude
) {
Expand All @@ -21,6 +22,7 @@ public Store toStore() {
.placeUrl(placeUrl)
.roadAddress(roadAddress)
.lotNumberAddress(lotNumberAddress)
.district(district)
.latitude(latitude)
.longitude(longitude)
.build();
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/db/migration/V1__init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ CREATE TABLE `store`
`place_url` VARCHAR(255) NOT NULL,
`road_address` VARCHAR(255) NOT NULL,
`lot_number_address` VARCHAR(255) NOT NULL,
`district` VARCHAR(31) NOT NULL,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

이미 배포된 초기 마이그레이션(V1)을 수정하지 마세요 — 신규 마이그레이션으로 분리 필요

운영/공용 DB에 V1이 적용된 상태에서 V1__init.sql을 수정하면 마이그레이션 불일치가 발생합니다. store.district 추가는 신규 마이그레이션(예: V2__add_store_district.sql)으로 처리하세요.

권장 절차:

  1. 새 마이그레이션 추가:
  • (안전) NULL 허용으로 추가 → 데이터 백필 → NOT NULL로 변경
  • 지역 검색 대비 인덱스 추가

예시(DDL):

-- V2__add_store_district.sql
ALTER TABLE `store` ADD COLUMN `district` VARCHAR(31) NULL AFTER `lot_number_address`;

-- 필요 시: 모든 기존 row를 ETC로 백필
UPDATE `store` SET `district` = 'ETC' WHERE `district` IS NULL;

-- NOT NULL 강제
ALTER TABLE `store` MODIFY COLUMN `district` VARCHAR(31) NOT NULL;

-- 향후 지역별 조회 최적화용 인덱스
CREATE INDEX `idx_store_district` ON `store`(`district`);

또한, 현재 PR에서 dev/local seed는 district 컬럼을 전제로 작성되어 있으므로, 새 마이그레이션 추가 후 적용 순서가 보장되도록 스크립트/파이프라인을 점검해주세요.

🤖 Prompt for AI Agents
In src/main/resources/db/migration/V1__init.sql around line 23: do not modify
the already-deployed V1 migration to add the `district` column; instead create a
new migration file (e.g., V2__add_store_district.sql) that (1) ALTER TABLE store
ADD COLUMN district VARCHAR(31) NULL AFTER lot_number_address, (2) run a
backfill UPDATE to set a default like 'ETC' for existing NULLs, (3) ALTER TABLE
to MODIFY COLUMN district VARCHAR(31) NOT NULL, and (4) CREATE INDEX
idx_store_district ON store(district); also update dev/local seed scripts and
CI/deployment pipeline to run the new migration before any seed/logic that
assumes the district column exists.

`latitude` DOUBLE NOT NULL,
`longitude` DOUBLE NOT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
Expand Down
18 changes: 9 additions & 9 deletions src/main/resources/db/seed/dev/V2__dev_init_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ VALUES (1, 123456789, 'default1@kakao.com', '이승로', '01012345678', true),
(6, 324569987, 'default6@kakao.com', '박희수', '01043609998', false),
(7, 323487985, 'default7@kakao.com', '하아얀', '01065083298', false);

INSERT INTO store (id, kakao_id, category, phone_number, name, place_url, road_address, lot_number_address, latitude,
longitude)
INSERT INTO store (id, kakao_id, category, phone_number, name, place_url, road_address, lot_number_address, district,
latitude, longitude)
VALUES (1, '99999999999', 'KOREAN', '01012345678', '맛있는 한식집', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 123-45', '서울시 강남구 역삼동 123-45', 37.503708148482524, 127.05300772497776),
'서울시 강남구 역삼동 123-45', '서울시 강남구 역삼동 123-45', 'GANGNAM', 37.503708148482524, 127.05300772497776),
(2, '99999999998', 'WESTERN', '01087654321', '아름다운 양식집', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 67-89', '서울시 강남구 역삼동 67-89', 37.4979, 127.0276),
'서울시 강남구 역삼동 67-89', '서울시 강남구 역삼동 67-89', 'GANGNAM', 37.4979, 127.0276),
(3, '99999999997', 'CHINESE', '01045678912', '정통 중식당', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 101-112', '서울시 강남구 역삼동 101-112', 37.56259825108099, 126.97715943361476),
'서울시 강남구 역삼동 101-112', '서울시 강남구 역삼동 101-112', 'GANGNAM', 37.56259825108099, 126.97715943361476),
(4, '99999999996', 'WESTERN', '01078912345', '고급 양식 레스토랑', 'https://place.map.kakao.com/17163273', '',
'서울시 강남구 역삼동 131-415', 37.4979, 127.0276),
'서울시 강남구 역삼동 131-415', 'GANGNAM', 37.4979, 127.0276),
(5, '99999999995', 'OTHER', '01034574568', '달콤한 디저트 카페', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 161-718', '서울시 강남구 역삼동 161-718', 37.49491300989233, 127.03150463098274),
'서울시 강남구 역삼동 161-718', '서울시 강남구 역삼동 161-718', 'GANGNAM', 37.49491300989233, 127.03150463098274),
(6, '99999999994', 'OTHER', '01043609998', '아늑한 커피숍', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 192-021', '서울시 강남구 역삼동 192-021', 37.5298343127044, 126.919484339847),
'서울시 강남구 역삼동 192-021', '서울시 강남구 역삼동 192-021', 'GANGNAM', 37.5298343127044, 126.919484339847),
(7, '99999999993', 'OTHER', '01065083298', '빠른 패스트푸드점', 'https://place.map.kakao.com/17163273', '',
'서울시 강남구 역삼동 222-324', 37.5036675804016, 127.05305858911);
'서울시 강남구 역삼동 222-324', 'GANGNAM', 37.5036675804016, 127.05305858911);

INSERT INTO cheer (id, member_id, store_id, description, image_key, is_admin)
VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'cheer/dummy/1.jpg', true),
Expand Down
18 changes: 9 additions & 9 deletions src/main/resources/db/seed/local/V2__local_init_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ VALUES (1, 123456789, 'default1@kakao.com', '이승로', '01012345678', true),
(6, 324569987, 'default6@kakao.com', '박희수', '01043609998', false),
(7, 323487985, 'default7@kakao.com', '하아얀', '01065083298', false);

INSERT INTO store (id, kakao_id, category, phone_number, name, place_url, road_address, lot_number_address, latitude,
longitude)
INSERT INTO store (id, kakao_id, category, phone_number, name, place_url, road_address, lot_number_address, district,
latitude, longitude)
VALUES (1, '99999999999', 'KOREAN', '01012345678', '맛있는 한식집', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 123-45', '서울시 강남구 역삼동 123-45', 37.503708148482524, 127.05300772497776),
'서울시 강남구 역삼동 123-45', '서울시 강남구 역삼동 123-45', 'GANGNAM', 37.503708148482524, 127.05300772497776),
(2, '99999999998', 'WESTERN', '01087654321', '아름다운 양식집', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 67-89', '서울시 강남구 역삼동 67-89', 37.4979, 127.0276),
'서울시 강남구 역삼동 67-89', '서울시 강남구 역삼동 67-89', 'GANGNAM', 37.4979, 127.0276),
(3, '99999999997', 'CHINESE', '01045678912', '정통 중식당', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 101-112', '서울시 강남구 역삼동 101-112', 37.56259825108099, 126.97715943361476),
'서울시 강남구 역삼동 101-112', '서울시 강남구 역삼동 101-112', 'GANGNAM', 37.56259825108099, 126.97715943361476),
(4, '99999999996', 'WESTERN', '01078912345', '고급 양식 레스토랑', 'https://place.map.kakao.com/17163273', '',
'서울시 강남구 역삼동 131-415', 37.4979, 127.0276),
'서울시 강남구 역삼동 131-415', 'GANGNAM', 37.4979, 127.0276),
(5, '99999999995', 'OTHER', '01034574568', '달콤한 디저트 카페', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 161-718', '서울시 강남구 역삼동 161-718', 37.49491300989233, 127.03150463098274),
'서울시 강남구 역삼동 161-718', '서울시 강남구 역삼동 161-718', 'GANGNAM', 37.49491300989233, 127.03150463098274),
(6, '99999999994', 'OTHER', '01043609998', '아늑한 커피숍', 'https://place.map.kakao.com/17163273',
'서울시 강남구 역삼동 192-021', '서울시 강남구 역삼동 192-021', 37.5298343127044, 126.919484339847),
'서울시 강남구 역삼동 192-021', '서울시 강남구 역삼동 192-021', 'GANGNAM', 37.5298343127044, 126.919484339847),
(7, '99999999993', 'OTHER', '01065083298', '빠른 패스트푸드점', 'https://place.map.kakao.com/17163273', '',
'서울시 강남구 역삼동 222-324', 37.5036675804016, 127.05305858911);
'서울시 강남구 역삼동 222-324', 'GANGNAM', 37.5036675804016, 127.05305858911);

INSERT INTO cheer (id, member_id, store_id, description, image_key, is_admin)
VALUES (1, 1, 1, '정말 맛있어요! 강추합니다!', 'cheer/dummy/1.jpg', true),
Expand Down
45 changes: 45 additions & 0 deletions src/test/java/eatda/client/map/MapClientStoreSearchResultTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import eatda.domain.store.StoreCategory;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;

class MapClientStoreSearchResultTest {

Expand Down Expand Up @@ -49,4 +52,46 @@ class GetStoreCategory {
assertThat(category).isEqualTo(StoreCategory.OTHER);
}
}

@Nested
class GetDistrict {

@Test
void 제공된_지번_주소에_따라_해당_구를_반환한다() {
MapClientStoreSearchResult store = new MapClientStoreSearchResult(
"1062153333",
"FD6",
"음식점 > 한식 > 순대",
"02-755-5232",
"농민백암순대 시청직영점",
"http://place.map.kakao.com/1062153333",
"서울 중구 북창동 19-4",
"서울 중구 남대문로1길 33",
37.56259825108099,
126.97715943361476
);

assertThat(store.getDistrict()).isEqualTo(eatda.domain.store.District.JUNG);
}

@ValueSource(strings = {" ", "\t", "이것은 주소가 아닙니다.", "empty"})
@NullAndEmptySource
@ParameterizedTest
void 지번_주소가_정해진_형식이_아니면_ETC를_반환한다(String lotNumberAddress) {
MapClientStoreSearchResult store = new MapClientStoreSearchResult(
"1062153333",
"FD6",
"음식점 > 한식 > 순대",
"02-755-5232",
"농민백암순대 시청직영점",
"http://place.map.kakao.com/1062153333",
lotNumberAddress,
null,
37.56259825108099,
126.97715943361476
);

assertThat(store.getDistrict()).isEqualTo(eatda.domain.store.District.ETC);
}
}
}
5 changes: 3 additions & 2 deletions src/test/java/eatda/controller/cheer/CheerControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import eatda.controller.BaseControllerTest;
import eatda.domain.cheer.Cheer;
import eatda.domain.member.Member;
import eatda.domain.store.District;
import eatda.domain.store.Store;
import eatda.util.ImageUtils;
import eatda.util.MappingUtils;
Expand Down Expand Up @@ -63,8 +64,8 @@ class GetCheers {
@Test
void 요청한_응원_중_최신_응원_N개를_조회한다() {
Member member = memberGenerator.generateRegisteredMember("nickname", "ac@kakao.com", "123", "01011111111");
Store store1 = storeGenerator.generate("111", "서울시 노원구 월계3동 123-45");
Store store2 = storeGenerator.generate("222", "서울시 성북구 석관동 123-45");
Store store1 = storeGenerator.generate("111", "서울시 노원구 월계3동 123-45", District.NOWON);
Store store2 = storeGenerator.generate("222", "서울시 성북구 석관동 123-45", District.SEONGBUK);
LocalDateTime startAt = LocalDateTime.of(2025, 7, 26, 1, 0, 0);
Cheer cheer1 = cheerGenerator.generateAdmin(member, store1, startAt);
Cheer cheer2 = cheerGenerator.generateAdmin(member, store1, startAt.plusHours(1));
Expand Down
6 changes: 4 additions & 2 deletions src/test/java/eatda/document/store/StoreDocumentTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import eatda.document.RestDocsRequest;
import eatda.document.RestDocsResponse;
import eatda.document.Tag;
import eatda.domain.store.District;
import eatda.domain.store.StoreCategory;
import eatda.domain.store.StoreSearchResult;
import eatda.exception.BusinessErrorCode;
Expand Down Expand Up @@ -242,9 +243,10 @@ class SearchStores {
String query = "농민백암순대";
List<StoreSearchResult> responses = List.of(
new StoreSearchResult("123", StoreCategory.KOREAN, "010-1234-1234", "농민백암순대 본점",
"https://yap.co.kr", "서울 강남구 대치동 896-33", "서울 강남구 선릉로86길 40-4", 37.0d, 128.0d),
"https://yap.co.kr", "서울 강남구 대치동 896-33", "서울 강남구 선릉로86길 40-4", District.GANGNAM,
37.0d, 128.0d),
new StoreSearchResult("456", StoreCategory.KOREAN, "010-1234-1234", "농민백암순대 시청점",
"https://yapp.kr", "서울 중구 북창동 19-4", null, 37.0d, 128.0d)
"https://yapp.kr", "서울 중구 북창동 19-4", null, District.JUNG, 37.0d, 128.0d)
);
doReturn(responses).when(storeSearchService).searchStores(anyString());

Expand Down
2 changes: 2 additions & 0 deletions src/test/java/eatda/domain/cheer/CheerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import eatda.domain.ImageKey;
import eatda.domain.member.Member;
import eatda.domain.store.District;
import eatda.domain.store.Store;
import eatda.domain.store.StoreCategory;
import eatda.exception.BusinessErrorCode;
Expand All @@ -26,6 +27,7 @@ class CheerTest {
.placeUrl("https://place.kakao.com/1234567890")
.roadAddress("서울시 성북구 대학로 1길 1")
.lotNumberAddress("서울시 성북구 동선동 1-1")
.district(District.SEONGBUK)
.latitude(37.5665)
.longitude(126.978)
.build();
Expand Down
35 changes: 35 additions & 0 deletions src/test/java/eatda/domain/store/DistrictTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package eatda.domain.store;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;

class DistrictTest {

@Nested
class FromName {

@CsvSource({"강남구, GANGNAM", "강동구, GANGDONG", "강북구, GANGBUK", "강서구, GANGSEO", "관악구, GWANAK",
"광진구, GWANGJIN", "구로구, GURO", "금천구, GEUMCHEON", "노원구, NOWON", "도봉구, DOBONG",
"동대문구, DONGDAEMUN", "동작구, DONGJAK", "마포구, MAPO", "서대문구, SEODAEMUN", "서초구, SEOCHO",
"성동구, SEONGDONG", "성북구, SEONGBUK", "송파구, SONGPA", "양천구, YANGCHEON", "영등포구, YEONGDEUNGPO",
"용산구, YONGSAN", "은평구, EUNPYEONG", "종로구, JONGNO", "중구, JUNG", "중랑구, JUNGNANG"})
@ParameterizedTest
void 구_이름을_통해_해당_구를_반환한다(String name, District expected) {
District actual = District.fromName(name);

assertThat(actual).isEqualTo(expected);
}

@ValueSource(strings = {"서구", "사사구", "기구", ""})
@ParameterizedTest
void 구_이름이_존재하지_않으면_ETC를_반환한다(String name) {
District actual = District.fromName(name);

assertThat(actual).isEqualTo(District.ETC);
}
}
}
5 changes: 3 additions & 2 deletions src/test/java/eatda/domain/store/StoreTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ class StoreTest {
.placeUrl("https://place.kakao.com/123456789")
.roadAddress("")
.lotNumberAddress("서울특별시 강남구 역삼동 123-45")
.district(District.GANGNAM)
.latitude(37.5665)
.longitude(126.978);

@Nested
class GetAddressDistrict {

@Test
void 주소_구_정보를_지번_주소에서_반환한다() {
void 주소_구_정보를_ENUM을_통해_반환한다() {
Store store = DEFAULT_BUILDER
.lotNumberAddress("서울특별시 성북구 석관동 123-45")
.district(District.SEONGBUK)
.build();

String actual = store.getAddressDistrict();
Expand Down
Loading