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

11 KiB
Raw Blame History

План 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. Проверить текущий список импортов:

    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.

Проверка этапа:

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 на обе ошибки.

Проверка этапа:

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.

Проверка этапа:

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 и правила авторизации.

Проверка этапа:

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 скачивания отсутствующего файла.

Проверка этапа:

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.

Проверка этапа:

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. Запустить полный набор проверок:

    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 ./... проходят в поддерживаемом окружении.