Symfony — первая программа
Для читателей, которые знают основы PHP (первая программа, синтаксис) и Composer. Symfony — компонентный фреймворк для веб-приложений и API: маршруты, DI-контейнер (Dependency Injection), Twig, явная конфигурация YAML и PHP-атрибутов.
Расширенный разбор с Lab-плеем — в 1441.md; здесь — пошаговый маршрут от нуля до HTML-страницы, JSON API и сервиса с DI.
| Шаг | Тема | Зачем |
|---|---|---|
| 1 | Требования и CLI | Проверить PHP и Composer |
| 2 | symfony new | Каркас проекта |
| 3 | Контроллер и маршрут | URL → Response |
| 4 | Twig | HTML-шаблон |
| 5 | JSON API | REST для фронта |
| 6 | Сервис и DI | Логика вне контроллера |
| 7 | Env и отладка | Конфиг и типичные ошибки |
| Термин | Значение |
|---|---|
| Kernel | Ядро: загрузка бандлов, обработка запроса |
| Controller | Класс, возвращающий Response |
| Route | Сопоставление URL → контроллер |
| Twig | Шаблонизатор {{ variable }} |
| DI | Зависимости через конструктор автоматически |
| Bundle | Пакет функций (Framework, Twig, Security) |
Обзор экосистемы — Symfony, фреймворки PHP.
Symfony CLI поднимает локальный HTTPS-сервер с одной командой. Логи запросов видны в терминале — удобно при первой отладке маршрутов.
Шаг 1 — требования
| Компонент | Версия |
|---|---|
| PHP | 8.2+ |
| Composer | 2.x |
| Symfony CLI | Рекомендуется (symfony.com/download) |
| Расширения PHP | ctype, iconv, json, mbstring |
Проверка:
php -v
composer -V
symfony -v
Локальный сервер и Docker — 113 локальная среда.
Шаг 2 — создать проект
symfony new hello-symfony --webapp
cd hello-symfony
composer install
symfony server:start
Откройте https://127.0.0.1:8000 — welcome-страница Symfony. CLI выдаёт URL и предупреждение о self-signed сертификате — для локальной разработки это нормально.
Структура:
hello-symfony/
bin/console ← CLI Symfony (миграции, cache, debug)
config/ ← routes, services, packages
public/index.php ← единственная точка входа для веба
src/Controller/ ← ваши контроллеры
templates/ ← Twig
var/ ← cache, logs (не коммитить)
vendor/ ← Composer deps
composer.json
.env
| Каталог | Назначение |
|---|---|
public/ | Document root — наружу только он |
src/ | PHP-код приложения (PSR-4 App\) |
config/ | Маршруты, сервисы, пакеты |
templates/ | Twig-шаблоны |
var/ | Кэш и логи |
vendor/ | Зависимости Composer |
Поток запроса:
HTTP → public/index.php → Kernel → Router → Controller → Response
HTTP и маршруты, веб-разработка.
Шаг 3 — контроллер и маршрут
Создайте src/Controller/HelloController.php:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class HelloController extends AbstractController
{
#[Route('/hello/{name}', name: 'app_hello', methods: ['GET'])]
public function hello(string $name): Response
{
return $this->render('hello/index.html.twig', [
'name' => $name,
]);
}
#[Route('/api/hello', name: 'api_hello', methods: ['GET'])]
public function apiHello(): JsonResponse
{
return $this->json(['message' => 'Hello from Symfony API']);
}
}
Разбор:
#[Route(...)]— PHP 8 атрибут вместо YAML-маршрута вconfig/routes.yaml.{name}в path автоматически попадает в аргумент$name(param converter по типу).$this->render()— Twig-ответ с массивом переменных.$this->json()— JSON с правильнымContent-Type.
Список маршрутов:
symfony console debug:router
| Имя | Метод | Путь |
|---|---|---|
app_hello | GET | /hello/{name} |
api_hello | GET | /api/hello |
Шаг 4 — шаблон Twig
templates/hello/index.html.twig:
{% extends 'base.html.twig' %}
{% block title %}Привет{% endblock %}
{% block body %}
<h1>Привет, {{ name|e }}!</h1>
<p>Маршрут: {{ path('app_hello', { name: name }) }}</p>
{% endblock %}
| Конструкция | Назначение |
|---|---|
{% extends %} | Наследование layout из base.html.twig |
{{ name|e }} | Вывод с экранированием HTML (XSS) |
{% block %} | Переопределяемые области |
path('app_hello', ...) | URL по имени маршрута |
Шаблонизаторы — Twig / Blade, HTML.
Шаг 5 — проверка
| URL | Ожидаемый результат |
|---|---|
/hello/World | HTML "Привет, World!" |
/hello/<script> | Экранированный текст (без XSS) |
/api/hello | {"message":"Hello from Symfony API"} |
curl -k https://127.0.0.1:8000/api/hello
curl -k https://127.0.0.1:8000/hello/ Symfony
Флаг -k — игнорировать self-signed сертификат локального сервера.
Шаг 6 — сервис и DI
Логику приветствия выносят в сервис — контроллер остаётся тонким.
src/Service/GreetingService.php:
<?php
namespace App\Service;
final class GreetingService
{
public function greet(string $name): string
{
$trimmed = trim($name);
return $trimmed === '' ? 'Гость' : $trimmed;
}
public function formatMessage(string $name): string
{
return sprintf('Привет, %s!', $this->greet($name));
}
}
Контроллер с внедрением зависимости:
final class HelloController extends AbstractController
{
public function __construct(
private readonly GreetingService $greetingService,
) {}
#[Route('/hello/{name}', name: 'app_hello', methods: ['GET'])]
public function hello(string $name): Response
{
return $this->render('hello/index.html.twig', [
'name' => $this->greetingService->greet($name),
]);
}
}
Symfony autowire создаст GreetingService и передаст в конструктор — см. ООП в PHP.
Проверка контейнера:
symfony console debug:container GreetingService
| Понятие | Смысл |
|---|---|
| Service | Класс в src/, регистрируется автоматически |
| Autowire | Symfony подставляет зависимости по типам |
| Autoconfigure | Теги для event subscriber, command и т.д. |
Шаг 7 — переменные окружения
.env (коммитится с placeholder-значениями):
APP_ENV=dev
APP_SECRET=change_me_in_production
Локальные секреты — .env.local (в .gitignore):
APP_SECRET=local_random_string_here
config/services.yaml по умолчанию включает autowire для всего src/. Секреты в prod — через реальные env на сервере, не в git.
Шаг 8 — форма POST (расширение)
Для закрепления данных со страницы добавьте Form Type:
symfony console make:form HelloType
Форма с CSRF защитой отправляет POST на тот же или отдельный маршрут. Symfony генерирует токен — без него форма отклоняется.
Типичные ошибки
| Симптом | Причина | Решение |
|---|---|---|
| 404 на маршрут | Опечатка в path или namespace | debug:router, класс в App\Controller |
| Twig not found | Неверный путь шаблона | templates/hello/index.html.twig |
| Class not found | Autoload не обновлён | composer dump-autoload |
| 500 APP_SECRET | Пустой secret | .env.local с APP_SECRET |
| Белый экран prod | APP_ENV=prod, cache | symfony console cache:clear |
| JSON без CORS | Браузерный фронт на другом порту | NelmioCorsBundle или proxy |
Как превратить учебный проект в API-сервис
План эволюции
- Контроллеры + JSON (
$this->json()). - Doctrine + SQLite/PostgreSQL — 1432.
- Валидация входных DTO (Symfony Validator).
- Тесты PHPUnit + WebTestCase.
- Deploy за Nginx + PHP-FPM.
Базовые контракты API
| Эндпоинт | Успех | Ошибка клиента |
|---|---|---|
GET /api/hello | 200 + JSON | 405 неверный метод |
POST /api/items | 201 + объект | 400 validation |
GET /api/items/{id} | 200 | 404 |
Связанные материалы
| Тема | Материал |
|---|---|
| Развёрнутая первая программа | 1441 + Lab play |
| Справочник Symfony | 1442 |
| Doctrine / БД | 1432 |
| Laravel (другой стиль) | 1431 |
| WordPress (CMS) | 164 |
Добавьте Form Type с CSRF для POST /hello — закрепите данные со страницы и валидацию. Затем вынесите обработку в GreetingService и покройте unit-тестом.
На боевом сервере — APP_ENV=prod, OPcache, HTTPS за reverse proxy, секреты только в env. Document root — только каталог public/.
Шаг 9 — кэш и окружения Symfony
symfony console cache:clear
symfony console cache:warmup
symfony console about
APP_ENV | Поведение |
|---|---|
dev | Profiler, подробные ошибки |
prod | Кэш compiled, без debug |
test | PHPUnit, mock services |
Переключение:
symfony console debug:config framework
Шаг 10 — PHPUnit smoke test
composer require --dev symfony/test-pack
tests/Controller/HelloControllerTest.php:
<?php
namespace App\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
final class HelloControllerTest extends WebTestCase
{
public function testApiHello(): void
{
$client = static::createClient();
$client->request('GET', '/api/hello');
self::assertResponseIsSuccessful();
self::assertJsonStringEqualsJsonString(
'{"message":"Hello from Symfony API"}',
$client->getResponse()->getContent()
);
}
}
symfony console phpunit
# или
./bin/phpunit
Маршрутизация YAML (альтернатива атрибутам)
config/routes.yaml:
controllers:
resource: ../src/Controller/
type: attribute
Legacy проекты могут использовать анnotations или YAML per route — атрибуты PHP 8 предпочтительны для новых контроллеров.
Event Subscriber (расширение)
<?php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
final class RequestLogSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [KernelEvents::REQUEST => 'onRequest'];
}
public function onRequest(RequestEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
// логирование URI — учебный пример
}
}
Autoconfigure регистрирует subscriber автоматически.
Навигация по блоку PHP / Symfony
- Вы здесь: 163 — первая программа Symfony
- PHP база: 13 — первая программа PHP
- Composer: 111
- Обзор: 144 Symfony
- WordPress CMS: 164
Шаг 11 — валидация JSON API
composer require symfony/validator
DTO с constraints — 151 данные со страницы. Возвращайте 422 при validation errors через Problem+json или свой формат.
Шаг 12 — Makefile для команды
install:
composer install
symfony console cache:clear
test:
symfony console phpunit
serve:
symfony server:start
Шаг 13 — структура src для роста
src/
Controller/
Service/
Repository/
Entity/ # после Doctrine
DTO/
Thin controllers — логика в Service; persistence в Repository.
Symfony и Laravel — краткое сравнение
| Symfony | Laravel | |
|---|---|---|
| Философия | components, explicit | conventions, batteries |
| Config | YAML + PHP attributes | .env + facades |
| Learning | круче для enterprise | быстрее старт |
Сравнение первых шагов — Laravel 1431.
Шаг 9 — консольные команды Symfony
Symfony CLI и bin/console — не только веб. Учебная команда приветствия:
symfony console make:command app:greet
src/Command/GreetCommand.php:
<?php
namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
#[AsCommand(name: 'app:greet', description: 'Печатает приветствие')]
final class GreetCommand extends Command
{
protected function configure(): void
{
$this->addArgument('name', InputArgument::OPTIONAL, 'Имя', 'мир');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$name = (string) $input->getArgument('name');
$output->writeln(sprintf('Привет, %s!', $name));
return Command::SUCCESS;
}
}
Запуск:
symfony console app:greet Symfony
symfony console list
Разбор:
#[AsCommand]регистрирует команду без ручного YAML.- Код возврата
Command::SUCCESS— 0, ошибка —Command::FAILURE. debug:container,cache:clear,router:match /hello/World— диагностика без браузера.
Шаг 10 — тесты WebTestCase
Установите тестовый пакет (если не в --webapp):
composer require --dev symfony/test-pack
tests/Controller/HelloControllerTest.php:
<?php
namespace App\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
final class HelloControllerTest extends WebTestCase
{
public function testApiHelloReturnsJson(): void
{
$client = static::createClient();
$client->request('GET', '/api/hello');
$this->assertResponseIsSuccessful();
$this->assertJson($client->getResponse()->getContent());
$data = json_decode($client->getResponse()->getContent(), true);
$this->assertSame('Hello from Symfony API', $data['message']);
}
}
symfony console doctrine:database:create --if-not-exists # если подключена БД
./vendor/bin/phpunit
WebTestCase поднимает kernel in-process — быстрее, чем curl в CI. Unit-тест GreetingService без HTTP — обычный PHPUnit с new GreetingService().
Шаг 11 — маршрутизация YAML и атрибуты
Два стиля сосуществуют. Атрибуты на классе (как выше) — предпочтительны в новых проектах. Альтернатива в config/routes.yaml:
controllers:
resource:
path: ../src/Controller/
namespace: App\Controller
type: attribute
Префикс API для группы контроллеров:
#[Route('/api', name: 'api_')]
final class NoteApiController extends AbstractController
{
#[Route('/notes', name: 'notes_list', methods: ['GET'])]
public function list(): JsonResponse
{
return $this->json(['items' => []]);
}
}
Имя маршрута api_notes_list — генерация URL в Twig: path('api_notes_list').
Шаг 12 — валидация входных данных
DTO с Symfony Validator:
<?php
namespace App\Dto;
use Symfony\Component\Validator\Constraints as Assert;
final class CreateNoteRequest
{
public function __construct(
#[Assert\NotBlank(message: 'text обязателен')]
#[Assert\Length(max: 500)]
public readonly string $text,
) {}
}
В контроллере — #[MapRequestPayload] (Symfony 6.3+) или ручной $validator->validate($dto). Ошибки — 422 Unprocessable Entity с массивом полей. Теория HTTP-кодов — REST API.
Работа в PhpStorm и VS Code
| IDE | Настройка |
|---|---|
| PhpStorm | Open Directory, включить Symfony plugin, PHP 8.2 interpreter |
| VS Code | PHP Intelephense + Symfony extension, path to php |
Xdebug — breakpoint в HelloController::hello, запуск symfony server:start с XDEBUG_MODE=debug. Подробнее — отладка.
Symfony и Laravel — ориентиры выбора
| Критерий | Symfony | Laravel |
|---|---|---|
| Философия | Компоненты, явная конфигурация | Convention over configuration |
| ORM | Doctrine (отдельная кривая) | Eloquent (проще старт) |
| Экосистема | Enterprise EU, API Platform | Стартапы, быстрый MVP |
| Обучение | Больше концепций сразу | Меньше порог для CRUD |
Оба — зрелые PHP-фреймворки. Symfony выбирают за модульность и долгоживущие enterprise-проекты; Laravel — за скорость прототипирования — Laravel 1431.
Расширенный troubleshooting
| Симптом | Причина | Решение |
|---|---|---|
| 500 после deploy | Нет composer install --no-dev | Prod deps и APP_ENV=prod |
| Маршрут не в списке | Кэш prod | bin/console cache:clear --env=prod |
| Twig syntax error | Незакрытый block | Проверить {% endblock %} |
| CSRF invalid | Сессия истекла | Обновить страницу формы |
| Permission denied var/ | Права на cache/logs | chmod -R u+w var/ на сервере |
| Autowire fail | Интерфейс без binding | Явный alias в services.yaml |
Логи: var/log/dev.log в dev, Monolog в prod — логирование.
Дополнительные упражнения
- Добавьте
POST /api/notesс валидациейCreateNoteRequestи ответом 201. - Напишите
GreetingServiceTest— unit без kernel. - Создайте
app:notes:export— вывод списка заметок в JSON в stdout. - Подключите
nelmio/api-doc-bundle— Swagger UI для API. - Docker Compose: PHP-FPM + Nginx + PostgreSQL — healthcheck на
/api/hello.
Расширенный FAQ
Нужен ли Apache?
Нет. symfony server или Nginx + PHP-FPM достаточно. Document root — только public/.
Можно ли API без Twig?
Да. Создайте проект --version=7.0 с минимальным набором или удалите Twig — останутся контроллеры и JSON.
Где Doctrine?
Отдельная глава 1432. Для первой программы достаточно in-memory или SQLite.
Symfony Flex что делает?
Recipes автоматически добавляют конфиг при composer require — не пугайтесь новых файлов в config/.
Как версионировать API?
Префикс /api/v1/ в #[Route] или отдельный namespace контроллеров.
FAQ — полный список
1. Нужен ли Apache?
symfony server или Nginx + PHP-FPM. Document root — public/.
2. API без Twig?
Да — минимальный набор или только JSON controllers.
3. Doctrine где?
1432. Для первой программы — in-memory или SQLite.
4. Symfony Flex?
Recipes при composer require — автоконfig.
5. Версионирование API?
Префикс /api/v1/ в Route.
6. APP_SECRET?
.env.local — не в git.
7. Autowire fail?
Явный alias в services.yaml для интерфейсов.
8. WebTestCase vs unit?
WebTestCase — HTTP in-process. Unit — без kernel.
9. Laravel или Symfony?
Symfony — enterprise модульность. Laravel — быстрый MVP 1431.
10. Form CSRF?
Symfony генерирует токен автоматически.
11. Xdebug?
12. Production cache?
APP_ENV=prod, cache:clear, OPcache.
13. CORS для SPA?
NelmioCorsBundle или proxy.
14. make:command?
Консольные задачи через bin/console.
15. Validator DTO?
MapRequestPayload или ручной validate — 422.
16. WordPress рядом?
CMS vs framework — 164.
17. HTTP коды?
Упражнения — расширенный набор
- POST /api/notes с CreateNoteRequest и 201.
- GreetingServiceTest unit.
- app:notes:export command.
- Swagger nelmio/api-doc-bundle.
- Docker Compose PHP-FPM + Nginx + PostgreSQL.
- Form Type с CSRF POST /hello.
- debug:router и router:match.
- PHPUnit WebTestCase api/hello.
- GreetingService в DI — debug:container.
- Production checklist в README.
Практикум — дополнительный блок 1 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 1
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 1"
Практикум — дополнительный блок 2 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 2
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 2"
Практикум — дополнительный блок 3 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 3
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 3"
Практикум — дополнительный блок 4 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 4
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 4"
Практикум — дополнительный блок 5 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 5
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 5"
Практикум — дополнительный блок 6 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 6
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 6"
Практикум — дополнительный блок 7 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 7
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 7"
Практикум — дополнительный блок 8 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 8
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 8"
Практикум — дополнительный блок 9 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 9
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 9"
Практикум — дополнительный блок 10 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 10
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 10"
Практикум — дополнительный блок 11 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 11
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 11"
Практикум — дополнительный блок 12 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 12
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 12"
Практикум — дополнительный блок 13 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 13
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 13"
Практикум — дополнительный блок 14 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 14
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 14"
Практикум — дополнительный блок 15 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 15
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 15"
Практикум — дополнительный блок 16 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 16
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 16"
Практикум — дополнительный блок 17 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 17
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 17"
Практикум — дополнительный блок 18 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 18
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 18"
Практикум — дополнительный блок 19 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 19
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 19"
Практикум — дополнительный блок 20 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 20
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 20"
Практикум — дополнительный блок 21 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 21
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 21"
Практикум — дополнительный блок 22 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 22
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 22"
Практикум — дополнительный блок 23 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 23
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 23"
Практикум — дополнительный блок 24 (163)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 24
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (163)
echo "Smoke block 24"