Appearance
HUB Templates Workbench System V1
Обновлено: 2026-03-04
Назначение
Это каноничный документ (single source of truth) по логике конструктора шаблонов HUB:
registry -> build -> autosave -> publish -> runtime- Единые data contracts:
manifest,instance,i18n,responsive - QA gate и критерии готовности для новых секций
Документ синхронизирован с текущим кодом в репозитории hub.
Границы и маршруты
- Админка конструктора:
/{locale}/admin/templates - Вьюхи админки:
/{locale}/admin/templates(build)/{locale}/admin/templates/theme/{locale}/admin/templates/release/{locale}/admin/templates/registry
- Runtime шаблонов:
- static:
/{locale}/offers/templates/beauty-courses,beauty-salon - registry:
/{locale}/offers/templates/{templateSlug}
- static:
End-to-End Flow
1) Registry
Источник: src/app/[locale]/admin/templates/page.tsx
- Каталог шаблонов собирается через
listTemplateCatalog({ includeArchived: true }). - Поддерживаются
staticиregistryшаблоны в одном selector. - CRUD registry выполняется server actions из
admin/leads/actions. - Базовый storage-key реестра:
hub.templates.registry.v1(см. smoke script).
2) Build (Library -> Canvas -> Inspector)
Источники:
src/components/admin/TemplateSectionsEditor.tsxsrc/components/admin/templates-workbench/TemplateLibraryPanel.tsxsrc/components/admin/templates-workbench/TemplateCanvasPanel.tsxsrc/components/admin/templates-workbench/TemplateInspectorPanel.tsx
Фактическая модель:
items: состояние секций (TemplateSectionConfig[]).instanceItems: состояние unified block instances (UnifiedBlockInstance[]).- Inspector рендерится schema-driven по
BlockManifest, без ветвления по конкретным section-id. - Canvas поддерживает viewport scopes:
desktop | tablet | mobile.
3) Autosave (единый draft write-path)
Источники:
src/components/admin/templates-workbench/useTemplateSectionsAutosave.tssrc/app/api/admin/templates/sections-autosave/route.tssrc/lib/offers/template-instance-provisioning.ts
Фактический pipeline:
- Клиент отправляет
sections + blockInstances + baseRevision. - API проверяет owner session и revision guard.
- Секции пишутся в
hub.templates.<template>.sections. - Затем вызывается
ensureTemplateSectionProvisioning(...):- миграция legacy-моделей в unified instances
- merge responsive overrides из payload/хранилища
- запись в
hub.templates.<template>.instances
Важно: это единый write-path для изменений секций в Build.
4) Publish (Draft -> Immutable Snapshot)
Источники:
src/app/api/admin/templates/publish/route.tssrc/lib/offers/template-published-snapshots.ts
Фактический pipeline:
POST /api/admin/templates/publishвызываетpublishTemplateSnapshot(templateKey).- Формируется immutable snapshot payload:
themesectionsenrollmentBlockSettingsprogramBlockSettingsextraSectionContentByLocale (ru/en/pl/ua)
- Записываются:
- snapshot record
- current pointer
- history item (
publish)
5) Runtime
Источники:
src/app/[locale]/offers/templates/beauty-courses/page.tsxsrc/app/[locale]/offers/templates/beauty-salon/page.tsxsrc/app/[locale]/offers/templates/[templateSlug]/page.tsxsrc/components/templates/premium/PremiumTemplatePage.tsxsrc/lib/offers/template-block-instance-runtime.ts
Фактический pipeline:
- Runtime получает published payload.
- Legacy payload нормализуется в
blockInstancesчерезresolveTemplateInstances(...). PremiumTemplatePageрезолвит контент из instances с учетом:- locale chain
- responsive scope chain
- Fallback rules:
- responsive:
mobile -> tablet -> desktop,tablet -> desktop,desktop - locale:
current -> configured fallback -> en -> known locales
- responsive:
Data Contracts
BlockManifest
Источник: src/lib/offers/block-manifest.ts
Минимальный контракт:
blockId,version,categoryinspectorTabsfields[]:key,type,tab,default- optional:
validators,i18n,responsive,scope
previewmetadata
UnifiedBlockInstance
Источник: src/lib/offers/template-block-manifest.ts
Минимальный контракт:
instanceId,sectionId,blockId,manifestVersionenabled,removed,order,syncMode,syncStatedata: BlockInstanceData
Field Value Container
Источник: src/lib/offers/block-manifest.ts
BlockInstanceFieldValue поддерживает:
valuei18n[locale]responsive[scope]responsiveI18n[scope][locale]
Это единая модель для Inspector/Canvas/Runtime резолва.
Текущее ограничение (важно)
Состояние на 2026-03-04:
- Draft autosave уже сохраняет
blockInstancesи responsive overrides. - Publish snapshot сейчас сериализует legacy payload (
theme/sections/enrollment/program/extra), без отдельного rawblockInstancesв snapshot схеме. - Runtime для published шаблонов реконструирует instances из snapshot payload.
Следствие: responsive/tablet/mobile overrides, сохраненные только в draft instances, должны быть отдельно учтены в следующем шаге эволюции snapshot schema.
QA Gate (обязательно перед закрытием задач V2)
A. Автоматические проверки (hub repo)
pnpm lintpnpm buildpnpm test:smoke:new-template
B. Manual smoke (Build -> Publish -> Runtime)
- Создать registry-шаблон.
- Добавить секцию из Library.
- Проверить, что поля появились в Inspector без ручного кода.
- Изменить:
- style (включая color + HEX input)
- content для
ru/en/pl/ua - responsive scope для
desktop/tablet/mobile
- Проверить
reorder,enable/disable,remove/re-add. - Publish и открыть runtime URL.
- Проверить, что published страница рендерится без fallback "no snapshot".
C. Docs gate (docs-designcorp repo)
pnpm docs:build- Проверить, что ссылки из этого документа открываются и якоря корректны.
Definition of Done для новой секции
Новая секция считается внедренной, если выполнены все пункты:
- Есть block entry в registry/section mapping.
- Есть manifest fields с default/validators/tab/scope.
- Секция появляется в Library и добавляется в Canvas.
- Поля секции автоматически рендерятся в Inspector (без hardcoded веток).
- Значения секции сохраняются через autosave write-path.
- Рендер секции работает в Canvas preview.
- Publish не ломается, snapshot создается.
- Runtime рендерит секцию из published данных.
- Для текстов поддержаны локали
ru/en/pl/ua. - Для style/layout полей проверены responsive scopes.
- Пройдены QA Gate A/B/C.
Anti-Regression Checklist
Перед merge/push проверять:
- Нет второго параллельного write-path для тех же данных.
- Нет section-specific ветвлений в Inspector для стандартных типов полей.
- Нет пустых/null состояний из-за неинициализированных instance fields.
- Draft статус (
clean/dirty/saving/conflict/error) корректно обновляется. - Publish не меняет live без создания snapshot.
- Runtime одинаково работает для static и registry шаблонов.
Связанные задачи
Исходники
src/app/[locale]/admin/templates/page.tsxsrc/components/admin/TemplateSectionsEditor.tsxsrc/app/api/admin/templates/sections-autosave/route.tssrc/app/api/admin/templates/publish/route.tssrc/lib/offers/block-manifest.tssrc/lib/offers/template-block-manifest.tssrc/lib/offers/template-block-instance-runtime.tssrc/lib/offers/template-instance-provisioning.tssrc/lib/offers/template-published-snapshots.tsscripts/smoke-new-template.mjs