Тестовое задание: форма обратной связи. Монорепо из двух частей — Laravel 11 API (backend/) и Vue 3 SPA (frontend/).
- Frontend: Vue 3 + Vite + TypeScript, Vuex 4, Vue Router 4.
- Backend: Laravel 11, PHP 8.2+. Паттерн Factory для выбора сохранения (
databaseилиemail). Физическая запись не производится — реализации логируют факт вызова (по ТЗ это необязательно). - Инфра: Docker Compose (один сервис на каждую часть, named volumes для
vendor/иnode_modules/).
test-envy/
├── backend/ Laravel 11 API
│ ├── app/
│ │ ├── Http/Controllers/FeedbackController.php
│ │ ├── Http/Requests/StoreFeedbackRequest.php
│ │ └── Services/Feedback/ Factory + реализации + DTO
│ ├── config/{app,cors,logging}.php
│ ├── routes/api.php POST /api/feedback
│ ├── docker/entrypoint.sh авто .env + key:generate
│ └── Dockerfile
├── frontend/ Vue 3 SPA
│ ├── src/
│ │ ├── views/{HomeView,ListView}.vue
│ │ ├── store/index.ts Vuex
│ │ ├── router/index.ts Vue Router
│ │ └── types/feedback.ts
│ └── Dockerfile
├── docker-compose.yml
└── README.md
Нужен только Docker Desktop (macOS/Windows) или Docker Engine + docker compose plugin (Linux). Локально PHP, Composer или Node ставить не нужно.
docker compose up --buildПосле сборки:
- Frontend: http://localhost:5173
- Backend: http://localhost:8000
- Health: http://localhost:8000/up
Повторный запуск (без пересборки образов):
docker compose upВ фоне / остановить / очистить тома:
docker compose up -d
docker compose down
docker compose down -v- Открой http://localhost:5173 — отобразится шапка с двумя ссылками («Форма», «Список»).
- На странице «Форма» заполни имя и обращение, нажми «Отправить». Появится сообщение об успехе.
- Перейди на «Список» — увидишь только что отправленное обращение (данные держатся в Vuex и пропадут после F5 — это по ТЗ).
- Можно продублировать через curl:
curl -i -X POST http://localhost:8000/api/feedback \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"name":"Ivan","message":"Hello there","destination":"email"}'Ответ 201 Created:
{
"id": "…uuid…",
"name": "Ivan",
"message": "Hello there",
"savedVia": "email",
"createdAt": "2026-04-24T12:34:56+00:00"
}Body (application/json):
| поле | тип | обязательное | ограничения |
|---|---|---|---|
name |
string | да | 1..100 |
message |
string | да | 1..2000 |
destination |
string | нет | database | email (default: database) |
Контроллер получает FeedbackSaverFactory через DI и вызывает $factory->make($destination)->save($data). Фабрика реализована в app/Services/Feedback/FeedbackSaverFactory.php.
Ответ 201 с телом { id, name, message, savedVia, createdAt }. Ошибки валидации — 422 с полями в стандартном формате Laravel.
cd backend
composer install
cp .env.example .env
php artisan key:generate
php artisan servecd frontend
npm install
npm run devЕсли бэк лежит не на http://localhost:8000, укажи URL во фронте:
echo "VITE_API_URL=http://localhost:8000" > frontend/.env.local- SPA на Vue.js + Vuex (не Pinia) + Vue-Router — да, две страницы, навигация без перезагрузки.
- Страница 1 — форма «имя / обращение», POST на бэк, результат в Vuex.
- Страница 2 — список только из Vuex, без повторного запроса, данные теряются на F5.
- Laravel + PHP, паттерн Factory с параметром
database | email, методsave(). Физическое сохранение пропущено (по ТЗ необязательно) — вместо этогоLog::info.