Skip to content

11 Development and Testing

Mikhail Deynekin edited this page Oct 31, 2026 · 1 revision

11 · Разработка и тесты

Раскладка

fornex-control/
  index.php                  вход (он же точка входа `php -S`)
  backend/
    bootstrap.php            настройки → база → сервисы → маршруты; единственная сборка
    bin/fornex               CLI, те же сервисы
    config/defaults.php      значения по умолчанию
    config/routes.php        таблица маршрутов
    config/presets.json      пресеты и шаги мастера (данные, не код)
    src/Kernel/              настройки, env, запрос/ответ, роутер, сессия, журнал
    src/Fornex/              клиент API
    src/Service/             зона, планировщик, пресеты, проверка, NS, токены, аудит
    src/Http/                контроллеры и оболочка SPA
    src/Security/            вход и CSRF
    src/Cli/                 командная строка
  assets/                    css/js без сборки
  tests/plan_test.php        весь набор тестов
  tools/lint.php             синтаксис PHP и чистота файлов
  tools/secret-scan.php      поиск строк, похожих на учётные данные

Четыре проверки перед каждым изменением

php tools/lint.php
php tools/lint.php --text
php tests/plan_test.php
php tools/secret-scan.php

CI запускает ровно их плюс smoke-проверку сборки: FORNEX_API_KEY=ci-dummy … php backend/bin/fornex help — это доказывает, что приложение собирается без веб-сервера и без файла настроек.

Почему тесты именно такие

Набор проверяет правила, ошибка в которых молчит:

Правило Что сломается без теста
повторный пресет не копит дубли SPF/DMARC/DKIM permerror для всего домена
MX на ту же цель с другим приоритетом — это правка, а не вторая запись половина писем уходит мимо
слияние SPF сохраняет сторонний ip4:/include: письма сторонних сервисов перестают проходить
DMARC не ослабляется политика, выставленная человеком, тихо понижается
нормализация DKIM ключ, вставленный фрагментами, не становится валидной записью
статусы шагов done/todo/blocked/empty интерфейс выключает кнопку, которая должна работать

Каждая проверка печатает [ok] или [FAIL] с причиной, поэтому регрессия называет себя сама.

Куда относится изменение

Изменение Файл
Правило о дублях, слиянии SPF, политике DMARC backend/src/Service/ZonePlanner.php
Пресет или шаг мастера backend/config/presets.json, при новом типе поля — PresetService
Новый HTTP-маршрут backend/config/routes.php + контроллер
Новая команда CLI backend/src/Cli/Application.php + docs/CLI.md
Поведение интерфейса assets/js/app.js (один файл, hash-маршруты, без фреймворка)
Новая настройка defaults.php, Config::ENV_MAP, .env.example, docs/CONFIGURATION.md

Как добавить пресет

  1. Запись в presets.json: плоский пресет (records, params) или мастер (steps).
  2. Подстановки в значении: {domain}, {default_ip}, {param_key}.
  3. present_if превращает «запись уже в зоне» в статус done.
  4. confirm: true — только там, где значение заменяется.
  5. Тесты: пустая зона, повторный запуск, зона с чужим ip4: и строгим DMARC.
  6. Прогнать мастер на своей зоне и приложить к pull request план, а не результат применения.

Соглашения

  • PHP 8.5, declare(strict_types=1), классы final, один класс на файл, пространство имён повторяет каталог.
  • Комментарии и текст интерфейса — по-русски; идентификаторы, коммиты, документация и README — по-английски.
  • Зависимостей нет: библиотека на 200 строк не стоит цепочки обновлений.
  • Файлы: UTF-8 без BOM, LF, перевод строки в конце. .gitattributes объявляет, tools/lint.php проверяет.

Выпуск версии

  1. CHANGELOG.md: [Unreleased] → ## [X.Y.Z] - ГГГГ-ММ-ДД и ссылки сравнения.
  2. Поднять app.version в defaults.php и APP_VERSION в .env.example.
  3. Четыре проверки плюс живой прогон на своей зоне.
  4. Коммит, тег vX.Y.Z, push, релиз с разделом из changelog.

Clone this wiki locally