/** * Production-Ready Node.js API Server * For testing git serverless deployment */ const express = require('express'); const cors = require('cors'); const helmet = require('helmet'); const morgan = require('morgan'); const compression = require('compression'); const { v4: uuidv4 } = require('uuid'); // Load environment variables require('dotenv').config(); const app = express(); const PORT = process.env.PORT || 8080; const NODE_ENV = process.env.NODE_ENV || 'development'; // =========================================== // Middleware // =========================================== app.use(helmet()); // Security headers app.use(cors()); // CORS support app.use(compression()); // Gzip compression app.use(morgan('combined')); // Request logging app.use(express.json()); // Parse JSON bodies app.use(express.urlencoded({ extended: true })); // =========================================== // In-Memory Database (for testing) // =========================================== const database = { users: [ { id: '1', name: 'John Doe', email: 'john@example.com', createdAt: new Date().toISOString() }, { id: '2', name: 'Jane Smith', email: 'jane@example.com', createdAt: new Date().toISOString() }, ], tasks: [ { id: '1', userId: '1', title: 'Complete project', status: 'pending', createdAt: new Date().toISOString() }, { id: '2', userId: '1', title: 'Review PR', status: 'done', createdAt: new Date().toISOString() }, ] }; // =========================================== // Health Check Routes // =========================================== app.get('/', (req, res) => { res.json({ service: 'test-git-fcz5', version: '1.0.0', status: 'healthy', timestamp: new Date().toISOString(), environment: NODE_ENV, }); }); app.get('/health', (req, res) => { res.json({ status: 'ok', uptime: process.uptime(), timestamp: new Date().toISOString(), }); }); app.get('/ready', (req, res) => { res.json({ ready: true }); }); // =========================================== // Environment Info Route (for testing) // =========================================== app.get('/api/env', (req, res) => { res.json({ message: 'Environment variables (for testing config overrides)', environment: { NODE_ENV: process.env.NODE_ENV || 'not-set', PORT: process.env.PORT || 'not-set', // Boltic system variables BOLT_APPLICATION_NAME: process.env.BOLT_APPLICATION_NAME || 'not-set', BOLT_APPLICATION_SLUG: process.env.BOLT_APPLICATION_SLUG || 'not-set', BOLT_APPLICATION_REGION_ID: process.env.BOLT_APPLICATION_REGION_ID || 'not-set', // Custom env vars (set from UI or boltic.yaml) API_KEY: process.env.API_KEY ? '***hidden***' : 'not-set', DATABASE_URL: process.env.DATABASE_URL ? '***hidden***' : 'not-set', CUSTOM_VAR: process.env.CUSTOM_VAR || 'not-set', UI_TEST_VAR: process.env.UI_TEST_VAR || 'not-set', }, testInfo: { purpose: 'Verify environment variables from UI and boltic.yaml', configFormat: 'Check if serverlessConfig overrides are applied', } }); }); // =========================================== // Users API // =========================================== app.get('/api/users', (req, res) => { res.json({ success: true, data: database.users, total: database.users.length, }); }); app.get('/api/users/:id', (req, res) => { const user = database.users.find(u => u.id === req.params.id); if (!user) { return res.status(404).json({ success: false, error: 'User not found' }); } res.json({ success: true, data: user }); }); app.post('/api/users', (req, res) => { const { name, email } = req.body; if (!name || !email) { return res.status(400).json({ success: false, error: 'Name and email are required' }); } const newUser = { id: uuidv4(), name, email, createdAt: new Date().toISOString(), }; database.users.push(newUser); res.status(201).json({ success: true, data: newUser }); }); app.put('/api/users/:id', (req, res) => { const index = database.users.findIndex(u => u.id === req.params.id); if (index === -1) { return res.status(404).json({ success: false, error: 'User not found' }); } database.users[index] = { ...database.users[index], ...req.body }; res.json({ success: true, data: database.users[index] }); }); app.delete('/api/users/:id', (req, res) => { const index = database.users.findIndex(u => u.id === req.params.id); if (index === -1) { return res.status(404).json({ success: false, error: 'User not found' }); } const deleted = database.users.splice(index, 1); res.json({ success: true, data: deleted[0] }); }); // =========================================== // Tasks API // =========================================== app.get('/api/tasks', (req, res) => { const { userId, status } = req.query; let tasks = [...database.tasks]; if (userId) tasks = tasks.filter(t => t.userId === userId); if (status) tasks = tasks.filter(t => t.status === status); res.json({ success: true, data: tasks, total: tasks.length, }); }); app.post('/api/tasks', (req, res) => { const { userId, title } = req.body; if (!userId || !title) { return res.status(400).json({ success: false, error: 'userId and title are required' }); } const newTask = { id: uuidv4(), userId, title, status: 'pending', createdAt: new Date().toISOString(), }; database.tasks.push(newTask); res.status(201).json({ success: true, data: newTask }); }); app.patch('/api/tasks/:id/status', (req, res) => { const { status } = req.body; const validStatuses = ['pending', 'in-progress', 'done']; if (!status || !validStatuses.includes(status)) { return res.status(400).json({ success: false, error: `Invalid status. Must be one of: ${validStatuses.join(', ')}` }); } const task = database.tasks.find(t => t.id === req.params.id); if (!task) { return res.status(404).json({ success: false, error: 'Task not found' }); } task.status = status; res.json({ success: true, data: task }); }); // =========================================== // Echo/Debug Route (for testing) // =========================================== app.all('/api/echo', (req, res) => { res.json({ method: req.method, path: req.path, query: req.query, headers: req.headers, body: req.body, timestamp: new Date().toISOString(), }); }); // =========================================== // 404 Handler // =========================================== app.use((req, res) => { res.status(404).json({ success: false, error: 'Not Found', path: req.path, }); }); // =========================================== // Error Handler // =========================================== app.use((err, req, res, next) => { console.error('Error:', err); res.status(500).json({ success: false, error: NODE_ENV === 'production' ? 'Internal Server Error' : err.message, }); }); // =========================================== // Start Server // =========================================== app.listen(PORT, '0.0.0.0', () => { console.log('========================================'); console.log(`🚀 Server started successfully!`); console.log(`📍 Environment: ${NODE_ENV}`); console.log(`🌐 Listening on: http://0.0.0.0:${PORT}`); console.log(`💚 Health check: http://0.0.0.0:${PORT}/health`); console.log('========================================'); }); module.exports = app;