# План 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-тестами. После каждого шага проверять запрещённые импорты: ```sh 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. Проверить чистое состояние тестов: ```sh 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` не менять. Проверка: ```sh 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`. Проверка: ```sh 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` и не дублировать структуры. Проверка после механического переноса: ```sh 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 ./...`, чтобы не осталось пустого/дублирующего пакета. Проверка: ```sh 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: ```sh 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 ./...` проходят.