Files
marketplaces/docs/platform/00-bootstrap-example.md
sdarbinyan 1a8f916942
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
feat(catalog): implement sprint 10 advanced search experience
2026-07-09 00:55:50 +04:00

24 KiB
Raw Blame History

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 с явно именованными сущностями.

{
  "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
    }
  ],
  "catalog": {
    "layout": "grid",
    "navigationMode": "default",
    "defaultSort": "relevance",
    "availableSorts": ["relevance", "latest", "price_asc", "price_desc", "rating", "popular", "discount"],
    "enabledFilters": ["price", "availability", "rating", "brand", "category", "subcategory", "discount", "new", "color", "size", "attributes"],
    "showBreadcrumbs": true,
    "showCategoryBanner": true,
    "showSubcategoryChips": true,
    "showRatings": true,
    "showDiscounts": true,
    "showAvailability": true,
    "suggestionsEnabled": true,
    "searchHistoryEnabled": true
  },
  "productPage": {
    "rating": { "enabled": true },
    "reviews": {
      "enabled": true,
      "pageSize": 5,
      "showSummary": true
    },
    "questions": {
      "enabled": true,
      "pageSize": 5
    },
    "tabs": {
      "enabled": true,
      "items": ["description", "specifications", "reviews", "questions", "delivery", "warranty"]
    },
    "relatedProducts": { "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:

{
  "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:

{
  "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:

{
  "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:

{
  "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:

{
  "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.
  1. Новый layout:
  • Добавляется в layoutProfiles.
  • Назначается страницам через pages[].layoutProfile.
  1. Новая страница:
  • Добавляется в pages с route, sections и widgets.
  • Сразу участвует в runtime-рендеринге.
  1. Контентные изменения:
  • Меняются только JSON-конфигурации и backend-данные.
  • Изменения контента не требуют модификации frontend-кода при сохранении контрактов.

Итоговая модель масштабирования:

  • Tenant onboarding выполняется через домен, bootstrap и данные.
  • Продукт расширяется через registry-подход.
  • Архитектура остается стабильной при росте количества магазинов.