All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Integrated MongoDB 7.0 with Mongoose ODM - Added CRUD API endpoints (GET, POST, PUT, DELETE) - Created Family model with validation - Added database seeding script with initial data - Implemented Add Family modal form in frontend - Updated docker-compose with MongoDB service - Updated Helm chart to v0.3.0 with MongoDB StatefulSet - Updated documentation with MongoDB setup instructions
157 lines
4.3 KiB
JavaScript
157 lines
4.3 KiB
JavaScript
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 }));
|
|
|
|
// 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([]);
|
|
}
|
|
|
|
// Search by family name (case-insensitive)
|
|
const matches = await Family.find({
|
|
family: { $regex: query, $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 {
|
|
const { family, city, lat, lng } = req.body;
|
|
|
|
// Validation
|
|
if (!family || !city || lat === undefined || lng === undefined) {
|
|
return res.status(400).json({
|
|
error: 'Missing required fields',
|
|
required: ['family', 'city', 'lat', 'lng']
|
|
});
|
|
}
|
|
|
|
// Validate coordinates
|
|
if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
|
|
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();
|
|
|
|
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`);
|
|
});
|