From 22ce21f9089cc2dd80fa4b6d956a5a45b016e734 Mon Sep 17 00:00:00 2001 From: caadiq Date: Wed, 21 Jan 2026 20:47:40 +0900 Subject: [PATCH] =?UTF-8?q?refactor(backend):=20=EC=9D=BC=EC=A0=95=20API?= =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=20=ED=98=95=EC=8B=9D=EC=9D=84=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20API=EC=99=80=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 변경 사항: - getMonthlySchedules: 날짜별 그룹화 → 플랫 배열 - getUpcomingSchedules: 날짜별 그룹화 → 플랫 배열 새 형식: { "schedules": [ { "id": 123, "title": "...", "datetime": "2025-01-21T19:00:00", "category": { "id": 1, "name": "...", "color": "#..." }, "source": { "name": "...", "url": "..." }, "members": ["name1", "name2"] } ] } 주요 변경: - date/time 분리 → datetime 통합 - members: [{ name: "..." }] → ["name1", "name2"] - categories 카운트 제거 - _rankingScore 없음 (검색 API에만 존재) Co-Authored-By: Claude Opus 4.5 --- backend/src/services/schedule.js | 134 +++++++++---------------------- 1 file changed, 40 insertions(+), 94 deletions(-) diff --git a/backend/src/services/schedule.js b/backend/src/services/schedule.js index 40f8e66..1457fb9 100644 --- a/backend/src/services/schedule.js +++ b/backend/src/services/schedule.js @@ -121,10 +121,11 @@ export async function getScheduleDetail(db, id, getXProfile = null) { /** * 월별 일정 조회 (생일 포함) + * 검색 API와 동일한 형식으로 반환 * @param {object} db - 데이터베이스 연결 * @param {number} year - 연도 * @param {number} month - 월 - * @returns {object} 날짜별로 그룹화된 일정 + * @returns {object} { schedules: [] } 형식의 일정 배열 */ export async function getMonthlySchedules(db, year, month) { const startDate = `${year}-${String(month).padStart(2, '0')}-01`; @@ -169,7 +170,7 @@ export async function getMonthlySchedules(db, year, month) { if (!memberMap[sm.schedule_id]) { memberMap[sm.schedule_id] = []; } - memberMap[sm.schedule_id].push({ name: sm.name }); + memberMap[sm.schedule_id].push(sm.name); } } @@ -182,37 +183,31 @@ export async function getMonthlySchedules(db, year, month) { WHERE m.is_former = 0 AND MONTH(m.birth_date) = ? `, [month]); - // 날짜별로 그룹화 - const grouped = {}; + // 결과 배열 + const result = []; // 일정 추가 for (const s of schedules) { - const dateKey = s.date instanceof Date + const dateStr = s.date instanceof Date ? s.date.toISOString().split('T')[0] : s.date; - if (!grouped[dateKey]) { - grouped[dateKey] = { - categories: [], - schedules: [], - }; - } + // datetime 생성 + const datetime = s.time ? `${dateStr}T${s.time}` : dateStr; - // 멤버 정보 (5명 이상이면 프로미스나인) - const scheduleMembers = memberMap[s.id] || []; - const members = scheduleMembers.length >= 5 - ? [{ name: '프로미스나인' }] - : scheduleMembers; + // 멤버 이름 배열 (문자열 배열) + const members = memberMap[s.id] || []; const schedule = { id: s.id, title: s.title, - time: s.time, + datetime, category: { id: s.category_id, name: s.category_name, color: s.category_color, }, + source: null, members, }; @@ -232,20 +227,7 @@ export async function getMonthlySchedules(db, year, month) { }; } - grouped[dateKey].schedules.push(schedule); - - // 카테고리 카운트 - const existingCategory = grouped[dateKey].categories.find(c => c.id === s.category_id); - if (existingCategory) { - existingCategory.count++; - } else { - grouped[dateKey].categories.push({ - id: s.category_id, - name: s.category_name, - color: s.category_color, - count: 1, - }); - } + result.push(schedule); } // 생일 일정 추가 @@ -259,54 +241,37 @@ export async function getMonthlySchedules(db, year, month) { const birthdayThisYear = new Date(year, birthDate.getMonth(), birthDate.getDate()); const dateKey = birthdayThisYear.toISOString().split('T')[0]; - if (!grouped[dateKey]) { - grouped[dateKey] = { - categories: [], - schedules: [], - }; - } - - // 생일 카테고리 - const BIRTHDAY_CATEGORY = { - id: CATEGORY_IDS.BIRTHDAY, - name: '생일', - color: '#f472b6', - }; - const birthdaySchedule = { id: `birthday-${member.id}`, title: `HAPPY ${member.name_en} DAY`, - time: null, - category: BIRTHDAY_CATEGORY, + datetime: dateKey, + category: { + id: CATEGORY_IDS.BIRTHDAY, + name: '생일', + color: '#f472b6', + }, + source: null, + members: [member.name], is_birthday: true, - member_name: member.name, member_image: member.image_url, }; - grouped[dateKey].schedules.push(birthdaySchedule); - - // 생일 카테고리 카운트 - const existingBirthdayCategory = grouped[dateKey].categories.find(c => c.id === CATEGORY_IDS.BIRTHDAY); - if (existingBirthdayCategory) { - existingBirthdayCategory.count++; - } else { - grouped[dateKey].categories.push({ - ...BIRTHDAY_CATEGORY, - count: 1, - }); - } + result.push(birthdaySchedule); } - return grouped; + // 날짜 + 시간 순으로 정렬 + result.sort((a, b) => a.datetime.localeCompare(b.datetime)); + + return { schedules: result }; } /** * 다가오는 일정 조회 (startDate부터 limit개) - * getMonthlySchedules와 동일한 형식으로 반환 + * 검색 API와 동일한 형식으로 반환 * @param {object} db - 데이터베이스 연결 * @param {string} startDate - 시작 날짜 * @param {number} limit - 조회 개수 - * @returns {object} 날짜별로 그룹화된 일정 + * @returns {object} { schedules: [] } 형식의 일정 배열 */ export async function getUpcomingSchedules(db, startDate, limit) { // 일정 조회 (YouTube, X 소스 정보 포함) @@ -349,40 +314,34 @@ export async function getUpcomingSchedules(db, startDate, limit) { if (!memberMap[sm.schedule_id]) { memberMap[sm.schedule_id] = []; } - memberMap[sm.schedule_id].push({ name: sm.name }); + memberMap[sm.schedule_id].push(sm.name); } } - // 날짜별로 그룹화 (getMonthlySchedules와 동일한 형식) - const grouped = {}; + // 결과 배열 + const result = []; for (const s of schedules) { - const dateKey = s.date instanceof Date + const dateStr = s.date instanceof Date ? s.date.toISOString().split('T')[0] : s.date; - if (!grouped[dateKey]) { - grouped[dateKey] = { - categories: [], - schedules: [], - }; - } + // datetime 생성 + const datetime = s.time ? `${dateStr}T${s.time}` : dateStr; - // 멤버 정보 (5명 이상이면 프로미스나인) - const scheduleMembers = memberMap[s.id] || []; - const members = scheduleMembers.length >= 5 - ? [{ name: '프로미스나인' }] - : scheduleMembers; + // 멤버 이름 배열 (문자열 배열) + const members = memberMap[s.id] || []; const schedule = { id: s.id, title: s.title, - time: s.time, + datetime, category: { id: s.category_id, name: s.category_name, color: s.category_color, }, + source: null, members, }; @@ -402,21 +361,8 @@ export async function getUpcomingSchedules(db, startDate, limit) { }; } - grouped[dateKey].schedules.push(schedule); - - // 카테고리 카운트 - const existingCategory = grouped[dateKey].categories.find(c => c.id === s.category_id); - if (existingCategory) { - existingCategory.count++; - } else { - grouped[dateKey].categories.push({ - id: s.category_id, - name: s.category_name, - color: s.category_color, - count: 1, - }); - } + result.push(schedule); } - return grouped; + return { schedules: result }; }