Files
agents/GO-001-plan.md
T
2026-10-02 23:32:30 +07:00

218 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# План GO-001: убрать прямые зависимости handler-ов от repos и modules
## Цель
`internal/app` принимает transport-вход, извлекает пользователя и параметры,
вызывает прикладной service и преобразует результат в protobuf/HTTP. Handler не
импортирует repository и не владеет прикладной операцией.
Не трогаем в этой задаче:
- `proto/`, API-контракт и protobuf-генерацию;
- wiring в `cmd`, где repositories и modules должны собираться;
- `roles` и `processor_jwt`, если они используются только для извлечения
identity/проверки transport-доступа;
- единое исправление `err.Error()` во всех handler-ах — это GO-003.
## Текущие точки нарушения
| Участок | Прямые зависимости app | Что оставить в app | Что должно уйти в service |
| --- | --- | --- | --- |
| `app/team_registration.go` | `teams_repo` | HTTP/JSON, auth token, timeout | смысл ошибок регистрации |
| `app/team_qr.go` | `games_repo`, `team_qr_pdf` | auth, headers, `HttpBody` | ошибки игры и PDF |
| `app/users.go` | `users_repo` | claims, metadata, transport auth | ошибка отсутствующего пользователя |
| `app/scenario_archive.go` | `scenarios_repo`, archive/string modules | auth, ZIP headers, `HttpBody` | лимиты/ошибки сценарного архива |
| `app/files.go` | `file_storage` | auth, headers, `HttpBody` | ошибка отсутствующего файла |
| mapper-ы app | `game_model`, `formatter_utils` | protobuf mapping | модели и преобразования use-case |
## Маленькие этапы
### GO-001.0 — зафиксировать baseline и границы
1. Проверить текущий список импортов:
```sh
rg -n 'internal/(repos|modules)' evening_detective_server/internal/app --glob '*.go'
cd evening_detective_server && go test ./internal/app ./internal/services/...
```
2. Выписать в diff только файлы из таблицы выше.
3. После каждого следующего этапа проверять, что импорт repository исчез только
из app, а wiring в `cmd` остался.
Готово, если до изменений есть зафиксированный список импортов и понятен
targeted test для каждого участка.
### GO-001.1 — webhook регистрации команды
Файлы: `internal/app/team_registration.go`,
`internal/services/team_service/registration.go` и связанные тесты.
1. Найти, какие sentinel-ошибки `TeamService.RegisterTeam` уже возвращает.
2. Сделать ошибку закрытой регистрации частью контракта `team_service`, чтобы
handler не импортировал `teams_repo` только ради `errors.Is`.
3. Оставить `TeamRegistrationHandler` ответственным только за проверку bearer
token, разбор JSON/JSON-RPC, timeout и HTTP-код.
4. Обновить тесты handler-а на публичную ошибку service; не переносить JSON
parsing в service.
Проверка этапа:
```sh
cd evening_detective_server
go test ./internal/app ./internal/services/team_service
! rg 'internal/repos' internal/app/team_registration.go
```
Ожидаемый результат: регистрация с закрытым окном по-прежнему даёт `409`,
ошибочный payload — `400`, а app больше не знает `teams_repo`.
### GO-001.2 — выдача QR-кодов команд
Файлы: `internal/app/team_qr.go`,
`internal/services/team_service/service.go`, `team_qr.go` и тесты.
1. Перенести наружный смысл ошибок из repository/PDF-модуля на границу
`team_service`: игра не найдена и у команды нет карточек.
2. Не переносить в service формирование `HttpBody` и HTTP-заголовков.
3. В handler оставить проверку claims/ролей, валидацию `id`, mapping ошибок в
gRPC-коды и headers.
4. Проверить существующие тесты `team_qr_test.go` и добавить только недостающий
regression case на обе ошибки.
Проверка этапа:
```sh
cd evening_detective_server
go test ./internal/app ./internal/services/team_service
! rg 'internal/repos|team_qr_pdf' internal/app/team_qr.go
```
Ожидаемый результат: `DownloadTeamQR` сохраняет PDF и заголовки без прямой
зависимости app от repository/PDF implementation.
### GO-001.3 — операции пользователей
Файлы: `internal/app/users.go`, `internal/services/users_service/*` и тесты.
1. Найти, почему app использует `users_repo.ErrUserNotFound` только в
`ChangeUserPassword`.
2. Передать наружу ошибку через контракт `users_service` (владелец прикладного
смысла), не раскрывая в app storage-пакет.
3. Не менять здесь многочисленные protobuf-поля `Error`: их единое исправление
относится к GO-003.
4. Оставить в app извлечение claims, пароля из metadata, роли и вызов service.
5. Обновить unit-тесты на `NotFound` через service-owned error.
Проверка этапа:
```sh
cd evening_detective_server
go test ./internal/app ./internal/services/users_service
! rg 'internal/repos' internal/app/users.go
```
Ожидаемый результат: app не импортирует `users_repo`, а код gRPC для
отсутствующего пользователя не меняется.
### GO-001.4 — архив сценария
Файлы: `internal/app/scenario_archive.go`,
`internal/services/scenarios_service/*` и тесты.
1. Отделить transport-часть от прикладной: app оставляет auth, `HttpBody`,
`Content-Disposition` и проверку размера запроса.
2. Ошибку сценария не найдено получать через `scenarios_repo` в app; использовать
service-owned контракт ошибки.
3. Проверить, нужен ли app доступ к `scenario_archive.MaxArchiveSize()` только
как к transport-лимиту. Если да, предоставить лимит через service-owned
константу/функцию; не тащить repository или storage-модель.
4. `string_tools` оставить только если это чистая transport-санитизация имени;
иначе вернуть готовое безопасное имя из service. Не переносить бизнес-логику
в mapper.
5. Не менять формат ZIP и правила авторизации.
Проверка этапа:
```sh
cd evening_detective_server
go test ./internal/app ./internal/services/scenarios_service
! rg 'internal/repos' internal/app/scenario_archive.go
```
Ожидаемый результат: archive handler знает HTTP-представление, а не repository
и внутреннюю реализацию архива.
### GO-001.5 — скачивание файлов
Файлы: `internal/app/files.go`, `internal/services/file_service/*` и тесты.
1. Перенести `ErrFileNotFound` на публичную границу `file_service` (или сделать
service-owned alias без нового слоя), чтобы handler не импортировал
`file_storage`.
2. Оставить в app авторизацию автора, `nosniff`, `HttpBody` и mapping MIME-типа.
3. Проверить, что service уже возвращает полную модель файла и контекст;
новых DTO и интерфейсов не добавлять.
4. Добавить/обновить тест на `404` скачивания отсутствующего файла.
Проверка этапа:
```sh
cd evening_detective_server
go test ./internal/app ./internal/services/file_service
! rg 'internal/modules/file_storage' internal/app/files.go
```
### GO-001.6 — app mapper-ы и чистка импортов
Файлы: `internal/app/game_mapper.go`, `team_mapper.go`, `story_mapper.go`,
`internal/app/*`.
1. Не переносить protobuf mapping в service: он остаётся в `app`.
2. Проверить, что входные типы mapper-ов являются контрактом service, а не
типами repository/module. Если mapper использует `game_model` или
`formatter_utils` только как промежуточный use-case тип, перенести границу
в service минимальным изменением, сохранив существующий protobuf output.
3. Не переименовывать пакеты `*_utils` в рамках GO-001 — это GO-006.
4. После каждого переноса удалить неиспользуемые импорты и проверить callers.
Проверка этапа:
```sh
cd evening_detective_server
find internal/app internal/services -name '*.go' -print0 | xargs -0 gofmt -l
go vet ./...
go test ./internal/app ./internal/services/...
```
### GO-001.7 — финальная проверка архитектурного правила
1. Runtime-файлы `internal/app` не должны импортировать `internal/repos`.
2. Каждый RPC/HTTP handler должен вызывать service, а не repository/module
с бизнес-операцией.
3. `cmd/evening_detective_server/main.go` продолжает собирать repositories,
modules и services — его зависимости не удалять.
4. Проверить все callers изменённых ошибок и конструкторов.
5. Запустить полный набор проверок:
```sh
cd evening_detective_server
find internal/app internal/services -name '*.go' -print0 | xargs -0 gofmt -l
go vet ./...
go test ./...
```
6. В `todo.md` отметить GO-001 выполненной только после успешной проверки
за пределами sandbox, где разрешён loopback TCP.
## Критерий готовности GO-001
- Runtime `internal/app` не импортирует `internal/repos`.
- В app не осталось прямого вызова repository или технического module для
выполнения бизнес-операции.
- Существующие transport-коды, headers, JSON payloads и protobuf responses не
изменились намеренно.
- Для каждого перенесённого error mapping есть targeted test.
- `gofmt`, `go vet ./...` и полный `go test ./...` проходят в поддерживаемом
окружении.