# Laravel + Vue Ads

Backend: 54f1be9aa1057163edd9d095d27e8c5451935de7
Frontend: ba775c53a6b3b33c1524797390e09a9fb0a432a1

## Описание

- Обновление 7 сентября 2026: frontend опубликован по /catalog/ на основном домене. Старый ads-поддомен перенаправляет сюда, поскольку браузерный блокировщик рекламы блокировал его JS/CSS. Backend Laravel сохранён.
- Кейс объединяет laravel-sandbox и laravel-sandbox-ui. Это один проект с двумя репозиториями; SHA обоих сохраняются в release metadata.
- Сборка выполняется вне VPS через Dockerfile.portfolio и отдельный build context ads-ui. Версии фиксируются composer.lock и package-lock.json.
- Nginx → localhost:18402 → Apache/Laravel. БД ads и пользователь отдельные. Проверять /healthz, GET /api/ad, POST /api/ad, чтение/удаление своего ID. Команда php artisan demo:cleanup вызывается системным таймером; сброс не удаляет seed и чужие записи.
- Общие правила эксплуатации: готовые файлы и закреплённые образы собираются вне VPS; секреты не входят в артефакты. Общесерверный docker prune не применяется. Логи backend ограничены ротацией, изменения log options требуют пересоздания контейнера.
- Перед изменением пройти code-map от функции к экрану/API, модулю и данным. После изменения обновить карту и схемы, выполнить связанные сценарии, включая ошибку, повтор и сброс. Источник истины — конкретная версия кода, а не старая диаграмма.
- Откат проверен 2026-09-07T01:00:33.586236+00:00: 20260907-verified → 20260907b → 20260907-verified. После каждого переключения подтверждены HTTPS, readiness и SHA. Это проверка конфигурации и артефактов на одном проверенном SHA; обратная миграция БД не выполнялась.

## Сценарии

- Откройте каталог, измените сортировку и перейдите на следующую страницу.
- Посмотрите карточку и создайте объявление с локальным изображением.
- Проверьте валидацию пустого/ошибочного ввода.
- Откройте чужой ID во второй сессии: получите 404. Удалите своё объявление и сбросьте пример.

## Проверки

- Повторный полный production QA каталога на /catalog/: создание, удаление, поиск, сортировка, пагинация, сессии и мобильный вид — passed. В исходной Chrome-сессии страница открывается с включённым блокировщиком.
- Sorting, pagination, search, empty state
- Required form validation
- Signed Secure HttpOnly cookie; cross-session GET/DELETE both 404
- Server rejects negative price, short text and external image URL
- Cancel, delete and restored seed count
- Подтверждённого GitHub CI для этого SHA нет; перечислены выполненные локальные проверки и сценарии опубликованной версии. Исторические CI-ссылки, если есть, отмечены отдельно.

## Ограничения

- Все объявления и изображения учебные. Продажи и произвольные загрузки отключены.
- 20 собственных объявлений на сессию, 1000 суммарно; TTL один час и cleanup timer каждые пять минут.
- Legacy инструменты Vue-сборки имеют известные dev-зависимости; полный переход frontend tooling не выполнялся.

## Code-map

| Функция | Экран / API | Модуль | Данные / проверка |
|---|---|---|---|
| Каталог, поиск, сортировка | AdList / GET api/ad | AdController::index | ads, owner scope |
| Карточка | AdItem / GET api/ad/id | AdController::show | seed или своя запись |
| Создание | AdNew / POST api/ad | Validator, Eloquent | allowlist + session_id + expires_at |
| Удаление и сброс | AdItem / DELETE, POST demo/reset | AdController, DemoSession | только своя сессия |
| Очистка | CLI demo:cleanup | scheduled command | expired rows |
