Commit graph

93 commits

Author SHA1 Message Date
7c20e9bb17 feat(schedule): 행사 수정 폼 + 공개 상세 페이지 + 지도
- Admin: EventEditForm 추가 (기존 포스터 유지 + 신규 추가 조합), ScheduleItem 편집 경로에 '행사' 분기
- PC 공개 상세: EventSection 추가 - 포스터 Swiper 슬라이드 + 호버 화살표, 클릭 시 Lightbox, 카카오맵 + 마커 + 장소명 오버레이, 관련 링크는 중간점+primary 색상, max-w-5xl 및 text-2xl로 크기 확대
- Mobile 공개 상세: MobileEventSection 추가 (포스터/장소/지도/링크)
- KakaoMap 공용 컴포넌트 신규 (SDK 1회 로드 공유), VITE_KAKAO_JS_KEY 사용
- .gitignore: frontend/.env 제외
- routes/admin/events.js: PUT 핸들러의 addOrUpdateSchedule → syncScheduleById 정정
- 관련 문서(api/architecture/development) 업데이트

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 12:24:01 +09:00
f2a15e07d6 feat(youtube-bot): 주간 지정 시간 폴링 모드 추가
- bot_youtube에 weekly_schedule_config JSON 컬럼 추가, cron_interval nullable로 변경
- weekly 모드: 지정 요일/시각에만 cron 트리거 → setInterval로 intervalSeconds 간격 폴링
- 종료 조건: 새 영상 1개 발견(stopOnFound) 또는 durationMinutes 경과
- 평상시 API 호출 없어 주 1회 업로드 채널(워크맨 등)의 할당량 낭비 최소화
- 프론트 폼에 상시/주간 모드 토글 추가, 요일 드롭다운 월~일 순서로 정렬
- 관련 문서(api/development/architecture) 갱신

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 20:56:54 +09:00
8ece4b1850 feat(backend): 봇 연속 오류 시 자동 정지 로직 추가
- consecutiveErrors 카운터로 실패 횟수 추적 (성공 시 0으로 리셋)
- 동일 에러 루프에서 sync/error 로그는 첫 1회만 기록하여 스팸 방지
- 10회 연속 실패 시 stopBot 호출 및 bot/stop 로그 1건 남김
- docs/logs.md, docs/development.md 관련 설명 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 11:38:37 +09:00
aa95f737ba refactor(admin): 활동 로그 컴포넌트 분리 및 빈 상세정보 처리
Logs.jsx에서 상수/유틸과 다이얼로그를 components/pc/admin/log/로 분리하여
프로젝트 구조 패턴에 맞춤. 빈 객체 {} details가 표시되던 버그 수정.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:49:14 +09:00
abf71d97d7 docs: 새 기능 추가 시 logActivity 호출 필수 안내 추가
development.md에 로그가 자동 수집이 아님을 명시하고,
CLAUDE.md 작업 주의사항에 활동 로그 필수 항목 추가.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:23:00 +09:00
aa6c05e6b5 docs: 활동 로그 시스템 문서 업데이트
api.md에 GET /admin/logs 명세 추가, architecture.md에
logs 테이블/파일 추가, development.md에 로그 시스템 가이드 추가,
logs.md를 실제 구현 결과에 맞게 갱신.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:08:35 +09:00
c6332c4f96 refactor: activity_logs → logs로 네이밍 통일
- DB 테이블: activity_logs → logs
- 문서: activity-logs.md → logs.md
- 컴포넌트: ActivityLogs.jsx → Logs.jsx
- 라우트 import 업데이트

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:54:08 +09:00
c4cd0dec30 feat(admin): 활동 로그 페이지 컴포넌트 및 설계 문서 추가
더미데이터로 활동 로그 UI 구현 (필터, 테이블, 페이지네이션)
라우트/메뉴 연결은 다음 단계에서 진행

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:16:59 +09:00
9335720fa8 docs: YouTube 봇 API 최적화 관련 문서 업데이트
- architecture.md: YouTube 서비스 파일 구조 추가
- development.md: 동기화 흐름, API 할당량, 주요 함수 목록 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 15:55:50 +09:00
91d4442d30 docs: X 봇 extract_youtube 관련 문서 및 스키마 업데이트
- bot_x.sql에 누락된 컬럼 추가 (text_filters, include_retweets, extract_youtube)
- api.md에 X 봇 API 응답 스키마 및 필드 설명 추가
- architecture.md bot_x 테이블 설명 구체화
- development.md API 클라이언트 함수 목록 보완

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:12:00 +09:00
d4ed9ef66b chore: x-bots-plan.md 삭제
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 22:56:15 +09:00
294018c93b refactor(x-bot): x_profiles 테이블 제거, bot_x로 통합
- x_profiles 테이블 삭제 (bot_x에 프로필 정보 포함)
- saveProfile(), getProfile() 함수가 bot_x 테이블 사용하도록 수정
- Redis 캐시는 그대로 유지 (성능)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 09:42:26 +09:00
9ceef6c656 feat(x-bot): 키워드 필터링 및 전체 동기화 기능 추가
Backend:
- bot_x 테이블에 text_filters 컬럼 추가
- syncNewTweets/syncAllTweets에 텍스트 필터링 로직 적용
- 봇 추가 시 전체 트윗 동기화 수행 (백그라운드)
- X 봇 API에 text_filters 필드 처리

Frontend:
- XBotDialog에 고급 설정 (키워드 필터) UI 추가
- BotTableRow에서 X 봇 수정/삭제 버튼 활성화

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 09:23:45 +09:00
4f11e14b12 refactor(db): 봇 테이블 이름 통일 및 X 봇 스키마 추가
- youtube_bots → bot_youtube, x_bots → bot_x로 테이블 이름 변경
- bot_x 테이블 생성 및 시드 데이터 추가
- 관련 백엔드 코드에서 테이블 참조 업데이트
- X 봇 동적 관리 구현 계획 문서 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-07 19:52:41 +09:00
1c04f4ed6d refactor: 봇 관리 페이지 타입별 섹션 분리
- Meilisearch, YouTube, X 세 섹션으로 분리
- 각 섹션에 아이콘 및 색상 적용
- YouTube 섹션에 "봇 추가" 버튼 추가 (기능은 추후 구현)
- YouTube 봇 동적 관리 계획서 추가 (docs/youtube-bots-plan.md)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 17:58:30 +09:00
dc216a0f98 docs: API 문서 업데이트
- 멤버 API: 영문명 조회 지원 추가
- 일정 API: 특수 일정 ID 형식 설명 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 20:39:39 +09:00
f8c73c5a0a docs: Meilisearch 동기화 정보 업데이트
- description 필드 제거 (schedules 테이블에 없음)
- 실시간 동기화 정보 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:27:31 +09:00
5b9d93b37f feat: 데뷔/주년 기념일 카드 및 축하 다이얼로그 추가
- DebutCard 컴포넌트 추가 (PC/모바일)
- DebutCelebrationDialog 축하 다이얼로그 추가
- Fromis9Logo SVG 컴포넌트 추가
- 기념일 카테고리 추가 (ID: 9)
- 데뷔일(2018.01.24) 및 주년 일정 자동 생성
- 폭죽 효과 추가 (fireDebutConfetti)
- 카테고리 정보 DB에서 동적 조회하도록 개선

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 15:04:29 +09:00
87a69c0cbd refactor: API 응답에서 datetime을 date와 time으로 분리
- datetime 필드를 date와 time 필드로 분리하여 00:00 시간도 정상 표시되도록 수정
- 백엔드: formatSchedule, Meilisearch 검색 결과, 스키마 업데이트
- 프론트엔드: datetime 파싱 로직 제거, date/time 직접 사용
- 문서: API 응답 예시 업데이트

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 10:11:02 +09:00
8bc09e7c0d docs: 문서 업데이트 및 improvements.md 삭제
- improvements.md: 모든 개선 작업 완료로 삭제
- api.md:
  - 로그인 Rate Limit 정보 추가
  - 봇 API에 last_sync_duration, version 필드 추가
  - 타임스탬프 KST 형식으로 업데이트
- architecture.md: backend/utils 폴더 구조 추가
- development.md: Redis KEYS → SCAN 반영

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:06:25 +09:00
bdd2dfcd84 feat: 성능 최적화 (Phase 4)
- cache.js: Redis KEYS → SCAN으로 변경 (블로킹 방지)
- suggestions.js: 동기식 파일 I/O → 비동기 변경
  - readFileSync → readFile (fs/promises)
  - writeFileSync → writeFile (fs/promises)
- improvements.md: Phase 4 완료로 업데이트

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:04:27 +09:00
52a655bf76 feat: 외부 서비스 안정성 개선 (Phase 3)
- Nitter 요청에 10초 타임아웃 및 HTTP 상태 코드 검증 추가
- Meilisearch syncAllSchedules에서 불필요한 deleteAllDocuments 제거
  - addDocuments는 같은 ID면 자동 업데이트(upsert)
- 일정 삭제 시 Meilisearch 동기화 코드 정리 (동적 import 제거)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 21:01:35 +09:00
e852f215a3 feat: 보안 강화 및 인증 개선 (Phase 2)
- 로그인 Rate Limit 추가 (5회/분, 마지막 시도 기준 리셋)
- Multipart JSON 파싱 에러 처리 추가
- 로그아웃 시 무한 리다이렉트 버그 수정
- 인증 라우트 가드(RequireAuth) 추가로 비로그인 접근 차단
- Zustand hydration 대기로 페이지 깜빡임 해결
- admin/public 라우트 조건부 렌더링으로 경로 매칭 경고 해결

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 20:47:05 +09:00
4edef16310 fix: 일정 저장/삭제에 트랜잭션 적용
- youtube/index.js: saveVideo에 withTransaction 적용
- x/index.js: saveTweet, saveYoutubeFromTweet에 withTransaction 적용
- schedules/index.js: DELETE 핸들러에 withTransaction 적용
- 중간 실패 시 자동 롤백으로 데이터 무결성 보장
- docs/improvements.md 문서 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 20:21:56 +09:00
d29c966ae0 docs: 문서 업데이트 및 code-review.md 삭제
- architecture.md: routes/ 폴더 구조 추가
- development.md: API 클라이언트 헬퍼 사용법 추가
- code-review.md: 모든 작업 완료로 삭제

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 13:40:59 +09:00
bd7fbea082 refactor: API 클라이언트 레거시 export 삭제
마이그레이션 완료로 더 이상 사용되지 않는 개별 export 제거
- get, post, put, del
- authGet, authPost, authPut, authDel

현재 방식: api.get(), authApi.post() 등

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 13:35:33 +09:00
1c9b30b783 에러 유틸리티 함수를 모든 라우트에 적용
utils/error.js에 정의된 헬퍼 함수들(badRequest, unauthorized, notFound,
conflict, serverError)을 전체 라우트 파일에 적용하여 에러 응답 처리 일관성 확보

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 11:24:42 +09:00
b8137935c2 refactor: 보안 강화 및 앨범 삭제 로직 개선
- JWT_SECRET 환경변수 필수화 (기본값 제거)
- 앨범 삭제 시 S3 파일(사진, 티저, 비디오) 함께 삭제
- 앨범 삭제 시 관련 DB 테이블 정리 (album_photo_members, album_photos, album_teasers)
- Meilisearch latest 태그로 변경 (v1.6 → latest)
- 코드 리뷰 문서 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 11:00:17 +09:00
980ae3fe1d refactor: frontend-temp를 frontend로 대체 및 문서 업데이트
- frontend 폴더를 새로 리팩토링된 frontend-temp로 교체
- docs/architecture.md: 현재 프로젝트 구조 반영
- docs/development.md: API 클라이언트 구조 업데이트
- docs/frontend-improvement.md 삭제 (완료된 개선 계획)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 10:29:30 +09:00
218b825878 refactor: 일정 관리 컴포넌트 분리 (Phase 3)
- AnimatedNumber 공통 컴포넌트 추출 (32줄)
- BotCard 컴포넌트 분리 + XIcon, MeilisearchIcon 포함 (233줄)
- CategoryFormModal 컴포넌트 분리 (195줄)
- ScheduleBots.jsx: 570줄 → 339줄 (231줄 감소)
- ScheduleCategory.jsx: 441줄 → 289줄 (152줄 감소)
- 문서 업데이트: 개선 결과 테이블 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 10:21:06 +09:00
d2f6670795 docs: 일정 관리 페이지 개선 계획 문서 작성
- 5개 파일 분석 (Schedules, ScheduleForm, ScheduleDict, ScheduleBots, ScheduleCategory)
- 공통 코드 중복 문제 정리 (colorMap/getColorStyle)
- 파일별 개선 사항 및 우선순위 정리

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 09:28:09 +09:00
cf8cdb7ec6 refactor: AlbumPhotos.jsx 분리 - 4개 컴포넌트 추출
- PendingFileItem.jsx 추출 (업로드 대기 파일 아이템)
- BulkEditPanel.jsx 추출 (일괄 편집 도구 + parseRange 함수)
- PhotoGrid.jsx 추출 (컨셉 포토/티저 그리드)
- PhotoPreviewModal.jsx 추출 (이미지/비디오 미리보기)
- AlbumPhotos.jsx: 1536줄 → 1033줄 (503줄 감소)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 23:46:52 +09:00
f436cf4367 refactor: AlbumForm.jsx 분리 - CustomSelect, TrackItem 컴포넌트 추출
- CustomSelect.jsx 추출 → common/ (재사용 가능한 드롭다운)
- TrackItem.jsx 추출 → album/ (트랙 입력 폼)
- AlbumForm.jsx: 631줄 → 443줄 (188줄 감소)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 23:39:44 +09:00
e31cb82649 refactor: ScheduleDict.jsx 분리 - WordItem 컴포넌트 추출
- WordItem.jsx 컴포넌트 추출 (단어 테이블 행 + 품사 드롭다운)
- POS_TAGS 상수 분리하여 export
- ScheduleDict.jsx: 714줄 → 572줄 (142줄 감소)
- 일정 관련 대형 파일 분리 완료

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 23:31:58 +09:00
cbce382d94 refactor: Schedules.jsx, ScheduleForm.jsx 대형 파일 분리
Phase 2 대형 파일 분리 작업:

Schedules.jsx (1465줄 → 1159줄, 306줄 감소)
- ScheduleItem.jsx 컴포넌트 추출
- 검색 모드와 일반 모드에서 공통 사용

ScheduleForm.jsx (1047줄 → 765줄, 282줄 감소)
- LocationSearchDialog.jsx 추출 (장소 검색 모달)
- MemberSelector.jsx 추출 (멤버 선택 UI)
- ImageUploader.jsx 추출 (이미지 업로드)

새 컴포넌트 (components/pc/admin/schedule/):
- ScheduleItem.jsx
- LocationSearchDialog.jsx
- MemberSelector.jsx
- ImageUploader.jsx

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 23:28:57 +09:00
5f9f9789aa feat: 관리자 404 에러 페이지 추가
- pages/pc/admin/common/NotFound.jsx 생성
- AdminLayout 사용, 대시보드 이동 버튼 포함
- App.jsx에 /admin/* catch-all 라우트 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 23:03:18 +09:00
6a96b8a5f9 refactor: CATEGORY_ID 하드코딩 제거 및 봇 관리 페이지 애니메이션 추가
- constants/index.js에서 CATEGORY_ID 상수 삭제
- 카테고리 API 데이터의 name으로 비교하도록 변경 (유튜브, X)
- 봇 관리 페이지에 stagger 애니메이션 및 AnimatedNumber 추가
- admin/schedules API 경로 수정 (/admin/schedules/:id → /schedules/:id)
- authApi export 누락 수정
- 문서 업데이트 (Phase 1 완료, 관리자 에러 페이지 추가 예정)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 22:04:37 +09:00
b314b70014 refactor: 프론트엔드 개선 계획 수립
- 기존 마이그레이션 문서 삭제 (admin-migration.md, frontend-refactoring.md, migration.md)
- 새로운 개선 계획서 작성 (frontend-improvement.md)
- constants 정리: CATEGORY_NAMES, ALBUM_TYPES, 불필요한 SNS 링크 삭제
- schedule.js: getMemberList에서 쉼표 구분 로직 제거

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 21:30:28 +09:00
1d5626568a feat: 일정 추가 폼 카테고리별 분기 마이그레이션
- form/index.jsx: 카테고리 선택 메인 페이지
- form/YouTubeForm.jsx: YouTube URL 기반 일정 추가
- form/XForm.jsx: X 게시글 ID 기반 일정 추가
- form/components/CategorySelector.jsx: 카테고리 선택기
- edit/YouTubeEditForm.jsx: YouTube 일정 수정 폼
- App.jsx 라우트 업데이트
  - /admin/schedule/new → 새로운 카테고리 선택 폼
  - /admin/schedule/new-legacy → 기존 레거시 폼
  - /admin/schedule/youtube/:id/edit → YouTube 수정 폼

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 21:11:59 +09:00
9515db712d feat: 전체 멤버인 경우 '프로미스나인'으로 표시
- 백엔드: buildMemberMap, getScheduleDetail 함수에서 현재 활동 멤버 전원인 경우
  "프로미스나인"으로 대체하여 반환
- 프론트엔드: getDisplayMembers 함수에서 멤버 수 계산 로직 제거 (백엔드에서 처리)
- 탈퇴 멤버(is_former=1) 제외하고 현재 활동 멤버만 계산

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 20:42:05 +09:00
ff5c168529 docs: admin-migration.md 5단계 일정 관리 완료 체크
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 20:36:16 +09:00
7dc3ec692e feat: 관리자 페이지 마이그레이션 완료 (Phase 4-5)
- 관리자 페이지 폴더 구조 재구성 (pages/pc/admin/)
  - login/, dashboard/, members/, albums/, schedules/
- 앨범 관리 페이지 마이그레이션 (Albums, AlbumForm, AlbumPhotos, AlbumTeasers)
- 일정 관리 페이지 마이그레이션 (Schedules, ScheduleForm, ScheduleCategory, ScheduleDict, ScheduleBots)
- DatePicker 컴포넌트 버그 수정 (월 이동 및 연도 선택)
- 일정 관리 라우트 경로 수정 (/admin/schedule)
- 마이그레이션 문서 업데이트

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 20:35:05 +09:00
f64f6cee00 feat: 관리자 간단한 페이지 마이그레이션 (Phase 3)
- AdminDashboard 페이지 추가
- AdminMembers 페이지 추가
- AdminMemberEdit 페이지 추가
- useToast 훅 추가
- App.jsx에 관리자 라우트 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 19:03:21 +09:00
4a26369dff refactor: 관리자 기반 설정 마이그레이션 (Phase 2)
- 관리자 API 추가 (albums, members, schedules, categories, stats, suggestions, bots)
- AdminLayout/Header 컴포넌트 추가
- 공통 컴포넌트 추가 (ConfirmDialog, DatePicker, TimePicker, NumberPicker)
- AdminLogin 페이지 마이그레이션
- App.jsx에 관리자 라우트 추가 (/admin)
- ScheduleDetail.jsx import 경로 수정

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 18:44:15 +09:00
58f359adfa docs: 관리자 마이그레이션 계획서 추가 및 완료된 문서 삭제
- 관리자 페이지 마이그레이션 계획서 추가 (admin-migration.md)
- 완료된 백엔드 리팩토링 문서 삭제
- 완료된 코드 개선 문서 삭제
- 파비콘 복사

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 18:27:52 +09:00
772eda21e0 docs: 코드 개선 문서 최종 업데이트
- 3.7 리스트 key 검토 완료 (정적 리스트는 index 유지, 동적은 고유 ID 사용 중)
- 품질 점수 요약 업데이트 (6/10 → 8.5/10 달성)
- 모든 Phase 완료 표시

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 16:33:12 +09:00
a0fc67adae refactor: Low 우선순위 코드 품질 개선
- constants에 GROUP_INFO 상수 추가 (데뷔일, 팬덤명)
- PC Home에서 멤버 수 동적 계산 (API 기반)
- mobile/Layout.jsx 컴포넌트 분리 (Header.jsx, BottomNav.jsx)
- 미사용 유틸리티 함수는 관리자 페이지용으로 유지

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 16:30:39 +09:00
116d41ff07 refactor: Medium 우선순위 코드 품질 개선
- API client: fetchFormData에 requireAuth 옵션 추가
- API client: HTTP 헬퍼 함수를 팩토리 함수로 통합 (api, authApi)
- useMediaQuery: 리스너 핸들러 useCallback 메모이제이션
- useCalendar: 반환 객체 useMemo 메모이제이션
- schedule.js: date.js의 extractDate/extractTime 재사용
- format.js: decodeHtmlEntities 순수 함수화 (SSR 호환)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 14:25:20 +09:00
21639171e1 fix(lightbox): X 버튼 이벤트 버블링 및 닫기 애니메이션 수정
- PC Lightbox X 버튼에 e.stopPropagation() 추가 (이중 닫힘 방지)
- MobileLightbox AnimatePresence 구조 수정 (exit 애니메이션 활성화)
- 모바일 앨범 상세/갤러리 페이지에 헤더 표시 (hideHeader → pageTitle)
- 문서에 MobileLightbox 컴포넌트 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 14:21:56 +09:00
57d4f1dd5c refactor: High 우선순위 코드 품질 개선
- utils/youtube.js: YouTube URL 파싱 유틸리티 생성
  - getYoutubeVideoId, getYoutubeThumbnail, getYoutubeEmbedUrl
- utils/format.js: parseCredits, calculateTotalDuration 함수 추가
- hooks/useLightbox.js: 라이트박스 상태 관리 훅 생성
- components/common/ErrorMessage.jsx: 에러 메시지 컴포넌트 생성
- components/common/Loading.jsx: size prop 추가 (sm, md, lg)
- TrackDetail (PC/Mobile): 중복 함수 제거, 유틸리티 사용
- AlbumDetail (PC/Mobile): getTotalDuration -> calculateTotalDuration 유틸리티 사용

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 12:40:31 +09:00