const express = require('express'); const cors = require('cors'); const path = require('path'); const connectDB = require('./config/database'); const Family = require('./models/Family'); const app = express(); // Enable CORS for frontend app.use(cors()); // Body parser middleware app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Request logging middleware app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`); if (req.method === 'POST' || req.method === 'PUT') { console.log(' Body:', JSON.stringify(req.body)); } next(); }); // Connect to MongoDB connectDB(); // Serve static files from the public directory (for standalone mode) if (process.env.SERVE_STATIC === 'true') { app.use(express.static(path.join(__dirname, '../public'))); } // API endpoint for family search app.get('/api/search', async (req, res) => { try { const query = req.query.family?.toLowerCase(); if (!query) { return res.json([]); } // Escape special regex characters to allow literal search const escapedQuery = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Search by family name (case-insensitive) const matches = await Family.find({ family: { $regex: escapedQuery, $options: 'i' } }).select('-__v -createdAt -updatedAt'); res.json(matches); } catch (error) { console.error('Search error:', error); res.status(500).json({ error: 'Search failed', message: error.message }); } }); // Get all families app.get('/api/families', async (req, res) => { try { const families = await Family.find() .select('-__v -createdAt -updatedAt') .sort({ family: 1 }); res.json(families); } catch (error) { console.error('Get families error:', error); res.status(500).json({ error: 'Failed to fetch families', message: error.message }); } }); // Create new family app.post('/api/families', async (req, res) => { try { console.log('πŸ“ POST /api/families - Creating new family'); const { family, city, lat, lng } = req.body; console.log(` Data: ${family}, ${city}, (${lat}, ${lng})`); // Validation if (!family || !city || lat === undefined || lng === undefined) { console.log(' ❌ Validation failed: Missing fields'); return res.status(400).json({ error: 'Missing required fields', required: ['family', 'city', 'lat', 'lng'], received: { family: !!family, city: !!city, lat: lat !== undefined, lng: lng !== undefined } }); } // Validate coordinates if (lat < -90 || lat > 90 || lng < -180 || lng > 180) { console.log(' ❌ Validation failed: Invalid coordinates'); return res.status(400).json({ error: 'Invalid coordinates', message: 'Latitude must be between -90 and 90, Longitude between -180 and 180' }); } const newFamily = new Family({ family, city, lat, lng }); await newFamily.save(); console.log(` βœ… Family created successfully: ${newFamily._id}`); res.status(201).json({ message: 'Family added successfully', family: newFamily }); } catch (error) { console.error('❌ Create family error:', error); res.status(500).json({ error: 'Failed to create family', message: error.message }); } }); // Update family app.put('/api/families/:id', async (req, res) => { try { const { id } = req.params; const { family, city, lat, lng } = req.body; const updatedFamily = await Family.findByIdAndUpdate( id, { family, city, lat, lng }, { new: true, runValidators: true } ); if (!updatedFamily) { return res.status(404).json({ error: 'Family not found' }); } res.json({ message: 'Family updated successfully', family: updatedFamily }); } catch (error) { console.error('Update family error:', error); res.status(500).json({ error: 'Failed to update family', message: error.message }); } }); // Delete family app.delete('/api/families/:id', async (req, res) => { try { const { id } = req.params; const deletedFamily = await Family.findByIdAndDelete(id); if (!deletedFamily) { return res.status(404).json({ error: 'Family not found' }); } res.json({ message: 'Family deleted successfully', family: deletedFamily }); } catch (error) { console.error('Delete family error:', error); res.status(500).json({ error: 'Failed to delete family', message: error.message }); } }); // Health check endpoint app.get('/api/health', (req, res) => { const mongoose = require('mongoose'); const dbStatus = mongoose.connection.readyState === 1 ? 'connected' : 'disconnected'; res.json({ status: 'ok', timestamp: new Date().toISOString(), database: dbStatus }); }); const port = process.env.PORT || 3000; app.listen(port, '0.0.0.0', () => { console.log(`πŸ—ΊοΈ Ora Map Backend API running at http://localhost:${port}`); console.log(`πŸ“ Search endpoint: http://localhost:${port}/api/search`); console.log(`πŸ’š Health endpoint: http://localhost:${port}/api/health`); });