Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
194 commits
Select commit Hold shift + click to select a range
38c6e5c
feat(restaurant): 식당 좌표와 관광 지역 저장 모델 추가 (#220)
hwistlezz Sep 26, 2026
cdb9320
build(deps): 주소 조회용 HTTP client 추가 (#222)
hwistlezz Sep 26, 2026
087c3e9
feat(restaurant): 식당 주소의 Google 좌표 후보 조회 추가 (#222)
hwistlezz Sep 26, 2026
55fc280
fix(restaurant): 공백 관광 지역명 검증 일치 (#220)
hwistlezz Sep 26, 2026
73eeec2
fix(restaurant): DNS 지연 시 주소 조회 대기 제한 (#222)
hwistlezz Sep 26, 2026
7a3cda4
build(deps): 주소 조회용 HTTP client 추가 (#222)
hwistlezz Sep 26, 2026
5d9d815
feat(restaurant): 식당 주소의 Google 좌표 후보 조회 추가 (#222)
hwistlezz Sep 26, 2026
ef65e88
fix(restaurant): DNS 지연 시 주소 조회 대기 제한 (#222)
hwistlezz Sep 26, 2026
09020c8
fix(restaurant): 위치 UTC 시각의 JDBC 변환 방지 (#220)
hwistlezz Sep 26, 2026
5d6d2d0
fix(restaurant): 위치 UTC 시각의 JDBC 변환 방지 (#220)
hwistlezz Sep 26, 2026
98299f2
feat(restaurant): 지도 범위와 지역 조회 추가 (#223)
hwistlezz Sep 26, 2026
9f2f336
feat(restaurant): 주소 위치 작업과 호출 예산 추가 (#224)
hwistlezz Sep 26, 2026
da0aa04
feat(admin): 식당 위치 상태와 재처리 API 추가 (#224)
hwistlezz Sep 26, 2026
303fb5c
fix(restaurant): 지도 ID 검증 오류 필드 추가 (#223)
hwistlezz Sep 26, 2026
0d77d91
fix(restaurant): 위치 작업 경합과 전역 대기 보완 (#224)
hwistlezz Sep 26, 2026
672f567
fix(restaurant): 위치 작업 경합과 전역 대기 보완 (#224)
hwistlezz Sep 26, 2026
31a7998
feat(restaurant): 지도 목록 페이지와 조회 세션 추가 (#227)
hwistlezz Sep 26, 2026
4ad25ea
feat(restaurant): 기존 좌표 보완과 기한 전 정리 추가 (#228)
hwistlezz Sep 26, 2026
c956780
fix(restaurant): 지도 Redis 대기 전 DB 연결 반환 (#227)
hwistlezz Sep 26, 2026
aaacb5d
fix(dev): 더미 식당 생성의 작업 잠금 경합 방지 (#224)
hwistlezz Sep 26, 2026
91864cd
fix(dev): 더미 식당 생성의 작업 잠금 경합 방지 (#224)
hwistlezz Sep 26, 2026
4635276
fix(restaurant): 갱신 기간 정밀도 검증 추가 (#228)
hwistlezz Sep 26, 2026
fa7bc1e
test(restaurant): CLI 실행 테스트 격리 (#228)
hwistlezz Sep 26, 2026
69307c5
fix(restaurant): 지도 위치 migration을 V31로 이동 (#220)
hwistlezz Sep 30, 2026
64289e9
Merge remote-tracking branch 'origin/develop' into feat/#220/restaura…
hwistlezz Sep 30, 2026
efbea66
Merge remote-tracking branch 'origin/develop' into feat/#222/google-g…
hwistlezz Sep 30, 2026
1f797a4
Merge branch 'feat/#220/restaurant-map-location' into feat/#223/map-r…
hwistlezz Sep 30, 2026
f06fad2
Merge branch 'feat/#220/restaurant-map-location' into feat/#224/resta…
hwistlezz Sep 30, 2026
0288746
test(restaurant): 최신 develop에서 V31 업그레이드 검증 (#220)
hwistlezz Sep 30, 2026
8c6800b
Merge branch 'feat/#220/restaurant-map-location' into feat/#224/resta…
hwistlezz Sep 30, 2026
53ed783
Merge branch 'feat/#220/restaurant-map-location' into feat/#223/map-r…
hwistlezz Sep 30, 2026
9094189
fix(restaurant): 위치 작업 migration을 V32로 이동 (#224)
hwistlezz Sep 30, 2026
fd3a29c
Merge branch 'feat/#223/map-restaurant-query' into feat/#227/restaura…
hwistlezz Sep 30, 2026
7ad99a3
Merge branch 'feat/#224/restaurant-location-job' into feat/#228/resta…
hwistlezz Sep 30, 2026
754e232
fix(restaurant): 유지보수 migration을 V33로 이동 (#228)
hwistlezz Sep 30, 2026
1ceffd6
test(restaurant): isolate location job fixtures after duplicate valid…
hwistlezz Sep 30, 2026
ea79a29
Merge #224 location job candidate into #228
hwistlezz Sep 30, 2026
2adebbe
fix(map): constrain region candidates to camera bounds
hwistlezz Sep 30, 2026
1c5221c
Merge #223 map query candidate into #227
hwistlezz Sep 30, 2026
998d064
test(restaurant): supply location service in review slice
hwistlezz Sep 30, 2026
6c855b3
Merge #224 reviewed candidate into #228
hwistlezz Sep 30, 2026
c645e38
test(map): await Redis slot expiry before reuse
hwistlezz Sep 30, 2026
49485e3
fix(map): classify Google 403 quota status without retaining errors
hwistlezz Sep 30, 2026
9eba6e5
docs(map): gate public sessions on verified ingress limits
hwistlezz Sep 30, 2026
b613fd3
fix(map): keep daily quota and billing failures terminal
hwistlezz Sep 30, 2026
caf853e
Merge #222 final Google adapter into #224
hwistlezz Sep 30, 2026
0a78f1f
Merge #224 final Google classification into #228
hwistlezz Sep 30, 2026
bad36b4
fix(restaurant): 지오코딩 실패 진단 및 v4 오류 분류 수정 (#222)
hwistlezz Oct 2, 2026
718d33a
fix(restaurant): 위치 출처를 ADMIN으로 통일 (#220)
hwistlezz Oct 2, 2026
e65ce73
fix(restaurant): 지도 검색과 오류 처리 일관성 보완 (#223)
hwistlezz Oct 2, 2026
2b2af07
merge(restaurant): ADMIN 위치 모델을 지도 조회에 반영 (#223)
hwistlezz Oct 2, 2026
83fa3d3
fix(restaurant): 위치 작업 선행 리뷰 수정 전파 (#224)
hwistlezz Oct 2, 2026
8c4efab
fix(restaurant): 위치 유지보수 출처 정정 전파 (#228)
hwistlezz Oct 2, 2026
d10858f
fix(restaurant): 저장명 내부 공백을 검색에 보존 (#223)
hwistlezz Oct 2, 2026
0eb3d7b
fix(restaurant): 지도 페이지에 리뷰 수정 전파 (#227)
hwistlezz Oct 2, 2026
5ca37a0
fix(restaurant): 위치 작업 진단과 삭제 식당 상태 보존 (#224)
hwistlezz Oct 2, 2026
e45ea9d
fix(restaurant): 위치 작업 진단과 삭제 식당 상태 보존 (#224)
hwistlezz Oct 2, 2026
aa04c0d
fix(restaurant): 지도 세션 공개 활성화를 기본 비활성화 (#227)
hwistlezz Oct 2, 2026
c56dafe
fix(restaurant): 위치 관리 감사와 상시 정리 경계 보완 (#228)
hwistlezz Oct 2, 2026
cce282f
fix(admin): 위치 재시도 검증 메시지와 연결 문서 보완 (#224)
hwistlezz Oct 2, 2026
bf88d1f
fix(admin): 위치 재시도 검증 메시지와 연결 문서 보완 (#224)
hwistlezz Oct 2, 2026
1ea8ad7
Merge remote-tracking branch 'origin/develop' into feat/#220/restaura…
hwistlezz Oct 5, 2026
9b7de40
fix(restaurant): 위치 갱신 중 유효한 기존 좌표 보존 (#220)
hwistlezz Oct 5, 2026
a14ec93
docs(restaurant): 지도 갱신과 조회 세션 구현 기준 정리 (#220)
hwistlezz Oct 5, 2026
5349e41
chore(restaurant): 좌표 갱신 보존 정책 병합 (#224)
hwistlezz Oct 6, 2026
1165626
fix(restaurant): 위치 작업 재시도와 호출 중단 처리 보완 (#224)
hwistlezz Oct 6, 2026
7ad6357
docs(restaurant): 좌표 보존과 재시도 변경 내용 정리 (#224)
hwistlezz Oct 6, 2026
700a68c
fix(restaurant): 호출 중단 중에도 소진 작업 종료 (#224)
hwistlezz Oct 6, 2026
f5c32c2
merge(restaurant): 좌표 갱신 모델을 지도 조회에 반영 (#223)
hwistlezz Oct 6, 2026
bdd0a1c
fix(restaurant): 갱신 중 유효 좌표를 지도 조회에 유지 (#223)
hwistlezz Oct 6, 2026
f9552d1
Merge commit 'bdd0a1c' into feat/#227/restaurant-map-pagination
hwistlezz Oct 7, 2026
a006868
merge: 최신 위치 작업 변경 반영
hwistlezz Oct 7, 2026
d6b87df
fix(restaurant): 좌표 갱신과 만료 작업의 상태 보존 (#228)
hwistlezz Oct 7, 2026
092a487
feat(restaurant): 지도 조회 수명과 용량 제한 개선 (#227)
hwistlezz Oct 7, 2026
7f76b0d
fix(restaurant): 설정 변경 시 지도 용량 예약 수명 보존 (#227)
hwistlezz Oct 7, 2026
09ad888
fix(restaurant): 지도 세션 수명을 Redis 시각으로 통일 (#227)
hwistlezz Oct 7, 2026
d472cd0
Merge remote-tracking branch 'origin/develop' into feat/#220/restaura…
hwistlezz Oct 7, 2026
c4cdb4a
fix(restaurant): 미적용 지도 migration 번호 정리 (#220)
hwistlezz Oct 7, 2026
ed72710
Merge remote-tracking branch 'origin/develop' into feat/#222/google-g…
hwistlezz Oct 7, 2026
216671c
Merge branch 'feat/#220/restaurant-map-location' into feat/#224/resta…
hwistlezz Oct 7, 2026
978810f
Merge branch 'feat/#222/google-geocoding-adapter' into feat/#224/rest…
hwistlezz Oct 7, 2026
1040ac5
fix(restaurant): 위치 작업 migration을 V33으로 정리 (#224)
hwistlezz Oct 7, 2026
00306cd
Merge branch 'feat/#220/restaurant-map-location' into feat/#223/map-r…
hwistlezz Oct 7, 2026
2743a97
Merge branch 'feat/#224/restaurant-location-job' into feat/#228/resta…
hwistlezz Oct 7, 2026
24727fc
Merge branch 'feat/#223/map-restaurant-query' into feat/#227/restaura…
hwistlezz Oct 7, 2026
5aded19
fix(restaurant): 위치 유지보수 migration을 V34로 정리 (#228)
hwistlezz Oct 7, 2026
c0912ba
docs(restaurant): Google 연동 계획의 migration 번호 정리 (#222)
hwistlezz Oct 7, 2026
29cbf84
fix(restaurant): 숫자 premise의 번지 검증 지원 (#224)
hwistlezz Oct 7, 2026
fed8d3c
fix(restaurant): premise의 혼합 주소 역할 거부 (#224)
hwistlezz Oct 7, 2026
6a5bad2
Merge branch 'feat/#224/restaurant-location-job' into feat/#228/resta…
hwistlezz Oct 7, 2026
a5792a6
fix(restaurant): map migration을 V38로 재번호 (#220)
hwistlezz Oct 8, 2026
69f98e2
docs(restaurant): map migration 순서를 V38 이후로 갱신 (#222)
hwistlezz Oct 8, 2026
9666d69
Merge remote-tracking branch 'origin/develop' into feat/#220/restaura…
hwistlezz Oct 8, 2026
77c8a00
Merge remote-tracking branch 'origin/develop' into feat/#222/google-g…
hwistlezz Oct 8, 2026
e2b2bd7
fix(restaurant): location job migration을 V39로 재번호 (#224)
hwistlezz Oct 8, 2026
682bdf6
fix(restaurant): maintenance migration을 V40으로 재번호 (#228)
hwistlezz Oct 8, 2026
66f73aa
Merge branch 'feat/#220/restaurant-map-location' into feat/#223/map-r…
hwistlezz Oct 8, 2026
b7dad6e
Merge branch 'feat/#223/map-restaurant-query' into feat/#227/restaura…
hwistlezz Oct 8, 2026
8348da1
Merge branch 'feat/#220/restaurant-map-location' into feat/#224/resta…
hwistlezz Oct 8, 2026
1ef4b62
Merge branch 'feat/#222/google-geocoding-adapter' into feat/#224/rest…
hwistlezz Oct 8, 2026
3071160
Merge branch 'feat/#224/restaurant-location-job' into feat/#228/resta…
hwistlezz Oct 8, 2026
006094b
test(restaurant): 지도 MVC 보안 의존성 반영 (#223)
hwistlezz Oct 8, 2026
3392e8f
test(admin): 위치 API 보안 의존성 반영 (#224)
hwistlezz Oct 8, 2026
44d2e32
test(restaurant): 지도 페이지 보안 의존성 반영 (#227)
hwistlezz Oct 8, 2026
13cafaa
Merge branch 'feat/#223/map-restaurant-query' into feat/#227/restaura…
hwistlezz Oct 8, 2026
2e8d269
Merge branch 'feat/#224/restaurant-location-job' into feat/#228/resta…
hwistlezz Oct 8, 2026
ae298aa
feat: add explicit restaurant geocoding address
hwistlezz Oct 8, 2026
673e505
feat: add explicit restaurant geocoding address
hwistlezz Oct 8, 2026
026d3ca
fix: normalize Unicode geocoding whitespace
hwistlezz Oct 8, 2026
6ac288a
fix: normalize Unicode geocoding whitespace
hwistlezz Oct 8, 2026
8a6d29a
fix: include country in structured geocoding request
hwistlezz Oct 8, 2026
28908cc
fix(restaurant): 지도 세션 용량 사용과 진단 개선 (#227)
hwistlezz Oct 8, 2026
9f96d13
fix(restaurant): 손상된 지도 후보 tuple 거절 (#227)
hwistlezz Oct 8, 2026
2d28957
fix: geocode production addresses in English
hwistlezz Oct 8, 2026
c510720
fix: automate verified Tokyo address adoption
hwistlezz Oct 8, 2026
47ce3ad
Merge branch 'feat/#222/google-geocoding-adapter' into feat/#224/rest…
hwistlezz Oct 8, 2026
0a3078a
fix: reject conflicting input address numbers
hwistlezz Oct 8, 2026
bd46a3c
fix: include country in structured geocoding request
hwistlezz Oct 8, 2026
f628673
fix: geocode production addresses in English
hwistlezz Oct 8, 2026
ff0cf8c
fix: automate verified Tokyo address adoption
hwistlezz Oct 8, 2026
7f031bd
fix: reject conflicting input address numbers
hwistlezz Oct 8, 2026
01a80fe
docs: explain legacy location backfill input
hwistlezz Oct 8, 2026
86b508a
fix: keep address component number roles consistent
hwistlezz Oct 8, 2026
bbd1bc3
fix: keep address component number roles consistent
hwistlezz Oct 8, 2026
a1b9f57
docs(restaurant): 지도 migration 재번호 범위 명확화 (#220)
hwistlezz Oct 8, 2026
ff34602
fix(restaurant): 지도 조회 수용량 안내 정정 (#227)
hwistlezz Oct 8, 2026
0eb80b9
feat(restaurant): 지도 키워드 검색 계약 반영 (#223)
hwistlezz Oct 8, 2026
e7c37b2
docs(restaurant): 지도 검색어 계약 명시 (#227)
hwistlezz Oct 8, 2026
0836397
perf(restaurant): 지도 조회 단계 시간 계측 (#227)
hwistlezz Oct 8, 2026
b8acb4b
docs(admin): 식당 위치 계약 문서화 (#224)
hwistlezz Oct 8, 2026
9d05b5d
test(restaurant): 지도 OR 검색 회귀 범위 분리 (#223)
hwistlezz Oct 8, 2026
c55fca1
feat(restaurant): 지도 검색 결과 범위 집계 (#223)
hwistlezz Oct 8, 2026
43100ea
Merge commit 'c55fca1cc84be5b193801c3cc564ccc2b4591bb9' into feat/#22…
hwistlezz Oct 8, 2026
7722e2b
docs(restaurant): 공개 지도 API 문서화 (#223)
hwistlezz Oct 8, 2026
597e777
Merge commit '7722e2b34805a2c4fbd1d2d715cca7c097566e86' into feat/#22…
hwistlezz Oct 8, 2026
f71fcfc
fix(restaurant): 지도 결과 경계 만료 상한 포함 (#223)
hwistlezz Oct 8, 2026
9ee58e7
Merge commit 'f71fcfc7a8418113e7b53d7e02b1d95039c66cf4' into feat/#22…
hwistlezz Oct 8, 2026
6a73eac
docs(restaurant): 지도 migration 재번호 범위 명확화 (#220)
hwistlezz Oct 8, 2026
72a494b
docs(restaurant): 지도 migration 재번호 범위 명확화 (#220)
hwistlezz Oct 8, 2026
a8aaa9b
feat(restaurant): 지도 검색 결과 요약 유지 (#227)
hwistlezz Oct 8, 2026
94e0f2f
docs(restaurant): 지도 migration 재번호 범위 명확화 (#220)
hwistlezz Oct 8, 2026
191ad60
docs(restaurant): 위치 API 문서 반영 (#228)
hwistlezz Oct 8, 2026
2f581d1
docs(restaurant): 지도 검색 결과 계약 갱신 (#223)
hwistlezz Oct 8, 2026
f61b6b2
Merge commit '2f581d187bad2cbfb81d5fce4d0dc5058b63c1d0' into feat/#22…
hwistlezz Oct 8, 2026
1593035
feat(admin): 식당 위치 검토 목록 조회 추가 (#224)
hwistlezz Oct 8, 2026
b629208
fix(restaurant): 지도 검색 집계를 반복 읽기로 고정 (#223)
hwistlezz Oct 8, 2026
c42df24
Merge commit 'b62920856d4331ad6be9ea76f4804b592bde6a51' into feat/#22…
hwistlezz Oct 8, 2026
09955bf
fix(restaurant): 지도 세션 문서와 계측 보정 (#227)
hwistlezz Oct 8, 2026
348c0a6
fix(admin): 위치 목록 UTC 시각 변환 보정 (#224)
hwistlezz Oct 8, 2026
fd8c94d
Merge commit '348c0a613f8674bcb27d6d78cae7f45e770d41d1' into feat/#22…
hwistlezz Oct 8, 2026
acbb52b
feat(map): include Places in location maintenance scans (#228)
hwistlezz Oct 8, 2026
7114c8c
feat(map): Google Places provider 어댑터 추가 (#224)
hwistlezz Oct 8, 2026
67bb8f7
docs: 지도 마이그레이션 보존 검증 기준 정리 (#220)
hwistlezz Oct 8, 2026
c6510be
docs: 지도 마이그레이션 보존 검증 기준 정리 (#220)
hwistlezz Oct 8, 2026
9360ee4
docs: 지도 마이그레이션 보존 검증 기준 정리 (#220)
hwistlezz Oct 8, 2026
19716a1
docs: 지도 마이그레이션 보존 검증 기준 정리 (#220)
hwistlezz Oct 8, 2026
2155279
feat(restaurant): Places 위치 검토 흐름 추가 (#224)
hwistlezz Oct 8, 2026
205adaf
docs: 지도 마이그레이션 보존 검증 기준 정리 (#220)
hwistlezz Oct 8, 2026
aa86a2f
Merge commit '21552797d6ef87d16a279568240d72139e57a420' into feat/#22…
hwistlezz Oct 8, 2026
3cb01e5
Merge commit '205adaf02a72954f4a5afce928df0a4ba7651bad' into feat/#22…
hwistlezz Oct 8, 2026
1a81775
feat(map): retain Places location lifecycle policy (#228)
hwistlezz Oct 8, 2026
52c64ff
fix: Places 조회 경계와 호출 예산 검증 보완 (#224)
hwistlezz Oct 8, 2026
ce558b8
merge: Places 리뷰 수정과 API 오류 계약 반영 (#228)
hwistlezz Oct 8, 2026
173a261
[Test] Places migration까지 기존 데이터 보존 검증 (#224)
hwistlezz Oct 8, 2026
e7f1363
Merge commit '173a261df4a8d8d29f8bd6a83e357edc79966b36' into feat/#22…
hwistlezz Oct 8, 2026
f4bc13d
[Docs] Places migration 순서와 위치 실패 예시 정리 (#224)
hwistlezz Oct 8, 2026
8f4a3fa
fix(admin): use offset pagination for location reviews
hwistlezz Oct 8, 2026
6ab5572
Merge commit '8f4a3faca49ad8d87f0060b7eb2f522612eac30a' into feat/#22…
hwistlezz Oct 8, 2026
b1008cf
docs(admin): clarify Places selection revision fields
hwistlezz Oct 8, 2026
825624b
docs(map): clarify sorting and capacity retry guidance
hwistlezz Oct 8, 2026
084f766
Merge branch 'feat/#224/restaurant-location-job' into feat/#228/resta…
hwistlezz Oct 8, 2026
4693691
feat(restaurant): 지도 조회 Redis 연결 분리 (#227)
hwistlezz Oct 10, 2026
2b6db58
fix(restaurant): 지도 Redis 설정 오류 격리 (#227)
hwistlezz Oct 10, 2026
b120ffd
feat(restaurant): 공유 Redis 지도 세션 보호 추가 (#227)
hwistlezz Oct 11, 2026
7c82385
feat(restaurant): preview Places for create (#224)
hwistlezz Oct 11, 2026
f61a3a9
docs(restaurant): 지도 Redis 연결 생성 시점 정정 (#227)
hwistlezz Oct 11, 2026
da20fd8
docs(restaurant): clarify confirmation timing (#224)
hwistlezz Oct 11, 2026
4d585e9
merge: sync location confirmation into upkeep (#228)
hwistlezz Oct 11, 2026
7fd1d64
docs(map): align refresh confirmation rules (#228)
hwistlezz Oct 11, 2026
a25a4a9
docs(restaurant): 지도 Redis 거절 사유 목록 보완 (#227)
hwistlezz Oct 11, 2026
b420090
test(restaurant): cover confirmation schema (#224)
hwistlezz Oct 11, 2026
48bfef0
Merge location audit migration verification into maintenance
hwistlezz Oct 11, 2026
90c84a5
feat(auth): 관리자 표시용 로그인 ID 일괄 조회 추가 (#224)
hwistlezz Oct 11, 2026
6072336
feat(restaurant): 위치 검토 목록에 확인자 ID 추가 (#224)
hwistlezz Oct 11, 2026
3ab5b07
feat(admin): 위치 확인자의 로그인 ID 표시 (#224)
hwistlezz Oct 11, 2026
69b0f47
feat(admin): 위치 확인자 계정 표시 반영 (#228)
hwistlezz Oct 11, 2026
eeb9463
chore(restaurant): 위치 모델 선행 PR 반영 (#222)
hwistlezz Oct 11, 2026
0e81826
chore(restaurant): 지오코딩 선행 PR 반영 (#223)
hwistlezz Oct 11, 2026
93a17d9
chore(restaurant): 지도 조회 선행 PR 통합 (#224)
hwistlezz Oct 11, 2026
62b3a47
chore(restaurant): 위치 작업 선행 PR 통합 (#227)
hwistlezz Oct 11, 2026
5423a6b
chore(restaurant): 지도 페이지 선행 PR 반영 (#228)
hwistlezz Oct 11, 2026
c0325e7
test(restaurant): 지도 통합 후 위치 작업 mock 보완 (#224)
hwistlezz Oct 11, 2026
5b56395
test(restaurant): 선행 위치 작업 mock 반영 (#227)
hwistlezz Oct 11, 2026
1697bde
test(restaurant): 선행 위치 작업 mock 반영 (#228)
hwistlezz Oct 11, 2026
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
22 changes: 22 additions & 0 deletions .env.dev.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ REDIS_PORT=6379

JWT_SECRET=

# 키 준비와 공개 활성화는 별개다. ingress·정상 트래픽 용량·후보 규모/byte 예산 검증 전 비활성화한다 (#252).
HASHI_RESTAURANT_MAP_SESSION_ENABLED=false
HASHI_RESTAURANT_MAP_SESSION_SIGNINGKEY=
# shared는 기존 ElastiCache의 volatile-lru 정책을 유지한다. 접속값은 명시하며 자동 대체하지 않는다.
# dedicated는 별도 noeviction Redis. 최초 shared 사용/회계 유실 후 30분간 지도 요청은 503이다.
HASHI_RESTAURANT_MAP_REDIS_MODE=dedicated
# 로컬 격리 검증용 컨테이너: docker/docker-compose.map-redis.local.yml
HASHI_RESTAURANT_MAP_REDIS_HOST=
HASHI_RESTAURANT_MAP_REDIS_PORT=6379
HASHI_RESTAURANT_MAP_REDIS_SSL=false
HASHI_RESTAURANT_MAP_REDIS_USERNAME=
HASHI_RESTAURANT_MAP_REDIS_PASSWORD=
HASHI_RESTAURANT_MAP_REDIS_CONNECTTIMEOUT=2s
HASHI_RESTAURANT_MAP_REDIS_TIMEOUT=3s

KAKAO_CLIENT_ID=
KAKAO_CLIENT_SECRET=
KAKAO_REDIRECT_URI=
Expand All @@ -30,5 +45,12 @@ CLOUDFRONT_DOMAIN=
CORS_ALLOWED_ORIGINS=http://localhost:5173
CORS_ALLOWED_ORIGIN_PATTERNS=

# Google Places 관리자 위치 검토는 기본 비활성화다. 실제 비밀값은 이 예시 파일에 기록하지 않는다.
HASHI_MAP_GOOGLE_PLACES_ENABLED=false
HASHI_MAP_GOOGLE_PLACES_API_KEY=
HASHI_MAP_PLACES_SELECTION_ENABLED=false
HASHI_MAP_PLACES_SELECTION_SIGNING_KEY=
HASHI_MAP_PLACES_SELECTION_TOKEN_TTL=10m

GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=''
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ ext {
dependencies {
// web / docs
implementation 'org.springframework.boot:spring-boot-starter-web'
// Geocoding: RestClient transport with explicit retry/redirect disabling (Boot-managed version).
implementation 'org.apache.httpcomponents.client5:httpclient5'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'
// 로그 JSON 인코딩(Loki 수집용) — logback-spring.xml에서 사용
Expand Down Expand Up @@ -94,13 +96,17 @@ dependencyManagement {

tasks.named('bootJar') {
archiveFileName = 'app.jar'
mainClass = 'org.sopt.hashi.HashiApplication'
}

tasks.named('jar') {
enabled = false
}

tasks.named('test') {
// The maintenance smoke test launches the same artifact shipped by the existing build.
dependsOn tasks.named('bootJar')
systemProperty 'location.maintenance.jar', tasks.named('bootJar').get().archiveFile.get().asFile.absolutePath
useJUnitPlatform()
testLogging {
exceptionFormat = 'full'
Expand Down
18 changes: 18 additions & 0 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ services:

JWT_SECRET: ${JWT_SECRET}

HASHI_RESTAURANT_MAP_SESSION_ENABLED: ${HASHI_RESTAURANT_MAP_SESSION_ENABLED:-false}
HASHI_RESTAURANT_MAP_SESSION_SIGNINGKEY: ${HASHI_RESTAURANT_MAP_SESSION_SIGNINGKEY:-}
# shared는 기존 ElastiCache 재사용, dedicated는 별도 noeviction Redis. 호스트는 명시한다.
HASHI_RESTAURANT_MAP_REDIS_MODE: ${HASHI_RESTAURANT_MAP_REDIS_MODE:-dedicated}
HASHI_RESTAURANT_MAP_REDIS_HOST: ${HASHI_RESTAURANT_MAP_REDIS_HOST:-}
HASHI_RESTAURANT_MAP_REDIS_PORT: ${HASHI_RESTAURANT_MAP_REDIS_PORT:-6379}
HASHI_RESTAURANT_MAP_REDIS_SSL: ${HASHI_RESTAURANT_MAP_REDIS_SSL:-false}
HASHI_RESTAURANT_MAP_REDIS_USERNAME: ${HASHI_RESTAURANT_MAP_REDIS_USERNAME:-}
HASHI_RESTAURANT_MAP_REDIS_PASSWORD: ${HASHI_RESTAURANT_MAP_REDIS_PASSWORD:-}
HASHI_RESTAURANT_MAP_REDIS_CONNECTTIMEOUT: ${HASHI_RESTAURANT_MAP_REDIS_CONNECTTIMEOUT:-2s}
HASHI_RESTAURANT_MAP_REDIS_TIMEOUT: ${HASHI_RESTAURANT_MAP_REDIS_TIMEOUT:-3s}

KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID}
KAKAO_CLIENT_SECRET: ${KAKAO_CLIENT_SECRET}
KAKAO_REDIRECT_URI: ${KAKAO_REDIRECT_URI}
Expand All @@ -47,6 +59,12 @@ services:
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
CORS_ALLOWED_ORIGIN_PATTERNS: ${CORS_ALLOWED_ORIGIN_PATTERNS:-}

HASHI_MAP_GOOGLE_PLACES_ENABLED: ${HASHI_MAP_GOOGLE_PLACES_ENABLED:-false}
HASHI_MAP_GOOGLE_PLACES_API_KEY: ${HASHI_MAP_GOOGLE_PLACES_API_KEY:-}
HASHI_MAP_PLACES_SELECTION_ENABLED: ${HASHI_MAP_PLACES_SELECTION_ENABLED:-false}
HASHI_MAP_PLACES_SELECTION_SIGNING_KEY: ${HASHI_MAP_PLACES_SELECTION_SIGNING_KEY:-}
HASHI_MAP_PLACES_SELECTION_TOKEN_TTL: ${HASHI_MAP_PLACES_SELECTION_TOKEN_TTL:-10m}

prometheus:
image: prom/prometheus:v2.53.1
container_name: hashi-dev-prometheus
Expand Down
20 changes: 20 additions & 0 deletions docker/docker-compose.map-redis.local.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 로컬 연결 검증 전용. dev/prod compose에 자동으로 추가하지 않는다.
services:
map-redis:
image: redis@sha256:858f009f9709ce576febc734aa78b8f6d624b82571f9ddb6bda4377c833b3499
command: [redis-server, --maxmemory, 64mb, --maxmemory-policy, noeviction, --appendonly, "no", --save, ""]
ports:
- "127.0.0.1:16379:6379"
mem_limit: 128m
memswap_limit: 128m
cpus: 0.5
healthcheck:
test: [CMD, redis-cli, ping]
interval: 5s
timeout: 2s
retries: 3
logging:
driver: json-file
options:
max-size: "5m"
max-file: "2"
18 changes: 18 additions & 0 deletions docker/docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ services:

JWT_SECRET: ${JWT_SECRET}

HASHI_RESTAURANT_MAP_SESSION_ENABLED: ${HASHI_RESTAURANT_MAP_SESSION_ENABLED:-false}
HASHI_RESTAURANT_MAP_SESSION_SIGNINGKEY: ${HASHI_RESTAURANT_MAP_SESSION_SIGNINGKEY:-}
# shared는 기존 ElastiCache 재사용, dedicated는 별도 noeviction Redis. 호스트는 명시한다.
HASHI_RESTAURANT_MAP_REDIS_MODE: ${HASHI_RESTAURANT_MAP_REDIS_MODE:-dedicated}
HASHI_RESTAURANT_MAP_REDIS_HOST: ${HASHI_RESTAURANT_MAP_REDIS_HOST:-}
HASHI_RESTAURANT_MAP_REDIS_PORT: ${HASHI_RESTAURANT_MAP_REDIS_PORT:-6379}
HASHI_RESTAURANT_MAP_REDIS_SSL: ${HASHI_RESTAURANT_MAP_REDIS_SSL:-false}
HASHI_RESTAURANT_MAP_REDIS_USERNAME: ${HASHI_RESTAURANT_MAP_REDIS_USERNAME:-}
HASHI_RESTAURANT_MAP_REDIS_PASSWORD: ${HASHI_RESTAURANT_MAP_REDIS_PASSWORD:-}
HASHI_RESTAURANT_MAP_REDIS_CONNECTTIMEOUT: ${HASHI_RESTAURANT_MAP_REDIS_CONNECTTIMEOUT:-2s}
HASHI_RESTAURANT_MAP_REDIS_TIMEOUT: ${HASHI_RESTAURANT_MAP_REDIS_TIMEOUT:-3s}

KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID}
KAKAO_CLIENT_SECRET: ${KAKAO_CLIENT_SECRET}
KAKAO_REDIRECT_URI: ${KAKAO_REDIRECT_URI}
Expand All @@ -50,6 +62,12 @@ services:
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
CORS_ALLOWED_ORIGIN_PATTERNS: ${CORS_ALLOWED_ORIGIN_PATTERNS:-}

HASHI_MAP_GOOGLE_PLACES_ENABLED: ${HASHI_MAP_GOOGLE_PLACES_ENABLED:-false}
HASHI_MAP_GOOGLE_PLACES_API_KEY: ${HASHI_MAP_GOOGLE_PLACES_API_KEY:-}
HASHI_MAP_PLACES_SELECTION_ENABLED: ${HASHI_MAP_PLACES_SELECTION_ENABLED:-false}
HASHI_MAP_PLACES_SELECTION_SIGNING_KEY: ${HASHI_MAP_PLACES_SELECTION_SIGNING_KEY:-}
HASHI_MAP_PLACES_SELECTION_TOKEN_TTL: ${HASHI_MAP_PLACES_SELECTION_TOKEN_TTL:-10m}

# 운영은 API 문서를 노출하지 않는다 (springdoc.api-docs.enabled / springdoc.swagger-ui.enabled)
SPRINGDOC_API_DOCS_ENABLED: "false"
SPRINGDOC_SWAGGER_UI_ENABLED: "false"
Expand Down
51 changes: 51 additions & 0 deletions docker/prometheus/rules/map-redis-alerts.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copy the expressions into Grafana alert rules and select the existing notification policy.
# This file is not mounted or loaded automatically; it contains no contact point or credentials.
groups:
- name: hashi-map-redis
rules:
- alert: HashiMapRedisMemoryWarning
expr: |
(hashi_restaurant_map_redis_used_bytes > hashi_restaurant_map_redis_warning_limit_bytes)
and (hashi_restaurant_map_redis_probe_success == 1)
and (hashi_restaurant_map_redis_enabled == 1)
for: 5m
labels:
severity: warning
component: map-redis
annotations:
summary: "Redis memory is approaching the map admission limit"
description: "Check total Redis growth and map reservations before map requests are rejected."
- alert: HashiMapRedisNearAdmissionLimit
expr: |
(hashi_restaurant_map_redis_used_bytes > 0.9 * hashi_restaurant_map_redis_admission_limit_bytes)
and (hashi_restaurant_map_redis_probe_success == 1)
and (hashi_restaurant_map_redis_enabled == 1)
for: 1m
labels:
severity: critical
component: map-redis
annotations:
summary: "Redis memory is close to stopping map admission"
description: "Keep authentication Redis settings unchanged and inspect map and non-map memory growth."
- alert: HashiMapRedisEvictionObserved
expr: |
(hashi_restaurant_map_redis_evicted_keys - hashi_restaurant_map_redis_evicted_keys offset 1m > 0)
and (hashi_restaurant_map_redis_probe_success == 1)
and (hashi_restaurant_map_redis_enabled == 1)
labels:
severity: critical
component: map-redis
annotations:
summary: "The shared Redis instance has evicted keys"
description: "This is an instance-wide count; inspect authentication as well as map session failures."
- alert: HashiMapRedisProbeUnavailable
expr: |
(hashi_restaurant_map_redis_probe_success == 0)
and (hashi_restaurant_map_redis_enabled == 1)
for: 2m
labels:
severity: warning
component: map-redis
annotations:
summary: "Map Redis telemetry is unavailable"
description: "Inspect connection, TLS, ACL and map configuration; previous memory values are not current."
16 changes: 15 additions & 1 deletion docs/adr/0002-restaurant-map-query-and-location.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- 상태: #219에서 채택한 후속 구현 기준. 이 문서의 병합은 기능 구현·운영 활성화를 뜻하지 않는다.
- 결정일: 2026-09-26
- 갱신: 2026-10-06, #225에서 좌표 유지와 조회 세션 수명 정책 보완
- 관련 이슈: [#219](https://github.com/TEAM-HASHI/HASHI-SERVER/issues/219), [#216](https://github.com/TEAM-HASHI/HASHI-SERVER/issues/216)
- 외부 계약: [Map Contract v1](../map/map-contract-v1.md)
- 구현·인수 계획: [Implementation Plan](../map/implementation-plan.md)
Expand Down Expand Up @@ -65,15 +66,28 @@ M1에서는 새 공개 이벤트를 도입하지 않는다. 같은 모듈 안의

- MySQL: 식당·위치·관광 지역·변환 작업·저장 관계의 원본, BBOX·필터 후보 검색.
- Redis: 조회 조건, 후보 ID, 추천 순서, 별점·리뷰 수 기준값의 일시적인 조회 세션.
생성 후 절대 TTL 15분을 초기 설정으로 채택한다. 읽기·정렬 변경으로 연장하지 않는다.
조회 ID별 키 하나와 TTL부터 검증한다. 유휴 5분·최대 수명 30분을 초기값으로 두고,
정상적인 다음 페이지 조회·재정렬 때 `min(현재 시각 + 유휴 시간, 최초 생성 + 최대 수명)`으로 갱신한다.
유휴 시간은 사용 간격·만료 비율·메모리 측정으로 우선 5~10분 안에서 조정한다. 최적값으로 단정하지 않는다.
- 세션에 식당 사진·Google 좌표/원본 응답·개인 저장 여부를 복제하지 않는다.
- 현재 DB의 삭제·위치 수명·필터를 매 페이지 다시 확인한다. 신규 후보·최신 순위는 새 조회부터 반영한다.
작은 묶음으로 유효한 10개와 다음 1개를 확보하면 멈추며, 확인한 11번째는 다음 페이지에 남긴다.
- 유실·만료는 전용 410, Redis 접근 장애는 503으로 구분한다. 새 순서를 기존 cursor에 연결하지 않는다.
- 세션을 전부 저장할 수 없으면 명시적으로 실패한다. 일부 후보만 성공처럼 저장하지 않는다.

현재 Redis 설정이 있다는 사실은 지도 용량 확보의 증거가 아니다. 인증 토큰과 같은 인스턴스를
쓴다면 memory·eviction 영향을 확인하고 세션별/전체 admission 한도를 측정한다.
키 prefix는 메모리 격리 수단이 아니다. 이 결정은 성능 향상이 검증됐다는 뜻이 아니다.
여러 키로 후보를 나누거나 정렬별 자료구조를 중복 보관하는 최적화는 측정상 필요할 때 검토한다.
갱신 실패·동시 요청·만료 직후 요청의 규칙과 용량 인수 기준은 [구현 계획](../map/implementation-plan.md)에 둔다.

### 2.4 좌표와 갱신 작업 상태

같은 주소의 갱신은 현재 작업 상태만 바꾸고 기존 검증 좌표·출처·취득/만료 시각을 유지한다.
유효한 기존 좌표는 갱신 대기·재시도·실패 중에도 사용할 수 있다. 주소 변경 시에는 바로 제거하며,
새 결과가 검증을 통과했을 때만 교체한다. 만료 시각을 넘겨 사용하거나 실패만으로 수명을 연장하지 않는다.
정리 작업은 갱신 상태와 관계없이 보관 기한을 지키되 진행 중 작업을 취소하지 않아야 한다.
이 모델 전이는 #225에서 구현하며, 조회 SQL·worker·수명 정리의 연결은 후속 PR의 공개 전 조건이다.

## 3. 대안과 영향

Expand Down
77 changes: 77 additions & 0 deletions docs/adr/0003-restaurant-location-jobs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# ADR 0003: 식당 위치 확인 작업과 호출 예산

- 범위: #224. 선행 계약은 [M1 #219](https://github.com/TEAM-HASHI/HASHI-SERVER/pull/221).
- 운영 Google 활성화, 기존 식당 backfill, 만료 전 갱신과 보관 데이터 정리는 별도 gate다.

## 결정

식당 등록/주소 변경과 처리할 작업을 같은 MySQL transaction에 저장한다. 메모리 이벤트만으로
commit 직후의 종료를 복구할 수 없으므로 `restaurant_location_job`을 Restaurant의 작업 이력으로 둔다.
주소, 좌표, Google 원문은 작업 테이블에 복사하지 않는다. 소유 식당의 ID만 FK로 연결한다.

별도 `RestaurantLocationWorker` Bean이 polling → claim → HTTP/판정 → 완료를 수행한다.
worker는 transaction이 있으면 실행을 거절한다. 별도 `LocationJobTransactions` Bean의 claim/완료는
`REQUIRES_NEW`, `READ_COMMITTED`다. HTTP는 claim commit 뒤에 시작한다.
모든 쓰기 경로는 식당 → 해당 작업(복수이면 ID 순) → 전역 예산 순서로 잠근다.
관리자 저장은 예산 행을 잠그지 않으며 외부 호출도 하지 않는다.

관리자 등록/수정/삭제/재처리의 Port와 Service 진입점도 READ_COMMITTED로 맞춘다.
기본 REPEATABLE_READ에서는 비어 있는 작업 범위의 FOR UPDATE 뒤 INSERT가 서로 다른 식당의
동시 등록에서도 gap lock deadlock을 일으켰다. 부모 식당 잠금으로 같은 식당의 변경을 직렬화하면서
범위 gap lock을 피한다. 후속 작업이 enqueue/cancel을 호출할 때도 이 transaction 조건을 지킨다.

HTTP를 기다리는 polling cycle은 전용 단일 스레드 scheduler에서 실행한다. cycle 중복 적재가 없고,
기존 미디어 작업의 기본 scheduler를 점유하지 않는다. 전용 Bean은 defaultCandidate=false로 두어
Spring Boot의 기본 scheduler 구성을 유지한다. 종료 중인 호출은 중단 후 lease 만료로 복구한다.

`addressRevision`, `requestId`, 작업 ID, lease token, lease 만료와 soft delete를 완료 시 다시 검사한다.
마지막 예산 잠금을 얻은 뒤 DB 시각을 다시 읽는다. 유효하지 않은 성공/실패는 모두 no-op이다.
주소 변경/삭제로 대체된 작업도 이미 예약한 동시 슬롯은 원래 기한까지 유지한다.
HTTP 자체는 중복 실행될 수 있다. DB 완료 실패나 crash 후에는 lease 만료를 기다렸다가 재처리한다.

자동 재시도는 같은 작업 행에서 새로운 M2 requestId를 이어받고 attempt는 보존한다.
최초 요청을 포함해 기본 8회다. 실패 후 1분·5분·30분·2시간·6시간·12시간·24시간을 기다리고,
동시 재요청을 분산하도록 간격의 0~10%를 더한다. 취소도 마지막 시도라면 즉시 종료한다.
같은 주소의 이전 좌표는 작업 상태와 별개로 원래 validUntil까지 유지한다. 주소 변경 시에는 제거한다.
관리자 재처리와 주소 변경은 새 작업을 만들며 누적 전역 호출 예산을 우회하지 않는다.
PENDING 재처리는 기존 작업을 돌려준다. 작업 행은 최소 처리 이력만 남긴다.

## 환경 독립적인 제어 행

`V39__add_restaurant_location_jobs.sql`은 `restaurant_geocoding_budget(id=1)`을 `enabled=false`, `daily_limit=0`,
`max_concurrent=0`, `reserved_calls=0`으로 최초 생성한다. 이는 업무 데이터/운영 seed가 아닌
안전한 필수 제어 상태이므로 database convention의 제어 데이터 예외를 사용한다.
시작 코드나 repeatable migration으로 값을 초기화하지 않는다. 행 누락도 호출을 차단한다.

서버별 application 설정으로 전역 한도를 각각 계산하면 서버 수에 따라 비용이 늘어난다.
따라서 같은 DB 행 잠금 아래 UTC 일자·예약량·동시 실행 예약 수를 검사한다. 호출 직전 claim의
commit에 예산을 보수적으로 예약한다. 실제 전송 여부가 불확실해도 일일 사용량을 환급하지 않는다.
timeout/cancel의 실행 슬롯은 lease 기한까지 유지하고 같은 작업을 그 전에 다시 실행하지 않는다.
공유 quota 대기 중에는 다른 식당의 작업과 관리자 재처리도 호출할 수 없다.
마지막 자동 시도에서 quota 오류를 받아도 공유 대기는 기록하며 해당 작업만 FAILED로 끝낸다.

동시 예약 count는 예산 잠금을 얻은 후 최신 commit을 읽어야 하므로 READ_COMMITTED를 사용한다.
식당/작업은 부모 잠금으로 직렬화한다. 전역 예산만 변경하는 운영 transaction은 예산 행만 잠그고
식당/작업을 추가로 잠그지 않아야 한다. 중단은 이미 예약된 호출을 소급 취소하지 않는다.

## UTC 기준

lease·재시도·일일 예산 기준은 DB `UTC_TIMESTAMP(6)`이다. 이 시각은 DATE_FORMAT 문자열로 읽어
JDBC Timestamp의 connectionTimeZone 변환을 피한다. 새 job/budget DATETIME 필드는
`SqlTypes.LOCAL_DATE_TIME`으로 직접 읽고 쓴다. M2 위치 시각도 같은 선행 보완을 사용한다.
응답은 UTC Instant의 ISO-8601이다. 애플리케이션 Clock은 enqueue 이력 시각에 instant 기준으로만 쓴다.

Google 좌표 수명은 예약 직전 DB 시각을 보수적인 취득 기준으로 사용한다. `validUntil`은 이 값에
명시된 retention을 더해 계산한다. 응답 도착/DB 저장 지연은 수명을 연장하지 않는다.
재시도는 새 호출이므로 그 호출의 새 취득 기준을 사용하며 이전 결과/만료일을 재활용하지 않는다.

## 영향

두 테이블과 한 제어 행이 추가된다. 기존 migration과 주소/관광 지역 ID는 유지한다.
새 dependency, 인증 규칙 변경, Redis 의존은 없다. 관리자 저장 응답은 기존 201/200 성공 코드를
유지하고 상태/revision만 추가한다. 기존 위치 없는 식당은 UNRESOLVED/revision 0이며 일반 조회를 유지한다.
일반 정보만 수정할 때 새 작업이나 revision을 만들지 않는다.
삭제된 식당의 기존 관리자 편집 허용 정책은 유지하되 새 위치 작업은 등록하지 않는다.

테스트용 fake provider와 실제 MySQL에서 저장 원자성, lease 경합, 늦은 성공/실패, retry 예산,
JDBC Asia/Seoul 세션의 UTC 원시 값과 왕복을 검증한다. 실행 결과는 PR의 최종 HEAD evidence로 확인한다.
Loading
Loading