docs
Some checks failed
Architecture Governance / architecture (push) Has been cancelled

This commit is contained in:
sdarbinyan
2026-07-05 04:23:47 +04:00
parent c901ec1e49
commit 10251f2fc6
24 changed files with 2424 additions and 0 deletions

View File

@@ -0,0 +1,714 @@
# 1. SYSTEM OVERVIEW
Платформа является полностью configuration-driven SaaS-решением для запуска и масштабирования multi-tenant маркетплейсов.
Ключевые принципы:
- Поведение витрины определяется конфигурацией, а не кастомным кодом под каждого клиента.
- Каждый домен однозначно резолвится в конкретный tenant.
- UI формируется только на основе bootstrap JSON.
- Во frontend отсутствуют hardcoded правила по layout, страницам и tenant-ветвлению.
Это позволяет запускать новые магазины без форка frontend-приложения: меняется конфигурация и данные, а не архитектура продукта.
# 2. BOOTSTRAP FLOW
Стандартный поток инициализации:
1. Пользователь открывает домен магазина.
2. Backend определяет tenant по домену.
3. Backend возвращает tenant-specific bootstrap JSON.
4. Frontend валидирует конфигурацию.
5. Frontend динамически строит:
- тему,
- навигацию,
- страницы,
- секции,
- виджеты,
- статические страницы.
6. Данные каталога и товаров подгружаются через API-контракты, указанные в bootstrap.
Итог: один frontend runtime обслуживает множество магазинов, различающихся конфигурацией.
# 3. FULL BOOTSTRAP JSON EXAMPLE
Ниже приведен полный production-grade пример bootstrap JSON с явно именованными сущностями.
```json
{
"schemaVersion": "1.0.0",
"generatedAt": "2026-07-05T10:00:00Z",
"tenant": {
"id": "tenant-dexar-ru",
"name": "Dexar Market RU",
"domain": "dexarmarket.ru",
"slug": "dexar-ru",
"defaultLocale": "ru",
"supportedLocales": ["ru", "en", "hy"],
"defaultCurrency": "RUB",
"supportedCurrencies": ["RUB", "USD", "EUR", "AMD"],
"timezone": "Europe/Moscow"
},
"api": {
"baseUrl": "https://api.dexarmarket.ru",
"endpoints": {
"bootstrap": "/bootstrap",
"categories": "/categories",
"products": "/products",
"productDetails": "/products/{id}",
"search": "/search",
"cart": "/cart"
},
"timeouts": {
"defaultMs": 10000,
"catalogMs": 12000,
"productMs": 12000
}
},
"theme": {
"themeId": "dexar-light",
"colors": {
"primary": "#2F6E5D",
"secondary": "#8FA9A2",
"accent": "#CBE4DA",
"textPrimary": "#1F322D",
"textSecondary": "#5F6E6A",
"backgroundPrimary": "#FFFFFF",
"backgroundSecondary": "#F6F8F7",
"border": "#D5DDDB",
"success": "#1FA97A",
"warning": "#D9941A",
"danger": "#D64545"
},
"typography": {
"fontFamily": "DM Sans, sans-serif",
"headingFontFamily": "DM Sans, sans-serif",
"baseFontSize": 16,
"scale": {
"h1": 40,
"h2": 32,
"h3": 24,
"body": 16,
"caption": 14
}
},
"radius": {
"sm": "8px",
"md": "12px",
"lg": "16px"
},
"shadows": {
"sm": "0 2px 8px rgba(0,0,0,0.08)",
"md": "0 6px 18px rgba(0,0,0,0.12)",
"lg": "0 14px 36px rgba(0,0,0,0.16)"
}
},
"layoutProfile": "default",
"layoutProfiles": {
"default": {
"description": "Стандартный storefront layout с верхней навигацией",
"pageContainer": {
"maxWidth": 1280,
"paddingX": 16,
"paddingY": 24
},
"sectionSpacing": 24,
"grid": {
"gap": 16,
"columnsDesktop": 4,
"columnsTablet": 2,
"columnsMobile": 1
},
"regions": ["header", "content", "footer"]
},
"side-menu-layout": {
"description": "Layout с левой боковой навигацией",
"pageContainer": {
"maxWidth": 1360,
"paddingX": 16,
"paddingY": 24
},
"sectionSpacing": 24,
"grid": {
"gap": 16,
"columnsDesktop": 3,
"columnsTablet": 2,
"columnsMobile": 1
},
"regions": ["header", "side", "content", "footer"]
},
"grid-layout": {
"description": "Плиточная витрина с усиленным grid-представлением",
"pageContainer": {
"maxWidth": 1440,
"paddingX": 20,
"paddingY": 24
},
"sectionSpacing": 20,
"grid": {
"gap": 20,
"columnsDesktop": 5,
"columnsTablet": 3,
"columnsMobile": 2
},
"regions": ["header", "content", "footer"]
},
"landing-page-layout": {
"description": "Промо-лендинг с акцентом на hero и banner секции",
"pageContainer": {
"maxWidth": 1200,
"paddingX": 16,
"paddingY": 32
},
"sectionSpacing": 32,
"grid": {
"gap": 24,
"columnsDesktop": 2,
"columnsTablet": 1,
"columnsMobile": 1
},
"regions": ["header", "content", "footer"]
}
},
"navigation": {
"header": [
{
"id": "nav-logo",
"type": "logo",
"label": "Dexar",
"route": "/",
"order": 1,
"visible": true
},
{
"id": "nav-side-menu",
"type": "side-menu",
"label": "Меню",
"route": "/catalog",
"order": 2,
"visible": true
},
{
"id": "nav-category-menu",
"type": "category-menu",
"label": "Категории",
"route": "/catalog",
"order": 3,
"visible": true
},
{
"id": "nav-search",
"type": "search",
"label": "Поиск",
"route": "/search",
"order": 4,
"visible": true
},
{
"id": "nav-language",
"type": "language-switcher",
"label": "Язык",
"order": 5,
"visible": true
},
{
"id": "nav-currency",
"type": "currency-switcher",
"label": "Валюта",
"order": 6,
"visible": true
},
{
"id": "nav-cart",
"type": "cart",
"label": "Корзина",
"route": "/cart",
"order": 7,
"visible": true
}
],
"footer": [
{
"id": "footer-about",
"type": "footer-links",
"label": "О компании",
"route": "/about",
"order": 1,
"visible": true
},
{
"id": "footer-terms",
"type": "footer-links",
"label": "Условия",
"route": "/terms",
"order": 2,
"visible": true
},
{
"id": "footer-privacy",
"type": "footer-links",
"label": "Конфиденциальность",
"route": "/privacy",
"order": 3,
"visible": true
}
]
},
"widgetManifest": [
{
"type": "hero-widget",
"version": "1.0.0",
"component": "HeroWidgetComponent",
"dataSource": "static",
"enabled": true
},
{
"type": "category-widget",
"version": "1.0.0",
"component": "CategoryWidgetComponent",
"dataSource": "categories",
"enabled": true
},
{
"type": "product-grid-widget",
"version": "1.0.0",
"component": "ProductGridWidgetComponent",
"dataSource": "products",
"enabled": true
},
{
"type": "product-carousel-widget",
"version": "1.0.0",
"component": "ProductCarouselWidgetComponent",
"dataSource": "products",
"enabled": true
},
{
"type": "cart-widget",
"version": "1.0.0",
"component": "CartWidgetComponent",
"dataSource": "cart",
"enabled": true
},
{
"type": "side-menu-widget",
"version": "1.0.0",
"component": "SideMenuWidgetComponent",
"dataSource": "navigation",
"enabled": true
}
],
"pages": [
{
"id": "page-home",
"key": "home",
"title": "Главная",
"route": { "path": "/", "exact": true },
"layoutProfile": "default",
"sections": [
{
"id": "home-hero",
"type": "hero",
"order": 1,
"widgets": [
{
"id": "widget-home-hero",
"type": "hero-widget",
"version": "1.0.0",
"props": {
"title": "Маркетплейс нового поколения",
"subtitle": "Запущен на configuration-driven SaaS платформе",
"ctaText": "Перейти в каталог"
}
}
]
},
{
"id": "home-categories",
"type": "categories",
"order": 2,
"widgets": [
{
"id": "widget-home-categories",
"type": "category-widget",
"version": "1.0.0",
"dataSource": {
"name": "categories",
"params": { "rootOnly": true, "limit": 12 }
}
}
]
},
{
"id": "home-featured",
"type": "featured-products",
"order": 3,
"widgets": [
{
"id": "widget-home-featured-carousel",
"type": "product-carousel-widget",
"version": "1.0.0",
"dataSource": {
"name": "products",
"params": { "preset": "featured", "limit": 10 }
}
}
]
},
{
"id": "home-banner",
"type": "banner",
"order": 4,
"widgets": [
{
"id": "widget-home-banner",
"type": "hero-widget",
"version": "1.0.0",
"props": {
"title": "Летняя распродажа",
"subtitle": "Скидки до 30%",
"ctaText": "Смотреть предложения"
}
}
]
},
{
"id": "home-footer-links",
"type": "footer-links",
"order": 5,
"widgets": [
{
"id": "widget-home-footer-links",
"type": "side-menu-widget",
"version": "1.0.0",
"dataSource": { "name": "navigation", "params": { "zone": "footer" } }
}
]
}
]
},
{
"id": "page-catalog",
"key": "catalog",
"title": "Каталог",
"route": { "path": "/catalog", "exact": true },
"layoutProfile": "side-menu-layout",
"sections": [
{
"id": "catalog-sidebar",
"type": "sidebar-categories",
"order": 1,
"widgets": [
{
"id": "widget-catalog-side-menu",
"type": "side-menu-widget",
"version": "1.0.0",
"dataSource": { "name": "categories", "params": { "tree": true } }
}
]
},
{
"id": "catalog-grid",
"type": "product-grid",
"order": 2,
"widgets": [
{
"id": "widget-catalog-product-grid",
"type": "product-grid-widget",
"version": "1.0.0",
"dataSource": {
"name": "products",
"params": { "sort": "priority_desc", "pageSize": 20 }
}
}
]
}
]
},
{
"id": "page-product",
"key": "product",
"title": "Карточка товара",
"route": { "path": "/product/:id", "exact": true },
"layoutProfile": "default",
"sections": [
{
"id": "product-main-grid",
"type": "product-grid",
"order": 1,
"widgets": [
{
"id": "widget-product-main",
"type": "product-grid-widget",
"version": "1.0.0",
"dataSource": {
"name": "productDetails",
"params": { "fromRoute": "id" }
}
}
]
},
{
"id": "product-recommendations",
"type": "product-carousel",
"order": 2,
"widgets": [
{
"id": "widget-product-recommendations",
"type": "product-carousel-widget",
"version": "1.0.0",
"dataSource": {
"name": "products",
"params": { "preset": "related", "limit": 12 }
}
}
]
},
{
"id": "product-cart",
"type": "featured-products",
"order": 3,
"widgets": [
{
"id": "widget-product-cart",
"type": "cart-widget",
"version": "1.0.0",
"dataSource": { "name": "cart", "params": {} }
}
]
}
]
}
],
"staticPages": [
{
"id": "static-about",
"key": "about",
"title": "О компании",
"route": { "path": "/about", "exact": true },
"content": {
"source": "cms",
"contentType": "html",
"value": "<h1>О компании</h1><p>Dexar Market - платформа маркетплейса для B2B/B2C продаж.</p>"
},
"visible": true
},
{
"id": "static-terms",
"key": "terms",
"title": "Условия использования",
"route": { "path": "/terms", "exact": true },
"content": {
"source": "cms",
"contentType": "html",
"value": "<h1>Условия использования</h1><p>Правила работы сервиса и обязательства сторон.</p>"
},
"visible": true
},
{
"id": "static-privacy",
"key": "privacy",
"title": "Политика конфиденциальности",
"route": { "path": "/privacy", "exact": true },
"content": {
"source": "cms",
"contentType": "html",
"value": "<h1>Политика конфиденциальности</h1><p>Порядок обработки персональных данных.</p>"
},
"visible": true
}
],
"features": {
"multiLanguage": true,
"multiCurrency": true,
"regionSelector": true,
"guestCheckout": true,
"searchEnabled": true,
"recommendationsEnabled": true
}
}
```
# 4. FEATURE REGISTRY TABLE
Ниже перечислены поддерживаемые возможности платформы в удобном формате: что это, где применяется и как выглядит в JSON.
## 4.1 Layout Features
- `default` (type: layout): базовый профиль витрины с верхней навигацией.
- `side-menu-layout` (type: layout): профиль с боковым меню категорий и контентной зоной.
- `grid-layout` (type: layout): плиточный профиль для плотного товарного листинга.
- `landing-page-layout` (type: layout): профиль лендинга с акцентом на hero/banner.
Пример использования layout:
```json
{
"layoutProfile": "side-menu-layout",
"layoutProfiles": {
"default": { "sectionSpacing": 24 },
"side-menu-layout": { "regions": ["header", "side", "content", "footer"] },
"grid-layout": { "grid": { "columnsDesktop": 5 } },
"landing-page-layout": { "sectionSpacing": 32 }
}
}
```
## 4.2 Navigation Features
- `logo` (type: navigation): блок логотипа в header.
- `side-menu` (type: navigation): триггер бокового меню.
- `category-menu` (type: navigation): навигация по категориям.
- `cart` (type: navigation): переход к корзине.
- `search` (type: navigation): точка входа в поиск.
- `language-switcher` (type: navigation): переключение языка.
- `currency-switcher` (type: navigation): переключение валюты.
Пример использования navigation:
```json
{
"navigation": {
"header": [
{ "type": "logo", "route": "/" },
{ "type": "side-menu", "route": "/catalog" },
{ "type": "category-menu", "route": "/catalog" },
{ "type": "search", "route": "/search" },
{ "type": "language-switcher" },
{ "type": "currency-switcher" },
{ "type": "cart", "route": "/cart" }
]
}
}
```
## 4.3 Section Features
- `hero` (type: section): главная промо-секция страницы.
- `categories` (type: section): блок категорий.
- `product-grid` (type: section): сетка товаров.
- `product-carousel` (type: section): карусель товаров.
- `sidebar-categories` (type: section): боковая колонка категорий.
- `featured-products` (type: section): выделенный блок рекомендованных товаров.
- `banner` (type: section): баннерная секция.
- `footer-links` (type: section): секция ссылок в футере.
Пример использования sections:
```json
{
"sections": [
{ "type": "hero", "order": 1 },
{ "type": "categories", "order": 2 },
{ "type": "featured-products", "order": 3 },
{ "type": "banner", "order": 4 },
{ "type": "footer-links", "order": 5 }
]
}
```
## 4.4 Widget Features
- `hero-widget` (type: widget): виджет hero-контента.
- `category-widget` (type: widget): виджет списка/сетки категорий.
- `product-grid-widget` (type: widget): виджет товарной сетки.
- `product-carousel-widget` (type: widget): виджет товарной карусели.
- `cart-widget` (type: widget): виджет корзины.
- `side-menu-widget` (type: widget): виджет бокового меню.
Пример использования widgets:
```json
{
"widgets": [
{ "type": "hero-widget", "version": "1.0.0" },
{ "type": "category-widget", "version": "1.0.0" },
{ "type": "product-grid-widget", "version": "1.0.0" },
{ "type": "product-carousel-widget", "version": "1.0.0" },
{ "type": "cart-widget", "version": "1.0.0" },
{ "type": "side-menu-widget", "version": "1.0.0" }
]
}
```
## 4.5 Feature Flags
- `multiLanguage` (type: feature): включает мультиязычность storefront.
- `multiCurrency` (type: feature): включает мультивалютный режим.
- `regionSelector` (type: feature): включает выбор региона.
- `guestCheckout` (type: feature): разрешает checkout без авторизации.
- `searchEnabled` (type: feature): включает поиск по каталогу.
- `recommendationsEnabled` (type: feature): включает рекомендательные блоки.
Пример использования feature flags:
```json
{
"features": {
"multiLanguage": true,
"multiCurrency": true,
"regionSelector": true,
"guestCheckout": true,
"searchEnabled": true,
"recommendationsEnabled": true
}
}
```
# 5. LAYOUT ENGINE EXPLANATION
Layout Engine применяет выбранный профиль layoutProfile для каждой страницы и определяет:
- контейнер страницы (ширина, внутренние отступы);
- интервалы между секциями;
- grid-параметры (колонки и gap);
- доступные regions (header/content/side/footer).
Как отличается side-menu-layout от default:
- default: акцент на центральный контент и верхнюю навигацию;
- side-menu-layout: добавляется регион side для боковой навигации и фильтров, контентный поток меняется на двухзонный.
Позиционирование виджетов:
- виджеты размещаются по секциям и регионам, заданным конфигурацией страницы;
- порядок и тип секций контролируются order и type;
- frontend не содержит hardcoded матриц layout.
Ключевой принцип: layout полностью декларативен, а не зашит в Angular-компоненты страниц.
# 6. STRICT RULES
## DO NOT
- Do NOT hardcode tenant logic in frontend.
- Do NOT define layout in Angular components.
- Do NOT call APIs inside widgets.
- Do NOT add project-specific conditions.
- Do NOT duplicate config logic across JSON files.
Дополнительные обязательные ограничения:
- Нельзя смешивать обязанности модулей конфигурации (theme, navigation, pages, features).
- Нельзя добавлять новые обязательные поля без повышения schemaVersion.
- Нельзя нарушать domain-to-tenant резолвинг альтернативными источниками истины.
# 7. EXTENSIBILITY MODEL
Платформа расширяется конфигурационно без изменений бизнес-логики frontend:
1. Новый виджет:
- Добавляется в widgetManifest.
- Привязывается к section через widgets[].type.
- Контент/данные подаются через props/dataSource.
2. Новый layout:
- Добавляется в layoutProfiles.
- Назначается страницам через pages[].layoutProfile.
3. Новая страница:
- Добавляется в pages с route, sections и widgets.
- Сразу участвует в runtime-рендеринге.
4. Контентные изменения:
- Меняются только JSON-конфигурации и backend-данные.
- Изменения контента не требуют модификации frontend-кода при сохранении контрактов.
Итоговая модель масштабирования:
- Tenant onboarding выполняется через домен, bootstrap и данные.
- Продукт расширяется через registry-подход.
- Архитектура остается стабильной при росте количества магазинов.

View File

@@ -0,0 +1,88 @@
# 00. Обзор платформы
## Master Summary
Платформа представляет собой многоарендный SaaS-конструктор маркетплейсов, в котором витрина, структура страниц, виджеты, темы и навигация формируются из конфигурации, а не из кастомного кода под каждого клиента. Каждый магазин (tenant) определяется строго по доменному имени, после чего frontend загружает bootstrap.json и строит UI динамически.
### Что это за платформа
- Конфигурационно-управляемая marketplace-платформа для запуска нескольких магазинов на единой кодовой базе.
- Визуальная и функциональная сборка витрины выполняется через bootstrap.json и связанные JSON-модули.
- Backend предоставляет данные домена: категории, товары, остатки, цены, медиа и справочники.
### Как создается новый маркетплейс
1. Регистрируется домен нового клиента и на backend настраивается tenant-конфигурация.
2. Готовится bootstrap.json (страницы, секции, виджеты, тема, маршруты, feature flags).
3. Подключаются API-эндпоинты каталога, категорий и карточек товаров.
4. Выполняется smoke-проверка: tenant resolution, загрузка bootstrap, рендер главной, каталог, карточка товара.
### Что должен сделать клиент для запуска нового магазина
- Предоставить домен и бренд-материалы (логотип, цвета, шрифты, иконки).
- Утвердить структуру страниц и навигации.
- Подтвердить каталогные правила (категории, витрины, карточки, фильтры).
- Подтвердить статический контент (о компании, политика, доставка, возвраты).
### Что обязаны реализовать backend-команды
- Доменную идентификацию tenant и выдачу tenant-aware bootstrap-конфигурации.
- API для категорий, товаров, карточек и связанных коллекций.
- Гарантированную стабильность контрактов JSON и версионирование schemaVersion.
- SLA по доступности и времени ответа, достаточные для runtime-инициализации UI.
## Назначение документа
Документ описывает бизнес-границы платформы, обязательные принципы архитектуры и процесс запуска нового tenant без изменения frontend-кода.
## Обязательные JSON-поля платформенного bootstrap
- schemaVersion: версия контракта конфигурации.
- tenant: идентификатор и параметры арендатора.
- theme: токены темы (цвета, типографика, радиусы, тени).
- pages: список страниц с секциями и виджетами.
- apiEndpoints: карта backend-эндпоинтов.
## Опциональные JSON-поля
- featureFlags: флаги включения функциональности.
- localization: список языков и словарей.
- seo: SEO-конфигурация страниц.
- permissions: роли и разрешения для административных зон.
## Строгие правила
- Нельзя хардкодить tenant-логику во frontend.
- Tenant определяется только по домену.
- UI генерируется из bootstrap.json; ручная сборка страниц запрещена.
- Виджеты не вызывают API напрямую.
- Layout управляется только конфигурацией.
- Изменения контрактов выполняются только через версионирование schemaVersion.
## Пример JSON (сокращенно)
```json
{
"schemaVersion": "1.0.0",
"tenant": {
"id": "tenant-acme",
"slug": "acme",
"host": "shop.acme.com",
"defaultLocale": "ru"
},
"theme": {
"themeId": "acme-light",
"palette": {
"primary": "#1F6B5C",
"backgroundPrimary": "#FFFFFF"
}
},
"pages": [
{
"id": "home",
"route": { "path": "/" },
"sections": []
}
]
}
```
## Ответственность Frontend
- Разрешить tenant по домену и загрузить bootstrap-конфигурацию.
- Валидировать обязательные поля и безопасно обрабатывать отсутствие опциональных.
- Построить страницы, секции и виджеты без tenant-specific условных веток.
## Ответственность Backend
- Возвращать валидный bootstrap JSON для каждого tenant.
- Поддерживать согласованные API-контракты каталога.
- Обеспечивать обратную совместимость либо явно повышать schemaVersion.

View File

@@ -0,0 +1,81 @@
# 01. Архитектура платформы
## Назначение
Документ определяет архитектурную модель многоарендной платформы маркетплейсов и обязательные границы между конфигурацией, frontend-runtime и backend-данными.
## Поведение системы
- Платформа использует единую frontend-кодовую базу для всех tenants.
- При старте приложение определяет tenant по домену.
- Затем загружается bootstrap-конфигурация.
- На основе конфигурации рендерятся страницы, секции и виджеты.
- Доменный контент (товары, категории, остатки) подгружается через backend API.
## Архитектурные слои
1. Tenant Resolution Layer: определение tenant из host.
2. Bootstrap Layer: загрузка конфигурации UI и маршрутов.
3. Section/Layout Engine: построение структуры страницы.
4. Widget Engine: отрисовка и наполнение reusable виджетов.
5. Domain Data Layer: доступ к API продуктов и категорий.
## Обязательные JSON-секции
- tenant
- layout
- pages
- sections
- widgets
- widgetRegistry
- theme
- apiEndpoints
- footer
- staticPages
## Опциональные JSON-секции
- featureFlags
- localization
- seo
- permissions
- integrations
## Строгие правила
- Запрещено смешивать layout-логику и data-fetch в виджетах.
- Запрещено tenant-specific ветвление в компонентах frontend.
- Backend может отдавать HTML-контент только для статических страниц (about/privacy/terms) через контролируемый контракт.
- Такой контент рендерится только через безопасную sanitization-цепочку.
- Запрещено добавлять новые обязательные поля без обновления schemaVersion.
## Пример архитектурного bootstrap-фрагмента
```json
{
"tenant": {
"id": "tenant-novo",
"host": "novo.marketplace.com"
},
"apiEndpoints": {
"catalog": { "baseUrl": "https://api.marketplace.com" }
},
"pages": [
{
"id": "home",
"sections": [
{
"id": "hero-1",
"type": "hero",
"widgets": [
{ "id": "w-hero", "type": "hero", "dataSource": { "kind": "static" } }
]
}
]
}
]
}
```
## Ответственность Frontend
- Следовать слоям архитектуры без cross-layer обходов.
- Выполнять fail-safe рендер при частично валидной конфигурации.
- Логировать нарушения контрактов конфигурации.
## Ответственность Backend
- Отдавать данные строго по контракту API.
- Гарантировать tenant-aware ответы.
- Поддерживать прогнозируемую схему и документацию изменений.

View File

@@ -0,0 +1,124 @@
# 02. Спецификация bootstrap.json
## Назначение
Bootstrap JSON является главным конфигурационным документом витрины. Он определяет структуру страниц, секций, виджетов, тему и подключение источников данных.
## Поведение системы
- Frontend загружает bootstrap.json на старте runtime.
- Конфигурация валидируется по обязательным полям.
- После валидации строится UI без хардкода tenant-логики.
## Обязательные свойства
- schemaVersion: string
- tenant: object
- theme: object
- layout: object
- pages: array
- apiEndpoints: object
### Обязательные свойства tenant
- id: string
- slug: string
- host: string
- defaultLocale: string
- supportedLocales: string[]
### Обязательные свойства страницы
- id: string
- key: string
- route.path: string
- sections: array
### Обязательные свойства секции
- id: string
- type: string
- order: number
- widgets: array
### Обязательные свойства виджета
- id: string
- type: string
- version: string
### Поддерживаемые layout.type
- default
- sidebar-left
- carousel-home
- minimal
## Опциональные свойства
- featureFlags
- localization
- seo
- permissions
- branding
- navigation
- footer
- staticPages
- widgetRegistry
- visibility
- layout
- dataSource
## Строгие правила
- Поля обязательной схемы не могут быть null.
- route.path должен быть уникальным в рамках tenant.
- id страниц, секций и виджетов должен быть уникальным в своей области.
- В одной секции порядок order не может дублироваться.
- Виджеты не содержат backend URL в props; URL управляются только apiEndpoints.
- Для виджетов допустимы metadata поля: order, padding, visibility.desktop/tablet/mobile.
- Для footer links/legal/payout icons источник истины — bootstrap JSON.
- Для staticPages контент поддерживается в формате multilingual HTML и рендерится только через safe sanitizer.
## Пример полного минимального bootstrap
```json
{
"schemaVersion": "1.0.0",
"tenant": {
"id": "tenant-default",
"slug": "default",
"host": "default.marketplace.com",
"defaultLocale": "ru",
"supportedLocales": ["ru", "en"]
},
"theme": {
"themeId": "default-light",
"palette": {
"primary": "#497671",
"textPrimary": "#1e3c38",
"backgroundPrimary": "#ffffff"
}
},
"apiEndpoints": {
"catalog": { "baseUrl": "https://api.marketplace.com" },
"bootstrap": { "path": "/bootstrap" }
},
"pages": [
{
"id": "page-home",
"key": "home",
"route": { "path": "/", "exact": true },
"sections": [
{
"id": "section-hero",
"type": "hero",
"order": 1,
"widgets": [
{ "id": "widget-hero", "type": "hero", "version": "1.0.0" }
]
}
]
}
]
}
```
## Ответственность Frontend
- Валидировать обязательные поля до рендера.
- Применять значения опциональных полей только при наличии.
- Прекращать инициализацию при критической невалидности схемы.
## Ответственность Backend
- Отдавать tenant-specific bootstrap.json.
- Поддерживать schemaVersion и changelog контракта.
- Не включать frontend-специфические runtime-хуки в JSON.

View File

@@ -0,0 +1,68 @@
# 03. Тема и дизайн-система
## Назначение
Тема задает визуальные токены бренда tenant: цвета, типографику, радиусы, тени и базовые параметры визуальной консистентности.
## Поведение системы
- Theme токены загружаются из bootstrap.json.
- Frontend применяет токены через CSS-переменные.
- Компоненты и виджеты используют только токены, а не hardcoded brand-значения.
## Обязательные свойства JSON
- theme.themeId
- theme.palette.primary
- theme.palette.textPrimary
- theme.palette.backgroundPrimary
- theme.typography.primaryFontFamily
- theme.typography.baseFontSize
## Опциональные свойства JSON
- theme.palette.secondary
- theme.palette.accent
- theme.borderRadiusScale
- theme.shadows
- theme.iconSet
- theme.mode
## Строгие правила
- Нельзя хардкодить tenant-цвета в компонентах.
- Нельзя задавать типографику вне theme токенов для брендовых элементов.
- Нельзя смешивать несколько themeId одновременно для одной витрины.
- При отсутствии опционального токена используется системный fallback.
## Пример theme JSON
```json
{
"theme": {
"themeId": "novo-light",
"mode": "light",
"palette": {
"primary": "#2F6E5D",
"secondary": "#8FA9A2",
"accent": "#B9D9CF",
"textPrimary": "#1F322D",
"backgroundPrimary": "#FFFFFF"
},
"typography": {
"primaryFontFamily": "DM Sans, sans-serif",
"headingFontFamily": "DM Sans, sans-serif",
"baseFontSize": 16
},
"borderRadiusScale": {
"sm": "8px",
"md": "12px",
"lg": "16px"
}
}
}
```
## Ответственность Frontend
- Маппить токены в CSS custom properties.
- Применять fallback токены для опциональных полей.
- Обеспечивать визуальную консистентность между страницами и виджетами.
## Ответственность Backend
- Выдавать валидный theme объект для каждого tenant.
- Контролировать полноту обязательных токенов.
- Поддерживать совместимость theme-контракта между версиями.

View File

@@ -0,0 +1,67 @@
# 04. Layout Engine
## Назначение
Layout Engine отвечает за композицию страницы из секций по данным конфигурации и управляет только структурой и позиционированием, без доменной бизнес-логики.
## Поведение системы
- Engine читает page.sections.
- Секции сортируются по order.
- Для каждой секции применяется layout-стратегия.
- Виджеты размещаются внутри секции согласно layout-параметрам.
## Обязательные свойства JSON
- section.id
- section.type
- section.order
- section.widgets
## Опциональные свойства JSON
- section.layout.strategy
- section.layout.columns
- section.layout.gap
- section.layout.align
- section.visibility.desktop/tablet/mobile
- section.featureFlag
## Строгие правила
- Layout определяется только конфигурацией.
- Виджет не может переопределять секционный grid/columns на уровне страницы.
- Если section.visible=false, секция не рендерится.
- Секция должна рендериться в стандартном каркасе: section + page container.
## Пример JSON секции
```json
{
"id": "section-featured-products",
"type": "product-collection",
"order": 2,
"layout": {
"strategy": "grid",
"columns": 4,
"gap": "16px",
"align": "stretch"
},
"visibility": {
"desktop": true,
"tablet": true,
"mobile": true
},
"widgets": [
{
"id": "widget-featured",
"type": "product-carousel",
"version": "1.0.0"
}
]
}
```
## Ответственность Frontend
- Корректно применять сортировку и layout-параметры.
- Гарантировать единые отступы и контейнеры секций.
- Безопасно деградировать при частично некорректном layout.
## Ответственность Backend
- Отдавать корректные layout-атрибуты в bootstrap.
- Не смешивать контентные данные с layout-инструкциями.
- Поддерживать непротиворечивость секций внутри страницы.

View File

@@ -0,0 +1,57 @@
# 05. Widget System
## Назначение
Widget System предоставляет переиспользуемые UI-блоки для сборки страниц из конфигурации без дублирования логики и без tenant-specific кода.
## Поведение системы
- Widget Engine выбирает компонент по widget.type и version.
- Виджет получает входные props и resolved data.
- В случае отсутствия регистрации используется fallback unknown-widget.
## Обязательные свойства JSON
- widget.id
- widget.type
- widget.version
## Опциональные свойства JSON
- widget.props
- widget.dataSource
- widget.featureFlag
- widget.visible
- widget.events
## Строгие правила
- Виджеты не вызывают API напрямую.
- Виджеты не управляют page-level margin/padding/layout.
- Виджет может управлять только внутренней разметкой и презентацией.
- Любой новый widget.type должен быть зарегистрирован в реестре.
## Пример JSON виджета
```json
{
"id": "widget-categories-main",
"type": "categories",
"version": "1.0.0",
"props": {
"title": "Категории",
"emptyMessage": "Категории скоро появятся"
},
"dataSource": {
"name": "categories",
"params": {
"rootOnly": true,
"limit": 12
}
}
}
```
## Ответственность Frontend
- Разрешать тип виджета через registry/manifest.
- Передавать только подготовленные данные в компонент виджета.
- Блокировать прямые API-вызовы из слоя UI-виджета.
## Ответственность Backend
- Поставлять данные в форматах, ожидаемых data resolvers.
- Обеспечивать консистентность ID и ссылок между сущностями.
- Не внедрять frontend-специфичные инструкции в props виджетов.

View File

@@ -0,0 +1,74 @@
# 06. API-контракты
## Назначение
Документ определяет стабильные контракты API для данных маркетплейса. Backend предоставляет только данные, frontend отвечает за представление.
## Поведение системы
- API base URL определяется tenant-конфигурацией.
- Frontend отправляет запросы через единый API слой и интерсепторы.
- Ответы маппятся в доменные модели frontend.
## Обязательные свойства JSON (ответы API)
- status или корректный HTTP status code
- data (основная полезная нагрузка)
- id для доменных сущностей
## Опциональные свойства JSON
- meta (pagination, total, filters)
- errors (детализация ошибок)
- warnings
## Строгие правила
- Backend не должен отдавать HTML для витрины.
- Контракты должны быть обратно совместимы в пределах одной major-версии.
- В ответах на списки должна поддерживаться пагинация.
- Ошибки API должны быть машиночитаемыми и локализуемыми на frontend.
## Пример API ответа: категории
```json
{
"data": [
{
"id": 101,
"title": "Смартфоны",
"parentId": null,
"priority": 1,
"visible": true
}
],
"meta": {
"total": 1
}
}
```
## Пример API ответа: товары
```json
{
"data": {
"items": [
{
"itemID": 5001,
"name": "Phone X",
"price": 49990,
"currency": "RUB",
"categoryID": 101,
"visible": true
}
],
"total": 1,
"skip": 0,
"count": 20
}
}
```
## Ответственность Frontend
- Маппинг API DTO в доменные модели.
- Центральная обработка ошибок и retry-стратегий.
- Кеширование и переиспользование данных без нарушения актуальности.
## Ответственность Backend
- Гарантировать SLA и стабильность контрактов.
- Возвращать tenant-correct данные.
- Поддерживать фильтрацию, пагинацию и сортировку для каталога.

View File

@@ -0,0 +1,55 @@
# 07. Tenant System
## Назначение
Tenant System обеспечивает запуск нескольких независимых магазинов на единой платформе через доменное разделение и конфигурационный bootstrap.
## Поведение системы
- Tenant определяется только по hostname запроса.
- По tenant выбираются конфигурации bootstrap, тема, локализация и API base.
- Frontend не хранит статических tenant-switch правил в коде.
## Обязательные свойства JSON
- tenant.id
- tenant.slug
- tenant.host
- tenant.defaultLocale
- tenant.supportedLocales
- tenant.defaultCurrency
## Опциональные свойства JSON
- tenant.timezone
- tenant.brandName
- tenant.websiteBaseUrl
- tenant.builderBaseUrl
- tenant.backofficeBaseUrl
## Строгие правила
- Нельзя определять tenant через query params или localStorage как источник истины.
- Нельзя хардкодить tenant ID внутри компонентов.
- Один домен может быть связан только с одним активным tenant в момент запроса.
- При отсутствии tenant-конфигурации runtime должен завершаться контролируемой ошибкой.
## Пример tenant JSON
```json
{
"tenant": {
"id": "tenant-lavero",
"slug": "lavero",
"host": "lavero.marketplace.com",
"defaultLocale": "ru",
"supportedLocales": ["ru", "en", "hy"],
"defaultCurrency": "RUB",
"timezone": "Europe/Moscow"
}
}
```
## Ответственность Frontend
- Резолвить tenant на старте приложения.
- Использовать tenant-параметры для формирования маршрутов, локали и API-слоя.
- Исключать fallback на чужой tenant без явной backend-политики.
## Ответственность Backend
- Поддерживать доменно-tenant маппинг.
- Возвращать корректную tenant-конфигурацию и bootstrap.
- Контролировать изоляцию данных между tenants.

View File

@@ -0,0 +1,55 @@
# 08. Каталогный домен
## Назначение
Каталогный домен описывает правила формирования витрин, листингов и поисковых выборок для tenant-магазина.
## Поведение системы
- Каталог строится из API-данных и bootstrap-конфигурации.
- Bootstrap определяет структуру страниц каталога и виджеты.
- API возвращает содержимое: товары, категории, метаданные фильтров.
## Обязательные JSON-свойства каталога
- catalog.settings.defaultSort
- catalog.settings.pageSize
- catalog.routes.list
- catalog.routes.details
## Опциональные свойства
- catalog.filters.available
- catalog.facets
- catalog.badges
- catalog.promotions
## Строгие правила
- Каталог не содержит tenant-specific условий в frontend-коде.
- Сортировка и фильтры должны быть согласованы между frontend и backend.
- Видимость товаров контролируется данными backend, а не frontend-хардкодом.
## Пример catalog JSON (bootstrap fragment)
```json
{
"catalog": {
"settings": {
"defaultSort": "priority_desc",
"pageSize": 20
},
"routes": {
"list": "/catalog",
"details": "/product/:id"
},
"filters": {
"available": ["price", "brand", "availability"]
}
}
}
```
## Ответственность Frontend
- Отобразить листинг, фильтры, сортировки и пагинацию.
- Синхронизировать состояние каталога с URL.
- Стабильно обрабатывать пустые и частично заполненные наборы данных.
## Ответственность Backend
- Возвращать согласованные данные для листингов и фильтров.
- Гарантировать корректные totals/pagination.
- Поддерживать стабильные ключи сортировки и фильтрации.

View File

@@ -0,0 +1,49 @@
# 09. Домен категорий
## Назначение
Категорийный домен описывает иерархию каталога, правила вложенности и отображения категорий.
## Поведение системы
- Frontend получает плоский список или дерево категорий из backend.
- Для витрины строится дерево root -> children.
- Выбор категории влияет на выборку товаров и хлебные крошки.
## Обязательные JSON-свойства категории
- id
- title
- parentId (null для корня)
- visible
- priority
## Опциональные свойства
- icon
- image
- itemCount
- seo
- translations
## Строгие правила
- id категории должен быть уникальным в tenant.
- Циклические ссылки parentId запрещены.
- Невидимые категории не отображаются в публичной витрине.
- Порядок показа определяется priority, затем id.
## Пример JSON категорий
```json
{
"data": [
{ "id": 1, "title": "Электроника", "parentId": null, "visible": true, "priority": 1 },
{ "id": 2, "title": "Смартфоны", "parentId": 1, "visible": true, "priority": 1 }
]
}
```
## Ответственность Frontend
- Корректно строить дерево категорий и breadcrumbs.
- Переходить в каталог категории по маршруту конфигурации.
- Не показывать скрытые категории.
## Ответственность Backend
- Поддерживать целостность иерархии категорий.
- Возвращать категории в tenant-контексте.
- Отдавать метрики itemCount при их поддержке.

View File

@@ -0,0 +1,59 @@
# 10. Домен товаров
## Назначение
Товарный домен определяет контракт карточки товара, листингов, ценовых и складских атрибутов.
## Поведение системы
- Товары загружаются по API для листинга, карточки и связанных коллекций.
- Frontend отображает только те поля, которые есть в контракте.
- Бизнес-правила доступности товара приходят из backend.
## Обязательные JSON-свойства товара
- itemID
- name
- price
- currency
- categoryID
- visible
## Опциональные свойства
- discount
- images
- badges
- simpleDescription
- attributes
- stockStatus
- rating
## Строгие правила
- Цена и валюта должны передаваться как валидная пара.
- Скрытые товары не участвуют в публичных витринах.
- categoryID должен ссылаться на существующую категорию.
- Виджет не изменяет товарные данные, только отображает.
## Пример JSON товара
```json
{
"itemID": 7812,
"name": "Laptop Pro 14",
"price": 129990,
"currency": "RUB",
"categoryID": 55,
"visible": true,
"discount": 10,
"images": [
{ "url": "https://cdn.example.com/items/7812/main.jpg", "isMain": true }
],
"badges": ["featured", "new"]
}
```
## Ответственность Frontend
- Показывать корректную цену, скидку, бейджи и доступность.
- Поддерживать переход из листинга в карточку товара.
- Учитывать locale/currency из tenant-конфигурации.
## Ответственность Backend
- Возвращать актуальные цены и доступность.
- Стабильно поддерживать идентификаторы товаров.
- Предоставлять медиа и атрибуты в согласованном формате.

View File

@@ -0,0 +1,51 @@
# 11. Система навигации
## Назначение
Навигационная система управляет маршрутами витрины, меню и ссылками на основе bootstrap-конфигурации.
## Поведение системы
- Frontend строит маршруты из конфигурации pages и navigation.
- Языковой префикс маршрута задается локализационной конфигурацией.
- Для категорий/товаров используются конфигурируемые route templates.
## Обязательные JSON-свойства
- pages[].route.path
- pages[].id
- navigation.header или navigation.footer (минимум один набор)
## Опциональные свойства
- route.exact
- route.redirectTo
- navigation.icon
- navigation.order
- navigation.visible
## Строгие правила
- Маршруты страниц должны быть уникальны в рамках tenant.
- Ссылка меню должна ссылаться на существующий маршрут или валидный внешний URL.
- Нельзя хардкодить статические tenant-пути в компонентах.
## Пример navigation JSON
```json
{
"navigation": {
"header": [
{ "id": "nav-home", "label": "Главная", "route": "/", "order": 1 },
{ "id": "nav-catalog", "label": "Каталог", "route": "/catalog", "order": 2 }
],
"footer": [
{ "id": "nav-privacy", "label": "Политика", "route": "/privacy-policy", "order": 1 }
]
}
}
```
## Ответственность Frontend
- Строить меню и роутинг из конфигурации.
- Соблюдать локализацию маршрутов.
- Обрабатывать недоступные маршруты через fallback-страницу.
## Ответственность Backend
- Возвращать валидную карту маршрутов/навигации в bootstrap.
- Поддерживать актуальность ссылок на статические страницы.
- Контролировать tenant-специфичность навигации.

View File

@@ -0,0 +1,53 @@
# 12. Система статических страниц
## Назначение
Система статических страниц управляет юридическими и информационными страницами (о компании, политика, доставка, возврат) через конфигурацию.
## Поведение системы
- Список страниц и маршруты берутся из bootstrap/pages.
- Контент может храниться как HTML/Markdown/структурированный JSON.
- Frontend рендерит контент безопасно, с tenant-aware навигацией.
## Обязательные JSON-свойства
- page.id
- page.key
- page.route.path
- page.type = "static"
- page.content.source
## Опциональные свойства
- page.seoKey
- page.visible
- page.translations
- page.lastUpdated
## Строгие правила
- Запрещено хардкодить список статических страниц во frontend.
- Контент должен быть изолирован по tenant.
- HTML-контент должен проходить sanitation на frontend и/или backend.
## Пример JSON статической страницы
```json
{
"id": "page-privacy",
"key": "privacy-policy",
"type": "static",
"route": { "path": "/privacy-policy", "exact": true },
"content": {
"source": "cms",
"contentType": "html",
"value": "<h1>Политика конфиденциальности</h1><p>...</p>"
},
"visible": true
}
```
## Ответственность Frontend
- Рендерить статические страницы по конфигурации маршрутов.
- Безопасно обрабатывать HTML-контент.
- Поддерживать локализованные версии страницы.
## Ответственность Backend
- Поставлять tenant-specific статический контент.
- Поддерживать версионирование и аудит контента.
- Гарантировать валидность route/content связки.

View File

@@ -0,0 +1,61 @@
# 13. Требования к backend
## Назначение
Документ фиксирует минимальный набор backend-возможностей для стабильной работы конфигурационно-управляемой multi-tenant платформы.
## Функциональные требования
- Tenant resolution по домену.
- Выдача bootstrap.json для tenant.
- API категорий, товаров, карточек, поисковых выборок.
- Выдача навигации, статических страниц и feature flags.
### Контракт статических страниц
Backend должен поддерживать формат:
```json
{
"slug": "about-us",
"content": {
"en": "<html>",
"ru": "<html>",
"hy": "<html>"
}
}
```
## Обязательные JSON-контракты
- Bootstrap контракт со schemaVersion.
- Категории: id/title/parentId/visible/priority.
- Товары: itemID/name/price/currency/categoryID/visible.
- Унифицированный формат ошибок API.
## Опциональные JSON-контракты
- Персонализированные рекомендации.
- Расширенные facets/filters.
- SEO-объекты и контентные блоки.
## Строгие правила
- Backend не должен возвращать frontend-specific разметку приложения (кроме контента статических страниц по согласованному контракту).
- Любое breaking change требует новой версии контракта.
- Данные tenants должны быть полностью изолированы.
- SLA bootstrap и catalog API должны обеспечивать запуск витрины без деградации UX.
- Bootstrap не должен содержать секреты: private keys, admin credentials, signing tokens.
## Пример JSON ошибки API
```json
{
"error": {
"code": "CATEGORY_NOT_FOUND",
"message": "Category does not exist",
"details": { "categoryId": 999 }
}
}
```
## Ответственность Frontend
- Корректно интерпретировать ошибки и показывать пользовательские сценарии восстановления.
- Не обходить публичные backend-контракты прямыми вызовами внутренних сервисов.
## Ответственность Backend
- Обеспечить мониторинг, логирование и трассировку критических endpoint.
- Поддерживать тестируемые и документированные контракты.
- Обеспечить безопасность, rate limiting и контроль доступа.

View File

@@ -0,0 +1,54 @@
# 14. Модель деплоя
## Назначение
Модель деплоя описывает запуск платформы в SaaS-режиме для нескольких tenants с общей frontend-сборкой и tenant-aware backend-конфигурацией.
## Поведение системы
- Одна frontend-сборка обслуживает несколько доменов.
- Tenant определяется на runtime по host.
- Backend/edge отдает соответствующий bootstrap и API конфигурацию.
- UI-режимы layout/widgets/footer/static pages переключаются только через bootstrap без перекомпиляции frontend.
## Обязательные параметры деплоя (JSON/env)
- supportedHosts
- defaultTenantPolicy
- apiGatewayBaseUrl
- bootstrapEndpoint
- observability (logs/metrics/traces)
## Опциональные параметры
- CDN policy
- региональные endpoint
- feature rollouts
- fallback tenant (только по утвержденной политике)
## Строгие правила
- Нельзя собирать отдельный frontend-бандл под каждый tenant как основной процесс.
- Нельзя использовать ручные правки frontend для запуска нового клиента.
- Деплой должен поддерживать zero-downtime обновления.
- Конфигурация окружений должна быть отделена от бизнес-данных tenants.
- В bootstrap и публичных API запрещено хранить секреты.
## Пример deployment-конфигурации (сокращенно)
```json
{
"environment": "production",
"supportedHosts": ["store-a.com", "store-b.com"],
"bootstrapEndpoint": "https://api.platform.com/bootstrap",
"apiGatewayBaseUrl": "https://api.platform.com",
"observability": {
"logs": true,
"metrics": true,
"traces": true
}
}
```
## Ответственность Frontend
- Корректно работать в multi-host режиме без перекомпиляции.
- Логировать runtime-ошибки tenant resolution/bootstrap.
## Ответственность Backend/DevOps
- Обеспечить маршрутизацию доменов на единый frontend runtime.
- Поддерживать tenant-aware конфигурацию на edge/API уровне.
- Обеспечить CI/CD с валидацией контрактов и smoke-тестами tenants.

View File

@@ -0,0 +1,54 @@
# 15. Правила и ограничения платформы
## Назначение
Документ фиксирует обязательные ограничения платформы для всех команд: frontend, backend, QA, DevOps и интеграционных партнеров.
## Базовые неизменяемые принципы
- Платформа полностью configuration-driven.
- Никакой hardcoded tenant/project логики во frontend.
- Tenant определяется только по домену.
- UI строится из bootstrap.json.
- Виджеты переиспользуемы и не обращаются к API напрямую.
- Backend предоставляет данные, а не layout.
- Layout управляется только конфигурацией.
## Обязательные правила JSON-модульности
- Bootstrap: структура страниц и подключение систем.
- Theme JSON: только визуальные токены.
- Navigation JSON: только маршруты и меню.
- Catalog/Product/Category API JSON: только доменные данные.
- Запрещено смешивать зоны ответственности между JSON-модулями.
## Что разрешено
- Добавлять новые виджеты через registry/manifest.
- Расширять опциональные поля с сохранением обратной совместимости.
- Добавлять новые секции/страницы через конфигурацию.
## Что запрещено
- Хардкод tenant-веток в компонентах.
- Прямые API-вызовы из widget UI слоя.
- Дублирование layout-правил в каждом виджете.
- Breaking изменения контрактов без schemaVersion.
## Пример policy JSON
```json
{
"platformPolicy": {
"configurationDriven": true,
"tenantResolution": "domain-only",
"widgetsCanCallApiDirectly": false,
"layoutControlledBy": "configuration",
"backendProvides": ["products", "categories", "items"]
}
}
```
## Ответственность Frontend
- Соблюдать архитектурные ограничения и слоистость.
- Не вводить локальные обходы конфигурации.
- Проводить регрессионные проверки на multi-tenant сценариях.
## Ответственность Backend
- Строго следовать контрактам данных.
- Поддерживать tenant isolation и аудируемость изменений.
- Предоставлять стабильные и документированные API.