165 lines
8.1 KiB
Markdown
165 lines
8.1 KiB
Markdown
# План 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 ./...` проходят.
|