diff --git a/backend/src/services/meilisearch/index.js b/backend/src/services/meilisearch/index.js index 308c10b..f3ad3ca 100644 --- a/backend/src/services/meilisearch/index.js +++ b/backend/src/services/meilisearch/index.js @@ -178,7 +178,7 @@ function formatScheduleResponse(hit) { } /** - * 일정 추가/업데이트 + * 일정 추가/업데이트 (데이터 직접 전달) */ export async function addOrUpdateSchedule(meilisearch, schedule) { try { @@ -187,7 +187,6 @@ export async function addOrUpdateSchedule(meilisearch, schedule) { const document = { id: schedule.id, title: schedule.title, - description: schedule.description || '', date: schedule.date, time: schedule.time || '', category_id: schedule.category_id, @@ -204,6 +203,59 @@ export async function addOrUpdateSchedule(meilisearch, schedule) { } } +/** + * 일정 ID로 DB에서 조회 후 Meilisearch에 동기화 + */ +export async function syncScheduleById(meilisearch, db, scheduleId) { + try { + const [rows] = await db.query(` + SELECT + s.id, + s.title, + s.date, + s.time, + s.category_id, + c.name as category_name, + c.color as category_color, + sy.channel_name as source_name, + GROUP_CONCAT(DISTINCT m.name ORDER BY m.id SEPARATOR ',') as member_names + FROM schedules s + LEFT JOIN schedule_categories c ON s.category_id = c.id + LEFT JOIN schedule_youtube sy ON s.id = sy.schedule_id + LEFT JOIN schedule_members sm ON s.id = sm.schedule_id + LEFT JOIN members m ON sm.member_id = m.id AND m.is_former = 0 + WHERE s.id = ? + GROUP BY s.id + `, [scheduleId]); + + if (rows.length === 0) { + logger.warn(`일정을 찾을 수 없음: ${scheduleId}`); + return false; + } + + const s = rows[0]; + const document = { + id: s.id, + title: s.title, + date: s.date instanceof Date ? s.date.toISOString().split('T')[0] : s.date, + time: s.time || '', + category_id: s.category_id, + category_name: s.category_name || '', + category_color: s.category_color || '', + source_name: s.source_name || '', + member_names: s.member_names || '', + }; + + const index = meilisearch.index(INDEX_NAME); + await index.addDocuments([document]); + logger.info(`일정 동기화: ${scheduleId}`); + return true; + } catch (err) { + logger.error(`일정 동기화 오류 (${scheduleId}): ${err.message}`); + return false; + } +} + /** * 일정 삭제 */ @@ -233,7 +285,6 @@ export async function syncAllSchedules(meilisearch, db) { SELECT s.id, s.title, - s.description, s.date, s.time, s.category_id, @@ -255,7 +306,6 @@ export async function syncAllSchedules(meilisearch, db) { const documents = schedules.map(s => ({ id: s.id, title: s.title, - description: s.description || '', date: s.date instanceof Date ? s.date.toISOString().split('T')[0] : s.date, time: s.time || '', category_id: s.category_id, @@ -310,7 +360,7 @@ async function recreateIndex(meilisearch) { // 설정 복원 await index.updateSearchableAttributes([ - 'title', 'member_names', 'description', 'source_name', 'category_name', + 'title', 'member_names', 'source_name', 'category_name', ]); await index.updateFilterableAttributes(['category_id', 'date']); await index.updateSortableAttributes(['date', 'time']); diff --git a/backend/src/services/x/index.js b/backend/src/services/x/index.js index cbc6cbe..a4a4dce 100644 --- a/backend/src/services/x/index.js +++ b/backend/src/services/x/index.js @@ -4,6 +4,7 @@ import { fetchVideoInfo } from '../youtube/api.js'; import { formatDate, formatTime, nowKST } from '../../utils/date.js'; import bots from '../../config/bots.js'; import { withTransaction } from '../../utils/transaction.js'; +import { syncScheduleById } from '../meilisearch/index.js'; const X_CATEGORY_ID = 3; const YOUTUBE_CATEGORY_ID = 2; @@ -141,8 +142,12 @@ async function xBotPlugin(fastify, opts) { // 관리 중인 채널이면 스킵 if (managedChannels.includes(video.channelId)) continue; - const saved = await saveYoutubeFromTweet(video); - if (saved) addedCount++; + const scheduleId = await saveYoutubeFromTweet(video); + if (scheduleId) { + // Meilisearch 동기화 + await syncScheduleById(fastify.meilisearch, fastify.db, scheduleId); + addedCount++; + } } catch (err) { fastify.log.error(`YouTube 영상 처리 오류 (${videoId}): ${err.message}`); } @@ -166,6 +171,8 @@ async function xBotPlugin(fastify, opts) { for (const tweet of tweets) { const scheduleId = await saveTweet(tweet); if (scheduleId) { + // Meilisearch 동기화 + await syncScheduleById(fastify.meilisearch, fastify.db, scheduleId); addedCount++; // YouTube 링크 처리 ytAddedCount += await processYoutubeLinks(tweet); @@ -187,6 +194,8 @@ async function xBotPlugin(fastify, opts) { for (const tweet of tweets) { const scheduleId = await saveTweet(tweet); if (scheduleId) { + // Meilisearch 동기화 + await syncScheduleById(fastify.meilisearch, fastify.db, scheduleId); addedCount++; ytAddedCount += await processYoutubeLinks(tweet); } diff --git a/backend/src/services/youtube/index.js b/backend/src/services/youtube/index.js index 28d9696..614df21 100644 --- a/backend/src/services/youtube/index.js +++ b/backend/src/services/youtube/index.js @@ -3,6 +3,7 @@ import { fetchRecentVideos, fetchAllVideos, getUploadsPlaylistId } from './api.j import bots from '../../config/bots.js'; import { CATEGORY_IDS } from '../../config/index.js'; import { withTransaction } from '../../utils/transaction.js'; +import { syncScheduleById } from '../meilisearch/index.js'; const YOUTUBE_CATEGORY_ID = CATEGORY_IDS.YOUTUBE; const PLAYLIST_CACHE_PREFIX = 'yt_uploads:'; @@ -126,6 +127,8 @@ async function youtubeBotPlugin(fastify, opts) { for (const video of videos) { const scheduleId = await saveVideo(video, bot); if (scheduleId) { + // Meilisearch 동기화 + await syncScheduleById(fastify.meilisearch, fastify.db, scheduleId); addedCount++; } } @@ -144,6 +147,8 @@ async function youtubeBotPlugin(fastify, opts) { for (const video of videos) { const scheduleId = await saveVideo(video, bot); if (scheduleId) { + // Meilisearch 동기화 + await syncScheduleById(fastify.meilisearch, fastify.db, scheduleId); addedCount++; } }