false, 'error' => 'Method not allowed'], 405); } $people = normalizePeopleList(readJsonFile('people.json')); $actor = requireActivePerson($people); $actorId = (string) ($actor['id'] ?? ''); $body = readJsonBody(); $meals = normalizeMealsList(readJsonFile('meals.json')); $meals = migrateLegacyMealsList($meals); $id = isset($body['id']) ? trim((string) $body['id']) : ''; if ($id !== '') { $idx = findMealIndexById($meals, $id); if ($idx === null) { sendJson(['success' => false, 'error' => 'Meal not found'], 404); } $existing = $meals[$idx]; $isAuthor = ($existing['author_id'] ?? '') === $actorId; $isHoH = ($actor['role'] ?? '') === ROLE_HEAD && isHohVerified(); if (!$isAuthor && !$isHoH) { sendJson(['success' => false, 'error' => 'You cannot edit this meal'], 403); } $row = $existing; } else { if (($actor['role'] ?? '') !== ROLE_HEAD || !isHohVerified()) { sendJson(['success' => false, 'error' => 'Only a verified Head of household can create meals'], 403); } $row = [ 'id' => bin2hex(random_bytes(8)), 'author_id' => $actorId, ]; $idx = null; } $title = isset($body['title']) ? trim((string) $body['title']) : ''; if ($title === '') { sendJson(['success' => false, 'error' => 'Title is required'], 400); } $row['title'] = $title; $row['image'] = isset($body['image']) ? trim((string) $body['image']) : ''; $row['description'] = isset($body['description']) ? trim((string) $body['description']) : ''; $row['directions'] = isset($body['directions']) ? trim((string) $body['directions']) : ''; $row['lists'] = normalizeChoreLists($body['lists'] ?? []); $row['tags'] = $body['tags'] ?? []; $row['ingredients'] = $body['ingredients'] ?? []; $row['items'] = $body['items'] ?? []; $row = normalizeMealRow($row); if ($idx === null) { $meals[] = $row; } else { $meals[$idx] = $row; } if (!writeJsonFile('meals.json', $meals)) { sendJson(['success' => false, 'error' => 'Failed to save meals'], 500); } sendJson(['success' => true, 'meal' => $row]);