Разработка и внедрение системы модерации контента на сайте

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка и внедрение системы модерации контента на сайте
Сложный
~1-2 недели
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1359
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1251
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    957
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    947

Автоматизация модерации: как избавиться от спама и токсичности

Представьте: ваш сайт получает 10 000 комментариев в день. Среди них — 30% спама, 5% токсичного контента. Ручная модерация не справляется, а автоматическая фильтрация на базе только стоп-слов пропускает хитрые схемы. В одном из проектов (интернет-магазин с отзывами) после внедрения нашей системы количество пропущенного спама снизилось с 15% до 1%, а время публикации легальных отзывов — с 4 часов до 5 минут. За счёт автоматизации вы экономите до 80% бюджета на модерацию — для среднего проекта это $2000–3000 в месяц. Окупаемость наступает через 3–6 месяцев при инвестициях от $5000 до $8000. Система модерации перестаёт быть узким горлышком.

Мы решаем эту задачу комбинацией алгоритмов на PHP и внешних API. Предлагаемое решение сочетает автоматическую фильтрацию на основе правил и машинного обучения (Perspective API) с удобной панелью для ручной проверки. Это снижает нагрузку на модераторов и ускоряет публикацию легального контента.

Как работает автоматическая фильтрация?

Автоматическая фильтрация использует набор правил: стоп-слова, регулярные выражения для ссылок и повторяющихся символов, а также анализ истории автора. Система присваивает каждому сообщению оценку риска (spamScore) и принимает решение: одобрить, отправить в очередь или пометить как спам. Мы используем статусы модерации: pending, approved, rejected, spam, shadow_banned. Eloquent-модель с кастомным трейтом:

class Comment extends Model
{
    use HasModerationStatus;

    protected $casts = [
        'moderation_metadata' => 'array',
        'moderated_at'        => 'datetime',
    ];

    public function scopeVisible(Builder $query): Builder
    {
        return $query->where('status', 'approved');
    }

    public function scopePendingModeration(Builder $query): Builder
    {
        return $query->where('status', 'pending');
    }
}

Сервис проверки анализирует контент и возвращает решение:

class ContentModerationService
{
    private array $spamPatterns = [
        '/https?:\/\/[^\s]+/i',         // внешние ссылки
        '/\b(casino|viagra|loan|crypto)\b/i',
        '/(.)\1{5,}/',                  // повторяющиеся символы
    ];

    private array $bannedWords;

    public function analyze(string $content, User|null $author): ModerationResult
    {
        $signals = [];
        $spamScore = 0;

        foreach ($this->bannedWords as $word) {
            if (stripos($content, $word) !== false) {
                $signals[] = "banned_word:{$word}";
                $spamScore += 40;
            }
        }

        foreach ($this->spamPatterns as $pattern) {
            if (preg_match($pattern, $content)) {
                $signals[] = "pattern_match:{$pattern}";
                $spamScore += 30;
            }
        }

        if ($author) {
            $authorSpamRate = $author->comments()
                ->where('status', 'spam')
                ->count() / max($author->comments()->count(), 1);
            if ($authorSpamRate > 0.3) {
                $signals[] = 'author_spam_history';
                $spamScore += 50;
            }
        } else {
            $spamScore += 10;
        }

        if (strlen($content) < 5) {
            $signals[] = 'too_short';
            $spamScore += 20;
        }

        return new ModerationResult(
            score: $spamScore,
            signals: $signals,
            decision: match (true) {
                $spamScore >= 80 => ModerationDecision::SPAM,
                $spamScore >= 50 => ModerationDecision::PENDING,
                default          => ModerationDecision::APPROVE,
            }
        );
    }
}

Панель модератора и система жалоб

Панель модератора предоставляет очередь на проверку с возможностью фильтрации по типу контента. Каждое действие логируется в ModerationDecisionLog:

class ModerationController extends Controller
{
    public function queue(Request $request): JsonResponse
    {
        $items = Comment::pendingModeration()
            ->with('user:id,name,email', 'entity')
            ->when($request->type, fn($q) => $q->where('entity_type', $request->type))
            ->orderBy('moderation_score', 'desc')
            ->paginate(50);

        return response()->json($items);
    }

    public function decision(Request $request, Comment $comment): JsonResponse
    {
        $request->validate([
            'action' => 'required|in:approve,reject,spam,shadow_ban',
            'reason' => 'nullable|string|max:500',
        ]);

        $previousStatus = $comment->status;

        $comment->update([
            'status'         => match ($request->action) {
                'approve'     => 'approved',
                'reject'      => 'rejected',
                'spam'        => 'spam',
                'shadow_ban'  => 'shadow_banned',
            },
            'moderated_by'   => auth()->id(),
            'moderated_at'   => now(),
            'rejection_reason' => $request->reason,
        ]);

        ModerationDecisionLog::create([
            'moderator_id'  => auth()->id(),
            'comment_id'    => $comment->id,
            'action'        => $request->action,
            'reason'        => $request->reason,
            'previous_status' => $previousStatus,
        ]);

        if ($request->action === 'approve') {
            event(new CommentApprovedEvent($comment));
        }

        if (in_array($request->action, ['reject', 'spam'])) {
            $comment->user?->notify(new CommentRejectedNotification($comment));
        }

        UpdateAuthorReputationJob::dispatch($comment->user, $request->action);

        return response()->json(['status' => 'ok']);
    }
}

Пользователи могут жаловаться на комментарий. После трёх жалоб он автоматически отправляется в очередь модерации:

class ReportController extends Controller
{
    public function store(Request $request, Comment $comment): JsonResponse
    {
        $request->validate(['reason' => 'required|in:spam,abuse,misinformation,other']);

        Report::firstOrCreate(
            ['reporter_id' => auth()->id(), 'comment_id' => $comment->id],
            ['reason' => $request->reason]
        );

        $reportCount = Report::where('comment_id', $comment->id)->count();
        if ($reportCount >= 3 && $comment->status === 'approved') {
            $comment->update(['status' => 'pending', 'auto_flagged' => true]);
        }

        return response()->json(['reported' => true]);
    }
}

Повышение точности через Perspective API

Подключаем Perspective API для анализа токсичности. Точность определения токсичности достигает 95% на русском и английском. Интеграция простая:

class PerspectiveApiService
{
    public function analyzeToxicity(string $text): float
    {
        $response = Http::post(
            "https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze?key={$this->apiKey}",
            [
                'comment'           => ['text' => $text],
                'languages'         => ['ru', 'en'],
                'requestedAttributes' => ['TOXICITY' => new \stdClass()],
            ]
        );
        return $response->json('attributeScores.TOXICITY.summaryScore.value', 0.0);
    }
}

Исследования показывают, что комбинация правил и ML повышает точность до 96%.

Почему автоматическая модерация выгоднее ручной?

Автоматическая фильтрация обрабатывает до 1000 сообщений в секунду, модератор — около 10 в минуту. Таким образом, автоматическая система быстрее ручной в 6000 раз по пропускной способности. При этом автоматические алгоритмы снижают количество пропущенного спама на 80% по сравнению с чисто ручной модерацией. Это подтверждает наш опыт внедрения систем для более чем 20 проектов. Ключевые метрики: доля ложных срабатываний, среднее время обработки, процент одобренных жалоб. Мы настраиваем дашборды для оперативной корректировки правил.

Параметр Ручная модерация Автоматическая система
Пропускная способность ~10 комментариев/мин до 1000 комментариев/с
Доля пропущенного спама 10–15% <1%
Стоимость Высокая Низкая
Точность токсичности ~80% ~95%

Что влияет на точность фильтрации?

Ключевые факторы: качество стоп-листа, настройка паттернов, репутация автора и интеграция с Perspective API. Ложные срабатывания чаще всего возникают из-за слишком жёстких правил. Мы настраиваем систему так, чтобы минимизировать блокировку легитимного контента — обычно доля ложных срабатываний не превышает 2%.

Что входит в проект

  • Разработка модуля автоматической фильтрации (стоп-слова, паттерны, репутация автора).
  • Интеграция с Perspective API или аналогами.
  • Панель модератора с очередью и журналом модерации.
  • Система жалоб пользователей.
  • Статистика и отчёты для руководителя.
  • Документация и обучение команды модераторов.
Детальная карта реализации
  1. Анализ текущей архитектуры и сбор требований.
  2. Проектирование схемы данных (статусы, логи, репутация).
  3. Разработка сервиса фильтрации и трейта модели.
  4. Создание панели модератора с API и интерфейсом.
  5. Интеграция Perspective API.
  6. Механизм жалоб и автоматической блокировки.
  7. Дашборды для мониторинга.
  8. Тестирование и корректировка правил.
  9. Деплой и документирование.

Как внедрить систему

  1. Создайте список стоп-слов и шаблонов ссылок.
  2. Реализуйте сервис анализа (см. пример ContentModerationService).
  3. Интегрируйте модель с трейтом HasModerationStatus.
  4. Настройте очередь модерации и панель модератора.
  5. Подключите Perspective API для токсичности.
  6. Добавьте механизм жалоб и репутации авторов.
  7. Запустите тестирование и обучите модераторов.

Срок реализации

Задача Срок
Автофильтр (стоп-слова + паттерны) 1–2 дня
Очередь модерации + панель модератора 2–3 дня
Жалобы пользователей +1 день
Perspective API интеграция +1 день
Статистика и отчёты +1–2 дня
Полная система с репутацией авторов 5–8 дней

Система модерации — это не просто код, а готовое решение. Свяжитесь с нами, чтобы обсудить ваш проект и получить консультацию. Закажите разработку системы модерации — мы подберём оптимальное решение под вашу нагрузку.

Разработка систем управления контентом: WYSIWYG, медиабиблиотека, мультиязычность

Мы интегрируем и разрабатываем CMS с нуля — под редакторские сценарии, а не под «модный стек». Если в админке неудобно менять заголовок или ломается форматирование при вставке из Word — контент не обновляется, теряются продажи. Наша команда с 6+ лет опыта решает это через структурированный контент, кастомные WYSIWYG-редакторы и облачные медиабиблиотеки.

Когда headless CMS оправдана, а когда — нет

Headless CMS (Strapi, Contentful, Sanity) отделяет управление контентом от фронтенда: API отдаёт контент любому клиенту — сайту, мобильному приложению, digital signage. Выбор для омниканальных проектов и когда фронтенд на React/Vue/Next.js. Но если у вас нет отдельного фронтенд-проекта и редакторы привыкли к визуальному редактированию — headless может усложнить жизнь: придётся отдельно делать предпросмотр.

Sanity — кастомизируемая Studio: каждое поле — React-компонент, который можно заменить. Portable Text (формат для rich content) портируется в любой рендерер. Для сложных редакторских workflow — лучший выбор. Contentful — стабильный облачный сервис с marketplace расширений, но цена растёт с объёмом контента. Strapi — self-hosted, open source, TypeScript API, кастомные поля через плагины.

Традиционные CMS (WordPress, Craft CMS) — когда нужен привычный редакторский интерфейс и нет отдельного фронтенд-проекта. Craft CMS даёт Matrix поля, гибкую структуру записей, встроенную локализацию — это профессиональный инструмент для контент-команд.

Как мы строим WYSIWYG-редактор, который не ломает вёрстку

Редактор — отдельная инженерная задача, не просто <textarea>. Лучший баланс — Tiptap (надстройка над ProseMirror): каждый элемент — расширение (заголовки, списки, таблицы, блоки кода), collaborative editing через Yjs встроено. Lexical (от Meta) — производительнее, но сложнее в настройке. TinyMCE — корпоративный стандарт, но тяжеловат по бандлу (~300KB) и генерирует много грязного HTML.

Главная проблема — вставка из Word. &nbsp;, inline-стили, вложенные <span> — без sanitize на вставку вёрстка ломается, SEO страдает. Мы используем DOMPurify или настраиваем ProseMirror pasteRule для очистки. Результат — чистый HTML, который не меняется при редизайне.

Медиабиблиотека: от загрузки до CDN

Загружать файлы через <input type="file"> на диск сервера — антипаттерн. Диск переполнится, масштабирование невозможно, CDN не подключить. Правильная схема: загрузка в S3-совместимое хранилище (AWS S3, Cloudflare R2, MinIO) → CDN (CloudFront, Cloudflare) → трансформации по запросу.

Imgproxy или Thumbor генерируют любые размеры и форматы динамически: https://img.example.com/resize:800:600/format:webp/plain/s3://bucket/photo.jpg. Оригинал хранится один раз, производные не занимают место. Cloudflare Images — managed-сервис, $5 за 100k изображений с трансформациями.

Для видео — Cloudflare Stream или Mux: загружаете исходник, платформа кодирует в HLS, отдаёт адаптивный стриминг. Без этого видео весит 500MB и грузится целиком.

Что входит в разработку медиабиблиотеки

Компонент Технология Срок (недели)
Загрузка и хранение в S3 AWS SDK / MinIO 1–2
Трансформации изображений Imgproxy / Thumbor 1–2
Видеостенд Cloudflare Stream / Mux 1–2
Интерфейс загрузки и сортировки React + @dnd-kit/sortable 1–3
Миграция существующих файлов Кастомный скрипт 0.5–1

Структурированный контент vs free-form HTML

Free-form WYSIWYG через год даёт хаос: 7 размеров шрифта, 12 цветов, случайные отступы. Редизайн без ручной чистки невозможен. Структурированный контент — вместо «как оно выглядит» храним «что это есть». Не <p style="font-size:24px; color:red">Важно!</p>, а тип блока callout с параметром variant: warning. CMS хранит структуру, фронтенд решает, как рендерить. Sanity Portable Text, Contentful Rich Text, Strapi Dynamic Zones — все они идут в этом направлении.

Процесс работы

  1. Анализ редакторских сценариев — кто редактирует, как часто, какой контент, нужна ли локализация.
  2. Выбор CMS под сценарии, а не по трендам.
  3. Проектирование контент-модели — типы записей, поля, связи.
  4. Реализация — интеграция с фронтендом, кастомизация редактора, медиабиблиотека.
  5. Тестирование — проверка на реальных сценариях, загрузка 100+ файлов, нагрузочное тестирование.
  6. Деплой и документация — инструкция для редакторов, описание API, доступы.

Сроки и бюджет

Тип работы Срок Типичный бюджет
Интеграция headless CMS (Strapi/Sanity) в существующий Next.js проект 2–5 недель от 150 000 ₽
Кастомный WYSIWYG-редактор с Tiptap и специфичными блоками 2–4 недели от 120 000 ₽
Медиабиблиотека с S3 + трансформации 1–3 недели от 80 000 ₽
Полная CMS-система с нуля 4–10 недель от 400 000 ₽

Бюджет рассчитывается индивидуально после аудита. Свяжитесь с нами — оценим ваш проект за один день.

Что вы получите после завершения

  • Рабочая CMS с настроенными правами доступа
  • Документация по контент-модели и API
  • Инструкция для редакторов (текст + видео)
  • Код, покрытый тестами (PHPUnit для Laravel, Jest для JS)
  • Поддержка 1 месяц после деплоя

Наш опыт

6 лет на рынке, 40+ выполненных проектов. Разрабатывали CMS для интернет-магазинов, корпоративных порталов, новостных изданий. Используем лицензионное ПО (sentry.io, sonarcloud) — гарантируем качество кода.

Источник: внутренняя статистика проектов за 2018–2024 гг.

Подробнее о WYSIWYG-редакторах читайте в Wikipedia.

Остались вопросы?

Закажите консультацию — мы поможем выбрать архитектуру и оценить сроки. Получите предложение в течение 2 рабочих дней.