Files
agents/GO-002-plan.md
T
2026-10-02 23:43:38 +07:00

8.1 KiB
Raw Blame History

План GO-002: разорвать зависимости modules от repos и services

Цель

Технические modules не импортируют прикладные services и storage repos. Модуль получает собственные входные типы, а преобразование repository-моделей делается на границе service.

Не меняем:

  • protobuf/API и сгенерированные файлы;
  • формат scenario.json, ZIP-архива и публичные ответы;
  • бизнес-правила и SQL;
  • internal/modules/storytelling, пока он не импортирует repos/services;
  • GO-006 (*_utils) и GO-003 (единый error mapping).

Фактические нарушения

Module Нарушение Callers
modules/game_model импортирует repos и services/scenarios_service game, gameplay, answer, team, MCP, app
modules/scenario_archive Pack принимает *repos.Scenario scenarios_service, module tests
modules/scenario_archive импортирует repos только для storage-модели только archive implementation

Правило миграции

Каждый кусок заканчивается рабочим компилятором и targeted-тестами. После каждого шага проверять запрещённые импорты:

cd evening_detective_server
rg -n '"evening_detective_server/internal/(repos|services)' internal/modules --glob '*.go' --glob '!*_test.go'
go test ./internal/modules/... ./internal/services/...

Маленькие этапы

GO-002.0 — зафиксировать baseline

  1. Сохранить список runtime-файлов с нарушениями: modules/game_model/game.go, game_mapper.go, team_mapper.go и modules/scenario_archive/interface.go/archive.go.

  2. Проверить чистое состояние тестов:

    GOCACHE=/tmp/evening-detective-go-cache go test ./internal/modules/... ./internal/services/...
    
  3. Не менять callers и не создавать common, domain или utils только для обхода импортов.

Готово, если baseline проходит и список зависимостей зафиксирован.

GO-002.1 — выделить собственный входной тип archive module

Файлы: internal/modules/scenario_archive/interface.go, archive.go и archive_test.go.

  1. Добавить в module небольшой тип входа для упаковки архива, содержащий только нужные поля: Name, Description, Image и сериализованную Story.
  2. Изменить IScenarioArchive.Pack так, чтобы он принимал этот тип, а не *repos.Scenario.
  3. В implementation заменить обращения к scenario.Scenario, scenario.Description и другим полям на поля нового типа.
  4. Перевести module tests на новый тип. Формат ScenarioJSON не менять.

Проверка:

cd evening_detective_server
find internal/modules/scenario_archive -name '*.go' -print0 | xargs -0 gofmt -w
go test ./internal/modules/scenario_archive
! rg 'internal/repos' internal/modules/scenario_archive --glob '*.go'

Ожидаемый результат: archive module полностью независим от storage package.

GO-002.2 — сделать mapping repository → archive в scenarios service

Файлы: internal/services/scenarios_service/service.go, mapper и тесты.

  1. В scenarios_service собрать новый archive input из уже полученного *repos.Scenario.
  2. Передавать его в scenarioArchive.Pack; repository-зависимость остаётся только в service, где ей место.
  3. Не переносить в module права, запросы, storage и protobuf.
  4. Сохранить поведение изображений, nil-описания и ссылок на story.
  5. Добавить/обновить один round-trip тест DownloadArchive → UploadArchive.

Проверка:

cd evening_detective_server
go test ./internal/services/scenarios_service ./internal/modules/scenario_archive
! rg 'internal/repos' internal/modules/scenario_archive --glob '*.go'

GO-002.3 — отделить game model от modules

Файлы: текущий internal/modules/game_model/* и callers.

  1. Переместить типы Game и Team в пакет с той же предметной ответственностью под internal/services/game_model.
  2. Сохранить имена типов и поля, чтобы это была механическая смена import path, а не новая модель или DTO.
  3. Перенести вместе с типами текущие MapGame, MapGames, MapTeam, MapTeams; они являются преобразованием storage-моделей в use-case-модели.
  4. Обновить callers в game_service, gameplay_service, answer_service, team_service, mcp_service, app и тестах.
  5. Не делать пакет common и не дублировать структуры.

Проверка после механического переноса:

cd evening_detective_server
find internal/services/game_model internal/services/game_service internal/services/gameplay_service internal/services/answer_service internal/services/team_service internal/services/mcp_service internal/app -name '*.go' -print0 | xargs -0 gofmt -w
go test ./internal/services/game_model ./internal/services/game_service ./internal/services/gameplay_service ./internal/services/answer_service ./internal/services/team_service ./internal/services/mcp_service ./internal/app
! rg 'internal/modules/game_model' --glob '*.go'

GO-002.4 — удалить старый module game_model

  1. После успешного переноса убедиться, что internal/modules/game_model больше не импортируется и не нужен через тесты.
  2. Удалить только старые файлы package; новые копии не оставлять параллельно.
  3. Проверить go list ./..., чтобы не осталось пустого/дублирующего пакета.

Проверка:

cd evening_detective_server
go list ./...
go test ./...
! test -d internal/modules/game_model

GO-002.5 — финальная проверка направления зависимостей

  1. Runtime modules не импортируют internal/repos, internal/services или internal/app.

  2. scenario_archive принимает только собственные типы и callbacks; SQL, права и storage остаются снаружи.

  3. cmd по-прежнему собирает concrete repositories/modules/services.

  4. Проверить, что сценарный архив и game/team responses побайтно/структурно не изменились в существующих тестах.

  5. Запустить финальный gate:

    cd evening_detective_server
    find internal -type f -name '*.go' -print0 | xargs -0 gofmt -l
    go vet ./...
    go test ./...
    
  6. Только после успешного полного gate отметить GO-002 как DONE в todo.md.

Критерий готовности GO-002

  • rg 'internal/(repos|services)' internal/modules --glob '*.go' --glob '!*_test.go' не находит runtime-импортов.
  • Нет дубликатов Game, Team или archive input model.
  • Все callers используют один пакет services/game_model.
  • ZIP/scenario.json, game/team responses и существующие error semantics не изменились.
  • gofmt, go vet ./... и go test ./... проходят.