/** * 일정 라우트 * GET: 공개, POST/PUT/DELETE: 인증 필요 */ import suggestionsRoutes from './suggestions.js'; export default async function schedulesRoutes(fastify) { const { db } = fastify; // 추천 검색어 라우트 등록 fastify.register(suggestionsRoutes, { prefix: '/suggestions' }); /** * GET /api/schedules * 월별 일정 목록 조회 * @query year - 년도 (필수) * @query month - 월 (필수) */ fastify.get('/', { schema: { tags: ['schedules'], summary: '월별 일정 목록 조회', querystring: { type: 'object', required: ['year', 'month'], properties: { year: { type: 'integer', description: '년도' }, month: { type: 'integer', minimum: 1, maximum: 12, description: '월' }, }, }, }, }, async (request, reply) => { const { year, month } = request.query; if (!year || !month) { return reply.code(400).send({ error: 'year와 month는 필수입니다.' }); } const startDate = `${year}-${String(month).padStart(2, '0')}-01`; const endDate = new Date(year, month, 0).toISOString().split('T')[0]; const [schedules] = 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 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 WHERE s.date BETWEEN ? AND ? ORDER BY s.date ASC, s.time ASC `, [startDate, endDate]); // 날짜별로 그룹화 const grouped = {}; for (const s of schedules) { const dateKey = s.date.toISOString().split('T')[0]; if (!grouped[dateKey]) { grouped[dateKey] = { categories: [], schedules: [], }; } // 일정 추가 const schedule = { id: s.id, title: s.title, time: s.time, category: { id: s.category_id, name: s.category_name, color: s.category_color, }, }; if (s.source_name) { schedule.source_name = s.source_name; } 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, }); } } return grouped; }); /** * GET /api/schedules/:id * 일정 상세 조회 */ fastify.get('/:id', { schema: { tags: ['schedules'], summary: '일정 상세 조회', }, }, async (request, reply) => { const { id } = request.params; const [schedules] = await db.query(` SELECT s.*, c.name as category_name, c.color as category_color, sy.channel_name as source_name 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 WHERE s.id = ? `, [id]); if (schedules.length === 0) { return reply.code(404).send({ error: '일정을 찾을 수 없습니다.' }); } const s = schedules[0]; const result = { id: s.id, title: s.title, date: s.date, time: s.time, category: { id: s.category_id, name: s.category_name, color: s.category_color, }, created_at: s.created_at, updated_at: s.updated_at, }; if (s.source_name) { result.source_name = s.source_name; } return result; }); }