import 'dotenv/config'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import Fastify from 'fastify'; import multipart from '@fastify/multipart'; import staticFiles from '@fastify/static'; import websocket from '@fastify/websocket'; import { initDb } from './db/models.js'; import { jobRoutes } from './routes/jobs.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); const PORT = parseInt(process.env.PORT ?? '3000', 10); const fastify = Fastify({ logger: { level: 'info' } }); // --------------------------------------------------------------------------- // Plugins // --------------------------------------------------------------------------- await fastify.register(multipart, { limits: { fileSize: 20 * 1024 * 1024, // 20 MB max image files: 1, }, }); await fastify.register(websocket); // Serve the built React app — dist/ is built by `npm run dev` (watch) // or `npm run build` before starting in production. await fastify.register(staticFiles, { root: join(__dirname, 'dist'), prefix: '/', }); // --------------------------------------------------------------------------- // Routes // --------------------------------------------------------------------------- await fastify.register(jobRoutes); fastify.get('/api/health', async () => ({ ok: true })); // SPA fallback — let React Router handle any path Fastify doesn't recognise fastify.setNotFoundHandler((_req, reply) => { reply.sendFile('index.html'); }); // --------------------------------------------------------------------------- // Boot // --------------------------------------------------------------------------- await initDb(); await fastify.listen({ port: PORT, host: '0.0.0.0' }); console.log(`✅ Server listening on http://localhost:${PORT}`);