Клієнт прийшов зі скаргою: сторінка товару завантажується 4 секунди через N+1 запити при виведенні відгуків. Середній рейтинг не оновлювався добами — кеш не скидався. Система відгуків гальмувала каталог. Ми переписали модуль за 5 днів: денормалізували рейтинг, додали кешування, впровадили автоматичну модерацію. Конверсія зросла на 22%.
На одному проєкті знайшли 47 копій запиту SELECT * FROM reviews WHERE product_id = ? на сторінці каталогу. Після денормалізації рейтингу та агрегації через Redis час завантаження знизився з 4.2 с до 0.3 с. LCP покращився на 60%.
Чому варто впровадити систему відгуків?
Відгуки — соціальний доказ, що впливає на конверсію сильніше, ніж опис товару. Середній рейтинг та кількість відгуків відображаються в сніпетах Google через структуровані дані — це дає перевагу в пошуку. Готова система відгуків економить 2–3 тижні розробки. Ми вже реалізували понад 50 проєктів в E-commerce, тому знаємо типові проблеми: N+1 запити, невірна денормалізація рейтингу, дублі при завантаженні фотографій. Наше рішення включає оптимізацію запитів, кешування та безпечне завантаження медіа.
Як ми усуваємо N+1 запити?
Денормалізуємо рейтинг: додаємо поля rating_avg та rating_count в таблицю products. При схваленні відгуку запускаємо recalculateRating(), який оновлює агрегати за один запит. Кешуємо результат на годину в Redis — каталог завантажується без підзапитів до reviews.
| Стратегія перерахунку | Затримка оновлення | Навантаження на БД | Узгодженість |
|---|---|---|---|
| Immediate (after each review) | Секунди | Середня | Повна |
| Scheduled (cron) | Години | Низька | Подійна |
Рекомендуємо immediate: ціна — один зайвий UPDATE на схвалення відгуку, зате рейтинг завжди актуальний. При високих навантаженнях перемикаємось на чергу через Laravel Horizon.
Як автоматизується модерація?
Автоматична модерація обробляє 80% відгуків без участі людини. Наш сервіс перевіряє текст за стоп-словами, аналізує рейтинг та історію користувача. Решта 20% йдуть в чергу адмін-панелі зі швидкими діями: схвалити, відхилити або позначити спамом. Це в 3 рази швидше ручної перевірки.
Як налаштовується список стоп-слів
Стоп-слова задаються в config/reviews.php як масив фраз. За замовчуванням блокуємо посилання та контактні дані. Можна додати свої патерни — регулярні вирази або цілі фрази. Модератор може переглядати спрацьовування в адмін-панелі.
Технічна реалізація
Модель даних
CREATE TABLE reviews ( id BIGSERIAL PRIMARY KEY, product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE, order_item_id BIGINT REFERENCES order_items(id), user_id BIGINT REFERENCES users(id), guest_name VARCHAR(100), rating SMALLINT NOT NULL CHECK (rating BETWEEN 1 AND 5), title VARCHAR(255), body TEXT, pros TEXT, cons TEXT, status VARCHAR(20) DEFAULT 'pending', is_verified_purchase BOOLEAN DEFAULT FALSE, helpful_count INT DEFAULT 0, not_helpful_count INT DEFAULT 0, created_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE review_photos ( id BIGSERIAL PRIMARY KEY, review_id BIGINT REFERENCES reviews(id) ON DELETE CASCADE, url VARCHAR(500) NOT NULL, sort_order SMALLINT DEFAULT 0 ); CREATE TABLE review_votes ( review_id BIGINT REFERENCES reviews(id) ON DELETE CASCADE, user_id BIGINT REFERENCES users(id) ON DELETE CASCADE, vote BOOLEAN NOT NULL, PRIMARY KEY (review_id, user_id) ); CREATE TABLE review_replies ( id BIGSERIAL PRIMARY KEY, review_id BIGINT REFERENCES reviews(id) ON DELETE CASCADE, user_id BIGINT REFERENCES users(id), body TEXT NOT NULL, created_at TIMESTAMP DEFAULT NOW() ); Ми реалізуємо три моделі доступу до відгуків:
| Модель | Довіра | Кількість відгуків | Модерація |
|---|---|---|---|
| Тільки покупці | Висока | Низька | Ручна (мінімум) |
| Авторизовані користувачі | Середня | Середня | Автоматична |
| Гості | Низька | Висока | Ручна (всі) |
Рекомендуємо авторизованих користувачів з позначкою «Підтверджена покупка» для тих, у кого є завершене замовлення. Це дає баланс довіри та кількості.
API для створення відгуку
public function store(Request $request, Product $product): JsonResponse { $request->validate([ 'rating' => 'required|integer|between:1,5', 'body' => 'required|string|min:20|max:2000', 'title' => 'nullable|string|max:255', 'pros' => 'nullable|string|max:500', 'cons' => 'nullable|string|max:500', 'photos' => 'nullable|array|max:5', 'photos.*' => 'url', ]); $isVerified = OrderItem::whereHas('order', fn($q) => $q->where('user_id', $request->user()->id)->where('status', 'completed') )->where('product_id', $product->id)->exists(); $review = Review::create([ ...$request->validated(), 'product_id' => $product->id, 'user_id' => $request->user()->id, 'is_verified_purchase' => $isVerified, 'status' => $this->needsModeration($request) ? 'pending' : 'approved', ]); $product->recalculateRating(); return response()->json(new ReviewResource($review), 201); } Автоматична модерація
class ReviewModerationService { private array $stopWords = ['http', 'www.', 't.me/', 'whatsapp']; public function needsModeration(string $text, User $user): bool { foreach ($this->stopWords as $word) { if (str_contains(strtolower($text), $word)) return true; } return $user->reviews()->where('status', 'approved')->count() === 0; } } Автоматичні правила: відгук від верифікованого покупця з рейтингом 4–5 та без стоп-слів → approved; перший відгук нового користувача → pending; текст з URL, телефоном або стоп-словами → pending або spam.
Перерахунок рейтингу товару
public function recalculateRating(): void { $stats = $this->reviews() ->where('status', 'approved') ->selectRaw('COUNT(*) as count, AVG(rating) as avg, SUM(CASE WHEN rating = 5 THEN 1 ELSE 0 END) as five_star') ->first(); $this->update([ 'rating_avg' => round($stats->avg, 2), 'rating_count' => $stats->count, ]); Cache::forget("product:{$this->id}:rating"); } Рейтинг зберігається денормалізовано в таблиці products для швидкого сортування в каталозі. Після кожного нового відгуку або видалення викликається recalculateRating.
Як відгуки впливають на SEO?
Відгуки експортуються в JSON-LD для Google. Зірки в сніпеті з'являються за наявності мінімум 1 відгуку. За нашими даними, це збільшує CTR на 15–30%. Приклад розмітки:
<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Product", "name": "{{ product.name }}", "aggregateRating": { "@type": "AggregateRating", "ratingValue": "{{ product.rating_avg }}", "reviewCount": "{{ product.rating_count }}", "bestRating": 5, "worstRating": 1 }, "review": [ {% for review in product.topReviews %} { "@type": "Review", "author": { "@type": "Person", "name": "{{ review.user_name }}" }, "reviewRating": { "@type": "Rating", "ratingValue": "{{ review.rating }}" }, "reviewBody": "{{ review.body }}", "datePublished": "{{ review.created_at }}" } {% endfor %} ] } </script> Сортування та фільтрація відгуків
На сторінці товару відгуки сортуються за датою, рейтингом та корисністю. Фільтр за зірками — клікабельні рядки в гістограмі. Це допомагає покупцю знайти релевантні відгуки та знижує bounce rate.
Відповіді магазину
Менеджер може відповідати на відгуки з адмін-панелі з позначкою «Відповідь магазину». Це підвищує довіру та стимулює користувачів залишати більше відгуків.
Що входить в роботу
- Документація API та опис ендпоінтів
- Навчання адміністраторів роботі з модерацією
- Вихідний код модуля відгуків (Laravel 11 + React 18)
- Безкоштовна підтримка 30 днів після здачі
- Гарантія на код 1 рік
Процес роботи
- Аналітика — вивчаємо поточну архітектуру, навантаження, вимоги до модерації.
- Проектування — модель даних, API-контракти, схема кешування.
- Реалізація — бекенд (Laravel 11, PostgreSQL), фронтенд (React 18, TypeScript).
- Тестування — навантажувальне тестування (до 1000 RPM), перевірка модерації.
- Деплой — контейнеризація Docker, налаштування CI/CD, моніторинг.
Терміни та вартість
Базова реалізація займає 4–7 робочих днів. Терміни збільшуються, якщо потрібна інтеграція з існуючою CRM або нестандартні сценарії модерації. Вартість розраховується індивідуально залежно від обсягу робіт. Зв'яжіться з нами для консультації — ми розрахуємо точні терміни під ваш проєкт. Замовте розробку та отримайте систему відгуків, яка підвищить конверсію та покращить SEO.







