Розробка CMS-системи для управління контентом сайту
Заказна CMS пишется тоді, коли ні одна з існуючих платформ не вписується в бізнес-логіку — або вписується, але потребує стільки кастомізації, що простіше побудувати своє. Типові випадки: специфічна модель даних, нестандартні рабочі процеси узгодження, інтеграція з внутрішніми корпоративними системами, вимоги до продуктивності на рівні десятків тисяч запитів на хвилину.
З чого складається CMS
Мінімальний набір модулів для функціональної CMS:
- Content Types — визначення структур даних: поля, типи, зв'язки
- Content Editor — інтерфейс створення та редагування записів
- Media Manager — завантаження, зберігання, обробка зображень та файлів
- User & Roles — аутентифікація, авторизація, розмежування прав
- Publishing Workflow — чорновики, узгодження, планувальник публікацій
- API — REST або GraphQL для фронту та мобільних
- Audit Log — хто що змінив та коли
Вибір стеку
Для адміністративної панелі CMS часто використовується React або Vue. Backend — Laravel, Node.js, Go або Django.
Приклад стеку:
Backend API: Laravel 11 + PostgreSQL
Admin SPA: React 18 + TypeScript + TanStack Query
Media CDN: S3-сумісне хранилище + imgproxy
Auth: JWT + refresh tokens
Модель даних: гнучкість vs строгість
Два підходи:
Structured — окрема таблиця на кожен тип контенту:
CREATE TABLE articles (
id BIGSERIAL PRIMARY KEY,
slug VARCHAR(255) UNIQUE,
title JSONB NOT NULL, -- {ru: "...", en: "..."}
body JSONB NOT NULL,
author_id BIGINT REFERENCES users(id),
status VARCHAR(32) DEFAULT 'draft',
published_at TIMESTAMPTZ,
created_at TIMESTAMPTZ
);
Переваги: індекси, типізація, JOINи. Недоліки: зміни схеми потребують міграцій.
EAV/JSONB — поля у JSON:
CREATE TABLE content_items (
id BIGSERIAL PRIMARY KEY,
type VARCHAR(64), -- 'article', 'product'
data JSONB NOT NULL, -- всі поля всередині
status VARCHAR(32),
created_at TIMESTAMPTZ
);
Переваги: нові поля без міграцій. Недоліки: складніше запитувати.
Гібридний підхід — загальна таблиця з ключовими полями (slug, status, author_id) + JSONB — дає найкраще з обох світів.
Content Editor
Вибір редактора впливає на весь UX:
- Lexical (Meta) — гнучкий, розширюваний
- TipTap (на базі ProseMirror) — добра екосистема розширень
- Slate.js — максимальна гнучкість
- TinyMCE / CKEditor — знайомий Word-подібний інтерфейс
Права доступу
RBAC-модель на основі розмежувань:
$permissions = [
'editor' => ['create:article', 'edit:own:article', 'publish:article'],
'moderator' => ['edit:any:article', 'delete:article'],
'admin' => ['*'],
];
Версіонування контенту
CREATE TABLE content_revisions (
id BIGSERIAL PRIMARY KEY,
content_id BIGINT REFERENCES content_items(id) ON DELETE CASCADE,
data JSONB NOT NULL,
author_id BIGINT REFERENCES users(id),
created_at TIMESTAMPTZ
);
Останні N ревізій зберігаються для кожної записи.
Медіа-менеджер
Завантаження через presigned S3 URL:
Client → POST /api/media/presign → presigned URL
Client → PUT presigned_url (S3) → завантаження
Client → POST /api/media/confirm → сповіщення про успіх
Server → imgproxy або CloudFront → ресайз за потребою
Терміни реалізації
Базова CMS: один тип контенту, редактор, медіа, ролі, REST API — 3–4 тижні. Повнофункціональна багатомовна CMS з кількома типами, версіонуванням, workflow узгодження, GraphQL, CDN — 2–3 місяці.







