Commit graph

25 commits

Author SHA1 Message Date
54e014c833 perf(schedule): 월별 일정 Redis 캐시 + 쓰기 시 무효화
캘린더(최다 호출 공개 엔드포인트) getMonthlySchedules를 getOrSet으로
캐시(TTL 60s). 무효화는 모든 쓰기가 수렴하는 3개 meili 동기화 함수
(addOrUpdateSchedule/syncScheduleById/deleteSchedule)에 redis 전달 시
schedule:monthly:* 무효화. 관리자 라우트·봇 경로에서 redis 전달(즉시
반영), festival/누락 경로는 60s TTL로 자동 치유.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 16:39:40 +09:00
3e56670e8a feat(x-bot): TikTok 카드 썸네일 온디맨드 프록시
TikTok은 OG 이미지를 막지만 oEmbed는 thumbnail_url 제공. 단 서명·만료
URL이라 저장하지 않고, /api/schedules/x-card-thumb/:postId 엔드포인트가
요청 시 oEmbed로 현재 썸네일을 받아 302 리다이렉트(Redis 6h 캐시).
resolveCard는 TikTok 카드 이미지를 이 프록시 경로로 설정.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 09:40:32 +09:00
0b730405a6 fix(x-bot): 만료되는 트위터 카드 이미지를 원본 OG 이미지로 대체
Nitter가 주는 pbs.twimg.com/card_img 이미지는 시간이 지나면 404로
만료됨. resolveCard에서 카드 이미지가 없거나 해당 만료성 URL이면
원본 URL의 OG 이미지(i.ytimg 등 안정적)로 대체.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 09:30:59 +09:00
134f5836b7 fix(x-bot): OG 카드 엔티티 디코딩 + YouTube 이미지 보강
- 스크래퍼가 Nitter HTML 엔티티(&#x2F; &amp; 등)를 디코딩하지 않아
  본문/카드 제목에 [JP&#x2F;EN]처럼 노출되던 문제 수정 (extractCard,
  extractTextFromHtml에 decodeEntities 적용)
- resolveCard가 Nitter 카드에 제목만 있고 이미지가 없을 때 OG로 이미지를
  보강하도록 변경 (YouTube 카드 이미지 누락 복구)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 09:26:54 +09:00
8b8b9a7f53 feat(x-schedule): 링크 미리보기(OG) 카드 추가 - 하이브리드
트윗의 외부 링크에 대해 미리보기 카드 표시.
- Nitter가 렌더링한 카드 우선 사용 (extractCard)
- Nitter 카드가 비어있으면 본문 URL로 OG 직접 추출 (og.js)
  - YouTube/Instagram 등 복구, HTML 엔티티 디코딩 포함
  - TikTok 등 봇 차단 사이트는 Nitter 카드로 커버
- schedule_x.card_data 컬럼 + getScheduleDetail 응답에 card 포함
- 가로 레이아웃 카드 (왼쪽 이미지 + 오른쪽 텍스트)
- CardImage: 이미지 로드 실패 시 fallback 아이콘 (인스타 CDN 만료 대비)
- 자체 영상/이미지가 있으면 OG 카드 숨김 (중복 방지)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:34:42 +09:00
d3d3c9cf75 feat(x-schedule): 트윗 네이티브 영상 썸네일 표시
Nitter는 영상 파일을 제공하지 않으므로 썸네일만 추출해 표시하고,
재생 시 원본 트윗으로 이동.

- scraper: extractVideoThumbnails 추가 (amplify_video_thumb 등)
- schedule_x.video_thumbnails 컬럼 + saveTweet 저장
- getScheduleDetail 응답에 videoThumbnails 포함
- PC/모바일 X 상세: 썸네일 + 재생버튼 + 'X에서 재생' 배지

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:02:29 +09:00
4cfa4ffc00 fix(x-bot): 리트윗 이중 저장 방지
같은 리트윗이 타임라인에서 래퍼 id / 원본 id 두 형태로 번갈아 나타나
post_id 중복 체크를 통과해 두 번 저장되던 문제 수정.

리트윗 저장 시 동일 내용 + (원작자 또는 봇계정) username이 이미 있으면
중복으로 간주해 건너뜀. hydration으로 양쪽 모두 전체 내용을 갖추므로
내용 기반 매칭이 안정적으로 동작.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 18:02:22 +09:00
2cfc580283 fix(x-bot): 잘린 긴 리트윗 전체 내용 복원 (hydration)
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>
2026-05-31 18:00:14 +09:00
678e228bc5 feat(x-bot): 관리 YouTube 채널 영상 제외 옵션 추가
- 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>
2026-04-23 18:45:45 +09:00
9498559f6b fix(x-bot): 리트윗 프로필/이미지 복구 및 원본 트윗 매칭
- getProfile: bot_x에 없는 계정도 Nitter에서 직접 조회 후 Redis 캐시
- refetch-retweets 스크립트: 원본 작성자 타임라인에서 매칭 트윗 찾아 이미지/내용 복구
- 기존 21건 리트윗 데이터 재수집 완료 (이미지 포함)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 14:07:43 +09:00
3ce8d7ec7d fix(x-bot): 리트윗 내용 잘림, Nitter 링크, 이미지 누락 수정
- extractTextFromHtml: Nitter 프록시 t.co URL을 원본 https://t.co/ URL로 변환
- parseTweets: 리트윗 원본 작성자(originalUsername) 추출, URL을 원본 작성자 기준으로 생성
- saveTweet: 리트윗인 경우 원본 작성자를 username으로 저장
- refetch-retweets 엔드포인트 및 스크립트 추가 (기존 잘못된 데이터 재수집)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 13:59:19 +09:00
1f1d6987d1 feat(backend): 관리자/봇 라우트에 logActivity 호출 추가
12개 관리자 라우트와 3개 봇 서비스 파일에 활동 로그 기록 추가.
관리자 작업(일정/앨범/멤버/봇 CRUD)과 봇 동기화(완료/에러)를
logs 테이블에 fire-and-forget으로 기록.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:04:07 +09:00
f8acb5450f fix(bot): 동시성 중복 INSERT 시 ER_DUP_ENTRY 에러 무시 처리
YouTube/X 봇의 영상 저장 트랜잭션에서 UNIQUE 제약 위반 발생 시
크래시 대신 null을 반환하여 gracefully 무시하도록 변경.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 15:28:27 +09:00
ba7def935c feat(x-bot): YouTube 영상 추출 옵션 추가
X 봇 설정에서 트윗 내 YouTube 링크 자동 추출 기능을 온/오프 가능하게 함:
- bot_x 테이블에 extract_youtube 컬럼 추가 (기본값: false)
- 고급 설정에 "YouTube 영상 추출" 토글 추가
- extractYoutube가 true일 때만 YouTube 일정 자동 생성

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 22:40:52 +09:00
7d140aa1f3 fix(x-bot): 동기화 결과에 total 필드 추가
- syncNewTweets(), syncAllTweets()에 total 필드 추가
- 프론트엔드 토스트에서 undefined 표시되던 문제 해결

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 09:57:04 +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
5d44434e36 feat(x-bot): 리트윗 옵션 및 고정 트윗 제외 기능 추가
- include_retweets 옵션으로 리트윗 포함 여부 설정 가능
- 고정된 트윗(pinned)은 기본적으로 파싱에서 제외
- XBotDialog에서 Twitter 아이콘을 X 아이콘으로 변경
- schedule_x의 username을 source_name으로 활용

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 09:37:57 +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
a8c12aa76d feat: YouTube 봇 DB 기반 관리로 마이그레이션
- YouTube 봇 설정을 bots.js에서 youtube_bots 테이블로 이동
- 봇 ID를 AUTO_INCREMENT로 변경 (youtube-{id} 형식)
- 고정 멤버 다중 선택 지원 (default_member_ids JSON)
- 제목 필터 다중 키워드 지원 (title_filters JSON)
- Redis 캐싱 제거 (Activities API 사용으로 불필요)
- 채널 배너 URL DB 저장 (youtube_bots.banner_url)
- YouTubeBotDialog UI 개선:
  - Portal 기반 드롭다운 (overflow 문제 해결)
  - AnimatePresence 애니메이션 적용
  - 다중 선택 컴포넌트 추가
  - 태그 입력 형태의 제목 필터
  - 뒷배경 클릭 방지

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-07 10:15:07 +09:00
2fec6c552d feat: 봇 일정 추가 시 Meilisearch 실시간 동기화
- syncScheduleById 함수 추가: 개별 일정 동기화
- YouTube 봇: 영상 추가 시 Meilisearch 동기화
- X 봇: 트윗/유튜브 링크 추가 시 Meilisearch 동기화
- description 컬럼 제거 (schedules 테이블에 없음)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 11:26:32 +09:00
85f03cb2d8 타임스탬프 KST 통일 및 Meilisearch 동기화 소요 시간 추가
- date.js: nowKST() 함수 추가
- 모든 타임스탬프를 UTC에서 KST(+09:00)로 변경
  - scheduler.js, bots.js, x/index.js, logger.js, app.js
- Meilisearch 봇에 동기화 소요 시간(ms) 추적 추가
- BotCard.jsx: 중복된 마지막 동기화 대신 소요 시간 표시

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 22:00:58 +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
149e85ebd9 feat: X 봇 프로필 정보 DB 저장 기능 추가
- x_profiles 테이블 생성 (username, display_name, avatar_url)
- saveProfile 함수로 DB + Redis 캐시 동시 저장
- getProfile 함수 Redis → DB 폴백 지원

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 10:19:32 +09:00
19ba8bcddf refactor: Express에서 Fastify로 백엔드 마이그레이션
- 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>
2026-01-16 21:11:02 +09:00