Тема
Открытые вопросы ТЗ
Статус: 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 нет |
| 11 | RBAC | Filament Shield + spatie/permission |
| 12 | Флит-дашборд | После нескольких клиентов |
Полное обоснование каждого — в Решениях брейншторма.
Кандидаты в каталог модулей (анализ пропусков, 2026-07-14 — ждёт решения)
Ревизия каталога (119 ТЗ) против типовых потребностей корпоративных сайтов и планов roadmap выявила пропуски. Решение «заводить/не заводить» — за владельцем продукта; до решения ТЗ не пишутся:
| Кандидат | Зачем | Обоснование пропуска |
|---|---|---|
cms/ai-content | AI-генерация текстов/мета/alt, AI-переводы для мультиязычности | /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) и движка типов контента выявило точечные ревизии контрактов ядра, зафиксированные здесь до внесения в канонические реестры:
Контракт— ✅ реализовано волной F (15.07.2026):FormRepositoryCms\Contracts\Forms\FormRepository(findBySlug/save/all) +cms_formsядра (schema — декларации движка полей, settings — success_text/антиспам/получатели); блокformстал schema-driven с BC-fallback, сабмит валидируется правилами движка, per-form throttle + шов капчи.- Швы
layout.head/layout.body_end— внести в канонический реестрFilterBus(phase0-three-axes.md), который их пока не перечисляет; нужныcms/head-scripts, а также пикселям иintegration-yandex/integration-google. - Полиморфная связь лида
leadable_type/leadable_idвcms_leads— привязка заявки к произвольной сущности (не только странице), нужнаcms/catalog-showcaseи другим лид-формам поверх нестраничных сущностей. - Шов «аннотации рендера» для режима правки — клик по блоку на публичной странице → deep-link в Filament-редактор; способность ядра, не отдельного модуля.
- Движок типов контента (property-sets + связи + шаблоны + генерик-ресурс) — спека создана (content-types-engine); на нём планируются к переезду
blog/reviews/galleries/faq/bannersкак пресеты (см. карту пресетов) — это ещё не свершившийся факт, ревизия каждого ТЗ предстоит (engine §16);faq— кандидат в пресет (модуль уже реализован в коде). - Отмена контракта
BlockDataSource— предполагался ранее, но не нужен: data-блоки тянут данные сами через свои сервисы/репозитории, отдельный контракт был бы лишним уровнем косвенности. - Уточнение границы SEO: мета/шаблоны (
cms_seo_meta/cms_seo_templates) — в ядре;seo-engine— краулер-аудитор поверх них, не хранилище мета-данных.
Дополнено ревизией документации 15.07.2026 (сверка спеки движка с кодом src/ и реестрами)
Критическая перепроверка выявила ещё пробелы — возможности ядра, которые спека движка типов и новые ТЗ подразумевают готовыми, но которых в коде/канонических реестрах нет (или которые расходятся с уже написанным кодом). До реализации движка их надо специфицировать явно:
Механизм публичной маршрутизации типа без деплоя— ✅ реализовано волной C (15.07.2026): единый резолверRoute::fallback(PublicContentController) — матчится последним конструктивно, приоритет «точный роут → persistent/модульный → тип контента → страница»; коллизии slug ловятся валидацией с обеих сторон; зарезервированные префиксы —config('cms.routing.reserved_prefixes').Механика индексации свойств— ✅ решено и реализовано волной 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 на прочее).Атрибуты свойства и типы— ✅ реализовано волной C:relation/entity-pickerFieldнесётfilterable/sortable/searchable/multiple/in_list/pii/owner_module(legacyindexedнормализуется вfilterable+sortableпри чтении схемы); типrelation(декларация связи в сырой схеме типа: cardinality/target/inverse/on_delete/max, порядок строго relation →cms_content_relations→entity-picker) иentity-picker(MVP-обёртка; модальный пикер с whitelist target — следующий срез) зарегистрированы.searchable-механика (tsvector) — атрибут заведён, реализация — следующий срез.Таблица— ✅ создана волной C (uniquecms_content_relations(from,to,relation_code), обратный индекс(to,relation_code), синк изdatarelation-свойств,on_deleterestrict/cascade/null,cms:content:cleanup-orphans); внесена в свод модели данных ядра.Рантайм-регистрация прав— ✅ реализовано волной C: пара прав создаётся в момент сохранения типа (content.{slug}.view/manageContentType::booted) +cms:rbac:syncзаводит обе; политика записей принимает.viewдля read-only. ОтдельныйPermissionRegistry-контракт не понадобился (spatiefindOrCreate+ сброс кеша).- Команды
cms:content:migrate {type}иcms:content:cleanup-orphans— частично ✅:cleanup-orphansреализована волной C и внесена в канон;cms:content:migrate {type}(батч data-миграции схемы, engine §10) — остаётся к реализации (ломающие миграции схем ещё не поддержаны). Блокcontent-listреализован и внесён в перечень блоков ядра. - Runtime-OpenAPI раздел на каждый динамический тип (§9 спеки) — подтвердить/дозаписать, что генератор рантайм-OpenAPI волны 24 умеет раздел per-type, а не только статический по коду.
— ✅ реализовано волной A (15.07.2026): контракт вPageTemplateRegistry+ полеcms_pages.templatecore-contracts, ядро регистрируетdefault/narrow, колонкаcms_pages.templateв канонической схеме (phase0-content-model), вьюха — каскад темыlayouts/<name>.blade.phpс fallback. NB:SectionPatternRegistry— это точка расширения самого модуляcms/section-patterns, не контракт ядра (мастер-план §10 п.2 ошибочно называет его core — исправлено).- Технический примитив «аннотации рендера» (edit-mode, п.4 выше) — не решено, что это: новый канал
FilterBus, обёртка надblock.render.{type}или отдельный слой рендера. В отличие отlayout.head/layout.body_end(уже решены как имена каналов), для edit-mode формы нет; ни один ТЗ не показывает, как встраиваться. SEO_CONTENT-шов (вставка SEO-блоков по позициям, мастер-план §10 п.5) — отсутствует в каноническом реестреFilterBusphase0-three-axes наравне сlayout.head/layout.body_end; внести туда же.- Реестр атрибутов товара
cms/catalog-showcase— ТЗ ссылается на «движок полей типа товара» для whitelist ключейattributes, но модуль бесспок (не на движке типов); решить: свой лёгкий реестр атрибутов модуля (правки ядра не нужно) либо переиспользование контракта ядра. Сейчас неопределённость. - Рассинхрон
reviews↔moderation:reviewsзаявлен потребителемcms/moderation, но фактически несёт свою статусную машину;moderation.mdэто фиксирует. Централизовать: либо реализоватьsuggests: cms/moderation, либо снять обещание изmoderation.md. Связано с вопросом «reviews— пресет или бесспок» (ниже). - Ревизии записей типа контента (engine §16): страница версионируется целиком (снимок дерева блоков в ревизии) — нужна ли отдельная история версий для записи типа контента (кто и когда поменял
data), или достаточноupdated_at+cms/audit(журнал изменений) без полноценных ревизий. Решение нужно до реализации истории изменений в Filament-форме записи. - Лёгкая фасетная надстройка на самом движке vs жёсткая граница «движок → каталог-модуль» (engine §16, см. также критерий «тип перерос движок», §12): есть ли смысл в ограниченной фасетной фильтрации для типов среднего объёма без выделенного
cms/catalog-showcase, или граница должна быть жёсткой и без полумер — решается на практике первых пилотных типов с реальным трафиком. 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 из инфраструктуры студии.
Порядок закрытия вопросов
Рекомендуемая последовательность в брейншторме:
- Границы виджет/блок и произвольные типы контента (4, 5) — определяют объём ядра.
- Уровень drag&drop-редактора (9) — определяет UX и защиту дизайна.
- Мультиязычность, черновики (6, 7) — в ядро 1.0 или позже.
- Конструктор форм, RBAC (8, 11) — ядро или модуль.
- Маркетплейс, лицензирование (3, 10) — перспектива, но влияет на архитектуру прав.
- Имя, репозиторий, первый заказ (1, 2, 12) — операционные, решаются перед стартом кода.