- Express → Fastify 5 프레임워크 전환
- 플러그인 기반 아키텍처로 재구성
- plugins/db.js: MariaDB 연결 풀
- plugins/redis.js: Redis 클라이언트
- plugins/scheduler.js: 봇 스케줄러 (node-cron)
- 봇 설정 방식 변경: DB 테이블 → 설정 파일 (config/bots.js)
- 봇 상태 저장: DB → Redis
- YouTube/X 봇 서비스 분리 및 개선
- 날짜 유틸리티 KST 변환 수정
- 미사용 환경변수 정리
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 생일 카드 컴포넌트 추가 (PC/모바일)
- 생일 폭죽(confetti) 애니메이션 적용 (하루에 한 번)
- 생일 상세 페이지 추가 (/birthday/멤버이름/년도)
- 관리자 일정 페이지에 생일 표시 (수정/삭제 버튼 숨김)
- 일정 상세 페이지 404 에러 UI 개선
- 일정 상세 페이지 불필요한 재시도 방지 (retry: false)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 같은 제목의 콘서트 일정을 모아서 회차별로 표시
- 현재 보고 있는 회차 강조 표시
- 카카오맵 SDK 키 수정 및 에러 처리 개선
- 길찾기 버튼 추가
- 회차 전환 시 부드러운 데이터 로딩 (keepPreviousData)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- KakaoMap 컴포넌트: 위도/경도 기반 지도 표시 기능
- ConcertSection: 포스터 이미지, 날짜 범위, 장소 정보 표시
- 위치 좌표가 없는 경우(해외) 장소명만 표시
- 백엔드 API에 이미지 정보 포함
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Schedule.jsx에서 useState 대신 useScheduleStore 사용
- 상세 페이지 이동 후에도 선택한 날짜/카테고리/검색어 유지
- X 상세 페이지 UI 개선 (X 아이콘 제거, 날짜 형식 변경)
- X 프로필 URL 디코딩 로직 수정
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- X 봇에서 Nitter 프로필 정보(이름, 아바타) 추출 및 Redis 캐싱
- X 프로필 조회 API 추가 (/api/schedules/x-profile/:username)
- X 상세 페이지 UI 구현 (트위터 카드 스타일)
- X 카테고리 클릭 시 상세 페이지로 이동하도록 변경
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 고정 트윗 체크 로직이 이전 컨테이너를 참조하여 다음 트윗도 고정으로 판단하는 버그 수정
- 현재 컨테이너 내에 'class="pinned"'가 있는지만 확인하도록 변경
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 최대 검색 횟수의 1% 또는 최소 10회 중 더 큰 값 적용
- GREATEST(MAX(count) * 0.01, 10) 사용
- 데이터가 적을 때도 오타 필터링 가능
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- DB: album_teasers 테이블에 video_url 컬럼 추가
- 백엔드: 비디오 업로드 시 ffmpeg로 썸네일 추출 후 WebP 저장
- 백엔드: video_url에 MP4 URL 저장, 썸네일은 기존 URL 필드 사용
- 프론트엔드: 썸네일 이미지 표시, 클릭 시 video_url로 재생
- Flutter 앱: Teaser 모델에 videoUrl 필드 추가 및 비디오 재생 수정
- Docker: ffmpeg 설치 추가 (Dockerfile, docker-compose.dev.yml)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- 히어로 섹션 (커버 중앙 + 블러 배경)
- 앨범 소개 바텀시트 다이얼로그 (드래그 닫기)
- 수록곡 더보기/접기 기능
- 컨셉 포토 전체보기 버튼 모바일화
- 뮤직비디오 버튼 제거
- 라이트박스 showNav 조건 추가
- 앨범 API folder_name 검색으로 수정
- PC: 앨범 상세에서 '타이틀곡: OOO' 텍스트 제거
- 모바일: 앨범 상세 UI 전면 개선
- 티저 포토 섹션 추가
- 수록곡 리스트 스타일 개선 (트랙번호, TITLE 뱃지)
- 컨셉 포토 6장 프리뷰 + 전체보기 링크
- 라이트박스 (다운로드, 이전/다음 네비게이션)
- 앨범 API에서 folder_name 반환 추가
- is_default 컬럼 추가 (기존 6개 카테고리 = 기본)
- 카테고리 ID 재정렬: 기타(1), 유튜브(2), X(3), 앨범(4), 팬사인회(5), 콘서트(6)
- 일정 테이블 category_id 동기화
- 기본 카테고리 삭제 불가 (백엔드 + 프론트엔드)
- 일정 사용 중인 카테고리 삭제 불가
- MariaDB 테이블 추가 (search_queries, word_pairs)
- Redis 컨테이너 추가 (Sorted Set 캐싱)
- 백엔드 suggestions 서비스 및 API 구현
- 검색 실행 시 검색어 저장 (bi-gram 학습)
- PC Schedule 프론트엔드 연동 완료
- X 봇 서비스 추가 (x-bot.js)
- Nitter를 통한 @realfromis_9 트윗 수집
- 트윗을 일정으로 자동 저장 (카테고리 12)
- 관리 채널 외 유튜브 링크 감지 시 별도 일정 추가
- 1분 간격 동기화 지원
- DB 스키마 변경
- bots.type enum 수정 (vlive, weverse 제거, x 추가)
- bot_x_config 테이블 추가
- 봇 스케줄러 수정 (youtube-scheduler.js)
- 봇 타입별 동기화 함수 분기 (syncBot)
- X 봇 지원 추가
- 관리자 페이지 개선 (AdminScheduleBots.jsx)
- 봇 타입별 아이콘 표시 (YouTube/X)
- X 아이콘 SVG 컴포넌트 추가
- last_added_count 로직 수정
- 추가 항목 없으면 이전 값 유지 (0으로 초기화 방지)
- 기존 X 일정에서 유튜브 영상 추출 스크립트 추가
- api/schedules, albums, members → api/public/로 이동
- pages/pc/*.jsx → pages/pc/public/로 이동
- pages/mobile/*.jsx → pages/mobile/public/로 이동
- App.jsx 라우터 경로 수정
- 모든 public 페이지의 import 경로 수정
- registerBot, unregisterBot, isBotRunning에서 botId를 parseInt()로 정수 변환
- URL 파라미터(문자열)와 DB 조회 결과(숫자) 간 타입 일치 문제 해결
- 10초 상태 동기화에서 메모리 스케줄러를 찾지 못해 stopped로 변경되던 버그 수정
- RSS 방식에서 YouTube API 방식으로 변경 (최근 10개 영상 조회)
- rss_url 컬럼 삭제
- Google Cloud Webhook으로 할당량 경고 수신
- 95% 도달 시 봇 자동 중지
- LA 시간 자정(할당량 리셋)에 봇 자동 재시작
- 봇 관리 페이지에 경고 배너 표시
- react-infinite-scroll-component를 useInfiniteQuery + useInView로 대체
- Schedule.jsx, AdminSchedule.jsx에 안정적인 무한 스크롤 적용
- source_name에 Link2 아이콘 추가 (카테고리 오른쪽 인라인 표시)
- 멤버 5명 이상일 경우 '프로미스나인'으로 표시 (탈퇴 멤버 고려)
- AdminSchedule 일반 모드에서 members 배열도 확인하여 멤버 표시
- QueryClientProvider 설정 추가 (main.jsx)
- 카테고리 정렬: 일정 개수 기준 내림차순, 0개 숨김, 기타는 맨 아래 고정
- useMemo로 카테고리 정렬 메모이제이션 (깜빡임 방지)
- 일정 수정 시 이미지 삭제 버그 수정 (existingImageIds 업데이트)
- 이미지 파일명에서 Date.now() 제거 (01.webp 형식 유지)
- 이미지 삭제 후 sort_order 재정렬 로직 추가
- 날짜 선택 시 요일 표시 추가 (2026년 1월 7일 (수) 형식)
- 백엔드: /api/schedules에 startDate, endDate, limit 파라미터 지원 추가
- 프론트엔드: 더미 데이터 제거, 실제 API 호출로 변경
- KST 기준으로 오늘 이후 3개 일정 표시
- 일정 페이지와 동일한 카드 스타일 적용
- 멤버 5명 이상이면 '프로미스나인'으로 표시
- 검색 결과 유사도순 정렬 (동일 유사도 시 최신 날짜 우선)
- 프론트엔드 검색 재정렬 제거 (Meilisearch 순서 유지)
- 관리자 일정 페이지 Meilisearch 검색 적용
- 일정 수정 시 Meilisearch 동기화 추가
- 서버 시작 시 자동 동기화
- 멤버 이름 쉼표 구분으로 통일
- Docker Compose에 Meilisearch 서비스 추가
- meilisearch.js 서비스 생성 (초기화, CRUD, 검색)
- 공개 일정 API에 Meilisearch 검색 통합
- 일정 생성/삭제 시 Meilisearch 자동 동기화
- YouTube 봇 일정 추가 시 Meilisearch 동기화
- sync-search API 추가 (기존 데이터 일괄 동기화)
- 다중 키워드, 오타 허용, 유사어 검색 지원
- 봇 스케줄러: 서버 시작 시 자동 초기화, 10초 간격 상태 동기화
- DB 리팩토링: bots 테이블에서 YouTube 컬럼 분리, bot_youtube_config 활용
- 봇별 커스텀 설정: BOT_CUSTOM_CONFIG 상수로 코드 내 관리
- 공개/관리자 일정 목록에 멤버 태그 표시 (5명 이상이면 '프로미스나인')
- 일정 목록 글씨 크기 증가 및 UI 개선
- source_name 관리자 일정에 뱃지로 표시
- 봇 시작/정지 토스트에 봇 이름 포함
- YouTube 일정 봇 서비스 추가 (youtube-bot.js, youtube-scheduler.js)
- 공개 일정 API 라우터 추가 (schedules.js)
- 관리자 일정 봇 관리 페이지 추가 (AdminScheduleBots.jsx)
- 백엔드 의존성 업데이트
- schedule_members 테이블 분리 (members 컬럼 → 별도 테이블)
- schedules 테이블 컬럼 comment 추가 및 순서 정리
- 상세주소(location_detail) 필드 추가
- 장소 검색 UI 개선 (탭 제거 → 입력 필드+검색 버튼 병합)
- 카카오 장소 검색 API 프록시 추가 (/api/admin/kakao/places)
- 백엔드 CRUD API 구현 (GET/PUT/DELETE /schedules/:id)
- 프론트엔드 삭제 기능 및 확인 다이얼로그 추가
- 프론트엔드 수정 모드 지원 (기존 데이터 로드)
- 일정 카테고리 CRUD API 추가 (backend/routes/admin.js)
- AdminScheduleCategory 페이지 신규 추가
- 카테고리 추가/수정/삭제 기능
- 드래그 앤 드롭 정렬 (framer-motion Reorder)
- react-colorful 기반 커스텀 색상 선택기
- 중복 카테고리 체크
- AdminScheduleForm에 동적 카테고리 로드 기능 추가
- 삭제 다이얼로그 앨범 스타일로 통일 (AlertTriangle 아이콘, 경고 메시지)
- Toast 컴포넌트 exit 애니메이션 수정
- 토스트 3초 자동 닫힘 기능 추가
- 멤버 수정 페이지 추가 (AdminMemberEdit.jsx)
- 커스텀 데이트픽커 적용 (앨범 폼과 동일)
- 활동 상태 버튼 토글 (활동 중/탈퇴)
- URL 라우터 멤버 이름 기반으로 변경 (/admin/members/:name/edit)
- 백엔드 멤버 조회/수정 API 추가 (이름 기반)
- 전 멤버 섹션 UI 개선 (배경 항상 표시, 포지션 제거)
- DB 스키마 변경: cover_url → cover_original_url, cover_medium_url, cover_thumb_url
- 백엔드: 앨범 생성/수정 시 original/800/400 3개 크기로 저장
- 프론트엔드: 용도에 맞게 적절한 해상도 사용
- 앨범 목록: medium
- 상세 페이지: medium
- 관리자 목록: thumb
- 인디케이터 슬라이딩 애니메이션 개선 (CSS transition으로 GPU 가속)
- React.memo로 인디케이터 분리하여 이미지 로딩 시 리렌더링 방지
- 양옆 페이드 그라데이션 효과 추가
- 업로드 시 시작 번호 자동 계산 (기존 사진 마지막 번호 +1)
- 동영상 썸네일 및 미리보기 지원
- 이미지 프리로딩 범위 확장 (±2개)
- Multer 업로드 제한 50 → 200개로 증가
- album_photos, album_teasers 테이블에 original_url, medium_url, thumb_url 컬럼 추가
- API에서 3가지 해상도 URL 및 width/height 반환
- AlbumDetail: 티저는 thumb_url(400), 컨셉포토는 medium_url(800) 사용
- AlbumGallery: 동적 비율 + CSS hover 효과 추가
- react-photo-album rowConstraints로 마지막 row 표시 문제 개선
- SSE 기반 실시간 업로드 진행률 표시
- 컨셉 포토/티저 이미지 분리 (photo/ vs teaser/ 폴더)
- album_photos, album_teasers 테이블에 분리 저장
- 3개 해상도별 URL 컬럼 분리 (original_url, medium_url, thumb_url)
- 파일 업로드 시 타입 선택 잠금
- 티저 모드: 순서만 변경 가능, 메타 정보 입력 불필요
- 이미지 처리 병렬화로 성능 개선
- RUSTFS_PUBLIC_URL 환경변수 추가