/** * Dataflow API Server * Simple REST API for data transformation */ require('dotenv').config(); const express = require('express'); const { Pool } = require('pg'); const app = express(); const PORT = process.env.API_PORT || 3000; // Database connection const pool = new Pool({ host: process.env.DB_HOST, port: process.env.DB_PORT, database: process.env.DB_NAME, user: process.env.DB_USER, password: process.env.DB_PASSWORD }); // Middleware app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Auth — protect all /api routes (health and static UI are exempt) const auth = require('./middleware/auth'); app.use('/api', auth); // Serve UI const path = require('path'); app.use(express.static(path.join(__dirname, '../public'))); // Set search path for all queries pool.on('connect', (client) => { client.query('SET search_path TO dataflow, public'); }); // Test database connection pool.query('SELECT NOW()', (err, res) => { if (err) { console.error('Database connection error:', err); process.exit(1); } console.log('✓ Database connected'); }); //------------------------------------------------------ // Routes //------------------------------------------------------ // Import route modules const sourcesRoutes = require('./routes/sources'); const rulesRoutes = require('./routes/rules'); const mappingsRoutes = require('./routes/mappings'); const recordsRoutes = require('./routes/records'); // Mount routes app.use('/api/sources', sourcesRoutes(pool)); app.use('/api/rules', rulesRoutes(pool)); app.use('/api/mappings', mappingsRoutes(pool)); app.use('/api/records', recordsRoutes(pool)); // Health check app.get('/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); // Root endpoint app.get('/', (req, res) => { res.json({ name: 'Dataflow API', version: '0.1.0', endpoints: { sources: '/api/sources', rules: '/api/rules', mappings: '/api/mappings', records: '/api/records', health: '/health' } }); }); // Error handler app.use((err, req, res, next) => { console.error('Error:', err); res.status(err.status || 500).json({ error: err.message || 'Internal server error', ...(process.env.NODE_ENV === 'development' && { stack: err.stack }) }); }); // SPA fallback — serve index.html for any non-API route app.use((req, res, next) => { if (req.path.startsWith('/api')) return next(); res.sendFile(path.join(__dirname, '../public/index.html')); }); // 404 handler (API routes only) app.use((req, res) => { res.status(404).json({ error: 'Endpoint not found' }); }); // Start server app.listen(PORT, '0.0.0.0', () => { console.log(`✓ Dataflow API listening on port ${PORT}`); console.log(` Health: http://localhost:${PORT}/health`); console.log(` API: http://localhost:${PORT}/api/sources`); }); module.exports = app;