Админ-панели и CMS
Что нужно настоящему бэк-офису: роли, CRUD, медиа, SEO, отчёты, экспорт и аудит-логи.
За 30 секунд
Админ-панель — это продукт, которым бизнес пользуется каждый день: управление товарами, заказами, клиентами, контентом и акциями. Ей нужны детальные роли, быстрые списки с фильтрами, медиатека, SEO-поля, отчёты и экспорт, а также аудит-лог, который отвечает на вопрос «кто это изменил?». Если строить её из конфигурации, а не писать каждый экран вручную, она остаётся единообразной и дёшево расширяется.
Почему я это использую
- Я использую админ-панели на основе конфигурации, потому что поддерживаю собственную React-админку с настраиваемыми CRUD-ресурсами, медиаменеджером и дизайн-системой, которая переиспользуется во многих клиентских проектах.
- Покупатели видят витрину, а сотрудники живут в админке. Медленная или запутанная админка каждый день стоит бизнесу часов работы.
- Большинство экранов админки следуют одному паттерну — список, фильтр, создание, редактирование, удаление, — поэтому их генерация из конфигурации освобождает время для действительно особых экранов.
- Роли, аудит-логи и экспорт — это то, что делает систему надёжной для растущей команды.
Как это работает
01Что нужно любой админке
Начинайте с пользователей админки, а не с таблиц базы данных. Оператору, который обрабатывает заказы, нужен быстрый список заказов с фильтрами по статусу и обновлениями в реальном времени. Контент-менеджеру нужны страницы, блог, медиа и SEO. Маркетологу — акции, сегменты и кампании. Руководителю — отчёты. За всеми ними стоят одни и те же строительные блоки: аутентификация (в идеале со вторым фактором или одноразовыми кодами для администраторов), роли и права, CRUD-экраны (create, read, update, delete) с поиском, фильтрами, сортировкой и пагинацией, массовые действия, медиатека, настройки, отчёты с экспортом и аудит-лог. Уведомления — web push или внутри приложения — сообщают сотрудникам о новых заказах или упавших синхронизациях.
- Списки: пагинация на сервере, фильтры в URL, чтобы представлениями можно было делиться.
- Формы: валидация на сервере, понятные ошибки, предупреждение о несохранённых изменениях.
- Массовые действия с подтверждением и сводкой того, что изменилось.
02Роли, права и аудит-логи
Роль — это именованный набор прав («оператор заказов», «редактор контента»); право — это одно действие над ресурсом, например orders.view или products.update. Проверяйте права на сервере в каждом запросе — скрыть кнопку в интерфейсе удобно, но это не безопасность. Держите имена прав единообразными, чтобы меню админки, маршруты и кнопки читали один и тот же список. Для чувствительных действий — возвратов, ручного изменения балансов, смены ролей — добавьте дополнительное трение: поле для причины, подтверждение, возможно, второго утверждающего. Аудит-лог записывает, кто что сделал, когда, с какой записью, и значения до и после. Когда в продакшене что-то идёт не так, аудит-лог превращает гадание в двухминутный поиск.
// Laravel: one permission check per action, enforced on the server
Route::middleware(['auth:admin', 'can:orders.refund'])
->post('/admin/orders/{order}/refund', RefundOrderController::class);
// Audit every sensitive change with before/after values
AuditLog::create([
'admin_id' => $request->user()->id,
'action' => 'order.refunded',
'subject' => $order->getMorphClass().':'.$order->id,
'before' => ['status' => $before],
'after' => ['status' => $order->status, 'amount' => $amount],
'reason' => $request->string('reason'),
'ip' => $request->ip(),
]);
03CRUD на основе конфигурации
Большинство экранов админки отличаются только полями и колонками. Вместо того чтобы писать каждый список и форму вручную, опишите ресурс в конфигурации: его API-эндпоинт, колонки списка, фильтры, поля формы с типами (text, number, select, rich text, image, slug, дерево категорий) и права. Универсальный движок рендерит список и форму по этому описанию, поэтому новый ресурс занимает минуты, а каждый экран получает одинаковую пагинацию, отображение ошибок валидации и массовые действия. На бэкенде универсальный ресурсный контроллер может обслуживать стандартный CRUD, а кастомные эндпоинты — обрабатывать особую логику. Оставьте запасной выход: некоторые экраны — страница деталей заказа, конструктор акций, дашборд — заслуживают кастомных компонентов, и система конфигурации должна позволять их подключать.
export const brandsResource = {
name: "brands",
endpoint: "/admin/brands",
permission: "brands",
list: {
columns: ["logo", "name", "productsCount", "isActive"],
filters: [{ field: "isActive", type: "boolean" }],
search: ["name"],
},
form: [
{ name: "name", type: "text", required: true, translatable: true },
{ name: "slug", type: "slug", from: "name" },
{ name: "logo", type: "media", accept: "image/*" },
{ name: "description", type: "richText", translatable: true },
{ name: "seo", type: "seo" },
],
} as const;
04Медиатека и SEO-поля
Медиатека хранит загрузки один раз и позволяет редакторам переиспользовать их: папки, поиск, кадрирование, замена (с сохранением работающих ссылок), alt-текст и отслеживание использования. Проверяйте загрузки по содержимому, а не только по расширению файла, ограничивайте размер и разрешение, удаляйте метаданные и генерируйте уменьшенные варианты, например WebP-миниатюры, в фоновой задаче. Когда сайт растёт, храните файлы в объектном хранилище (совместимом с S3) за CDN, а не на диске сервера приложения. SEO-поля нужны каждой публичной модели: slug, meta title, meta description, изображение для соцсетей, canonical URL и переключатель noindex, с разумными значениями по умолчанию, сгенерированными из контента. Админка также должна управлять редиректами, потому что переименованные slug иначе создают битые ссылки, а сайт должен генерировать sitemap из тех же данных.
05Отчёты и экспорт
Отчёты отвечают на бизнес-вопросы: продажи по дням и каналам, лучшие товары, новые и вернувшиеся покупатели, стоимость акций, среднее время доставки. Стройте их на запросах, рассчитанных на отчётность, — агрегированных таблицах, read-репликах или ночных сводках, — чтобы тяжёлый отчёт никогда не замедлял checkout. Всегда показывайте диапазон дат и часовой пояс и следите, чтобы цифры совпадали со списком заказов (одно и то же определение «оплачен» везде). Экспорт в Excel или CSV обязателен, потому что финансы и маркетинг живут в таблицах. Генерируйте большие выгрузки в задаче из очереди, стримьте строки, а не загружайте всё в память, и отправляйте ссылку на скачивание, когда файл готов. Выгрузки содержат персональные данные, поэтому защищайте их правами, короткоживущими ссылками и записью в аудит-логе.
06Встроенная CMS или headless CMS?
CMS (система управления контентом) позволяет людям без навыков разработки редактировать страницы и контент. Встроенная CMS живёт внутри вашей собственной админки и базы данных: страницы, блог, FAQ, баннеры и блоки рядом с товарами и заказами. Она идеальна, когда контент тесно связан с коммерческими данными, и ничего не стоит дополнительно. Headless CMS (Contentful, Sanity, Strapi, Payload) — это отдельный сервис, который хранит контент и отдаёт его через API; он хорош для редакционных команд, богатых блочных макетов, превью и процессов согласования. Часто встречается гибрид: структурированные бизнес-данные в собственном бэкенде, редакционный контент — в headless CMS. Что бы вы ни выбрали, моделируйте контент как типизированные блоки, а не как одно гигантское HTML-поле, чтобы дизайн контролировал фронтенд, а контент оставался переносимым.
Когда применять
- Любой продукт, где сотрудники ежедневно управляют данными: магазины, платформы заказов, CRM, системы бронирования.
- Нескольким проектам нужны похожие экраны админки, поэтому переиспользуемая система на конфигурации окупается.
- Командам с разными обязанностями нужны разные уровни доступа и подотчётность.
Когда не стоит
- Статичный маркетинговый сайт с редкими правками — headless CMS или даже Markdown-файлы проще.
- Когда готовый фреймворк админки хорошо подходит к вашему стеку; не пересобирайте Filament или Django admin для стандартного случая.
- Не используйте универсальный CRUD для сложных процессов вроде обработки заказов; им нужны специально спроектированные экраны.
Альтернативы
- Filament / Laravel Nova
Фреймворки админ-панелей для Laravel; очень быстрые для CRUD, с ресурсами, формами, таблицами и правами.
- React Admin / Refine
React-фреймворки, которые генерируют админ-интерфейсы из data providers; хороши для кастомных бэкендов.
- Headless CMS (Contentful, Sanity, Strapi, Payload)
Лучше всего для редакционного контента, превью и процессов согласования; добавляет ещё один сервис и расходы.
- Retool / конструкторы внутренних инструментов
Быстрые внутренние дашборды поверх баз данных и API; хуже подходят для контента, который видят клиенты.
Лучшие практики
- Проверяйте права на сервере для каждого эндпоинта; интерфейс только отражает их.
- Используйте второй фактор или одноразовые коды для входа в админку.
- Логируйте чувствительные действия со значениями до и после, автором и причиной.
- Генерируйте стандартный CRUD из конфигурации, а кастомные экраны оставляйте для сложных процессов.
- Проверяйте загрузки по содержимому и обрабатывайте изображения в фоновых задачах.
- Дайте каждой публичной модели SEO-поля и управляйте редиректами в админке.
- Запускайте тяжёлые отчёты и выгрузки в очередях, подальше от нагрузки на базу данных checkout.
Частые ошибки
- Одна роль «admin» для всех, из-за чего редактор контента может оформлять возвраты.
- Скрывать кнопки в интерфейсе, но оставлять API незащищённым.
- Загружать целые таблицы в браузер вместо пагинации на сервере.
- Выгрузки, которые строятся в веб-запросе и падают по таймауту или исчерпывают память.
- Хранить контент как сырые HTML-блобы, которые ломаются при смене дизайна.
Глубже
07Авторизация за пределами ролей: scopes и policies
Role-based access control (RBAC) отвечает на вопрос «может ли этот человек делать возвраты по заказам?», но не на вопрос «может ли он делать возвраты по заказам этого филиала?». Реальной админке нужно и то и другое. Совмещайте права со scopes: у менеджера филиала есть orders.refund, ограниченное его филиалами, а пользователь-поставщик видит только свои товары. Реализуйте проверку в одном месте для каждого ресурса — в классе policy, — который получает пользователя, действие и запись, и применяйте тот же scope к запросам списков, чтобы люди даже не видели строки, которые им трогать нельзя. Это шаг к attribute-based access control (ABAC), где правила используют атрибуты пользователя и записи. Кэшируйте права пользователя в рамках запроса, инвалидируйте кэш при изменении ролей и пишите тесты на каждую чувствительную policy, потому что баги авторизации молчат, пока не приведут к утечке данных.
// Laravel policy: permission plus scope in one place
class OrderPolicy
{
public function refund(Admin $admin, Order $order): bool
{
return $admin->can('orders.refund')
&& $admin->branches()->whereKey($order->branch_id)->exists();
}
}
// The same scope applied to list queries
Order::query()
->whereIn('branch_id', $admin->branches()->pluck('branches.id'))
->latest()
->paginate(50);
08Audit log, который выдержит разбор инцидента
Audit log полезен, только если ему доверяют. Пишите записи на сервисном слое, чтобы фиксировались изменения из экранов, API-вызовов, импортов и консольных команд. Сохраняйте diff изменённых полей, а не строки целиком, и маскируйте секреты и чувствительные персональные данные. Сделайте таблицу append-only: пользователь базы, под которым работает приложение, может вставлять, но не обновлять и не удалять, а очистка по сроку хранения запускается отдельной привилегированной задачей. Добавляйте к каждой записи request ID, чтобы одно действие админа, затронувшее десять записей, отслеживалось как одно событие. Для особо ценных действий логируйте и чтение — кто выгрузил список клиентов, кто просмотрел полный адрес держателя карты. Храните аудит достаточно долго для споров и требований регуляторов и обеспечьте поиск по записи, по человеку и по временному диапазону.
-- Append-only for the application user
REVOKE UPDATE, DELETE ON audit_logs FROM app_user;
GRANT INSERT, SELECT ON audit_logs TO app_user;
CREATE INDEX audit_logs_subject_idx ON audit_logs (subject_type, subject_id, created_at DESC);
CREATE INDEX audit_logs_actor_idx ON audit_logs (admin_id, created_at DESC);
09Производительность админки на больших таблицах
Списки в админке часто становятся самой медленной частью системы: таблица заказов на миллионы строк, десяток фильтров и общий счётчик на каждой странице. Делайте индексы под фильтры, которыми реально пользуются, — обычно составные индексы, начинающиеся со статуса или филиала и заканчивающиеся датой создания. Точный общий счётчик на огромных отфильтрованных таблицах дорог; после определённого порога показывайте «много результатов» или оценку либо считайте асинхронно. Offset-пагинация деградирует на глубоких страницах, потому что база всё равно проходит пропущенные строки; keyset (cursor) пагинация остаётся быстрой. Избегайте N+1 запросов, подгружая через eager loading связи, которые показываются в колонках. Поиску по множеству текстовых колонок место в поисковом движке или полнотекстовом индексе, а не в цепочках LIKE. И наконец, тяжёлые дашборды выносите на read replica или в сводные таблицы, чтобы менеджер, обновляющий отчёты, никогда не замедлял оформление заказов.
- Логируйте медленные запросы админки и разбирайте их раз в месяц.
- Для выгрузок и бесконечной прокрутки предпочитайте cursor-пагинацию.
- Подгружайте через eager loading связи, используемые в колонках списков.
10Защита админки
Админка — самая мощная дверь в бизнес, поэтому ей нужны самые крепкие замки. Требуйте второй фактор для каждого аккаунта администратора. Делайте сессии админки короткими, с таймаутом бездействия, и запрашивайте повторную аутентификацию перед критичными действиями, такими как смена ролей или реквизитов для выплат. Подумайте о том, чтобы отдавать админку на отдельном поддомене, с более строгими cookies и, где это реально, с IP allowlist или VPN. Защищайтесь от CSRF при сессиях на cookies и от stored XSS из полей с rich text, санитизируя HTML на сервере по allowlist тегов. Загруженные файлы никогда не должны быть исполняемыми: храните их вне web root или в object storage и осторожно отдавайте загруженные пользователями SVG, потому что SVG может содержать скрипты. Мониторьте входы в админку и поднимайте алерт на новые устройства или «невозможные перемещения».
Реальные ситуации
Кто изменил цену?
Проблема
Хит продаж неделю продавался за полцены. Доступ к админке есть у троих, никто не помнит, чтобы редактировал товар, а audit log отсутствует.
Как решить
По этому инциденту проверьте всё, что есть: логи веб-сервера на POST-запросы к эндпоинту товара, updated_at в базе, логи синхронизации с ERP и историю импорта цен. Затем предотвратите следующий: добавьте audit log на сервисном слое, который записывает исполнителя, действие, значения до и после, request ID и источник (экран, импорт или синхронизация). Разделите общую роль админа на реальные роли, чтобы цены могла менять только команда ценообразования, и требуйте поле с причиной для изменений цены выше порога. Добавьте ежедневный отчёт о самых крупных изменениях цен и правило-предохранитель, которое отправляет изменения больше чем на 30% на утверждение.
Список заказов загружается 12 секунд
Проблема
Операторы жалуются, что в часы пик экраном заказов невозможно пользоваться. В таблице три миллиона строк, а список загружается с фильтром по статусу, полем поиска и общим счётчиком.
Как решить
Сначала измерьте: включите логирование запросов или EXPLAIN ANALYZE для запроса списка. Типичные исправления по порядку: добавить составной индекс под фильтр и сортировку по умолчанию, например (status, created_at DESC); убрать точный счётчик или ограничить его порогом; подгрузить через eager loading связи с клиентом и филиалом, чтобы убрать N+1 запросы; заменить поиск через LIKE по нескольким колонкам выделенным поисковым полем или полнотекстовым индексом; перейти на keyset-пагинацию. По умолчанию показывайте последние 30 дней — это то, что операторам действительно нужно. Перемеряйте после каждого изменения и добавьте запрос в алерт по медленным запросам.
Маркетинг хочет лендинги без разработчиков
Проблема
Каждый лендинг кампании требует, чтобы разработчик его сверстал и задеплоил, а это занимает неделю. Маркетинг хочет публиковать страницы сам, но команда дизайна боится сломанной вёрстки.
Как решить
Сделайте конструктор страниц на блоках: разработчики создают библиотеку типизированных блоков — hero, сетка товаров, баннер, FAQ, текст с изображением, — у каждого есть схема полей с проверяемыми ограничениями, а рендерят их компоненты, следующие дизайн-системе. Редакторы собирают страницы из блоков, меняют их порядок, планируют публикацию и смотрят превью перед выходом в продакшен. Сетки товаров ссылаются на реальные товары или категории по ID, поэтому цены и остатки остаются актуальными. Версионируйте каждую страницу, чтобы редакторы могли откатиться. Так дизайн остаётся единым, ведь редакторы выбирают контент, а не CSS, а новые типы блоков можно добавить, когда маркетингу станет мало библиотеки.
Шпаргалка
- Middleware прав на маршруте (Laravel)
Route::post('/admin/orders/{order}/refund', RefundOrder::class)->middleware('can:refund,order');- Обход для super-admin в одном месте
Gate::before(fn (Admin $a) => $a->hasRole('super-admin') ? true : null);- Валидация загрузки изображений
'logo' => ['required', File::image()->max(5 * 1024)->dimensions(Rule::dimensions()->maxWidth(4000))]- Короткоживущая приватная ссылка на скачивание
Storage::disk('s3')->temporaryUrl($path, now()->addMinutes(15));- Потоковая выгрузка большого экспорта
Order::query()->where(...)->lazyById(1000)->each(fn ($o) => $writer->addRow($o->toExportRow()));- Keyset-пагинация
Order::orderByDesc('id')->cursorPaginate(50);- Найти медленные запросы списков (PostgreSQL)
EXPLAIN (ANALYZE, BUFFERS) SELECT ... FROM orders WHERE status = 'paid' ORDER BY created_at DESC LIMIT 50;- Таблица аудита только на добавление
REVOKE UPDATE, DELETE ON audit_logs FROM app_user;
В моих реальных проектах
- Я поддерживаю собственную React-админку в виде пакетов: CRUD-ресурсы на конфигурации, медиаменеджер, около 20 компонентов дизайн-системы и поля CKEditor, медиа, slug и дерева, а также её Laravel-часть со входом в админку по OTP, ролями, универсальным ресурсным контроллером и медиатекой.
- На платформе для сети ресторанов в админке 12 ролей, web push для администраторов, медиатека с папками, кадрированием и заменой, SEO и sitemap для каждой модели, около 30 контроллеров отчётов и около 40 эндпоинтов экспорта в Excel.
- На сайте агентства я построил гибридную CMS: структурированные данные в админке на Laravel, а редакционный блочный контент — в headless CMS; та самописная админка стала прародителем переиспользуемых пакетов админки.
Вопросы и ответы
Q1Как вы проектируете роли и права для админки?
Я определяю права как пары ресурс-действие, например orders.view, orders.refund или products.update, и группирую их в роли, соответствующие реальным должностям: оператор, редактор контента, маркетолог, руководитель. Сервер проверяет право на каждом маршруте; фронтенд читает тот же список, чтобы показывать меню и кнопки. Супер-админ — только для нескольких человек. Чувствительные действия получают дополнительный контроль: обязательную причину, запись в аудит-лог и иногда второго утверждающего. Кастомные роли позволяют бизнесу адаптироваться без изменения кода.
Q2Что такое админка на основе конфигурации и когда она оправдана?
Вместо того чтобы писать каждый список и форму вручную, вы описываете ресурс — эндпоинт, колонки, фильтры, поля и права, — а универсальный движок рендерит экраны. Это оправдано, когда у вас много похожих ресурсов или несколько проектов, потому что каждый новый ресурс занимает минуты и ведёт себя единообразно. Это не замена всему: сложные процессы вроде обработки заказов или конструктора акций всё равно требуют кастомных экранов, поэтому система должна поддерживать подключение кастомных компонентов.
Q3Headless CMS или встроенная CMS?
Встроенная CMS хранит контент в вашей собственной базе данных рядом с товарами и заказами — это просто, бесплатно и идеально, когда страницы смешивают коммерческие данные. Headless CMS — это отдельный сервис с сильным редакторским опытом, превью, локализацией и процессами согласования, который отдаёт контент через API. Я выбираю встроенную для магазинов, где контент — это в основном баннеры, страницы и блог, и headless, когда маркетинговая команда часто публикует богатый блочный контент. Гибрид обоих вариантов встречается часто и работает хорошо.
Q4Зачем нужен аудит-лог?
Потому что в команде обязательно спросят «кто изменил эту цену?» или «кто вернул деньги за тот заказ?», и часто — во время инцидента. Аудит-лог записывает автора, действие, целевую запись, значения до и после, время и IP. Он обеспечивает подотчётность, помогает поддержке отвечать клиентам, удерживает от злоупотреблений и часто требуется для compliance. Для администраторов он должен быть только на добавление, с поиском по записи и храниться в течение определённого срока. Логирование на сервисном слое ловит изменения со всех экранов и API.
Q5Как вы обрабатываете большие выгрузки?
Никогда не в веб-запросе. Администратор нажимает «экспорт», сервер ставит в очередь задачу с фильтрами, а задача стримит строки из базы данных порциями в CSV или Excel-файл, не раздувая память. По завершении она сохраняет файл в закрытом хранилище и уведомляет пользователя короткоживущей ссылкой на скачивание. Выгрузки содержат персональные и финансовые данные, поэтому требуют права, логируются в аудит-логе, а файлы удаляются через несколько дней.
Вопросы уровня senior
S1Писать свою админку, взять фреймворк вроде Filament или low-code инструмент?
Зависит от того, насколько центральна админка и сколько проектов её используют. Low-code инструменты быстрее всего дают внутренние дашборды поверх существующих данных, но плохо справляются со сложными процессами, кастомными правами и брендингом и добавляют оплату за каждое место. Фреймворки вроде Filament или Nova дают отличную скорость CRUD внутри одного стека, но взамен приходится следовать их соглашениям и циклам обновлений. Своя админка, управляемая конфигурацией, дороже всего на старте, но окупается, когда многим проектам нужны одни и те же паттерны, когда админка должна работать с несколькими бэкендами или когда UX — это часть продукта, например для операторов ресторанов. Для одного проекта я бы выбрал фреймворк, а свою систему — только когда переиспользование между проектами уже доказано.
S2Как спроектировать систему аудита, которая не замедляет запись и не разрастается до гигантских размеров?
Для критичных финансовых действий записывайте аудит в той же транзакции, потому что потерять его недопустимо, но держите записи маленькими: diff изменённых полей, а не строки целиком. Для массовых изменений с низким риском отправляйте события аудита в очередь или используйте change data capture базы, соглашаясь на небольшую задержку. Партиционируйте таблицу аудита по месяцам, чтобы запросы оставались быстрыми, а очистка по сроку хранения сводилась к дешёвому удалению старых партиций, возможно после их архивации в object storage. Индексируйте по объекту и по исполнителю — это покрывает большинство вопросов. Исключайте шумные поля вроде updated_at или счётчиков просмотров. Компромисс здесь — полнота против стоимости, поэтому классифицируйте действия: финансовые изменения и изменения прав всегда логируются синхронно, всё остальное — через best-effort конвейер.
S3Как добавить multi-tenancy в существующую админку?
Сначала выберите модель изоляции. Row-level tenancy — колонка tenant_id в каждой таблице — самая дешёвая и простая в эксплуатации, но один забытый фильтр приводит к утечке данных, поэтому обеспечивайте её централизованно через глобальный query scope или row-level security в PostgreSQL как вторую линию защиты. Схема на тенанта или база на тенанта дают более сильную изоляцию и более простые бэкапы по тенантам, ценой миграций по множеству схем и более сложных отчётов по всем тенантам. В админке тенант берётся из аутентифицированного пользователя, а никогда не из параметра запроса; super-admin переключает тенанта явно, и это переключение попадает в аудит. Медиа, кэши, очереди и поисковые индексы тоже требуют префиксов тенанта. Я добавляю автоматические тесты, которые пытаются прочитать записи другого тенанта через каждый эндпоинт.
Глоссарий
- CRUD
- Create, read, update, delete: четыре базовые операции, которые есть в большинстве экранов админки.
- RBAC
- Role-based access control: права выдаются ролям, а роли назначаются пользователям.
- ABAC
- Attribute-based access control: правила, которые учитывают также атрибуты пользователя и записи, например филиал.
- Policy
- Класс или функция, решающая, может ли пользователь выполнить действие над конкретной записью.
- Audit log
- Журнал только на добавление: кто, что, когда и с какой записью сделал, со значениями до и после.
- Keyset-пагинация
- Постраничная навигация по последнему увиденному ключу вместо offset, чтобы глубокие страницы оставались быстрыми.
- Headless CMS
- Контент-сервис, который хранит контент и отдаёт его через API, без собственного фронтенда.
- Контентный блок
- Типизированный переиспользуемый фрагмент контента страницы с заданной схемой, который рендерится компонентом.
- Stored XSS
- Вредоносный скрипт, сохранённый в контенте, например в rich text, который выполняется в браузерах других пользователей.
Что изучить дальше
Есть идея продукта?Давайте создадим его.
Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.