X long tweet(280자 초과)을 Nitter 타임라인이 간헐적으로 …로 잘라서
주는 경우, 개별 상태 페이지에서 재요청해 전체 내용으로 교체.
- parseTweets: …로 끝나는 트윗에 truncated 플래그 부여
- hydrateTruncatedTweets: 잘린 트윗 status 페이지 재요청 후 교체 (best-effort)
- fetchTweets/fetchAllTweets에 적용
- fetchSingleTweet을 timeout-safe하게 변경
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- logs API: longtext로 저장된 details를 JSON 객체로 파싱해 반환
- 응답 스키마에 additionalProperties: true 추가 (fast-json-stringify가
스키마 미정의 키를 제거하던 문제 해결)
- scheduler 에러 로그: err.cause / err.code / err.causeCode 함께 기록
(fetch failed 등 모호한 메시지의 진짜 원인 식별 가능)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 카테고리 카운트를 선택 날짜와 무관하게 해당 달 전체 기준으로 변경
- 카테고리 섹션이 길어지면 카드 내부 스크롤 (평소엔 콘텐츠 크기 유지)
- 달력 하단에 오늘 날짜로 이동하는 버튼 추가
- 달력 하단 여백 24px → 20px
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
검색 페이지(memogipost)를 크롤링하여 프로미스나인 출연 대학 축제를
Gemini url_context로 추출, 행사 일정을 자동 생성하는 봇.
백엔드:
- services/event.js: 이벤트 생성 로직 공유화 (upsertVenue, createEventSchedule, 카카오 검색)
- services/festival/: scraper(검색 페이지 크롤) + gemini(추출) + index(봇 플러그인)
- routes/admin/festival-bots.js: 축제 봇 CRUD API
- scheduler.js: festival 타입 지원, 시간 단위 cron(0 */H * * *) 변환
- 처리한 글 URL은 festival_crawl_log에 기록, 새 글 없으면 Gemini 미호출
- 학교명 부분일치 중복 감지, 활동 멤버 전체 자동 등록
- Gemini 503/500/429 재시도 로직
기타 수정:
- 행사 상세 페이지 관련 링크 줄바꿈 (truncate → break-all)
- 대학 축제 아이콘 변경 (GraduationCap → PartyPopper)
- docs/api.md, CLAUDE.md 환경변수 문서화
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- bot_festival, festival_crawl_log 테이블 SQL
- FestivalBotDialog: 봇 이름/크롤링 URL/동기화 간격(1~24시간) 입력
- 봇 관리 페이지에 '축제' 섹션 추가 (emerald, PartyPopper)
- BotCard: festival 타입 수정/삭제 버튼 표시
- API 클라이언트 함수 추가 (백엔드 라우트는 3단계)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- bot_youtube에 extract_members_from_title 컬럼 추가 (기본값 0)
- services/youtube/index.js: 설명과 제목에서 각각 멤버 이름 검색, 합집합으로 중복 제거
- YouTubeBotDialog 고급 설정에 토글 추가 (설명 추출 토글 아래)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- bot_x에 exclude_managed_channels 컬럼 추가 (기본값 1, 기존 동작 유지)
- X 봇이 트윗에서 YouTube 링크를 추출할 때 이미 등록된 YouTube 봇 채널의 영상을 중복 추가할지 옵션으로 제어
- XBotDialog에 토글 추가 (extract_youtube 활성 시만 노출, 왼쪽 border로 하위 옵션 시각화)
- services/x/index.js processYoutubeLinks 시그니처에 옵션 파라미터 추가
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 체크 아이콘 대신 선택 순서(1, 2, 3...) 숫자 뱃지 표시
- 선택 해제 시 남은 곡 번호 자동 재계산
- 숫자 시각 중심 보정 (leading-none + translate-y)
- 순서는 이미 클릭 순서대로 세트리스트에 추가됨 (selectedTracks push 순서 유지)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- framer-motion의 Reorder를 사용해 세트리스트 곡 순서를 드래그로 변경 가능
- 카드 왼쪽에 GripVertical 핸들 영역 분리, 오른쪽에 기존 폼 필드
- 내부 input/버튼은 드래그 임계값 덕분에 자유롭게 조작 가능
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 그리드 4열 레이아웃으로 전환해 카드 공백감 해소
- 세로 이미지 잘림 방지: aspect-[3/4] + object-contain + 회색 배경
- 호버 시 삭제 버튼 노출, 순서 뱃지 상시 표시
- 마지막 칸에 '+ 추가' 점선 타일 추가 (다중 업로드 가능)
- @dnd-kit 기반 드래그앤드롭 재정렬 도입 (DragOverlay, rectSortingStrategy)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 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>
- 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>
- 페이지네이션을 3-column grid로 배치해 버튼 그룹은 중앙 정렬, 오른쪽 구석에 입력 박스 추가
- 숫자만 입력, Enter 또는 blur 시 페이지 이동 (1~totalPages로 clamp)
- Enter 시 blur() 호출로 포커스 자동 해제
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 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>
- ScheduleDetail 모델: broadcaster, replayUrl, varietyThumbnailUrl 필드 추가
- 예능 섹션: 썸네일(블러 배경 + contain) + 정보 카드
- 방송사 뱃지(카테고리 색상), 날짜/시간, 제목, 멤버, 다시보기 버튼
- 썸네일 없을 때 카테고리 색상 배경 + Tv 아이콘 표시
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 높이 h-52로 고정
- 배경에 동일 이미지를 scale-110 blur-2xl로 깔아서 빈 공간 채움
- 메인 이미지는 object-contain으로 원본 비율 유지
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 썸네일: w-52 h-72 고정, object-cover
- 정보 카드: flex-1, 콘텐츠에 따라 높이 자유
- items-start로 서로 높이 영향 없음
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 가로 flex → 세로 분리 (썸네일 카드 + 정보 카드)
- 썸네일: object-contain으로 원본 비율 유지, max-h 제한
- 기본 이미지: 카테고리 색상 배경 + Tv 아이콘
- 제목이 길어져도 레이아웃 깨지지 않음
- PC/모바일 모두 적용
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- MobileVarietySection: 썸네일(w-32) + 콘텐츠 flex 레이아웃
- 방송사 뱃지, 제목, 멤버 칩, 다시보기 버튼
- PC 버전과 동일한 구조, 모바일 사이즈에 맞게 축소
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 썸네일 hover 효과 제거, 너비 w-44로 축소
- 다시보기 버튼: 멤버 칩과 같은 줄에 compact하게 배치 (회색 pill)
- 불필요한 border-t 구분선 제거
- 전체적으로 compact한 레이아웃
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 가로 전체 → 왼쪽 세로 포스터(w-52) + 오른쪽 콘텐츠 (flex 레이아웃)
- 세로 이미지가 잘리지 않도록 object-cover + 고정 너비
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 썸네일: aspect-video 비율, hover 시 확대 + 재생 버튼 오버레이
- 방송사 뱃지: 카테고리 색상 기반, 날짜와 한 줄로 배치
- 다시보기 버튼: 다크 pill 스타일, 유튜브면 Play 아이콘
- 전체 카드 레이아웃으로 통일
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- GET /admin/variety/broadcasters: DB에서 빈도수 상위 10개 조회 (Redis 1시간 캐시)
- 일정 생성/수정 시 캐시 무효화
- 프론트엔드: 하드코딩 프리셋 제거, API에서 동적으로 로드
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- schedule/{id}/thumbnail/ 경로에 original/medium_800/thumb_400 webp 업로드
- images 테이블로 이미지 관리, schedule_variety.thumbnail_id로 참조
- 프론트엔드: URL 입력 → 파일 업로드(드래그&드롭) + 미리보기로 변경
- 수정 시 기존 썸네일 교체/삭제 지원
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 백엔드: POST/PUT/GET /admin/variety/schedule API
- 백엔드: 일정 상세 응답에 broadcaster, replayUrl, thumbnailUrl 포함
- 프론트엔드: VarietyForm (추가), VarietyEditForm (수정) 페이지
- 방송사 프리셋 버튼 (KBS, MBC, SBS, tvN, 유튜브, 티빙 등)
- 출연 멤버 선택, 다시보기 링크, 썸네일 URL 지원
- 라우트 등록 및 일정 목록 편집 링크 연결
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- schedule_variety: broadcaster, replay_url, thumbnail_url
- 카테고리 ID 10 '예능' (#22c55e) 추가
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 액션바 제목 '트랙' → '앨범'
- YouTube 버튼: 빨간 배경 + 흰색 글씨로 변경
- 각 섹션(헤더, 영상, 크레딧, 가사)에 흰색 카드 배경 추가
- 앨범 이름 ellipsis 제거 (줄바꿈 허용)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TrackDetail.fromJson에서 music_video_url → video_url로 필드명 수정.
DB 컬럼명은 video_url인데 잘못된 키로 파싱하고 있었음.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>