import express from 'express'; import cors from 'cors'; import path from 'path'; import Database from 'better-sqlite3'; const app = express(); const PORT = 3000; app.use(cors()); app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true, limit: '10mb' })); app.use(express.static('./public')); const db = new Database('./data/meal-tracker.db'); const users = { 1: { id: 1, username: 'admin', password: 'admin123', isAdmin: true }, 2: { id: 2, username: 'rob', password: 'meal123', isAdmin: false } }; function getUserId(req) { return req.headers['x-user-id'] || req.body.user_id || 1; } app.get('/api/entries', (req, res) => res.json(db.prepare('SELECT * FROM entries WHERE user_id = ? ORDER BY created_at DESC').all(getUserId(req)))); // Single entry route - MUST come before wildcard app.get('/api/entries/:id', (req, res) => { const entry = db.prepare('SELECT * FROM entries WHERE id = ? AND user_id = ?').get(req.params.id, getUserId(req)); if (!entry) return res.status(404).json({error: 'Entry not found'}); res.json(entry); }); app.get('/api/summary/daily', (req, res) => { const u = getUserId(req); const s = db.prepare('SELECT COALESCE(SUM(calories),0) as total_calories, COALESCE(SUM(protein),0) as total_protein, COALESCE(SUM(carbs),0) as total_carbs, COALESCE(SUM(fat),0) as total_fat FROM entries WHERE user_id = ? AND date(created_at) = ?').get(u, new Date().toISOString().split('T')[0]); res.json(s); }); app.get('/api/favorites', (req, res) => res.json(db.prepare('SELECT * FROM entries WHERE favorite = 1 AND user_id = ?').all(getUserId(req)))); app.get('/api/goals', (req, res) => res.json({calories: 2000, protein: 150, carbs: 250, fat: 65})); app.get('/api/streak', (req, res) => res.json({currentStreak: 0, longestStreak: 0})); app.post('/api/entries', (req, res) => { const userId = getUserId(req); const { name, description, notes, calories, protein, carbs, fat, meal_time, image_url } = req.body; if (!name) return res.status(400).json({error: 'Name required'}); const result = db.prepare('INSERT INTO entries (name, description, notes, calories, protein, carbs, fat, meal_time, image_url, user_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)').run( name, description||null, notes||null, Number(calories)||0, Number(protein)||0, Number(carbs)||0, Number(fat)||0, meal_time||null, image_url||null, userId ); res.json({ id: result.lastInsertRowid, name, calories, protein, carbs, fat }); }); app.post('/api/entries/:id/favorite', (req, res) => { db.prepare('UPDATE entries SET favorite = CASE WHEN favorite = 1 THEN 0 ELSE 1 END WHERE id = ? AND user_id = ?').run(req.params.id, getUserId(req)); res.json({success: true}); }); app.delete('/api/entries/:id', (req, res) => { db.prepare('DELETE FROM entries WHERE id = ? AND user_id = ?').run(req.params.id, getUserId(req)); res.json({success: true}); }); app.post('/api/auth/login', (req, res) => { const {username, password} = req.body; const u = Object.values(users).find(x => x.username === username && x.password === password); if(u) res.json({id: u.id, username: u.username, isAdmin: u.isAdmin}); else res.status(401).json({error: 'Invalid credentials'}); }); app.post('/api/auth/register', (req, res) => res.json({id: 3, username: req.body.username, isAdmin: false})); app.get('/api/auth/me', (req, res) => { const u = users[req.headers['x-user-id']]; if(u) res.json({id: u.id, username: u.username, isAdmin: u.isAdmin}); else res.status(401).json({error: 'Not authenticated'}); }); app.get('/api/admin/users', (req, res) => { if(getUserId(req)!=1) return res.status(403).json({error:'Admin only'}); res.json(Object.values(users).map(u=>({id:u.id, username:u.username, isAdmin:u.isAdmin}))); }); app.delete('/api/admin/users/:id', (req, res) => res.json({success:true})); app.post('/api/admin/users/:id/reset-password', (req, res) => { if(users[req.params.id]) { users[req.params.id].password = req.body.password; res.json({success:true}); } else res.status(404).json({error:'Not found'}); }); app.post('/api/admin/users', (req, res) => res.json({id:3, username:req.body.username, isAdmin:false})); // SPA fallback - MUST be last app.get('*', (req, res) => res.sendFile(path.join(process.cwd(), 'public', 'index.html'))); app.listen(PORT, '0.0.0.0', () => console.log('Meal Tracker running on port ' + PORT));