aboutsummaryrefslogtreecommitdiff
path: root/api/src/server.ts
diff options
context:
space:
mode:
Diffstat (limited to 'api/src/server.ts')
-rw-r--r--api/src/server.ts115
1 files changed, 115 insertions, 0 deletions
diff --git a/api/src/server.ts b/api/src/server.ts
new file mode 100644
index 0000000..9ab75eb
--- /dev/null
+++ b/api/src/server.ts
@@ -0,0 +1,115 @@
+/**
+ * server.ts
+ *
+ * Entry point do backend Helpdesk.
+ *
+ * Responsabilidades (em ordem):
+ * 1. Executar migrações do banco no boot
+ * 2. Criar e configurar a instância Fastify
+ * 3. Registrar plugins globais
+ * 4. Registrar módulos de rotas
+ * 5. Iniciar o servidor HTTP
+ */
+
+import 'dotenv/config'; // Carrega .env antes de qualquer outro import
+import Fastify from 'fastify';
+import cors from '@fastify/cors';
+import sensible from '@fastify/sensible';
+import { validatorCompiler } from 'fastify-type-provider-zod';
+
+import { runMigrations } from '@/db/migrate.js';
+import dbPlugin from '@/plugins/db.plugin.js';
+import authPlugin from '@/plugins/auth.plugin.js';
+import authRoutes from '@/modules/auth/auth.routes.js';
+import ticketsRoutes from '@/modules/tickets/tickets.routes.js';
+import interactionsRoutes from '@/modules/interactions/interactions.routes.js';
+import categoriesRoutes from '@/modules/categories/categories.routes.js';
+import settingsRoutes from '@/modules/settings/settings.routes.js';
+import statsRoutes from '@/modules/stats/stats.routes.js';
+import usersRoutes from '@/modules/users/users.routes.js';
+import eventsPlugin from '@/plugins/events.plugin.js';
+import eventsRoutes from '@/plugins/events.routes.js';
+
+// ─── Configuração ─────────────────────────────────────────────────────────────
+const PORT = Number(process.env['PORT'] ?? 3000);
+const HOST = process.env['HOST'] ?? '0.0.0.0';
+const IS_DEV = process.env['NODE_ENV'] !== 'production';
+
+// ─── Factory da aplicação ─────────────────────────────────────────────────────
+// Exportar como função facilita testes de integração (cada teste cria uma instância)
+export async function buildApp() {
+ const fastify = Fastify({
+ logger: {
+ level: IS_DEV ? 'info' : 'warn',
+ // Formatação legível no terminal em desenvolvimento
+ transport: IS_DEV
+ ? { target: 'pino-pretty', options: { colorize: true } }
+ : undefined,
+ },
+ });
+
+ // Configura o Fastify para usar validação com Zod
+ fastify.setValidatorCompiler(validatorCompiler);
+
+ // ── Plugins Globais ───────────────────────────────────────────────────────
+ // CORS: permite requisições do frontend (Vite roda na porta 5173)
+ await fastify.register(cors, {
+ origin: IS_DEV ? 'http://localhost:5173' : process.env['FRONTEND_URL'],
+ methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
+ });
+
+ // Sensible: adiciona helpers como reply.notFound(), reply.badRequest(), etc.
+ await fastify.register(sensible);
+
+ // Banco de dados: disponibiliza fastify.db em todas as rotas
+ await fastify.register(dbPlugin);
+
+ // JWT: disponibiliza fastify.authenticate em todas as rotas
+ await fastify.register(authPlugin);
+
+ // ── Plugins Locais ────────────────────────────────────────────────────────
+ await fastify.register(eventsPlugin);
+
+ // ── Rotas ─────────────────────────────────────────────────────────────────
+ // Auth: rotas públicas (sem authenticate)
+ await fastify.register(authRoutes, { prefix: '/api/v1/auth' });
+ await fastify.register(statsRoutes, { prefix: '/api/v1/stats' });
+ await fastify.register(eventsRoutes, { prefix: '/api/v1/events' });
+ await fastify.register(categoriesRoutes, { prefix: '/api/v1/categories' });
+ await fastify.register(settingsRoutes, { prefix: '/api/v1/settings' });
+ await fastify.register(usersRoutes, { prefix: '/api/v1/users' });
+ await fastify.register(ticketsRoutes, { prefix: '/api/v1/tickets' });
+ await fastify.register(interactionsRoutes, { prefix: '/api/v1' });
+
+ // Health check — útil para monitoramento e load balancer
+ fastify.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
+
+ return fastify;
+}
+
+// ─── Bootstrap ───────────────────────────────────────────────────────────────
+async function start(): Promise<void> {
+ // 1. Aplica migrações pendentes antes de abrir o servidor para tráfego
+ await runMigrations();
+
+ // 2. Cria a instância configurada
+ const app = await buildApp();
+
+ // 3. Graceful shutdown — garante que requests em andamento terminem antes de fechar
+ const gracefulShutdown = async (signal: string) => {
+ app.log.info(`Sinal ${signal} recebido. Encerrando servidor...`);
+ await app.close();
+ process.exit(0);
+ };
+
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); // Kubernetes / systemd
+ process.on('SIGINT', () => gracefulShutdown('SIGINT')); // Ctrl+C no terminal
+
+ // 4. Inicia o servidor
+ await app.listen({ port: PORT, host: HOST });
+}
+
+start().catch((err) => {
+ console.error('❌ Falha ao iniciar o servidor:', err);
+ process.exit(1);
+});