import Fastify from 'fastify'; import corsPlugin from './plugins/cors'; import fastifyJwt from '@fastify/jwt'; import authRoutes from './modules/auth/auth.routes'; import dashboardRoutes from './modules/dashboard/dashboard.routes'; import incomesRoutes from './modules/incomes/incomes.routes'; import oneTimeExpensesRoutes from './modules/one-time-expenses/one-time-expenses.routes'; import recurringExpensesRoutes from './modules/recurring-expenses/recurring-expenses.routes'; import usersRoutes from './modules/users/users.routes'; const PORT = Number(process.env.PORT) || 3333; const HOST = process.env.HOST ?? '0.0.0.0'; const fastify = Fastify({ logger: { transport: process.env.NODE_ENV === 'development' ? { target: 'pino-pretty', options: { colorize: true } } : undefined, }, }); // --------------------------------------------------------------------------- // Plugins globais // --------------------------------------------------------------------------- fastify.register(corsPlugin); fastify.register(fastifyJwt, { secret: process.env.JWT_SECRET || 'super-secret-yaba-jwt-key-2026', }); // --------------------------------------------------------------------------- // JWT Middleware // --------------------------------------------------------------------------- fastify.addHook('onRequest', async (request, reply) => { if (request.url.includes('/api/v1/auth') || request.url.startsWith('/health')) { return; // Pula autenticação para rotas públicas } try { await request.jwtVerify(); } catch (err) { return reply.status(401).send({ error: 'Não autorizado.' }); } }); // --------------------------------------------------------------------------- // Rotas com prefixo /api/v1 // --------------------------------------------------------------------------- const API_PREFIX = '/api/v1'; fastify.register(authRoutes, { prefix: API_PREFIX }); fastify.register(usersRoutes, { prefix: API_PREFIX }); fastify.register(incomesRoutes, { prefix: API_PREFIX }); fastify.register(recurringExpensesRoutes, { prefix: API_PREFIX }); fastify.register(oneTimeExpensesRoutes, { prefix: API_PREFIX }); fastify.register(dashboardRoutes, { prefix: API_PREFIX }); // --------------------------------------------------------------------------- // Health check // --------------------------------------------------------------------------- fastify.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString(), version: '1.0.0', })); // --------------------------------------------------------------------------- // Handler de erros global // --------------------------------------------------------------------------- fastify.setErrorHandler((error, _request, reply) => { fastify.log.error(error); const statusCode = error.statusCode ?? 500; reply.status(statusCode).send({ error: statusCode >= 500 ? 'Erro interno do servidor.' : error.message, ...(process.env.NODE_ENV === 'development' && { stack: error.stack }), }); }); // --------------------------------------------------------------------------- // Start // --------------------------------------------------------------------------- try { await fastify.listen({ port: PORT, host: HOST }); console.log(`🚀 YABA API rodando em http://${HOST}:${PORT}`); console.log(`📖 Health check: http://${HOST}:${PORT}/health`); } catch (err) { fastify.log.error(err); process.exit(1); }