a1b80862f5
Suggest optimal 1-3 food combinations to fill remaining macro budget using weighted least-squares solver over a curated pantry (~55 foods) plus user favorites/recents. Recipes scored individually (no combining). Features: - Combinatorial solver (singles, pairs, triples) with macro-weighted scoring - MealTypePicker component (extracted from quick-log, shared) - Hero card with fit%, macro delta icons (Beef/Droplet/Wheat), ingredient cards, animated +/X toggle for logging - Responsive layout: sidebar on mobile, center column on desktop - MongoDB cache with ±5% tolerance, SSR on cache hit, TTL auto-expiry - Cache invalidation on food-log/favorites/custom-meals CRUD - Recipe per100g backfill admin endpoint
35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
import { json, error } from '@sveltejs/kit';
|
|
import type { RequestHandler } from './$types';
|
|
import { requireAuth } from '$lib/server/middleware/auth';
|
|
import { dbConnect } from '$utils/db';
|
|
import { CustomMeal } from '$models/CustomMeal';
|
|
import { RoundOffCache } from '$models/RoundOffCache';
|
|
|
|
export const GET: RequestHandler = async ({ locals }) => {
|
|
const user = await requireAuth(locals);
|
|
await dbConnect();
|
|
|
|
const meals = await CustomMeal.find({ createdBy: user.nickname }).sort({ updatedAt: -1 }).lean();
|
|
return json({ meals });
|
|
};
|
|
|
|
export const POST: RequestHandler = async ({ request, locals }) => {
|
|
const user = await requireAuth(locals);
|
|
await dbConnect();
|
|
|
|
const body = await request.json();
|
|
const { name, ingredients } = body;
|
|
|
|
if (!name?.trim()) throw error(400, 'name is required');
|
|
if (!Array.isArray(ingredients) || ingredients.length === 0) throw error(400, 'At least one ingredient is required');
|
|
|
|
const meal = await CustomMeal.create({
|
|
name: name.trim(),
|
|
ingredients,
|
|
createdBy: user.nickname,
|
|
});
|
|
|
|
RoundOffCache.deleteMany({ createdBy: user.nickname }).catch(() => {});
|
|
return json(meal.toObject(), { status: 201 });
|
|
};
|