Перейти к основному содержимому

Портирование Laravel → Goravel

Цель портирования — сохранить внешний контракт и поведение действующего Laravel-сервиса в реализации на Go/Goravel. Проверять нужно HTTP, данные, фоновые процессы и наблюдаемые побочные эффекты: события, файлы, вызовы соседних сервисов и изменения кэша.

Создание каркаса и локальный запуск описаны в первом запуске Go-сервиса. Эта статья объясняет организацию переноса и критерии готовности. Рабочая последовательность, чек-листы этапов и форматы артефактов поддерживаются в Go-шаблоне:

Документ шаблонаНазначение
PORTING_LARAVEL_TO_GORAVEL.mdОбзор процесса и запуск работы
instructions/README.mdПорядок этапов, переходы, статусы и возобновление
PORTING_PROMPT.mdПолный prompt для одного обращения к агенту
instructions/referenceТехнические требования по контракту, данным, интеграциям, тестам и эксплуатации

Для конкретного переноса зафиксируйте commit шаблона и читайте инструкции из этого checkout-а. Ссылки выше ведут к развиваемой версии; результаты проверок должны быть привязаны к использованным исходникам и инструментам.

Источники требований и расхождения​

ИсточникЧто из него определять
Laravel-код, конфигурация и тестыБизнес-правила, валидация, casts, observers, транзакции, ошибки и эффекты
OpenAPI и зарегистрированные маршрутыМетод и URI, параметры, security, форматы запросов и ответов, статусы, пагинация
Реальные данные и сообщения из изолированных копийПредставления JSON, nullable-значений, дат, идентификаторов и payload, которые нужно продолжать читать
Общие guidelines Ensi и раздел Go/GoravelПравила платформы и принятые способы реализации на Go
Шаблон и .agents/skillsРабочий каркас, порядок действий и проверки конкретной задачи
Уже перенесённые сервисыПримеры реализации после проверки применимости к исходному поведению

Если OpenAPI, фактическое Laravel-поведение или общая рекомендация расходятся, зафиксируйте конкретные метод/URI, исходные файлы, наблюдаемый результат и затронутых потребителей. Согласуйте ожидаемое поведение с владельцем API. Изменение URI, статуса, nullable или формата события при портировании требует отдельного решения.

Утверждённые отличия исходного OpenAPI учитываются механизмом PORTING_CONTRACT_EXCEPTIONS.json: file, reason, reviewed_by, source_sha256, target_sha256. Хеши привязаны к полному содержимому исходного и целевого файлов; изменение файла требует пересмотра исключения. Подробности — в требованиях к контракту.

Подготовить исходные данные​

Определите три отдельные директории: Laravel-источник, checkout Go-шаблона и целевой Go-сервис. Зафиксируйте commit и состояние рабочего дерева источника, версию инструкций, исходный diff цели, версии генератора и зависимостей. Прочитайте применимые AGENTS.md и AGENTS.local.md, затем соответствующие задаче статьи Go-раздела.

Laravel и референсные сервисы во время переноса используются для чтения. Для проверок перехода БД нужны отдельные базы и обезличенная копия данных. Секретные значения env, ключи и исходные пользовательские данные не включают в планы и отчёты.

Переносите подсистемы, которыми пользуется исходный сервис. Отсутствие Kafka, очередей, scheduler, auth или собственной БД подтверждайте ссылками на изученные исходники. Для используемой подсистемы отдельно учитывайте поддерживаемые альтернативные драйверы: локальное CACHE_DRIVER=file само по себе не означает, что можно удалить поддержку Redis из другого профиля.

Инвентаризировать поведение​

На этапе 02 скрипт scripts/inventory-laravel.sh создаёт исходные PORTING_PLAN.md, PORTING_ENV.json и PORTING_COVERAGE.json. Он требует Python 3 и PyYAML из scripts/requirements-porting.txt; настройка отдельного Python-окружения описана в инструкции инвентаризации.

Список операций из OpenAPI дополните чтением маршрутов, providers, actions, requests, resources, queries, моделей, observers, listeners и тестов. Отдельно проверьте web/callback-маршруты и команды. Результатом должны стать следующие матрицы:

ОбластьЧто учитывать
HTTPВсе метод/URI, middleware, нормализация, ошибки, авторизация, JSON и другие media types
SearchКаждый filter, sort, include, defaults, pagination и граничные значения
Изменения данныхОтсутствующее поле, null, false, 0, пустые значения, вложенная валидация, переходы статусов и no-op
БДИтоговая схема, обязательные данные, связи, scopes, casts, sequences и существующие JSON/JSONB-представления
Observers и событияТриггер, изменённые поля, payload, ключ, headers, порядок, момент публикации и ошибки
HTTP-интеграцииВерсия клиента, URL, метод, параметры, headers, таймауты, повторы и обработка отказов
ФайлыДиски, ключи и права, metadata, upload/replacement/delete и состояние после частичной ошибки
Фоновые ролиConsumer, job, command и расписание: вход, регистрация, locks, retry/backoff и повторная обработка
ЭксплуатацияHTTP/worker/consumer/cron, логи, метрики, health, shutdown, поиск и настройки сборки/деплоя

Каждому элементу назначьте будущий Go-пакет, зависимости и проверку результата. Скрипт формирует заготовку: пустые ссылки на тесты и pending на этом этапе означают предстоящую работу. Повторный запуск с --force перезаписывает все три артефакта; при возобновлении обновляйте заполненные записи выборочно.

PORTING_COVERAGE.json проверяется относительно исходного OpenAPI. Маршруты вне OpenAPI учитывайте отдельно в плане и очереди, с эквивалентными ссылками на проверки.

Выполнять перенос по этапам​

Одно обращение к агенту выполняет один этап; на этапах 05, 06, 07 — одну заранее определённую единицу работы (UNIT). После проверок агент сохраняет результат и параметры следующего обращения. Переход к следующему этапу или unit выполняется новым запросом.

ЭтапРезультат и граница проверки
01. КаркасЦелевой проект, Git, локальное окружение и исходные результаты сборки и тестов
02. ИнвентаризацияПолная карта исходного поведения и очередь задач с зависимостями и критериями
03. Контракт и общий HTTP-слойСовместимые OpenAPI, генерация, маршрутизация, общая валидация и ошибки
04. КонфигурацияКарта env и регистрация используемых подключений и опубликованных клиентов
05. Данные, повторяемыйОдна группа таблиц, моделей, фабрик и обязательных данных: чистая БД, копия Laravel-БД, повтор и rollback
06. HTTP-ресурс, повторяемыйОдин ресурс или заранее выделенный сценарий вместе с валидацией, эффектами и компонентными тестами
07. Фоновый процесс, повторяемыйОдин consumer, job, command или сценарий расписания, включая ошибки и повторную обработку
08. Система и эксплуатацияПолные цепочки, переход всей БД, smoke, shutdown и репетиция runbook в выделенном окружении
09. ПриёмкаПолные проверки без пропусков, сверка доказательств и итоговый REPORT.md

Точные предпосылки и допустимые возвраты определяет файл этапа. Например, зависимость auth из этапа 03 может потребовать отдельного обращения к этапу 04, после которого нужно вернуться к проверкам HTTP-слоя.

Единица работы должна иметь устойчивый slug и проверяемую границу: группа связанных таблиц, один ресурс, PATCH со статусными переходами, отдельный consumer. Большой ресурс разделяют до начала реализации, сохраняя общий список его операций. Родительский ресурс остаётся незавершённым до проверки всей матрицы.

Ресурс переносится вместе с эффектами его операций: публикация producer, удаление файлов, внешние вызовы и observers проверяются на этапе 06. Этап 07 нужен для обработчиков фоновых входов и не заменяет проверки исходящих событий HTTP-операции.

Этапы 05–07 остаются in_progress, пока есть незавершённые units. При подтверждённом отсутствии собственной БД этап 05 отмечают not_applicable; при отсутствии фоновых ролей так отмечают этап 07. В остальных этапах неприменимые пункты обосновывают отдельно. Если обязательная зависимость не готова, запишите blocker, действие для его устранения и возврат к зависимым проверкам.

Запуск и возобновление агента​

Скопируйте полный PORTING_PROMPT.md из выбранного checkout-а шаблона и заполните параметры. Пример блока параметров:

LARAVEL_SOURCE: /path/to/laravel-service
TEMPLATE_SOURCE: /path/to/backend-service-skeleton-go
DESTINATION: /path/to/service-go
DOMAIN: example
SERVICE: service
APP_URL: http://example-service-go.ensi.127.0.0.1.nip.io
STAGE: next
UNIT:
REFERENCE_SERVICES: /path/to/cms-go, /path/to/catalog-cache-go, /path/to/oms-go

Это параметры prompt, а не shell-команда или отдельный CLI. Укажите только применимые референсы; целевой сервис исключите из REFERENCE_SERVICES.

Для нового переноса без сохранённого состояния STAGE: next выбирает 01. Затем он выбирает первый незавершённый этап с выполненными предпосылками, а для повторяемого этапа — первую готовую unit из очереди. Для явного выбора используйте, например:

STAGE: 06
UNIT: pages-patch

pages-patch — пример slug: он должен существовать в очереди и иметь выполненные зависимости. Явный номер этапа не разрешает пропустить его предпосылки.

Перед каждым продолжением агент читает git status, PORTING_PROGRESS.md, план, env/coverage и необходимые checkpoints. Существующий частичный порт оценивается по критериям этапов с сохранением кода, истории и решений; отсутствие старого checkpoint не доказывает успешного завершения этапа.

После неуспешной проверки продолжайте ту же unit с указанием причины и результата повторной проверки. Если для неё нужна отдельная зависимость, запишите задачу на соответствующий этап и выполните разрешённую подготовку отдельным обращением. Независимая работа возможна только в явно выбранных границах.

Изменение Laravel-исходника, шаблона, генератора или общего кода требует определить затронутые units и повторить их проверки. Историю checkpoints сохраняйте; прежний успех относится к прежнему состоянию исходников.

Артефакты целевого сервиса​

Результаты конкретного переноса сохраняются в DESTINATION, инструкции читаются из TEMPLATE_SOURCE. Локальные env-файлы содержат настройки окружения, а документы ниже — описания и доказательства без секретных значений.

АртефактНазначение
PORTING_PROGRESS.mdВерсии исходников, этапы, очередь units, зависимости, blockers и параметры следующего обращения
PORTING_PLAN.mdИнвентаризация и матрицы исходное поведение → реализация → проверка
PORTING_ENV.jsonПеременные и поддерживаемые профили, target, файлы и режимы сравнения; формат version: 1
PORTING_COVERAGE.jsonОперации OpenAPI и ссылки на конкретные успешные и ошибочные тесты с описанием assertions
PORTING_CONTRACT_EXCEPTIONS.jsonСогласованные отличия OpenAPI, если они есть; причина, автор решения и хеши
porting/checkpoints/<stage>[-<unit>].mdОбъём обращения, выполненные действия, проверки, доказательства и незавершённые пункты
porting/evidence/Обезличенные логи, схемы и сравнения, если нужны отдельные файлы
porting/RUNBOOK.mdПроверенный на этапе 08 порядок переключения и возврата HTTP и фоновых ролей
REPORT.mdИтоговый отчёт этапа 09, черновик которого создают после успешного check:generated

Progress и checkpoint оформляют по шаблонам. Их заполняет агент: скрипты не выбирают этапы и не проверяют автоматически каждый пункт Markdown-чек-листа.

Статусы и результаты проверок​

В PORTING_PROGRESS.md используются:

Статус этапа или unitЗначение
not_startedРабота не начата
in_progressЧасть действий или units выполнена
blockedНазванная зависимость не позволяет выполнить обязательный пункт
doneВсе применимые критерии выполнены и подтверждены
not_applicableПоведение отсутствует; изученные исходники и причина указаны

Результаты отдельных проверок записываются отдельно: passed, failed, not_run, not_applicable. Для последних трёх нужны причины. Эти статусы не следует переносить в JSON произвольным образом: например, карта env использует used, optional, unused, а первоначальный pending требует разрешения до приёмки.

Для команды указывайте рабочий каталог, дату, параметры без секретов, exit code и ссылку на лог при его наличии. Для теста — точный файл, Test...-символ и проверяемые поля, состояние БД и эффекты. Ручное сравнение обозначайте как ручное.

В PORTING_COVERAGE.json у каждой операции есть method, path, operation_id, массивы success и errors. Элемент массива содержит file, symbol, assertions. Текущий validator требует оба массива непустыми и не поддерживает исключение для пустого errors. Если содержательного ошибочного сценария нет, требуется отдельное решение о политике проверки; фиктивная ссылка на тест не подтверждает покрытие. Формат и пример — в требованиях к тестам.

Проверять совместимость в границах этапа​

Все Go- и Artisan-команды выполняются через elc, тесты — с .env.testing. Пакеты выбираются по проверяемой unit. Полный запуск обязателен на системном этапе; промежуточные generated-заготовки других ресурсов учитываются как предстоящая работа.

ПроверкаЧто она подтверждает
check:openapiТекущая спецификация проходит настроенный lint
Семантическое сравнение контракта с LaravelОтличия деревьев исходной и целевой спецификаций учтены
check:generatedПовторная генерация не меняет файлы
Компонентный тест HTTP/action/consumer/commandНаблюдаемое поведение сценария при заданных данных и контролируемых зависимостях
Переход БД на изолированной копииПрименение миграций и сохранность проверенных схем и данных
Smoke, системные сценарии и репетиция runbookРабота проверенных цепочек и эксплуатационных шагов в выделенном окружении

Lint и компиляция не доказывают совместимость с Laravel. Fake подтверждает взаимодействие приложения с подменой; доставку через реальный брокер или совместимость живого upstream проверяют отдельно, когда это требуется сценарием. Тестовые сообщения и изменяющие запросы направляйте в выделенные окружения.

Особенно проверяйте:

  • исходные method/URI, включая /{id}:action, формат и статусы ошибок, middleware и доступ;
  • missing/null/false/zero, очистку ранее заполненных nullable-полей и вложенные FormRequest rules;
  • полный набор filters/sorts/includes, точный порядок, pagination и границы дат;
  • фактические Laravel casts/resources, legacy JSONB, даты, enum и пустые массивы;
  • транзакции, observers, каскадные эффекты, no-op и поведение после частичного отказа;
  • payload, key, headers, момент публикации, повторную доставку и восстановление;
  • подключение общего Kafka teardown во всех component-suites: базовый вызов из переопределённых hooks, t.Cleanup(s.TearDownTest) после ручного setup и отсутствие непроверенных сообщений;
  • файлы, входные/исходящие HTTP-вызовы, их количество, параметры и ошибки.

Для SQL-фикстур используйте CreateQuietly, если не проверяются model events подготовки. События операции проверяйте через AssertKafkaMessages и assertions содержимого; ConfirmKafkaMessages не заменяет проверки, а ResetKafka допустим после проверки завершённой фазы. У gateway без собственной БД сохраняйте его вариант ComponentSuite без PostgreSQL runner. Подробности — в автотестах.

Файлы, полностью принадлежащие генератору, меняют через resources/openapi, конфигурацию и elc ensi-gog server. Handler и тестовые заготовки дополняют в предусмотренных точках расширения. Удаление тестов с TODO не завершает перенос. SQL-транзакция не делает публикацию Kafka, внешний HTTP-вызов или операцию storage атомарными; сохраняйте исходные гарантии и проверяйте состояния после отказов.

Выбирать скилл по задаче​

Скиллы находятся в .agents/skills шаблона и целевого сервиса. Перед применением читайте его локальный SKILL.md вместе с правилами репозитория; проверьте наличие нужных helper-ов и версий. Ссылки ниже ведут к реализации в Go-шаблоне.

СкиллКогда применять
goravel-developmentBootstrap, providers, facades, ORM, команды и особенности установленного Goravel
add-sql-search-resourceДобавление SQL-ресурса и :search через миграцию, модель, query, action, mapper и handler
review-search-contractАудит согласованности OpenAPI, схемы, ORM, query, mapper и тестов существующего search
test-search-endpointПолная матрица HTTP search-тестов с PostgreSQL: filter, sort, include, pagination и изоляция
implement-api-mutationCreate/PATCH/delete, presence, валидация, переходы состояний, транзакции и эффекты
implement-http-client-integrationИсходящий вызов через клиент, конфигурацию и provider, context, ошибки и controlled tests
implement-file-storage-operationЗагрузка, привязка, замена и удаление файлов, metadata, ownership и компенсация
implement-kafka-model-eventТипизированный consumer события модели, синхронизация либо обновление существующей записи
publish-kafka-model-eventИсходящие model events, dirty, сериализация, ключи, headers и граница SQL/доставки
test-component-behaviorКомпонентные проверки mutations, actions, команд и событий с реальной БД и контролируемыми эффектами

Скилл дополняет выбранный этап и не расширяет его объём. Например, при переносе PATCH могут понадобиться mutation, publication и component-testing скиллы, если этот PATCH действительно публикует событие. Для :search этап 06 требует test-search-endpoint, для реализации на Goravel — goravel-development; остальные выбирайте по фактическим границам сценария.

Критерии готовности и финальная приёмка​

Порт готов после этапа 09, когда:

  • все действующие операции, таблицы, интеграции и фоновые процессы из инвентаризации реализованы и проверены; неприменимые подсистемы обоснованы по исходникам;
  • контракт и согласованные отличия сверены, генерация воспроизводится;
  • реальные success/error-тесты проверяют JSON, состояние и эффекты, а сгенерированные заготовки завершены или обоснованно сопоставлены с заменой;
  • переход используемой БД проверен на чистой базе и Laravel-копии, включая повтор и rollback на одноразовой копии;
  • полный набор тестов, стандартные проверки, системные сценарии и smoke пройдены;
  • роли процесса, наблюдаемость и восстановление подтверждены, porting/RUNBOOK.md прошёл репетицию;
  • итоговые progress, coverage, checkpoints и REPORT.md соответствуют текущему коду.

В этапе 09 после успешного elc mise run check:generated подготовьте черновик REPORT.md, затем выполните финальный контроль. Для shell-команд задайте реальные абсолютные пути — параметры prompt автоматически не создают переменные окружения:

LARAVEL_SOURCE=/path/to/laravel-service
DESTINATION=/path/to/service-go
cd "$DESTINATION"
LARAVEL_SOURCE="$LARAVEL_SOURCE" ./scripts/check-porting.sh --with-db

--with-db требует исполняемый scripts/check-porting-db.sh, реализованный для этого сервиса. Он проверяет изолированные базы; шаблонная проверка регистрации миграций его не заменяет. Для сервиса без собственной БД вместо последней команды используйте подтверждённое обоснование:

LARAVEL_SOURCE="$LARAVEL_SOURCE" ./scripts/check-porting.sh \
--no-database "Service has no database; source references are recorded in PORTING_PLAN.md"
Exit code check-porting.shРезультат
0Автоматические обязательные проверки прошли без пропусков; требуется также сверка ручных пунктов и assertions
1Проверка завершилась ошибкой
2Некорректные аргументы
3Выполнена только часть проверок из-за пропусков

Без явного режима проверки БД скрипт по умолчанию пропускает переход БД и возвращает частичный результат при успехе остальных проверок. Флаги --skip-go, --skip-tests, --skip-db пригодны для диагностики, но не подтверждают завершение. Полный check-porting.sh предназначен для этапа 09; на промежуточном этапе он ожидаемо обнаруживает незавершённую работу.

После контроля дополните REPORT.md фактическими результатами: что сохранено, какие изменения согласованы, что потребовало ручного переноса, какие подсистемы не используются, какие проверки выполнены и какие ограничения остались. Невыполненный обязательный критерий оставляет этап незавершённым.

Сосуществование Laravel и Go​

На этапе 08 подготовьте и отрепетируйте runbook переключения: HTTP-трафик и общая БД, Kafka groups/offsets, накопленные PHP jobs, Redis formats/prefixes/TTL/locks, файлы и поисковые индексы. Определите порядок остановки старых фоновых ролей, исключение двойного выполнения, условия возврата к Laravel и ответственных за действия.