joungmin
648ccde4d7
perf(parse): #326 parseJson truncated-array O(N²) → 단일 패스
...
OciGenAiService.parseJson:
- 잘린 배열 복구 시 각 idx에서 end를 1씩 늘려 readValue 시도하던 O(N²) 로직 제거
- findObjectEnd: brace depth counter (문자열/escape 처리) 단일 패스 O(N)
- 8192 token 응답 처리 시간 수백 ms → 10ms 이하 예상
- 매 try마다 Jackson 예외 객체/스택트레이스 생성하던 부담 제거
설계서: docs/design/326-parsejson-optimization/README.md (Approved)
Refs: #326
v0.1.33
2026-06-15 15:35:48 +09:00
joungmin
ed61d29632
docs(changelog): v0.1.32 #332 화이트리스트 기록
2026-06-15 15:33:52 +09:00
joungmin
51f7b5c7d3
feat(restaurant): #332 PUT body 화이트리스트 명시화
...
ALLOWED_UPDATE_FIELDS set으로 PUT /api/restaurants/{id} body를 SQL updateFields
컬럼 가드와 1:1로 매핑. 허용 외 키는 silent drop + DEBUG 로그.
기존 SQL <if containsKey>로 이미 임의 컬럼 갱신이 차단되어 있으나, Controller에
명시 화이트리스트가 없어 의도 모호. 본 변경으로 두 레이어 모두 화이트리스트 확보.
sanitized가 비면 200 no-op로 응답 (사용자 경험 우선).
DDG/isNameSimilar/DTO는 별도 후속 (예: #346 ) 분리.
설계서: docs/design/332-restaurant-update-whitelist/README.md
Refs: #332
v0.1.32
2026-06-15 15:31:56 +09:00
joungmin
f4cb95e88c
docs(design): #332 Restaurant 화이트리스트 설계서 (Architect)
...
ALLOWED_UPDATE_FIELDS set으로 PUT body 허용 키 명시. DDG/isNameSimilar/DTO는 후속.
설계서: docs/design/332-restaurant-update-whitelist/README.md (Approved)
Refs: #332 (Architect)
2026-06-15 15:30:38 +09:00
joungmin
109ad106ac
docs(changelog): v0.1.31 #337 봇/레이트리밋 기록
2026-06-15 15:28:52 +09:00
joungmin
319fd18258
feat(stats): #337 봇 UA 필터 + IP 레이트리밋
...
- BotDetector 유틸 (Pattern.CASE_INSENSITIVE: bot|crawler|spider|slurp|scrap|fetch|monitor|preview|lighthouse)
- RateLimitService: Redis SET NX EX(60s) 패턴으로 같은 IP 윈도우 차단
- Bucket4j 대신 spring-data-redis 기존 의존성 재사용 (간결)
- Redis 다운 시 fail-open (사용자 경험 우선)
- StatsController.recordVisit: HttpServletRequest 받아 UA + X-Forwarded-For 우선 IP
- 봇/리밋 초과 → 200 + counted:false (사용자 페이지 로드 지장 X)
- 통과 → 200 + counted:true → statsService.recordVisit()
- application.yml: app.rate-limit.visit-window-seconds (env VISIT_WINDOW_SECONDS) 기본 60
- dev 검증: 봇 UA → counted=false, Mozilla → true, 즉시 재호출 → false
설계서: docs/design/337-stats-bot-ratelimit/README.md
Refs: #337 (Developer 단계)
v0.1.31
2026-06-15 15:26:27 +09:00
joungmin
0fa58a622c
docs(design): #337 통계 봇 필터 + 레이트리밋 설계서 (Architect)
...
User-Agent 봇 패턴 필터 + Bucket4j-redis IP 레이트리밋(1/min).
응답은 항상 200 + counted:bool로 사용자 페이지 로드 지장 X.
설계서: docs/design/337-stats-bot-ratelimit/README.md (Approved, 12개 섹션)
Refs: #337 (Architect 단계)
2026-06-15 15:23:12 +09:00
joungmin
9743f96af7
docs(changelog): v0.1.30 #335 ShedLock 분산 락 기록
2026-06-15 15:21:20 +09:00
joungmin
e5dc0534c4
feat(daemon): #335 분산 락 (ShedLock + Redis)
...
build.gradle:
- shedlock-spring 5.16.0
- shedlock-provider-redis-spring 5.16.0
TastebyApplication: @EnableSchedulerLock(defaultLockAtMostFor=PT15M)
ShedLockConfig 신규: RedisLockProvider Bean (in-cluster Redis 재사용)
DaemonScheduler.run:
- @SchedulerLock(name="daemon-runner", lockAtMostFor=PT15M, lockAtLeastFor=PT30S)
- 멀티 파드 환경(RollingUpdate 등)에서 한 인스턴스만 실행
- Redis 키: lock:daemon-runner
설계서: docs/design/335-daemon-distributed-lock/README.md (commit c88cb6a )
Refs: #335 (Developer 단계)
v0.1.30
2026-06-15 15:18:14 +09:00
joungmin
c88cb6ad54
docs(design): #335 데몬 분산 락 설계서 (Architect)
...
ShedLock + Redis lock provider 선택. DaemonScheduler.run을
@SchedulerLock(name='daemon-runner', lockAtMostFor=PT15M, lockAtLeastFor=PT30S)
로 보호. RollingUpdate 시 두 파드 공존 중 YouTube/OCI 중복 호출 차단.
설계서: docs/design/335-daemon-distributed-lock/README.md (Approved, 12개 섹션)
Refs: #335 (Architect 단계)
2026-06-15 15:16:06 +09:00
joungmin
079384b645
docs(changelog): v0.1.29 #336 SCAN/UNLINK/복구/메트릭 기록
2026-06-15 15:09:57 +09:00
joungmin
c7bd3c4c09
feat(cache): #336 SCAN/UNLINK + disabled 자동 복구 + 에러 메트릭
...
- CacheService.flush: redis.keys() 블로킹 → SCAN cursor + UNLINK 논블로킹.
UNLINK 미지원 환경은 DEL로 폴백. 500 batch 단위.
- 30초 주기 @Scheduled checkHealth: Redis ping → disabled 자동 토글.
startup 시 disabled=true여도 Redis 재기동되면 자동 복구.
- recordError 헬퍼: AtomicLong errorCount + volatile lastError.
로그 throttle (n==1 || n%100==0만 WARN, 나머지 DEBUG).
- CacheStats record + GET /api/admin/cache/stats (admin only).
- 설계서: docs/design/336-cache-scan-recovery/README.md (Approved).
Refs: #336
v0.1.29
2026-06-15 15:07:22 +09:00
joungmin
1a5db34e15
fix(review): #334 ReviewService update/delete @Transactional 명시 (단일 SQL이지만 일관성)
v0.1.28
2026-06-15 14:55:51 +09:00
joungmin
f126664117
docs(changelog): P5-2 작은 후속 기록
2026-06-15 14:51:22 +09:00
joungmin
a0e8878d9a
feat: P5-2 작은 후속 (#338+#320+#340+#333)
...
#338 : /api/version 신규
- HealthController에 @Value 빌드 정보 + GET /api/version 추가
- SecurityConfig.permitAll에 /api/version 추가
- application.yml app.build.version/commit (env APP_VERSION/APP_COMMIT)
- 부수: SecurityConfig에서 /api/daemon/config permitAll 제거 (이미 admin-only)
#320 : findRegionFromCoords 거리 보정
- 유클리드 거리 → cos(lat) 가중치(equirectangular approx)로 위경도 실거리 보정
- 위도가 큰 지역(부산↔서울)에서 city 추정 정확도 향상
#340 : MapView 마커/범례 ARIA
- 클러스터 마커: role=button + aria-label
- 개별 식당 마커: role=button + aria-label (name + 폐업 여부)
- 채널 범례: role=region + aria-label, 색상 점은 aria-hidden
#333 : ChannelController 캐시 세분화
- cache.flush() 전체 무효화 → cache.del(makeKey("channels"))로 채널 키만 evict
- 다른 모듈(restaurants/search) 캐시 hit율 보존
후속: deploy.sh에 APP_VERSION/APP_COMMIT env 주입은 별도 (현재 dev/unknown 응답)
Refs: #338 #320 #340 #333
v0.1.26
v0.1.27
2026-06-15 14:48:32 +09:00
joungmin
3304b9c54f
docs(changelog): v0.1.24 P5-1 작은 후속 기록
2026-06-15 14:44:08 +09:00
joungmin
437e709a8d
feat: P5-1 작은 후속 묶음 (#319+#325+#344)
...
#325 (#291 후속):
- VideoSseController.bulkExtract: Math.random() → ThreadLocalRandom 통일
(bulkTranscript와 일관)
- VideoSseController.rebuildVectors: 즉시 complete(total=0) 대신 명시적
'not_implemented' SSE 이벤트로 운영자 가시성 확보 + timeout 600s → 60s
- YouTubeService.getTranscript JavaDoc: mode 인자가 youtube-transcript-api
폴백에서만 사용된다는 점, 브라우저 추출은 mode 무관 명시
#319 (#301 후속):
- RestaurantDetail: buildSearchQuery 헬퍼 추출 (외부 지도 검색 URL 조합)
'한국' 단독 region 더미 케이스 가드 포함
- BottomSheet SNAP_POINTS/VELOCITY_THRESHOLD 정책 fn-doc 신규
(docs/design/279-frontend-restaurant-detail/fn-bottomsheet-snap.md)
#344 (#283 후속):
- globals.css에 --z-bottom-sheet=50, --z-filter-sheet=60, --z-modal=70 토큰
- LoginMenu: zIndex 99999 매직 넘버 → var(--z-modal)
Refs: #319 #325 #344
v0.1.24
v0.1.25
2026-06-15 14:40:45 +09:00
joungmin
dcebb9f06f
docs(changelog): v0.1.23 P4-4 별점/로그인 결함 기록
2026-06-15 14:34:27 +09:00
joungmin
bff3dcc200
feat(ui): P4-4 별점 공통화 + 로그인 모달 접근성 (#281+#283)
...
#281 (리뷰/메모 UI):
- Stars 컴포넌트 신규 (lib 분리 가능한 공통 별점) — 0.5 단위 절반 채우기 시각 구분
- ReviewSection/MemoSection의 StarDisplay 제거 → 공통 Stars 사용 (시각 일관성)
- StarSelector: role='radiogroup'/role='radio' + aria-checked, 44×44px 터치 영역,
반쪽 별 '⯨' 표시로 시각 차별화
- ReviewSection/MemoSection: API 실패 try/catch + alert 사용자 피드백
- MyReviewsList: Math.round 별점 → Stars 0.5단위 정확 렌더
#283 (로그인 메뉴):
- LoginMenu: useEscapeKey + useFocusTrap + useBodyScrollLock 적용
- role='dialog' / aria-modal / aria-labelledby / aria-label='로그인 창 닫기'
- onError 콘솔만 → 인라인 role='alert' 메시지로 사용자 피드백
- max-w-xs → max-w-sm (위젯 260px + 패딩 24px = 308px 안전 수용)
후속 분리:
- #343 (next/image + ARIA Tabs + Stars 테스트)
- #344 (z-index 토큰 + i18n)
Refs: #281 #283
v0.1.23
2026-06-15 14:33:15 +09:00
joungmin
ea8db4bef3
docs(changelog): v0.1.22 P4-3 인증/지도 결함 기록
2026-06-15 14:29:10 +09:00
joungmin
ed076411ed
fix: P4-3 인증 메시지 + 지도 cleanup/터치/접근성 (#266+#278)
...
#266 (인증):
- AuthService.loginGoogle: catch-all에서 e.getMessage() 노출 → "Invalid Google token"
고정 메시지 + 상세는 log.warn (Google verifier 내부 오류 정보 누출 차단)
#278 (지도):
- boundsTimerRef 언마운트 cleanup (unmounted setState 경고 + 메모리 누수 방지)
- '내 위치' 버튼 36×36 → 44×44 + aria-label='내 위치로 이동' + touch-manipulation
- dead code 제거 (indexRef set-only, restaurantMap 미사용)
#277 (health) — 결함 모두 후속 분리 (deep health, version, 테스트, rate limit)
후속 분리:
- #338 (deep health/version/Actuator)
- #339 (hex → brand-* 토큰 + 마커 ARIA + 테스트)
- #340 (다중 audience verifier + AuthService 테스트)
Refs: #266 #277 #278
v0.1.22
2026-06-15 14:25:53 +09:00
joungmin
865cd86aff
docs(changelog): v0.1.21 데몬/캐시/통계 결함 기록
2026-06-15 14:22:13 +09:00
joungmin
c6428e5d5f
fix(infra): P4-2 데몬/캐시/통계 결함 (#275+#276+#274)
...
#275 (데몬):
- DaemonConfigService.updateConfig: 정수 필드 가드 (비숫자/0/음수 → 400)
- DaemonScheduler: 외부 호출(scan/process) try-finally로 updateLastX 보장
(예외 시에도 다음 cron까지 backoff)
- DaemonController.getConfig: AuthUtil.requireAdmin() 추가 (운영 설정 노출 차단)
#276 (캐시):
- CacheService 생성자: ping을 try-with-resources로 자원 누수 차단,
ConnectionFactory null 가드
- makeKey: null/빈 parts 가드 (잘못된 키 생성 방지)
#274 (통계):
- SiteVisitStats: int → long (21억 누적 시 오버플로 방지)
- StatsMapper: getTodayVisits/getTotalVisits long 반환
- StatsService.recordVisit: 자정 경계 동시성 DataIntegrityViolationException
1회 재시도, 2회 실패 시 1건 손실 수용 (운영 영향 미미)
후속 분리:
- #336 (#275 분산 락 + DTO + 테스트)
- #337 (#276 SCAN + 자동복구 + 메트릭)
- #338 (#274 봇/레이트리밋 + Redis INCR + 테스트)
Refs: #275 #276 #274
v0.1.21
2026-06-15 14:20:14 +09:00
joungmin
5579c5b00f
docs(changelog): v0.1.20 백엔드 CRUD 결함 기록 (#290+#294+#295)
2026-06-15 14:16:41 +09:00
joungmin
4b02293046
fix(crud): P4-1 백엔드 CRUD 결함 일괄 수정 (#290+#294+#295)
...
#294 (리뷰/메모):
- MemoService.upsert: 동시성 INSERT 시 DuplicateKeyException 폴백 → UPDATE
- ReviewService.toggleFavorite: 동시성 INSERT 시 DuplicateKeyException ignored (토글 ON)
- ReviewController: rating(0~5) Bean validation 헬퍼, body.rating null/비숫자 → 400
- ReviewMapper.xml getAvgRating: NVL로 0건 시에도 0.0 보장
#295 (채널):
- ChannelController.create: typed DataIntegrityViolationException으로 유니크 충돌 감지 (제약명 문자열 매칭 폐기)
- ChannelController.create: channel_id/channel_name null/빈값 → 400
- ChannelService.deactivate: "UC..." 형식 검증으로 명시적 분기 (이전 폴백 방식의 의도 모호함 해결)
- ChannelMapper.xml findByChannelId: description/tags/sort_order까지 SELECT
#290 (식당 CRUD):
- RestaurantController: @PreDestroy로 virtual thread executor shutdown
- RestaurantController: 캐시 역직렬화 실패를 silent ignore → log.warn + cache.del 자동 evict
- RestaurantController: setTablingUrl/setCatchtableUrl URL 스킴 화이트리스트 검증
- CacheService: 단일 키 del() 메서드 추가
후속 분리:
- #333 (#290 DTO 화이트리스트 + DDG 대체)
- #334 (#295 cache.flush 세분화 + scan 비동기)
- #335 (#294 테스트)
Refs: #290 #294 #295
v0.1.20
2026-06-15 14:14:41 +09:00
joungmin
eb1eaa91a6
docs(changelog): v0.1.19 #293 검색/벡터 결함 기록
2026-06-15 14:04:09 +09:00
joungmin
9c2dc9f43a
fix(search): #293 검색/벡터 결함 7건 일괄 수정
...
- SearchController: q 빈값 가드 (HTTP 400) — '%%' LIKE 응답 폭발 차단
- SearchService:
- keywordSearch: LIKE 와일드카드 escape (%, _, \\)
- hybrid 모드: semantic 결과에도 attachChannels 호출 (이전: keyword만)
- ObjectMapper/TypeReference static 재사용 (캐시 hit 경로 GC 압박 완화)
- 알 수 없는 mode → warn 로그 + keyword fallback (이전: silent)
- maxDistance를 @Value("${app.search.max-distance:0.57}")로 외부화
- SearchMapper.xml: LIKE 절에 ESCAPE '\\' 추가
- VectorService.searchSimilar: embeddings/first list null/empty 가드 (NPE 방지)
- application.yml: app.search.max-distance (env SEARCH_MAX_DISTANCE) 추가
후속 분리: batch insert + 테스트 (별도 후속 이슈)
Refs: #293
v0.1.19
2026-06-15 14:01:59 +09:00
joungmin
7779d5ddfd
docs(changelog): v0.1.18 어드민 검증 UI 기록 (#304+#323)
2026-06-15 13:58:56 +09:00
joungmin
6ea82a5561
feat(admin): #304+#323 LLM 검증 UI + 공통 유틸 추출
...
#323 (LLM 검증 어드민 UI):
- api.ts: getVerifyPending / verifyAll / verifyOne / setRestaurantHidden 추가
- Restaurant 타입에 hidden / hidden_reason / verified_at 추가
- RestaurantsPanel 헤더에 "미검증 N건 + LLM 검증" 버튼 추가
- 테이블에 "검증" 컬럼 추가:
- hidden=true → "숨김 (사유)" 버튼 (클릭 시 해제)
- verified_at 있고 visible → "OK" 버튼 (클릭 시 숨김)
- 미검증 → "미검증" 텍스트
#304 (어드민 공통 유틸):
- lib/admin-utils.ts 신규
- getAdminToken(): localStorage 직접 접근 통일
- authHeaders(): 표준 Bearer 헤더
- consumeSseStream(): SSE 라인 파싱 헬퍼
- colSpan 6 → 7로 검증 컬럼 반영
후속 분리: #329 (admin/page.tsx 전체 분리 + localStorage/SSE 호출 11+곳 교체)
Refs: #304 #323 #322
v0.1.18
2026-06-15 13:57:33 +09:00
joungmin
04c54d1b1a
docs(changelog): v0.1.17 백엔드 결함 일괄 수정 기록 (#291+#292)
2026-06-15 13:23:51 +09:00
joungmin
4407f2d67d
fix(pipeline): #291+#292 운영 영향 큰 결함 6건 일괄 수정
...
#292 :
- ExtractorService.extractRestaurants: transcript null/blank 가드 (NPE 방지)
- PipelineService.processExtract: 진입 시 status='processing' 명시 전이
- PipelineService.processExtract: geocode 실패(geo==null) 시 좌표/place_id/주소
관련 컬럼을 data에 put하지 않아 upsert COALESCE 보존 의도 명확화
- GeocodingService.parseRegionFromAddress: 빈 토큰을 region 문자열에 포함하지
않도록 정규화 (예: '한국||구' 같은 깨진 토큰 방지)
#291 :
- VideoService.saveVideosBatch: @Transactional 추가 → batch insert 원자성
- .gitignore: backend-java/cookies.txt 및 **/cookies.txt 명시 (보안 노출 차단)
후속 분리: #325 (#291 잔여 MINOR), #326 (#292 parseJson 최적화 + MINOR)
Refs: #291 #292
v0.1.17
2026-06-15 13:21:25 +09:00
joungmin
7fa623d22d
docs: CHANGELOG v0.1.15+v0.1.16 기록 + #322 설계서 Approved
2026-06-15 13:07:08 +09:00
joungmin
d2e78b0363
feat(verify): #322 LLM 검증으로 잘못된/프랜차이즈 식당 자동 숨김
...
DB 마이그레이션 (운영 ATP에 사전 실행 완료):
- restaurants.hidden NUMBER(1) DEFAULT 0 NOT NULL
- restaurants.hidden_reason VARCHAR2(120)
- restaurants.verified_at TIMESTAMP
- idx_restaurants_hidden 인덱스
코드:
- Restaurant 도메인에 hidden/hiddenReason/verifiedAt 필드 추가
- RestaurantMapper.xml resultMap 갱신 + findAll에 hidden=0 조건 (includeHidden=true 시 제외)
- RestaurantMapper에 updateVerification/clearHidden/findUnverified/countUnverified 추가
- RestaurantService.findAll() includeHidden 오버로드 + 검증 헬퍼 메서드
- RestaurantVerifyService 신규 (verify, verifyAsync, verifyAll, buildPrompt, parseVerifyResponse)
- LLM 응답이 JSON 아닐 때 안전 기본값(valid=true) → hidden 유지
- 백필은 식당당 200ms sleep으로 LLM rate 보호
- PipelineService.processExtract 끝에 verifyAsync(restId) 호출 (신규 등록 자동 검증)
- AdminRestaurantController 신규 — requireAdmin 필수:
- GET /api/admin/restaurants/verify/pending
- POST /api/admin/restaurants/verify/all?batchSize=10
- POST /api/admin/restaurants/{id}/verify
- PATCH /api/admin/restaurants/{id}/hidden {hidden, reason}
프롬프트:
- 식당명, 주소, 지역, cuisine, foods를 OCI GenAI로 보내 valid/is_franchise/reason 판정
- 보수적 가이드 (모호하면 valid=true)
설계서: docs/design/322-restaurant-llm-verify/README.md (Approved 대기)
Refs: #322
v0.1.16
2026-06-15 13:04:23 +09:00
joungmin
d3cd1b5d5f
feat(daemon): instance-level enable flag (dev/prod 중복 폴링 방지)
...
dev와 prod가 같은 Oracle ATP 인스턴스(_low vs _medium tier만 다름)를 공유하는
환경에서 dev/prod 양쪽 DaemonScheduler가 같은 daemon_config row를 폴링하면
같은 시점에 동일 채널 스캔이 발생 → YouTube 봇 감지 위험 증가.
수정:
- application.yml: app.daemon.enabled (env DAEMON_ENABLED, 기본 true)
- DaemonScheduler.run() 첫 줄에서 인스턴스 플래그 검사 후 차단
- dev/backend/.env에 DAEMON_ENABLED=false 설정 (이 커밋엔 미포함, 로컬만)
운영(OKE)은 env 미설정 → 기본 true로 정상 동작.
dev(PM2)는 .env로 false → 스케줄러 자체가 동작 안 함.
Refs: #275 #321
v0.1.15
2026-06-15 12:50:41 +09:00
joungmin
51dcacc728
fix(scan): #291 YouTubeService.fetchChannelVideos publishedAfter 조기 종료 버그
...
업로드 재생목록(uploads playlist) 스캔에서 publishedAfter 이전 영상을 만나
break해도, do-while 조건이 응답의 nextPageToken을 보고 paging을 지속하던 결함.
수정:
- stopPaging boolean 플래그 추가
- inner-loop 조기 break에서 stopPaging = true
- outer paging 갱신 시 stopPaging 검사 우선
영향:
- 백필 효율 향상 (불필요한 API quota 소모 방지)
- 봇 감지 회피 (과한 페이징 요청 안 함)
- daemon 자동 모드의 안정적 동작 기반
Refs: #291 #321
2026-06-15 12:41:35 +09:00
joungmin
dc8a8e9b4c
docs(changelog): #301+#302 모달 접근성 + race condition + 필터 동기화 (v0.1.14)
2026-06-15 12:25:12 +09:00
joungmin
43fd931824
fix(a11y): #301+#302 모달 접근성 + race condition + 필터 상태 동기화
...
CRITICAL — 모달 접근성:
- frontend/src/lib/hooks/useModalA11y.ts 신규 (useEscapeKey, useFocusTrap, useBodyScrollLock)
- BottomSheet: role='dialog' / aria-modal / aria-label / ESC 닫기 / focus trap
- FilterSheet: role='dialog' / aria-modal / aria-labelledby / ESC 닫기 / focus trap, 닫기 버튼 aria-label
MAJOR — race condition (#301 ):
- RestaurantDetail useEffect에 cancelled 플래그 추가 → restaurant.id 변경 시 이전 fetch 결과 폐기
MAJOR — 필터 상태 동기화 (#302 ):
- page.tsx에 exitSearchMode 헬퍼 추가
- 검색 모드(isSearchResult=true)에서 cuisine/price/country/city/district 변경 시 자동으로 검색 모드 해제 + 원본 restaurants 재로드
후속 분리: #319(BottomSheet 매직넘버/UX), #320(필터 정밀도/접근성/테스트)
Refs: #301 #302
v0.1.14
2026-06-15 12:23:15 +09:00
joungmin
2d41f22b83
fix(infra): #316 backend resource request 재산정 + RollingUpdate 25%/25% 복귀
...
노드 다운사이징(2×1OCPU/6GB) 이후 backend CPU request 500m이 노드 한도
의 절반을 차지해 rollingUpdate 데드락 발생. 임시 패치(maxSurge=0/
maxUnavailable=1) 상태를 합리화하여 25%/25% 기본 정책으로 복귀.
변경:
- cpu 500m/1 → 300m/800m
- mem 768Mi/1536Mi → 512Mi/1024Mi
- strategy 25%/25% 명시 (기본값 복귀)
근거: 실측 idle CPU 0.7%, RSS ~305 MB. peak 30-40% 추정 안에서 안전.
검증: 적용 후 노드 잔여 330m → 다음 배포 시 두 Pod 공존 가능 (무중단).
다운타임: 이번 1회 ~25초 (구 500m Pod 점유 해제), 다음 배포부터 0초.
설계서: docs/design/316-backend-resource-rightsize/README.md (Approved).
Refs: #316
2026-06-15 12:07:47 +09:00
joungmin
2a6d307260
docs(changelog): OKE 다운사이징 + Orphan LB 삭제 + v0.1.13 배포 기록
2026-06-15 11:55:16 +09:00
joungmin
4638f605aa
fix(security): [Developer] #267 AdminUserController GET 4종에 requireAdmin() 추가
...
CRITICAL: listUsers, userFavorites, userReviews, userMemos 4개 GET이 인증만 요구하고 admin 검사가 없어, 일반 사용자 토큰으로 전체 사용자 목록 및 타인 활동 조회 가능했음. 각 메서드 첫 줄에 AuthUtil.requireAdmin() 호출 추가 → non-admin은 403.
함께 커밋(이전 미커밋 작업):
- Logger 등록 (감사 로그용)
- AuthUtil/Logger/HttpStatus/ResponseStatusException import 정리
- updateAdmin: 자기 자신 admin 변경 차단 + 감사 로그
(이미 동작 중이던 변경이나 git 미커밋 상태였음)
문서:
- 설계서 §3 인수조건에 권한 강제 항목 추가, 상태 Draft → Approved
- CHANGELOG.md 2026-06-15 핫픽스 항목 추가
검증:
- Anonymous GET /api/admin/users → 403 ✓
- Bad-token GET /api/admin/users → 403 ✓
- 백엔드 빌드 성공, tasteby-api 재시작 완료
Refs: #267
v0.1.13
2026-06-15 11:17:48 +09:00
joungmin
80b553ec19
docs: 현행화 17개 설계서 Approved + 후속 이슈 백로그 등록
...
Reviewer 결과 17 PASS / 1 REJECT (#267 admin 권한 critical).
- 17개 설계서를 Draft → Approved로 갱신
- #267(backend-user)은 critical 결함으로 06-Reviewer 유지
- 후속 17개 개선 이슈(#289~#305) 자동 등록 — 결함 124건 백로그 반영
(critical 3 / major 46 / minor 75)
- docs/README.md에 18개 설계서 인덱스 추가
- CHANGELOG.md 2026-06-15 섹션 추가
Refs: #266 #268-#283 (현행화 완료) #267 (대기) #289-#305 (백로그)
2026-06-15 11:08:18 +09:00
joungmin
e97a36a8d9
docs/design: tasteby 18개 기능 현행화 설계서 추가
...
- 백엔드 12개: auth/user/restaurant/video/extract-pipeline/search/review-memo/channel/stats/daemon/cache/health
- 프론트 6개: map/restaurant-detail/filter/review-memo/admin/login
- 12개 섹션 전 항목 채움 (목적/범위/인수조건/제약/아키텍처/데이터모델/함수명세표/흐름/엣지/테스트/리스크/미해결)
- 추적성 헤더에 구현 파일 경로 명시, 테스트는 TBD (현재 없음)
- 코드 변경 없음 — 기존 구현의 설계 문서화
Refs: #266 #267 #268 #269 #270 #271 #272 #273 #274 #275 #276 #277 #278 #279 #280 #281 #282 #283
2026-06-15 10:48:50 +09:00
joungmin
c78f928a2d
ch-bootstrap: persona pipeline + Design-First + 안전-최대 권한
...
- Redmine 8단계 페르소나 파이프라인 (.claude/agents, workflows)
- Design-First docs 골격 (docs/design, docs/adr, docs/pipeline)
- 안전-최대 권한 정책 (.claude/settings.json)
- Tasteby 고유 규칙 보존 (CLAUDE.md 병합)
- scripts/enqueue.sh: Redmine 큐 투입
Refs: tasteby bootstrap
2026-06-15 10:20:50 +09:00
joungmin
f2861b6b79
홈 탭 장르 카드 UI + Tabler Icons 적용 + 지역 필터 추가
...
- 홈 탭: 장르 가로 스크롤 카드 (Tabler Icons 픽토그램)
- 홈 탭: 가격/지역/내위치 필터 2줄 배치
- 리스트 탭: 기존 바텀시트 필터 UI 유지
- cuisine-icons: Tabler 아이콘 매핑 추가 (getTablerCuisineIcon)
- 드래그 스크롤 장르 카드에 적용
- 배포 가이드 문서 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
v0.1.11
v0.1.12
2026-03-12 22:52:42 +09:00
joungmin
dda0da52c4
내위치 필터 모바일 리스트 적용 + 반경 4km
...
- mapBounds 없을 때 userLoc 기준 ~4km 반경 필터링
- 내위치 ON 시 setUserLoc도 업데이트
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-12 20:25:36 +09:00
joungmin
18776b9b4b
바텀시트 필터 글씨 크기 미세 조정
...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
v0.1.10
2026-03-12 20:15:59 +09:00
joungmin
177532e6e7
모바일 필터 바텀시트 UI 적용
...
- FilterSheet 컴포넌트 신규: 바텀시트로 올라오는 필터 선택 UI
- 장르/가격/지역 필터 모두 네이티브 select 대신 바텀시트 사용
- 카테고리별 그룹핑 + sticky 헤더 + 선택 체크 표시
- slide-up 애니메이션 추가
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-12 20:13:46 +09:00
joungmin
64d58cb553
모바일 필터 UI pill 스타일로 개선
...
- select를 둥근 칩(pill) 형태로 변경 (아이콘 + 드롭다운 화살표)
- 선택 시 브랜드 컬러 배경 + 링 하이라이트
- 장르/가격/지역 필터 모두 동일 스타일 적용
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-12 20:08:42 +09:00
joungmin
a766a74f20
모바일 리스트 레이아웃 개선 + 내위치 줌 조정
...
- 식당명/지역/별점 1줄, 종류+가격(왼)+유튜브채널(우) 2줄, 태그 3줄 배치
- 가격대: 종류가 공간 우선 차지, 나머지에서 truncate
- 내위치 줌 16→17로 조정
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-12 20:04:32 +09:00
joungmin
4b1f7c13b7
Playwright 제거 → DuckDuckGo HTML 검색 전환 + UI 미세 조정
...
- 테이블링/캐치테이블 검색: Google+Playwright → DuckDuckGo HTML 파싱 (브라우저 불필요)
- 검색 딜레이 5~15초 → 2~5초로 단축
- 프론트엔드: 정보 텍스트 계층 개선 (폰트 크기/색상 조정)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
v0.1.9
2026-03-12 19:28:49 +09:00