Skip to content

Открытые вопросы ТЗ

Статус: 12 вопросов брейншторма закрыты; открыт один новый блок — кандидаты в каталог модулей. Решения с мотивировкой — в разделе Решения брейншторма.

✅ Брейншторм завершён

Все архитектурные вопросы для ТЗ решены. Сводка:

#ВопросРешение
1Первый потребительПилот-копия universal (ревизия 14.07.2026)
2Имя/репозиторийСвоя инфра (Gitea/GitLab) + Satis
3МаркетплейсЗакрыт сейчас, архитектура под открытие
4Виджет vs блокВиджет — отдельная сущность
5Произвольные типы контентаДа, в ядре (через JSONB+GIN, не EAV)
6МультиязычностьЗаготовка в ядре, модуль позже
7Черновики/версииВ ядре 1.0
8Конструктор формВ ядре 1.0
9Уровень drag&dropСредняя свобода (без стилей на уровне блока)
10Лицензия клиентуSkeleton да, Satis нет
11RBACFilament Shield + spatie/permission
12Флит-дашбордПосле нескольких клиентов

Полное обоснование каждого — в Решениях брейншторма.

Кандидаты в каталог модулей (анализ пропусков, 2026-07-14 — ждёт решения)

Ревизия каталога (119 ТЗ) против типовых потребностей корпоративных сайтов и планов roadmap выявила пропуски. Решение «заводить/не заводить» — за владельцем продукта; до решения ТЗ не пишутся:

КандидатЗачемОбоснование пропуска
cms/ai-contentAI-генерация текстов/мета/alt, AI-переводы для мультиязычностиУпомянут в roadmap фазы 3 («AI-контент»), но модуля в каталоге нет — прямой пропуск Закрыто 15.07.2026: ТЗ создано (/cms-v2/modules/ai-content), модуль зарегистрирован в каталоге/реестре — приоритет P2, реализация отложена (проектируется, внедрение позже)
cms/eventsМероприятия/афиша: анонсы, архив, регистрация участников, iCalКорпоративный сайт; сейчас закрывается только типом контента без регистрации
cms/locationsФилиалы/офисы/точки на карте: часы работы, Schema.org LocalBusiness, блок «карта»Типовая потребность корпсайта; multicity — про домены/гео, не про сущность «филиал»
cms/bookingЛёгкая запись/бронирование слотов без полного commerce-слояСейчас слоты живут только в cms/commerce-services (тянет корзину/заказы) — для «записаться на консультацию» это перебор
cms/documentsЦентр документов: категории, версии файлов, права доступа, страница «Документы»Корпсайт/B2B; медиатека ядра не даёт версий и прав на скачивание
cms/autopostingАвтопостинг блога в Telegram-канал/VK + RSS-фидыМаркетинг; сейчас cms/telegram — только канал уведомлений
cms/migrate-cmsИмпортёры с чужих CMS (WordPress, Bitrix) поверх cms/importСтратегично для перевода клиентов на свою CMS; generic-import маппинг с чужих схем не покрывает
Скан загрузок → модуль-реализация upload-scannerАнтивирус-проверка загружаемых файлов (ClamAV) для UGC и медиатекиКонтракт upload-scanner и карантин в медиатеке введены в ядро ревизией №2; открытым остаётся только модуль-реализация (ClamAV/VirusTotal)
cms/ticketsОбращения/тикеты в кабинете (поддержка B2B)Опционально; частично закрывается chat + notifications
cms/geoipРеализация geo-provider: IP→город (MaxMind/dadata/ipinfo) для multicity, session, cookie-consentФантом графа (санитария 14.07.2026): 4 ТЗ ссылаются на него как на реализацию контракта, но модуля в каталоге нет — у geo-provider 0 реализаций; для продакшена мультигорода обязателен

Выносить из ядра ничего не предлагается: состав раздела A (страницы/блоки, формы/лиды, медиа, SEO-база, меню/виджеты) подтверждён как якорный минимум; базовый поиск ядра (tsvector) корректно замещается модулем cms/search через provides-контракт.

Дополнения по итогам углубления ТЗ (14.07.2026, волна 3):

  • кандидат cms/booking подтверждён со стороны коммерции: ТЗ commerce-services ожидает «держателя TTL-резерва слота», а cms/calendars отвечает только за CalDAV-синхронизацию — владельца резервирования в каталоге модулей нет;
  • cms/commerce-payments требует ревизии объёма: vault сохранённых способов оплаты (commerce_payment_methods, chargeSavedMethod(), срок действия карты) — без него commerce-subscriptions вынужден хранить платёжные токены у себя (нарушение границ);
  • cms/commerce-b2b: несколько плательщиков/грузополучателей одной компании (commerce_b2b_company_locations) — зафиксировано в ТЗ как будущее расширение, в объём 1.0 не входит.

Фаза 0 (спеки контрактов) — написана (см. дорожную карту). Следующий шаг — фаза 1 (реализация ядра-минимума), стартует с появлением первого клиентского заказа (Q1).

Ревизии ядра под корп-MVP (15.07.2026)

Проектирование новых модулей корп-MVP (cms/catalog-showcase, cms/section-patterns, cms/form-builder, cms/ai-content, cms/head-scripts) и движка типов контента выявило точечные ревизии контрактов ядра, зафиксированные здесь до внесения в канонические реестры:

  1. Контракт FormRepository — ✅ реализовано волной F (15.07.2026): Cms\Contracts\Forms\FormRepository (findBySlug/save/all) + cms_forms ядра (schema — декларации движка полей, settings — success_text/антиспам/получатели); блок form стал schema-driven с BC-fallback, сабмит валидируется правилами движка, per-form throttle + шов капчи.
  2. Швы layout.head/layout.body_end — внести в канонический реестр FilterBus (phase0-three-axes.md), который их пока не перечисляет; нужны cms/head-scripts, а также пикселям и integration-yandex/integration-google.
  3. Полиморфная связь лида leadable_type/leadable_id в cms_leads — привязка заявки к произвольной сущности (не только странице), нужна cms/catalog-showcase и другим лид-формам поверх нестраничных сущностей.
  4. Шов «аннотации рендера» для режима правки — клик по блоку на публичной странице → deep-link в Filament-редактор; способность ядра, не отдельного модуля.
  5. Движок типов контента (property-sets + связи + шаблоны + генерик-ресурс) — спека создана (content-types-engine); на нём планируются к переезду blog/reviews/galleries/faq/banners как пресеты (см. карту пресетов) — это ещё не свершившийся факт, ревизия каждого ТЗ предстоит (engine §16); faq — кандидат в пресет (модуль уже реализован в коде).
  6. Отмена контракта BlockDataSource — предполагался ранее, но не нужен: data-блоки тянут данные сами через свои сервисы/репозитории, отдельный контракт был бы лишним уровнем косвенности.
  7. Уточнение границы SEO: мета/шаблоны (cms_seo_meta/cms_seo_templates) — в ядре; seo-engine — краулер-аудитор поверх них, не хранилище мета-данных.

Дополнено ревизией документации 15.07.2026 (сверка спеки движка с кодом src/ и реестрами)

Критическая перепроверка выявила ещё пробелы — возможности ядра, которые спека движка типов и новые ТЗ подразумевают готовыми, но которых в коде/канонических реестрах нет (или которые расходятся с уже написанным кодом). До реализации движка их надо специфицировать явно:

  1. Механизм публичной маршрутизации типа без деплоя — ✅ реализовано волной C (15.07.2026): единый резолвер Route::fallback (PublicContentController) — матчится последним конструктивно, приоритет «точный роут → persistent/модульный → тип контента → страница»; коллизии slug ловятся валидацией с обеих сторон; зарезервированные префиксы — config('cms.routing.reserved_prefixes').
  2. Механика индексации свойств — ✅ решено и реализовано волной C (15.07.2026): functional partial-индексы с кастом по типу данных (::numeric, ::boolean; date/datetime — как text: ISO-8601 сортируется лексикографически, а text→timestamptz не IMMUTABLE и в выражении индекса запрещён), имена cms_ce_{type_key}_{code}_idx; sort= публичного API реализован тем же выражением (whitelist sortable, 422 на прочее).
  3. Атрибуты свойства и типы relation/entity-picker — ✅ реализовано волной C: Field несёт filterable/sortable/searchable/multiple/in_list/pii/owner_module (legacy indexed нормализуется в filterable+sortable при чтении схемы); тип relation (декларация связи в сырой схеме типа: cardinality/target/inverse/on_delete/max, порядок строго relation → cms_content_relationsentity-picker) и entity-picker (MVP-обёртка; модальный пикер с whitelist target — следующий срез) зарегистрированы. searchable-механика (tsvector) — атрибут заведён, реализация — следующий срез.
  4. Таблица cms_content_relations — ✅ создана волной C (unique (from,to,relation_code), обратный индекс (to,relation_code), синк из data relation-свойств, on_delete restrict/cascade/null, cms:content:cleanup-orphans); внесена в свод модели данных ядра.
  5. Рантайм-регистрация прав content.{slug}.view/manage — ✅ реализовано волной C: пара прав создаётся в момент сохранения типа (ContentType::booted) + cms:rbac:sync заводит обе; политика записей принимает .view для read-only. Отдельный PermissionRegistry-контракт не понадобился (spatie findOrCreate + сброс кеша).
  6. Команды cms:content:migrate {type} и cms:content:cleanup-orphans — частично ✅: cleanup-orphans реализована волной C и внесена в канон; cms:content:migrate {type} (батч data-миграции схемы, engine §10) — остаётся к реализации (ломающие миграции схем ещё не поддержаны). Блок content-list реализован и внесён в перечень блоков ядра.
  7. Runtime-OpenAPI раздел на каждый динамический тип (§9 спеки) — подтвердить/дозаписать, что генератор рантайм-OpenAPI волны 24 умеет раздел per-type, а не только статический по коду.
  8. PageTemplateRegistry + поле cms_pages.template — ✅ реализовано волной A (15.07.2026): контракт в core-contracts, ядро регистрирует default/narrow, колонка cms_pages.template в канонической схеме (phase0-content-model), вьюха — каскад темы layouts/<name>.blade.php с fallback. NB: SectionPatternRegistry — это точка расширения самого модуля cms/section-patterns, не контракт ядра (мастер-план §10 п.2 ошибочно называет его core — исправлено).
  9. Технический примитив «аннотации рендера» (edit-mode, п.4 выше) — не решено, что это: новый канал FilterBus, обёртка над block.render.{type} или отдельный слой рендера. В отличие от layout.head/layout.body_end (уже решены как имена каналов), для edit-mode формы нет; ни один ТЗ не показывает, как встраиваться.
  10. SEO_CONTENT-шов (вставка SEO-блоков по позициям, мастер-план §10 п.5) — отсутствует в каноническом реестре FilterBus phase0-three-axes наравне с layout.head/layout.body_end; внести туда же.
  11. Реестр атрибутов товара cms/catalog-showcase — ТЗ ссылается на «движок полей типа товара» для whitelist ключей attributes, но модуль бесспок (не на движке типов); решить: свой лёгкий реестр атрибутов модуля (правки ядра не нужно) либо переиспользование контракта ядра. Сейчас неопределённость.
  12. Рассинхрон reviewsmoderation: reviews заявлен потребителем cms/moderation, но фактически несёт свою статусную машину; moderation.md это фиксирует. Централизовать: либо реализовать suggests: cms/moderation, либо снять обещание из moderation.md. Связано с вопросом «reviews — пресет или бесспок» (ниже).
  13. Ревизии записей типа контента (engine §16): страница версионируется целиком (снимок дерева блоков в ревизии) — нужна ли отдельная история версий для записи типа контента (кто и когда поменял data), или достаточно updated_at + cms/audit (журнал изменений) без полноценных ревизий. Решение нужно до реализации истории изменений в Filament-форме записи.
  14. Лёгкая фасетная надстройка на самом движке vs жёсткая граница «движок → каталог-модуль» (engine §16, см. также критерий «тип перерос движок», §12): есть ли смысл в ограниченной фасетной фильтрации для типов среднего объёма без выделенного cms/catalog-showcase, или граница должна быть жёсткой и без полумер — решается на практике первых пилотных типов с реальным трафиком.
  15. related-content × cms_content_relations: тип контента с relation-свойством (§5.2 движка) и модуль cms/related-content решают смежные, но разные задачи. Нужно ли позволить related-content использовать типизированные cms_content_relations как дополнительный источник кандидатов рекомендаций (не только пересечение таксономий) — вопрос к ревизии related-content, не к спеке движка (engine §16).

Незакрытые вопросы самой спеки движка (content-types-engine §16) — пункты 20–22 выше плюс ревизия пресетов blog/faq/galleries/reviews/banners (п.5 выше); применимость lock_version ко всем типам решена (включён всегда, см. движок §16) и здесь не дублируется как открытая.

Вопросы заказчику (требуют продуктового/архитектурного решения, вынесены интерактивно 15.07.2026): механика индексации (generated-колонка vs текущий функциональный partial-индекс, п.9); судьба тел ТЗ-пресетов blog/faq/galleries/reviews/banners (переписать под движок сейчас vs пометить «до ревизии» и переписать в Волне G); reviews — пресет движка vs бесспок-таблица (полиморфный subject + агрегаты + модерация тяжелее движка).

Предлагаемый порядок ревизий ядра по волнам: до Волны A — внести layout.head/layout.body_end/SEO_CONTENT в FilterBus, добавить типы полей FieldEngine (entity-picker/media-gallery/icon/key-value/relation), вычистить противоречия baseline (BlockDataSource из мастер-плана §10/графа, развести SectionPatternRegistry/PageTemplateRegistry), поле cms_pages.template. Перед реализацией движка — RouteRegistry/динамический резолвер (п.8), рантайм-права Shield (п.12), cms_content_relations и команды в свод ядра (п.11,13), решение по индексации (п.9). Параллельно — полиморфный лид (нужен catalog-showcase, Волна E) и SEO_CONTENT (Волна C). После движка, перед Волной G — переписать тела пресетов под движок.


Исходный контекст (зафиксировано до брейншторма)

  • Аудитория: студия + клиенты ведут контент.
  • Публичный фронт: Blade + токены + острова. Админка: Filament. Кабинеты: Inertia SSR рядом.
  • SEO критичен → React-темы на публичной части отклонены.
  • Дистрибуция: приватные composer-пакеты + Satis. Обновления через composer, не свой транспорт.
  • Расширяемость: открытый BlockRegistry + события + фильтры + аналог /local.
  • drag&drop блоков — нужен (со строгими схемами). Маркетплейс — перспектива.

Открытые вопросы

1. Триггер старта — первый потребитель ядра

Какой реальный клиентский заказ станет первым потребителем ядра? Ядро без живого потребителя — долгострой; ядро на новом заказе строится в нужном объёме (YAGNI работает сам) и обкатывается под дедлайном. До появления заказа допустима только фаза 0 (контракты на бумаге).

2. Имя и репозиторий

Рабочее имя v1 — «Rosveb CMS». Нужно ли новое имя для v2-концепции? Монорепо на своей инфре или GitHub private? Структура: packages/core, packages/testing, skeleton/, базовая тема.

3. Глубина маркетплейса

Маркетплейс отмечен как перспектива. Вопросы:

  • С первого дня закрытый (только модули студии) или сразу для сторонних?
  • Если сторонние — нужна модель ревью безопасности плагинов (урок WordPress: 91% CVE в плагинах). Кто отвечает за качество чужого кода?
  • Лицензирование сторонних модулей: единый license key на сайт (Statamic-модель) или per-модуль?

4. Границы виджета и блока

Виджет — отдельная сущность или частный случай блока в области layout? От этого зависит объём ядра (см. глоссарий).

5. Произвольные типы контента (аналог инфоблоков)

Контент строго через типизированные блоки, или нужен механизм пользовательских типов контента с произвольными полями (как инфоблоки Битрикс / ACF WordPress)? Это большое архитектурное решение: EAV/custom fields добавляют гибкость, но усложняют и бьют по производительности. Для контент-менеджера клиента, возможно, избыточно.

6. Мультиязычность контента

Заготовка в ядре с 1.0 (дешевле сразу) или отдельный модуль позже? Два подхода из проектов: city-based (мультигород как у universal/gulaev-dev) vs полноценный spatie/laravel-translatable (как referendum). Выбрать модель.

7. Черновики и версии страниц

В ядро 1.0 или 1.x? Контент-менеджер клиента, вероятно, захочет предпросмотр и откат изменений страницы. Twill-подход (revisions) как референс.

8. Конструктор форм

Модуль или часть ядра? Склонение: ядро даёт заявки/нотификации, визуальный конструктор форм (клиент собирает форму сам) — отдельный модуль.

9. Уровень drag&drop-редактора

Насколько свободен редактор? Спектр:

  • только переупорядочивание блоков (безопасно, дизайн защищён);
    • вложенные блоки (колонки, секции);
    • настройка отступов/цветов на уровне блока (ближе к Tilda, риск разрушения дизайна). Где граница между «клиент собирает сам» и «защита дизайна»?

10. Лицензирование скелета клиенту

Что юридически передаётся клиенту при расторжении подписки? (Код skeleton — да, доступ к Satis — нет; проговорить в договоре.)

11. Модель RBAC

Filament Shield достаточно, или нужна своя ролевая модель (уровни как в Twill: Role/RoleGroup/RoleGroupItem) для парка сайтов с несколькими ролями контент-менеджеров?

12. Флит-дашборд — когда

Отдельное приложение телеметрии парка. Строить с первым клиентом (обкатывать безопасно, пока один) или после нескольких? Развитие паттерна панели лендингов и proxy dns watch из инфраструктуры студии.

Порядок закрытия вопросов

Рекомендуемая последовательность в брейншторме:

  1. Границы виджет/блок и произвольные типы контента (4, 5) — определяют объём ядра.
  2. Уровень drag&drop-редактора (9) — определяет UX и защиту дизайна.
  3. Мультиязычность, черновики (6, 7) — в ядро 1.0 или позже.
  4. Конструктор форм, RBAC (8, 11) — ядро или модуль.
  5. Маркетплейс, лицензирование (3, 10) — перспектива, но влияет на архитектуру прав.
  6. Имя, репозиторий, первый заказ (1, 2, 12) — операционные, решаются перед стартом кода.

Внутренняя база знаний студии