Версия: 2.0.0
Дата: 2026-01-07
Этап → Действие → Тест → Чекпоинт → Следующий этап
4 чекпоинта готовности:
1. Базовая тема (Lite)
2. Commerce (Shop)
3. Advanced Features (Advanced)
4. Production Ready (Max)
Создать минимальную рабочую тему Drupal.
Результат: Главная страница рендерится, CSS/JS работают
# 1. Создать проект (Drupal CMS — не vanilla Drupal, содержит SEO/media рецепты)
composer create-project drupal/cms ideal-shop
cd ideal-shop
# 2. Установить Drupal
vendor/bin/drush site:install standard \
--db-url=sqlite://db.sqlite \
--site-name="Ideal Shop" \
--account-pass=admin \
-y
# Проверка установки
vendor/bin/drush status | grep "Database"
# Ожидаемый вывод: Database: Connected
# Проверка доступности
vendor/bin/drush runserver 127.0.0.1:8080 &
sleep 3
curl -f http://127.0.0.1:8080/
# Ожидаемый код: 200
mkdir -p web/themes/custom/ideal_theme
cd web/themes/custom/ideal_theme
# Создать структуру
mkdir -p {components,templates,css,js,translations,images,pwa}
ideal_theme.info.yml:
name: Ideal Theme
type: theme
description: 'Дочерняя тема Bootstrap Barrio для e-commerce магазина'
package: Custom
core_version_requirement: ^11
base theme: bootstrap_barrio
libraries:
- ideal_theme/global-styling
regions:
header_top: 'Header Top'
header: Header
primary_menu: 'Primary menu'
content: Content
sidebar_first: 'Left sidebar'
footer_first: 'Footer column 1'
footer_second: 'Footer column 2'
footer_bottom: 'Footer bottom'
⚠️ Регионы должны совпадать с регионами Bootstrap Barrio или расширять их.
Bootstrap Barrio уже предоставляет Bootstrap 5 CSS/JS — не нужно подключать вручную.
ideal_theme.libraries.yml:
global-styling:
css:
theme:
css/tokens.css: {}
css/global.css: {}
js:
js/cart-ajax.js: {}
dependencies:
- core/drupal
- core/once
css/tokens.css (дизайн-токены из THEME-SPEC):
:root {
/* Цвета */
--color-primary: #1a4f8a;
--color-primary-h: #1a6abf;
--color-accent: #e63946;
--color-success: #28a745;
--color-text: #222222;
--color-muted: #6c757d;
--color-bg: #ffffff;
--color-bg-light: #f8f9fa;
--color-border: #dee2e6;
/* Типографика */
--font-base: 'Inter', -apple-system, sans-serif;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--font-size-lg: 1.125rem;
/* Скругления */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
/* Тени */
--shadow-card: 0 2px 8px rgba(0,0,0,0.08);
--shadow-hover: 0 4px 16px rgba(0,0,0,0.14);
}
js/main.js:
(function (Drupal) {
'use strict';
Drupal.behaviors.idealTheme = {
attach: function (context, settings) {
console.log('Ideal Theme loaded');
}
};
})(Drupal);
# Проверка структуры
ls -la web/themes/custom/ideal_theme/
# Должны быть: ideal_theme.info.yml, css/, js/
# Проверка YAML синтаксиса
yamllint ideal_theme.info.yml
yamllint ideal_theme.libraries.yml
cd /path/to/ideal-shop
# Включить тему
vendor/bin/drush theme:install ideal_theme -y
vendor/bin/drush config:set system.theme default ideal_theme -y
vendor/bin/drush cr
# Проверка активации
vendor/bin/drush theme:list | grep ideal_theme
# Ожидаемый вывод: ideal_theme (default theme)
# Тест страницы
curl -s http://127.0.0.1:8080/ | grep "Ideal Theme loaded"
# Должен найти JS код
# Проверка CSS
curl -s http://127.0.0.1:8080/themes/custom/ideal_theme/css/base.css
# HTTP 200
templates/layout/page.html.twig:
<div class="page-wrapper">
<header class="header">
<div class="container">
{{ page.header }}
</div>
</header>
<main class="main">
<div class="container">
{{ page.content }}
</div>
</main>
<footer class="footer">
<div class="container">
{{ page.footer }}
</div>
</footer>
</div>
# Очистить кэш
vendor/bin/drush cr
# Проверка структуры HTML
curl -s http://127.0.0.1:8080/ | grep '<div class="page-wrapper">'
curl -s http://127.0.0.1:8080/ | grep '<header class="header">'
curl -s http://127.0.0.1:8080/ | grep '<footer class="footer">'
# Все должны найтись
Автоматический тест:
#!/bin/bash
# tests/checkpoint-1.sh
echo "🧪 Testing Checkpoint 1: Base Theme"
# 1. Тема включена
drush theme:list | grep "ideal_theme (default theme)" || exit 1
# 2. Главная страница
HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/)
[ "$HTTP" = "200" ] || exit 1
# 3. CSS загружается
HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/themes/custom/ideal_theme/css/base.css)
[ "$HTTP" = "200" ] || exit 1
# 4. JS работает
curl -s http://127.0.0.1:8080/ | grep "Ideal Theme loaded" || exit 1
# 5. HTML структура
curl -s http://127.0.0.1:8080/ | grep '<div class="page-wrapper">' || exit 1
echo "✅ Checkpoint 1 PASSED"
Добавить e-commerce функционал.
Результат: Каталог товаров, страница товара, корзина, checkout работают
# Установить модули
composer require drupal/commerce
# Применить рецепт
vendor/bin/drush recipe recipes/ideal_shop_core
recipes/ideal_shop_core/recipe.yml:
name: 'Ideal Shop - Core Commerce'
description: 'Commerce + Store + Product type + Checkout flow'
type: 'Site'
install:
- commerce
- commerce_product
- commerce_cart
- commerce_checkout
- commerce_order
- commerce_payment
- commerce_price
- commerce_store
config:
actions:
commerce.settings:
simple:
default_country: 'RU'
# Проверка модулей
vendor/bin/drush pm:list | grep commerce_product
vendor/bin/drush pm:list | grep commerce_cart
vendor/bin/drush pm:list | grep commerce_checkout
# Все должны быть Enabled
# Создать product type через Drush
vendor/bin/drush commerce:create-product-type \
--label="Product" \
--id="product" \
--variation-type="default"
# Проверка
vendor/bin/drush entity:list commerce_product_type
# Должен быть: product
# Создать тестовый товар
vendor/bin/drush commerce:create-product \
--type="product" \
--title="Test Product" \
--sku="TEST-001" \
--price="100.00"
# Проверить что создался
vendor/bin/drush entity:list commerce_product
templates/commerce/commerce-product--full.html.twig:
<article class="product">
<h1 class="product-title">{{ product_entity.label }}</h1>
<div class="product-price">
{{ content.variations }}
</div>
<div class="product-description">
{{ content.body }}
</div>
<div class="product-add-to-cart">
{{ content.variations[0].add_to_cart }}
</div>
</article>
templates/commerce-cart/cart-block.html.twig:
<div class="cart-block">
{% if content.items %}
<div class="cart-items">
{{ content.items }}
</div>
<div class="cart-total">
{{ content.total }}
</div>
<a href="/cart" class="cart-link">View Cart</a>
{% else %}
<p>Cart is empty</p>
{% endif %}
</div>
# Очистить кэш
vendor/bin/drush cr
# Проверка товара
curl -s http://127.0.0.1:8080/product/1 | grep '<article class="product">'
# Проверка корзины
curl -s http://127.0.0.1:8080/cart | grep '<div class="cart-block">'
# Применить рецепт каталога
vendor/bin/drush recipe recipes/ideal_shop_catalog
recipes/ideal_shop_catalog/recipe.yml:
name: 'Ideal Shop - Catalog'
description: 'Категории + Views каталога + Facets + Search API'
type: 'Site'
install:
- views
- views_ui
config:
import:
catalog:
- views.view.products
recipes/ideal_theme_catalog/config/views.view.products.yml:
id: products
label: 'Products Catalog'
module: views
display:
default:
display_plugin: default
display_title: Default
page_1:
display_plugin: page
display_title: Page
path: catalog
# Проверка View
vendor/bin/drush views:list | grep products
# Проверка страницы
curl -f http://127.0.0.1:8080/catalog
# HTTP 200
Автоматический тест:
#!/bin/bash
# tests/checkpoint-2.sh
echo "🧪 Testing Checkpoint 2: Commerce"
# 1. Commerce модули
drush pm:list | grep "commerce_product.*Enabled" || exit 1
# 2. Product type
drush entity:list commerce_product_type | grep "product" || exit 1
# 3. Каталог
HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/catalog)
[ "$HTTP" = "200" ] || exit 1
# 4. Товар
HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/product/1)
[ "$HTTP" = "200" ] || exit 1
# 5. Корзина
HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/cart)
[ "$HTTP" = "200" ] || exit 1
# 6. Checkout
HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/checkout)
[ "$HTTP" = "302" ] || [ "$HTTP" = "200" ] || exit 1
echo "✅ Checkpoint 2 PASSED"
// tests/e2e/buy-product.spec.ts
import { test, expect } from '@playwright/test';
test('User can buy a product', async ({ page }) => {
// 1. Открыть каталог
await page.goto('/catalog');
await expect(page).toHaveTitle(/Catalog/);
// 2. Открыть товар
await page.click('.product-card:first-child a');
await expect(page).toHaveURL(/\/product\/\d+/);
// 3. Добавить в корзину
await page.click('button:has-text("Add to cart")');
await expect(page.locator('.cart-block')).toContainText('1 item');
// 4. Перейти в корзину
await page.click('a:has-text("View Cart")');
await expect(page).toHaveURL('/cart');
// 5. Checkout
await page.click('a:has-text("Checkout")');
await expect(page).toHaveURL(/\/checkout/);
});
→ Чекпоинт 3: Advanced Features
Добавить продвинутые функции.
Результат: Фильтры, поиск, отзывы, wishlist, промокоды работают
ℹ️ Search API + Facets уже включены в ideal_shop_catalog (Чекпоинт 2).
SEO (Pathauto, Metatag, Sitemap) входит в Drupal CMS по умолчанию.
Здесь добавляем: отзывы, избранное, промокоды.
composer require drupal/fivestar
vendor/bin/drush recipe recipes/ideal_shop_reviews
vendor/bin/drush pm:list | grep fivestar
# Ожидаемый вывод: fivestar Enabled
# Проверить поле на product type
vendor/bin/drush field:info commerce_product default
# Должно быть поле field_rating
composer require drupal/commerce_wishlist
vendor/bin/drush recipe recipes/ideal_shop_wishlist
vendor/bin/drush pm:list | grep commerce_wishlist
# Ожидаемый вывод: commerce_wishlist Enabled
# Проверить роут wishlist
vendor/bin/drush router:debug | grep wishlist
# Должен быть маршрут /wishlist
# commerce_promotion входит в drupal/commerce
vendor/bin/drush recipe recipes/ideal_shop_promo
vendor/bin/drush pm:list | grep commerce_promotion
# Ожидаемый вывод: commerce_promotion Enabled
# Создать тестовый промокод
vendor/bin/drush php-eval "
\$promotion = \Drupal\commerce_promotion\Entity\Coupon::create([
'code' => 'TEST10',
'promotion_id' => 1,
]);
\$promotion->save();
echo 'Coupon created';
"
#!/bin/bash
# tests/checkpoint-3.sh
echo "🧪 Testing Checkpoint 3: Advanced Features"
# 1. Fivestar
drush pm:list | grep "fivestar.*Enabled" || exit 1
# 2. Wishlist
drush pm:list | grep "commerce_wishlist.*Enabled" || exit 1
# 3. Wishlist page
HTTP=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/wishlist)
[ "$HTTP" = "200" ] || [ "$HTTP" = "403" ] || exit 1
# 4. Promotions enabled
drush pm:list | grep "commerce_promotion.*Enabled" || exit 1
# 5. Промокод в checkout flow
drush php-eval "echo \Drupal::service('plugin.manager.commerce_checkout_pane')->hasDefinition('coupon_redemption') ? 'yes' : 'no';" | grep "yes" || exit 1
echo "✅ Checkpoint 3 PASSED"
Подготовить тему к production.
Результат: Все тесты проходят, документация готова
# Запустить сервер
vendor/bin/drush runserver 127.0.0.1:8080 &
# Lighthouse (нужен Node.js + lighthouse пакет)
npx lighthouse http://127.0.0.1:8080/ \
--only-categories=performance,accessibility,best-practices,seo \
--output=json --output-path=./lighthouse-report.json
# Проверить Lighthouse scores из JSON
node -e "
const r = require('./lighthouse-report.json');
const scores = r.categories;
const perf = Math.round(scores.performance.score * 100);
const a11y = Math.round(scores.accessibility.score * 100);
console.log('Performance:', perf, perf >= 85 ? '✅' : '❌');
console.log('Accessibility:', a11y, a11y >= 90 ? '✅' : '❌');
"
# PHP syntax check (нет npm build — Bootstrap Barrio подключает Bootstrap сам)
find web/themes/custom/ideal_theme -name "*.php" -o -name "*.theme" | \
xargs -I{} php -l {}
# Все файлы: No syntax errors
# YAML валидация
find web/themes/custom/ideal_theme -name "*.yml" | \
xargs -I{} php -r "yaml_parse(file_get_contents('{}'));"
./scripts/test-install.sh
# Успешно
./tests/test-deployment.sh
# Все варианты (Lite/Shop/Max) работают
./tests/test-matrix.sh
# Критические комбинации проходят
Чеклист:
Готово к production!
Следующие шаги:
1. Создать git tag
2. Опубликовать на Drupal.org
3. Создать демо-сайт
4. Написать статью
Версия: 2.1.0
Дата: 2026-03-24