/** * REST API Server * Provides RESTful API for Brazil SWIFT Operations Platform */ import 'dotenv/config'; import express, { Express, Request, Response, NextFunction } from 'express'; import cors from 'cors'; import { getLogger } from '@brazil-swift-ops/utils'; import { evaluateTransaction } from '@brazil-swift-ops/rules-engine'; import type { Transaction } from '@brazil-swift-ops/types'; import { initializeDatabase, closeDatabase } from './db/connection'; import { runMigrations } from './db/migrate'; import { seedDatabase } from './db/seed'; import authRoutes from './routes/auth'; const app: Express = express(); const logger = getLogger(); const PORT = process.env.PORT || 3000; // Middleware app.use(cors()); app.use(express.json()); app.use((req: Request, res: Response, next: NextFunction) => { const correlationId = `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; logger.setCorrelationId(correlationId); req.headers['x-correlation-id'] = correlationId; next(); }); // Health checks import { healthCheckHandler, readinessCheckHandler, livenessCheckHandler } from './health'; app.get('/health', healthCheckHandler); app.get('/health/ready', readinessCheckHandler); app.get('/health/live', livenessCheckHandler); // Import all route handlers import transactionRoutes from './routes/transactions'; import accountRoutes from './routes/accounts'; import userRoutes from './routes/users'; import complianceRoutes from './routes/compliance'; import reportsRoutes from './routes/reports'; import fxContractRoutes from './routes/fx-contracts'; import metricsRoutes from './routes/metrics'; import { errorHandler } from './middleware/errorHandler'; import { incrementCounter, recordHistogram } from './monitoring/metrics'; // Request metrics middleware app.use((req: Request, res: Response, next: NextFunction) => { const startTime = Date.now(); incrementCounter('http_requests_total', { method: req.method, path: req.path }); res.on('finish', () => { const duration = Date.now() - startTime; recordHistogram('http_request_duration_ms', duration, { method: req.method, status: res.statusCode.toString(), }); incrementCounter('http_responses_total', { method: req.method, status: res.statusCode.toString(), }); }); next(); }); // Register routes app.use('/api/v1/auth', authRoutes); app.use('/api/v1/transactions', transactionRoutes); app.use('/api/v1/accounts', accountRoutes); app.use('/api/v1/users', userRoutes); app.use('/api/v1/compliance', complianceRoutes); app.use('/api/v1/reports', reportsRoutes); app.use('/api/v1/fx-contracts', fxContractRoutes); app.use('/metrics', metricsRoutes); // Legacy evaluate transaction endpoint app.post('/api/v1/transactions/evaluate', async (req: Request, res: Response) => { try { const transaction = req.body as Transaction; const result = evaluateTransaction(transaction); logger.info('Transaction evaluated', { transactionId: transaction.id }); res.json({ success: true, data: result, }); } catch (error) { logger.error('Error evaluating transaction', error as Error); res.status(500).json({ success: false, error: 'Failed to evaluate transaction', }); } }); // Error handler (must be last) app.use(errorHandler); // Initialize database and start server let server: any; async function startServer() { try { // Initialize database await initializeDatabase(); console.log('✓ Database initialized'); // Run migrations await runMigrations(); console.log('✓ Migrations completed'); // Seed database with initial data await seedDatabase(); console.log('✓ Database seeded'); // Start server server = app.listen(PORT, () => { logger.info(`API server started on port ${PORT}`); }); // Handle graceful shutdown process.on('SIGTERM', shutdown); process.on('SIGINT', shutdown); } catch (error) { console.error('Failed to start server:', error); process.exit(1); } } async function shutdown() { console.log('\nShutting down gracefully...'); if (server) { server.close(async () => { await closeDatabase(); console.log('Server closed'); process.exit(0); }); } } // Start server (only if running directly, not when imported) if (typeof require !== 'undefined' && require.main === module) { startServer(); } export default app;