RecipeBox — менеджер рецептів
Побудуй повноцінний CRUD-додаток на Next.js. Бекенд — API routes, що працюють з JSON-файлом. Фронтенд — серверні компоненти для відображення та клієнтські для форм.
Підготовка
npx create-next-app@latest recipe-box --typescript --tailwind --app
cd recipe-box
Створи файл для "бази даних":
data/
recipes.json
[
{
"id": "1",
"title": "Борщ класичний",
"category": "Перші страви",
"cookingTime": 90,
"ingredients": ["буряк", "картопля", "капуста", "морква", "цибуля", "томатна паста"],
"instructions": "1. Зварити бульйон...",
"imageUrl": "",
"createdAt": "2026-01-15T10:00:00Z"
}
]
Завдання
1. API Routes (бекенд)
Створи повний набір CRUD-ендпоінтів:
| Метод | URL | Що робить |
|---|---|---|
| GET | /api/recipes | Список всіх рецептів |
| GET | /api/recipes/[id] | Один рецепт за ID |
| POST | /api/recipes | Створити новий рецепт |
| PUT | /api/recipes/[id] | Оновити рецепт |
| DELETE | /api/recipes/[id] | Видалити рецепт |
Дані зберігаються у data/recipes.json. Читай/записуй через fs.readFileSync / fs.writeFileSync.
Порада
Для генерації ID використай crypto.randomUUID() — вбудована функція Node.js, не потребує бібліотек.
Валідація в POST/PUT:
title— обов'язкове, мін. 3 символиcategory— обов'язковеingredients— масив, мін. 1 елемент- При помилках — повертай статус 400 з описом
2. Список рецептів (головна сторінка)
Server Component, що завантажує рецепти і показує:
- Картки рецептів (назва, категорія, час приготування, кількість інгредієнтів)
- Фільтр за категорією (Перші страви, Другі страви, Десерти, Салати, Напої)
- Пошук за назвою
- Посилання на сторінку кожного рецепта
3. Сторінка рецепта (/recipes/[id])
- Повна інформація: назва, категорія, час, інгредієнти (список), інструкція
- Кнопки "Редагувати" та "Видалити"
- Видалення з підтвердженням (confirm або модальне вікно)
- Після видалення — перенаправлення на головну
4. Форма створення (/recipes/new)
Client Component з controlled формою:
- Поля: назва, категорія (select), час приготування (number), інгредієнти (динамічний список — додати/видалити), інструкція (textarea), URL зображення
- Валідація на клієнті перед відправкою
fetch('POST', '/api/recipes')при submit- Після створення — перенаправлення на сторінку нового рецепта
5. Форма редагування (/recipes/[id]/edit)
- Та ж форма, що й для створення, але заповнена поточними даними
fetch('PUT', '/api/recipes/[id]')при submit- Після збереження — перенаправлення на сторінку рецепта
6. Layout та навігація
- Спільний layout: header (логотип + навігація), main, footer
- Навігація: Всі рецепти, Додати рецепт
- Responsive дизайн
Структура проекту
src/
├── app/
│ ├── layout.tsx
│ ├── page.tsx # Список рецептів
│ ├── recipes/
│ │ ├── new/
│ │ │ └── page.tsx # Форма створення
│ │ └── [id]/
│ │ ├── page.tsx # Сторінка рецепта
│ │ └── edit/
│ │ └── page.tsx # Форма редагування
│ └── api/
│ └── recipes/
│ ├── route.ts # GET all, POST
│ └── [id]/
│ └── route.ts # GET one, PUT, DELETE
├── components/
│ ├── RecipeCard.tsx
│ ├── RecipeForm.tsx # Спільна форма для create/edit
│ └── DeleteButton.tsx
└── types/
└── recipe.ts
data/
└── recipes.json
Бонус
- Додай завантаження зображення (зберігай в
public/uploads/через API route) - "Улюблені рецепти" — мітка зірочкою, фільтр по улюблених (додай поле
favorite: boolean) - Сортування: за датою, за часом приготування, за назвою
- SEO:
generateMetadataдля кожної сторінки рецепта - Друк рецепта: кнопка, що відкриває print-friendly версію (
window.print())
Критерії оцінки
| Критерій | Бали |
|---|---|
| API routes: GET all + GET one + POST + PUT + DELETE | 25 |
| Валідація в API (400 для некоректних даних) | 10 |
| Список рецептів (Server Component, фільтр, пошук) | 15 |
| Сторінка рецепта (деталі + видалення) | 10 |
| Форма створення (controlled, валідація, redirect) | 15 |
| Форма редагування (заповнення поточними даними) | 10 |
| Layout, навігація, стилізація | 10 |
| TypeScript типи (Recipe, API responses) | 5 |
| Бонус: Завантаження зображень / Улюблені / Сортування / SEO | +20 |