Данный сайт, который существовал на платформе WordPress 5 лет, полностью переписан на современный стек с помощью искуственного интеллекта. Потратил на работающий прототип - 24 часа. На тот сайт, что вы сейчас видите - 5 дней + эпизодические допилы.
Стек и инфраструктура сайта «Другое IT»
Что это
Блог со статьями и анонимный форум. Контент мигрирован из WordPress. Пользователи создают темы и отвечают без регистрации — аутентификация нужна только для доступа в админ-панель.
Бэкенд
- Фреймворк: Laravel 13 (PHP 8.4)
- База данных: MySQL 8.4
- Кэш и сессии: Redis 8 (расширение phpredis)
- Очереди: database (таблица
jobs) - Админ-панель: Filament 5 (Livewire + Alpine.js)
- Роли и права: spatie/laravel-permission 8
- Аутентификация: Laravel Breeze 2
- Тесты: PHPUnit 13, база SQLite в памяти
Фронтенд
- Рендеринг: Inertia.js 3 + Vue 3.5, SSR (отдельный Node-контейнер)
- Сборка: Vite 8 на Node 22
- Стили: Tailwind CSS 4 — конфигурация задаётся прямо в CSS, отдельного JS-конфига и PostCSS нет
- Графики: Chart.js 4 (дашборд вакансий)
Контейнеризация (Docker Compose)
Всё развёрнуто в Docker. Базовый docker-compose.yml + продакшн-оверлей docker-compose.prod.yml:
| Контейнер | Назначение |
|---|---|
| php | Приложение Laravel (PHP-FPM 8.4) |
| nginx | Веб-сервер (nginx 1.29), TLS, статика |
| mysql | База данных (MySQL 8.4) |
| redis | Кэш, сессии (Redis 8) |
| queue | Воркер очередей (queue:work) |
| scheduler | Планировщик задач (schedule:work) |
| ssr | Node.js SSR-сервер для Vue |
| node | Vite dev-сервер на Node 22 (только dev-профиль) |
| mailpit | Перехват исходящей почты (только dev-профиль) |
| certbot | Автообновление Let's Encrypt |
| postfix | Отправка почты (DKIM) |
| cron | Бэкапы БД (ежедневно в 03:00) |
Nginx
- Dev: HTTP на порту 8000.
- Production: HTTPS (Let's Encrypt), HSTS, Gzip, кэширование статики.
Бэкапы
- MySQL-дамп ежедневно в 03:00 (контейнер
cron), сжатие gzip, ротация дампов старше 14 дней.
Почта
- Postfix в отдельном контейнере, DKIM, relay из Docker-сети. PHP → Postfix через msmtp. На dev письма никуда не уходят — их перехватывает Mailpit.
Обслуживание
- Еженедельная очистка Docker-ресурсов (неиспользуемые образы, build cache) — cron на хосте, воскресенье 04:00.
- Генерация sitemap ежедневно в 03:00 (планировщик Laravel).
- Сбор статистики вакансий с hh.ru ежедневно в 04:00.
- Ежечасная очистка осиротевших изображений статей (загруженных через форму подачи, но так и не прикреплённых к статье).
- Ротация журнала проверок бота ежедневно в 03:15: записи без решения «нарушение» старше полугода удаляются, нарушения хранятся бессрочно.
Фичи сайта
Статьи и контент
- Лента статей — главная страница с пагинацией, фильтрация по тегам.
- Страница статьи — Markdown-контент с поддержкой HTML, комментарии, лайтбокс для изображений.
- Профили авторов — страница автора со списком его статей.
- База знаний — полный список статей, сгруппированный по годам.
- Закрепление статьи — закреплённые статьи идут первыми в ленте.
- Отложенная публикация — статья со статусом «опубликована» и датой в будущем на сайте не показывается до наступления даты.
- Подача статей пользователями — публичная форма для отправки статьи с обложкой, тегами и inline-изображениями. Статья сохраняется как черновик, админы получают email-уведомление.
- Обратная связь — форма обратной связи с вложениями (до 5 файлов по 10 МБ); письмо уходит на почту сайта с Reply-To на автора.
Форум
- Анонимный форум — создание тем и ответов без регистрации (имя — необязательное поле).
- Древовидные комментарии — иерархическая структура через nested set.
- Теги тем — до 5 тегов на тему, общий справочник тегов со статьями.
- Голосование — лайки/дизлайки по IP.
- Изображения в комментариях — загрузка до 5 картинок (до 10 МБ каждая), лайтбокс для просмотра.
- Редактирование/удаление комментариев — по токену, в течение 60 минут после публикации; удалить можно, только пока на комментарий нет ответов.
- Закрепление тем — модератор может закрепить тему (pin).
- Ссылки между комментариями — синтаксис
@ID. Ссылка на отдельной строке разворачивается в цитату с текстом того комментария (вложенность — до 10 уровней), ссылка внутри строки остаётся обычной ссылкой. Кнопка «Сослаться» вставляет её в форму ответа. - Markdown в комментариях — жирный, курсив, зачёркнутый, ссылки, инлайн-код и блоки кода, списки, цитаты, заголовки, таблицы. Тулбар над полем ввода.
- Жалоба на комментарий — значок флажка рядом с ID комментария, необязательная причина. Одна жалоба с IP на комментарий, до 50 жалоб в час с адреса. Каждую жалобу проверяет бот (см. «Проверка жалоб ботом»), админам уходит email с вердиктом и тем, что по нему сделано.
Комментарии к статьям
- Те же возможности, что и на форуме (древовидность, голосование, изображения, редактирование, удаление, жалобы).
- Возможность закрытия комментариев к статье из админ-панели.
Бот-собеседник в обсуждениях
- Вызов из комментария — посетитель упоминает бота по имени (
@siteBot) прямо в тексте реплики и просит разобрать спор, подвести итог ветки или ответить на вопрос. Бот отвечает обычным комментарием в ответ на обращение. - Ответ по ветке обсуждения — бот видит не всё обсуждение, а разговор вокруг вызова: цепочку реплик до начала ветки и соседние ответы, то есть тех, с кем спорят. Участники в анонимной ветке разграничиваются между собой, поэтому доводы одного не приписываются другому.
- Ссылки на реплики — в ответе бот ссылается на комментарии тем же синтаксисом
@ID, что и посетители. - Чтение по запросу — если для ответа нужен комментарий из другой ветки или текст самой статьи, бот дочитывает их сам. Доступно ему только то, что открыто и обычному посетителю.
- Характер бота настраивается — тон, объём и манера ответа редактируются в админ-панели. Границы поведения заданы в коде и правкой настройки не снимаются: текст комментариев для бота — данные, а не команды, поэтому попытки переписать ему инструкции из обсуждения не работают.
- Жалоба на нарушение — бот-собеседник может отметить реплику жалобой (до 3 за один вызов, только реплики своей ветки), и она уходит на ту же автоматическую проверку, что и жалобы посетителей. Сам собеседник ничего не удаляет, не скрывает и не объявляет чужую реплику нарушением в ответе: решение принимает отдельная проверка, а отменяет его человек.
- Плашка ожидания — ответ готовится в фоне и появляется через несколько секунд, поэтому под обращением показывается индикатор ожидания, а ветка подгружается сама. При любом исходе — ответ, сбой, исчерпанный лимит — плашка гаснет.
- Лимиты вызовов — суточные ограничения по IP автора вызова и по обсуждению. Обращение без текста (одно упоминание имени) остаётся без ответа.
Проверка жалоб ботом
- Каждая жалоба проверяется моделью — и жалоба посетителя, и отметка бота-собеседника. Проверка идёт в фоне и занимает секунды; человек разбирает только то, что бот решить не смог, и отменяет ошибочные решения.
- Нарушение — только состав из перечня — 13 составов из законодательства РФ: дискредитация армии и фейки о ней, призывы к с#########у и экстремизму, оскорбление представителя власти, разжигание ненависти, оправдание терроризма, запрещённая символика, клевета, оскорбление чувств верующих, угрозы насилием, чужие персональные данные, реклама запрещённых товаров. Грубость, мат, оскорбления между посетителями, несогласие и критика нарушением не считаются. Перечень задан в конфигурации, из него собираются промпт, схема ответа модели и фильтры админки.
- Три решения — «нарушение», «нарушения нет», «неясно». Нарушение подтверждается вторым вызовом модели с рассуждением; если второй не согласен — «неясно». Сбой проверки вердиктом не является и пишется в журнал отдельно.
- Что делается по решению — «нарушение»: комментарий скрывается плашкой «удалён ботом за нарушение правил сайта», ответы под ним остаются, закреплённая тема не скрывается; «нарушения нет»: жалобы снимаются автоматически (кроме комментариев с изображениями — картинки бот не видит); «неясно»: ждёт человека. Стоп-кран
SITEBOT_REVIEW_ENFORCEоставляет проверку и журнал, но отключает скрытие, блокировку и снятие жалоб. - Автоблокировка адреса — когда подтверждённых нарушений с одного IP становится больше пяти, адрес попадает в чёрный список, счётчик обнуляется, админам уходит отдельное письмо. Отменённые человеком вердикты в счёт не идут.
- Журнал «Проверки бота» — по каждой проверке: снимок текста, решение, состав, пояснение модели, причины жалоб, стоимость вызовов. Строки с нарушением хранятся бессрочно как обоснование скрытия и блокировки. Отменить вердикт и вернуть комментарий на сайт — одно действие.
- Повторная жалоба на тот же текст проверку не запускает: решение действует, пока автор не изменит текст. Суточный предел проверок страхует бюджет; сверх него жалоба уходит модератору без автоматической проверки.
- Письма — админам уходит письмо с вердиктом, составом, пояснением и тем, что сделано; при решении «нарушения нет» в рабочем режиме письма нет. Исчерпанный баланс сервиса даёт отдельное письмо не чаще раза в сутки.
Навигация и UX
- Бейдж новых комментариев — отображение количества новых комментариев с момента последнего визита.
- Навигация по новым комментариям — кнопки для перехода между непрочитанными комментариями.
- Запоминание имени — имя пользователя сохраняется в localStorage для повторных комментариев.
- Идентиконы — уникальные автогенерируемые аватары на основе IP. Хэш солится названием страницы, поэтому отследить пользователя между страницами нельзя. По клику — список его комментариев на этой странице.
- Тултип в сайдбаре — превью текста комментария при наведении на элемент блоков «Последние комментарии». Только на устройствах с мышью.
- Плашка согласия на Cookies — до явного выбора посетителя аналитика (Яндекс.Метрика, Top.Mail.Ru, LiveInternet) не загружается. Выбор хранится в cookie на год, изменить его можно по ссылке «Настройки Cookies» в футере.
Производительность
- Комментарии вне исходного HTML — деревья комментариев и сайдбарные блоки «Последние комментарии» отдаются отложенными пропсами Inertia: в исходном документе их нет ни в SSR-разметке, ни в JSON-пропсах, браузер догружает их отдельным запросом. Страница статьи с ~950 комментариями похудела с 8,7 МБ до 80 КБ, время до первого байта — с ~2,9 с до ~0,14 с. Побочный эффект: краулеры без исполнения JavaScript комментариев не видят.
Аналитика вакансий
- Дашборд вакансий — статистика IT-вакансий по языкам/технологиям.
- Графики временных рядов: количество вакансий, % без опыта, соотношение специалистов на вакансию.
- Ежедневный сбор данных (скрапинг в 04:00).
RSS и XML
- RSS-лента статей — последние статьи блога.
- Sitemap — генерируется ежедневно, включает статьи, теги, авторов, темы форума.
Поддержка AI-агентов
- Markdown-ответы — при запросе с заголовком
Accept: text/markdownпубличные страницы (лента статей, статья, форум, тема, отдельный комментарий, автор, база знаний) отдают чистый Markdown вместо SPA-страницы. Для браузеров ничего не меняется. Все адреса внутри документа абсолютные, ссылки@IDразворачиваются в обычные Markdown-ссылки. Ветки обсуждения в Markdown-версию не попадают. - Content-Signal в robots.txt — декларация правил использования контента AI-агентами в формате Content Signals.
Безопасность контента
- Фильтр нецензурной лексики — автоматическая фильтрация при публикации комментариев.
- Sanitize Markdown — стриппинг HTML в комментариях, разрешённые теги в статьях. Внешние ссылки получают
rel="nofollow noopener noreferrer". - Rate limiting — ограничения по IP на создание комментариев, голосование, жалобы, загрузку изображений, подачу статей, вход и восстановление пароля. На проде вход и восстановление пароля дополнительно ограничены на уровне nginx.
- Регистрация отключена — публичных маршрутов регистрации нет, учётные записи заводятся только в админ-панели.
- Чёрный список IP — тихий shadow-ban: комментарий с заблокированного IP не сохраняется, но посетитель видит обычное сообщение об успехе. Пополняется вручную из админки и автоматически по подтверждённым нарушениям из проверок бота.
Админ-панель (Filament)
- Управление статьями, тегами, пользователями, ролями, правами доступа. Списки статей, комментариев и пользователей разбиты на вкладки-срезы (черновики, запланированные, корзина, жалобы, авторы, заблокированные) со счётчиками.
- Модерация комментариев: физическое удаление, скрытие плашкой и возврат, закрепление, перемещение между статьями и форумом, блокировка IP автора, разбор жалоб со снятием вердиктов бота, ручной запуск проверки ботом. Колонка «Бот» показывает последнее решение по комментарию. Корзина есть только у статьи — вместе с ней туда уходят её комментарии.
- Раздел «Проверки бота» — журнал проверок жалоб: вкладки «Нарушения», «Сбои», «Все», действия «Отменить вердикт» и «Заблокировать IP», сводка над списком.
- Управление изображениями комментариев.
- Чёрный список IP-адресов.
- Настройки сайта — произвольные скрипты в
<head>и счётчики в сайдбаре. - Виджеты дашборда: статистика статей, статистика комментариев, сводка проверок бота и график нарушений по составам, черновики и заявки авторов, последние комментарии, последние загруженные изображения.
- Действия строки во всех таблицах панели идут столбиком: колонка действий не растягивает страницу и не отбирает ширину у содержательных колонок.
- Персональные данные под отдельными правами — IP-адреса комментаторов (
Comment.viewIp) и email пользователей (User.viewEmail) скрыты от тех, кому эти права не выданы: ни в таблицах, ни в формах, ни в глобальном поиске. - Демо-роль — доступ только на просмотр, для показа панели: ни одного изменяющего действия и никаких персональных данных. Ограничения закреплены тестом, который выполняет действия в обход интерфейса.


Комментарии (296)