Тема
Blueprint: Отзывы (Reviews)
Когда применять
Отзывы клиентов с модерацией: на сайт целиком, на услугу/товар/организацию. Публичная подача (форма) или ручное занесение админом — blueprint покрывает оба режима.
Не применять для: комментариев-дискуссий (ветки, ответы — другая модель), двусторонних отзывов маркетплейса (см. guide/recipes «биржа»).
Состав решения
- Модель
Review+ миграция + фабрика App\Enums\ReviewStatus(pending, approved, rejected)- При привязке к сущности:
reviewablemorph либо явный FK — morph только если отзывы реально нужны на 2+ типах сущностей, иначе простой FK - FormRequest
StoreReviewRequest(если публичная подача) - Filament-ресурс с модерацией
- Blade-компонент
<x-reviews>(список + агрегат) и форма подачи - Денормализованные агрегаты на целевой сущности:
reviews_avg,reviews_count
Схема данных
| Столбец | Тип | Индекс | Cast / примечание |
|---|---|---|---|
| id | id | PK | |
reviewable_type/_id или {entity}_id | morph / FK | index | см. правило выше |
| author_name | string | подача без регистрации — норма для сайтов студии | |
| author_contact | string nullable | телефон/email для верификации, не публикуется | |
| rating | unsignedTinyInteger nullable | index | 1–5; nullable если ТЗ «отзыв без оценки» |
| text | text | ||
| status | enum(ReviewStatus) | index | default pending |
| is_featured | boolean default false | «закрепить» лучшие | |
| source | string nullable | site, admin, import-2gis | |
| published_at | timestamp nullable | дата для сортировки/вывода | |
| timestamps |
Правила реализации
- Публичная подача — та же защита, что у leads: honeypot + throttle, статус
pending, на сайте — толькоapproved(scopeapproved). - Агрегаты (средний рейтинг, количество) — денормализованно на целевой сущности, пересчёт при смене статуса отзыва (observer или в сервисе модерации). Не считать AVG на каждый рендер списка.
- Вывод рейтинга — Schema.org
AggregateRatingвнутри разметки сущности (specs/seo); не размечать при < 2 отзывов. - Модерация в Filament: bulk approve/reject, фильтр по статусу, бейдж pending.
- Пагинация списка отзывов; сортировка: featured → свежие.
- Кеш блока отзывов — тег
reviews(+ тег сущности), flush при модерации.
Пакеты
Без специальных: модель простая, готовые review-пакеты дают меньше, чем ограничивают. spatie/laravel-honeypot для формы.
Шаги
- Миграция + модель + Enum + scope
approved+ фабрика. - Агрегатные поля на целевой сущности + пересчёт в сервисе.
- Форма подачи (FormRequest, honeypot, throttle) → pending.
- Filament-ресурс с модерацией и бейджем.
- Blade-компонент вывода + Schema.org.
- Тесты: подача → pending и не видна; approve → видна, агрегат пересчитан; reject → не видна; валидация rating 1–5.
Чеклист приёмки
- [ ] Неотмодерированный отзыв не виден на сайте ни в одном месте вывода
- [ ] Агрегаты денормализованы и корректны после каждого перехода статуса
- [ ] Контакт автора не выводится публично
- [ ] AggregateRating в разметке соответствует видимым отзывам
- [ ] Морф использован только при реальных 2+ типах сущностей