Files
tasteby/CHANGELOG.md

156 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasteby 작업 기록
> 작업 내용, 이슈, 해결 방법을 기록하는 문서. 커밋/배포 시 참고용.
---
## 2026-06-15
### ♿ #301+#302 모달 접근성 + race condition + 필터 상태 동기화 (v0.1.14)
- 공통 훅 `frontend/src/lib/hooks/useModalA11y.ts` 신규 (useEscapeKey, useFocusTrap, useBodyScrollLock)
- BottomSheet/FilterSheet: role='dialog', aria-modal, aria-label/labelledby, ESC 닫기, focus trap
- RestaurantDetail: useEffect cancelled 플래그로 restaurant.id 변경 시 race condition 차단
- page.tsx: `exitSearchMode` 헬퍼 → 검색결과 모드에서 필터 변경 시 자동 검색 모드 해제 + 원본 재로드
- 후속 분리: #319 (BottomSheet 매직넘버/UX), #320 (필터 정밀도/접근성/테스트)
- Refs: #301 #302 (close)
### 🔧 #316 — backend resource request 재산정 + RollingUpdate 정책 복귀
- **변경 전**: cpu 500m/1, mem 768Mi/1536Mi, strategy maxSurge=0/maxUnavailable=1 (임시 패치)
- **변경 후**: cpu 300m/800m, mem 512Mi/1024Mi, strategy 25%/25% (기본 복귀)
- **근거**: 실측 idle 0.7% CPU, RSS ~305 MB. peak 30-40% 추정 안에서 안전.
- **검증**: rollout 후 노드 잔여 330m → 다음 배포 시 두 Pod 공존 가능, 무중단 RollingUpdate 회복.
- **다운타임**: 이번 1회 ~25초 (구 Pod 500m 점유 해제 위해 강제 종료). 다음 배포부터 0초.
- **설계서**: `docs/design/316-backend-resource-rightsize/README.md` (Approved).
- Refs: #316 (close)
### 🏗 OKE 인프라 — 노드 다운사이징 + LB 정리
- **Orphan Classic LB 삭제**: 132.226.175.247 (100Mbps shape, OKEclusterName 태그만 남고 DNS/Service 참조 없음) → 비용 절감
- **노드풀 교체 (블루-그린)**: `pool1` (2 노드 × 2 OCPU / 8 GB) → `pool2` (2 노드 × 1 OCPU / 6 GB)
- 사유: ARM64 Always Free 쿼터 변경 (4 OCPU/24 GB → 2 OCPU/12 GB)
- 절차: 새 노드풀 생성 → 기존 노드 cordon + drain → 기존 노드풀 삭제 → 무중단 확인
- **backend Deployment strategy 임시 패치**: `maxSurge: 25% → 0`, `maxUnavailable: 25% → 1`
- 노드당 1 OCPU 환경에서 backend(500m 요청) 두 Pod 공존 불가 → rollingUpdate 데드락 회피
- **⚠️ 다음 배포 시 ~30초 다운타임** 발생. 후속 이슈에서 resource request 재산정 권고.
### 🚀 운영 배포 v0.1.13
- 보안 핫픽스 #267 배포 (백엔드만)
- OCIR push + kubectl rolling update + git tag v0.1.13 완료
- 검증: `Anonymous /api/admin/users → 403`, `Bad-token → 403`, `정상 동작 영향 없음`
### 🔴 보안 핫픽스 #267 — AdminUserController GET 4종 권한 우회
- `listUsers`, `userFavorites`, `userReviews`, `userMemos`가 인증만 요구하고 admin 검사를 하지 않아 일반 사용자 토큰으로 전체 사용자 목록 및 타인 활동 조회 가능했음
- 4개 메서드 첫 줄에 `AuthUtil.requireAdmin()` 추가 → non-admin 호출 시 403
- 설계서 §3 인수조건에 `/api/admin/users/**` 권한 강제 항목 추가
- Refs: #267 (현행화 Reviewer 반려 → Developer 수정 → 다시 통과)
### ch-bootstrap 적용 (페르소나 파이프라인 + Design-First)
- Redmine 8단계 페르소나 큐(`01-Planner` ~ `09-Done`) + 9개 카테고리 자동 생성
- Design-First 게이트(설계서 없으면 코드 작성 금지) 도입
- `.claude/agents/` 8개 페르소나 + `.claude/workflows/persona-pipeline.js`
- 안전-최대 권한 정책(`.claude/settings.json`)
- `docs/{design,adr,pipeline}/` 골격 + `scripts/enqueue.sh`
- 기존 Tasteby 고유 규칙(존댓말, CHANGELOG, 디자인 패턴, CORS, PM2)은 `CLAUDE.md` 0/7/8장으로 보존
- Redmine 프로젝트 description + Wiki 4페이지(Overview/Dev-Env/Prod-Env/Deploy) 작성
### tasteby 기존 18개 기능 Design-First 현행화
- 백엔드 12개(auth/user/restaurant/video/extract-pipeline/search/review-memo/channel/stats/daemon/cache/health) + 프론트 6개(map/restaurant-detail/filter/review-memo/admin/login)
- 각 기능별 `docs/design/<issue>-<slug>/README.md` 12개 섹션 채움 (총 3,830줄)
- 추적성: 각 설계서가 구현 파일/Redmine 이슈/커밋 SHA와 연결됨
- **Reviewer 결과**: 17 PASS w/notes, 1 REJECT (#267 admin 권한 critical)
- 후속 17개 개선 이슈(#289~#305) 자동 등록 — 결함 총 124건(critical 3 / major 46 / minor 75) 백로그 반영
- 코드 변경 없음 — 문서화 + 백로그화 전용
---
## 2026-04-04
### 코드 리뷰 스크립트 추가 + 리뷰 지적사항 반영
- `scripts/code_review.py`: 페르소나 기반 코드 리뷰 스크립트 (OpenRouter API, 프론트/백엔드/보안/아키텍처 4관점)
- `UserService.updateAdmin()`: 존재하지 않는 userId에 대해 404 응답 추가
- `AdminUserController.updateAdmin()`: 자기 자신 admin 권한 변경 차단 + 감사 로그 추가 + 응답에 변경 결과 포함
- `JsonUtil.normalizeEvaluation()`: evaluation 정규화 로직을 공통 유틸로 통합 (RestaurantService, VideoService 중복 제거)
- `RestaurantService.linkVideoRestaurant()`: evaluation 저장 시 평문→JSON 정규화 + 300자 제한
### 가격대 필터 5단계 세분화
- 기존 3단계(저렴/보통/고가) → 5단계(저렴/가성비/보통/프리미엄/럭셔리)
- `PRICE_GROUPS` 상수 수정, 정규식 패턴 세분화
### 모바일 터치 영역 개선 (44×44px 통일)
- **별점 선택기**: 0.5단위 10개 숫자 버튼(24px) → 별 아이콘 5개(44px), 탭으로 정수/반점수 전환
- **FilterSheet 닫기 버튼**: `p-1``p-2` (터치 영역 확대)
- **RestaurantDetail 찜 버튼**: 패딩 추가 + `touch-manipulation` 적용
- **필터 초기화 X 버튼**: 아이콘 12px → 14px + 패딩 추가
### 채널 필터 시 식당이 3개만 나오는 버그 수정
- **원인**: 전체 식당 500개만 가져와서 클라이언트 필터링 → 특정 채널 식당이 상위 500개에 일부만 포함
- **수정**: `page.tsx`에서 채널 필터 변경 시 서버에 `channel` 파라미터를 보내 서버 사이드 필터링 적용
---
## 2026-03-29
### 식당 평가(evaluation) 표시 안 되는 버그 수정
- **원인**: LLM이 추출한 evaluation이 대부분 평문 문자열로 DB에 저장되어 있었으나, 프론트에서 `evaluation.text`로 접근하여 표시되지 않음
- **수정**:
- `JsonUtil.parseMap()`: JSON 파싱 실패 시 `{"text":"원본문자열"}`로 감싸서 반환
- `VideoService.findDetail()`: `VideoRestaurantLink`의 evaluation 평문을 JSON 객체로 정규화
---
## 2026-03-16
### Admin 유저 관리 — 관리자 권한 토글 기능 추가
- **Backend**
- `UserMapper.xml`: `findAllWithCounts``is_admin` 컬럼 추가, `updateAdmin` 쿼리 추가
- `UserMapper.java`: `updateAdmin()` 메서드 추가
- `UserService.java`: `updateAdmin()` 메서드 추가
- `AdminUserController.java`: `PATCH /api/admin/users/{userId}/admin` 엔드포인트 추가
- **Frontend**
- `api.ts`: `updateAdminUserAdmin()` API 함수 추가, 유저 타입에 `is_admin` 필드 추가
- `admin/page.tsx`: 유저 테이블에 "관리자" 컬럼 + ON/OFF 토글 버튼 추가
### CORS PATCH 메서드 허용
- **문제**: PATCH 요청 시 CORS preflight(OPTIONS)에서 403 차단
- **원인**: `WebConfig.java``allowedMethods``PATCH`가 빠져 있었음
- **해결**: `List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")``"PATCH"` 추가
### Icon 시스템 개선
- Material Symbols `sake` 아이콘 종횡비 문제 수정 — `width`/`height``fontSize`와 동일하게 고정 + `overflow: hidden`
- 이자카야 아이콘: `sake``local_bar` (술잔 모양으로 변경)
- 삼겹살/돼지구이, 족발/보쌈, 돈카츠: `PiggyBank``food:pig` (커스텀 돼지 SVG)
### LLM 추출 프롬프트 수정
- `ExtractorService.java`: `evaluation` 필드 → "평가 내용을 100자 이내로 요약"으로 변경
### 브랜드 가이드 문서 생성
- `frontend/docs/brand-guide.md`: 브랜드 아이덴티티, 컬러, 타이포, 아이콘 정책 등 정리
### PM2 프론트엔드 포트 고정
- **문제**: `pm2 restart` 후 Next.js가 3000(Gitea 포트)으로 fallback → nginx 502
- **해결**: PM2에 `PORT=3001` 환경변수 고정하여 재등록 + `pm2 save`
---
## 2026-03-14
### 홈 탭 장르 카드 픽토그램 적용
- Phosphor Icons (`@phosphor-icons/react`) + 커스텀 SVG FoodIcon 시스템 구축
- `cuisine-icons.ts``getPhosphorCuisineIcon()` 함수 추가 (46개 소분류 매핑)
- `FoodIcon.tsx` 생성 — jjigae, tteok, noodle, tempura, pig 커스텀 SVG 아이콘
- `food:` 접두어로 Phosphor vs 커스텀 SVG 분기 처리
### 지역 필터 추가 + 배포
- 홈 탭에 지역 필터 드롭다운 추가
- v0.1.11로 OKE 배포 완료
---
## 참고: 주의사항
| 항목 | 내용 |
|------|------|
| 새 HTTP 메서드 추가 시 | `WebConfig.java`의 CORS `allowedMethods`에 반드시 추가 |
| 백엔드 코드 수정 후 | `bootJar` 빌드 성공 확인 → `pm2 restart tasteby-api` |
| 프론트엔드 dev 포트 | 3001 고정 (3000은 Gitea) |
| tasteby-web 실행 방식 | `npm run dev` (standalone 아님) |