import Fastify from 'fastify'; import config from './config/index.js'; // 플러그인 import dbPlugin from './plugins/db.js'; import redisPlugin from './plugins/redis.js'; import authPlugin from './plugins/auth.js'; import youtubeBotPlugin from './services/youtube/index.js'; import xBotPlugin from './services/x/index.js'; import schedulerPlugin from './plugins/scheduler.js'; // 라우트 import adminRoutes from './routes/admin/index.js'; export async function buildApp(opts = {}) { const fastify = Fastify({ logger: { level: opts.logLevel || 'info', }, ...opts, }); // config 데코레이터 등록 fastify.decorate('config', config); // 플러그인 등록 (순서 중요) await fastify.register(dbPlugin); await fastify.register(redisPlugin); await fastify.register(authPlugin); await fastify.register(youtubeBotPlugin); await fastify.register(xBotPlugin); await fastify.register(schedulerPlugin); // 라우트 등록 await fastify.register(adminRoutes, { prefix: '/api/admin' }); // 헬스 체크 엔드포인트 fastify.get('/api/health', async () => { return { status: 'ok', timestamp: new Date().toISOString() }; }); // 봇 상태 조회 엔드포인트 fastify.get('/api/bots', async () => { const bots = fastify.scheduler.getBots(); const statuses = await Promise.all( bots.map(async bot => { const status = await fastify.scheduler.getStatus(bot.id); return { ...bot, ...status }; }) ); return statuses; }); return fastify; }