# Go чек-лист перед PR

Используется как self-check перед созданием PR. В PR достаточно написать: «чек-лист выполнен, релевантно N пунктов, все выполнены».

## Архитектура и структура
- Структура сервиса соответствует `docs/design-guidelines/go/services_design_requirements.md` (domain/transport/repository разделены; нет доменной логики в transport).
- Доменные модели разложены системно (`internal/domain/types/{entity,value,enum,query,mixin}`), а не объявлены ad-hoc внутри service/handler файлов.
- Репозиторные контракты не хранят доменные модели “вперемешку” в `repository.go`: модели вынесены в `internal/domain/types/**` и подключаются как aliases/imports.
- Для transport/domain persistence payload-моделей нет anonymous `struct{...}` в production-коде: используются именованные типы в профильных пакетах (`types/*`, `transport/*/models`, `casters`).
- В transport-слое ответы типизированы (DTO модели + кастеры); нет `map[string]any`/`[]any`/`any` как API-контрактов.
- JSON payload, сохраняемые в БД/события (например `*_payload`), типизированы через struct + caster; нет `map[string]any` в коммитнутом production-коде.
- Повторяющиеся строковые доменные значения вынесены в typed-константы (без копипасты литералов по коду).
- Типы событий и типы агрегатов доменных событий берутся из `libs/go/platformevents/**`, а не копируются руками.
- Scope/action ключи и другие доменные идентификаторы не передаются строковыми литералами там, где нужен повторно используемый контракт.
- Доменные enum сервиса не вынесены в shared-библиотеку без отдельного архитектурного решения; межсервисные классификаторы идут через protobuf/gRPC или generated AsyncAPI.
- Для repository/transport/server типов, которые должны реализовывать интерфейс, есть compile-time assertion.
- Для `pgx.Rows` используются pgx helpers (`CollectRows`, `RowTo*`) либо явно обоснованный ручной scanner с доменной конвертацией.
- SQL-параметры имеют явные касты там, где тип неоднозначен: nullable, arrays, JSON/JSONB, `LIMIT/OFFSET`; простые параметры не кастятся без необходимости.
- `optional` transport-поля выровнены с моделью БД: `NULL` только там, где отсутствие значения имеет отдельный бизнес-смысл.
- Имена операций для ошибок, логов, метрик, спанов и идемпотентного следа заданы константами в формате `<layer>.<Type>.<Method>`.
- Идемпотентный повтор команд не возвращает сохранённый aggregate без сверки фактической области доступа с текущим запросом; `command_id`/`idempotency_key` не используются как граница авторизации.
- Пользовательские тексты (UI/GitHub comments/уведомления) не захардкожены в Go-коде: используются `embed`-шаблоны или централизованные i18n-файлы.
- Системные тексты используют i18n message id и `libs/go/i18n`; пользовательские поля хранятся как введённые данные в одной локали.
- В циклах обработки коллекций нет N+1 обращений к БД, внешним API, Kubernetes API, кэшу или методам репозитория; если пакетный контракт ещё не готов, есть локальный кэш запроса и отдельная задача на устранение.
- В больших `service.go`/`handler.go` вспомогательные модели/типы/no-op реализации вынесены в отдельные файлы пакета (`*_types.go`, `*_helpers.go`, `*_noop.go`).
- Helper-код разложен по уровню переиспользования: локальный helper только для одного места; общий для пакета в `*_helpers.go`; межсервисный в `libs/*`.
- Если сервис импортирует новый или изменённый `libs/go/*`, путь библиотеки и связанные локальные контракты синхронно добавлены в `services.yaml` `spec.versions.<service>.bumpOn`, чтобы release automation пересобрала все потребители.
- Ошибки маппятся на границе транспорта (HTTP error handler / gRPC interceptor); в handlers нет ad-hoc маппинга межслойных ошибок.
- `context.Background()` создан только в `cmd/<service>/main.go`; `internal/app` и нижние слои используют прокинутый контекст или производный контекст через `context.WithoutCancel`.
- Функции/методы оформлены с компактными сигнатурами (предпочтительно в одну строку); при большом числе аргументов используется `Config/Params/Input` структура.
- Интеграция с Kubernetes идёт через интерфейс/адаптер; прямой shell-first сценарий не является основным путём.
- Интеграция с репозиториями идёт через provider-интерфейсы (без GitHub-specific логики в домене).
- Runtime config читается через `github.com/caarlos0/env/v11`; простые обязательные env отмечены `required`/`notEmpty`, а условно обязательные env проверяются только в ручной `Validate()`.
- HTTP gateway (если есть): OpenAPI в `specs/openapi/<gateway-surface>.v<major>.yaml`; validation/codegen выполнены.
- Внутренний доменный сервис не публикует прямой OpenAPI для бизнес-ручек; наружный HTTP идёт через gateway-спецификации.
- Async/webhook payload contracts (если есть): описаны в `specs/asyncapi/<service-name>.v<major>.yaml`, а Go event contracts регенерированы через `make gen-asyncapi-event-contracts`.
- Стабильные `v1` контракты покрывают весь согласованный объём доменного API, а не только уже реализованный срез.
- Если стабильный контракт опережает реализацию, документ поставки сервиса содержит таблицу реализованных операций и бэклог по оставшимся операциям.
- Breaking change в `proto`, OpenAPI или AsyncAPI проверен на live rolling gap: все потребители обновляются в согласованном срезе либо изменение выполнено через staged путь `add -> migrate consumers -> remove`.
- Если менялись контракты (OpenAPI/proto/AsyncAPI): выполнена регенерация через `make`, и изменения в `**/generated/**` закоммичены.

## Webhook и процессы
- Процессы запускаются webhook-событиями и внутренними событиями из БД; workflow-first зависимость не добавлена.
- Для long-running задач есть идемпотентность, ретраи и запись состояния/блокировок в БД.
- Изменения lifecycle pod/slot фиксируются в таблицах состояния и журнале событий.

## Postgres и SQL
- Миграции (goose): `services/<zone>/<db-owner-service>/cmd/cli/migrations/*.sql` (timestamp; `-- +goose Up/Down`); история не переписывается.
- Уже применённые migration-файлы не редактируются; destructive/drop/rename оформлены через `expand -> migrate -> contract`, а live drift исправлен новой миграцией или runbook/deploy шагом.
- Repo интерфейсы в `internal/domain/repository/<model>/repository.go`; реализации в `internal/repository/postgres/<model>/repository.go`.
- SQL только в `internal/repository/postgres/<model>/sql/*.sql` + `//go:embed`; SQL-строки в Go запрещены.
- SQL-запросы именованы комментариями `-- name: <model>__<operation> :one|:many|:exec`.
- Каждый named query находится в отдельном `.sql` файле, чтобы разные PR могли менять запросы без конфликтов.
- Нет SQL-файлов без `-- name` header (включая простые `get_by_id.sql`).
- Для динамических данных используются `JSONB`; для векторного поиска корректно применён `pgvector`.

## MCP-специфика (если затронута)
- MCP tool catalog синхронен между доменной политикой, транспортным каталогом MCP-инструментов и интерфейсом use-case слоя. Конкретные пути фиксируются в документах домена после создания новых сервисов.
- Изменения policy/tool scope сопровождаются синхронным обновлением проектной документации.

## Безопасность
- Секреты платформы читаются из env; не хардкодятся и не логируются.
- Новые обязательные env/secrets/config не ломают старт live deployment: есть staged rollout path, безопасный default/диагностика или явный runbook шаг.
- Repo-токены и чувствительные данные сохраняются только в шифрованном виде.
- Значения секретов, полученные по ссылке, представлены безопасным типом вроде `secretresolver.SecretValue`, не сериализуются в JSON/text/fmt, живут только в памяти процесса на время операции и очищаются через `defer value.Clear()` сразу после успешного разрешения.
- Детали реализации хранилища секретов остаются в resolver-клиенте; доменный код работает с `secret_store_type + secret_store_ref` и не хранит сырые значения.
- OAuth/аутентификация не обходятся через debug или “временные” backdoor-механизмы.

## Автопроверки (обязательно перед PR)
- Соблюдён `docs/design-guidelines/go/code_commenting_rules.md`.
- В каждом изменённом Go-модуле выполнен `go mod tidy`.
- Если добавлена/обновлена внешняя Go библиотека, обновлён
  `docs/design-guidelines/common/external_dependencies_catalog.md`.
- Прогнан `make test-go`: это герметичный unit/component контур без PostgreSQL, Docker и `KODEX_*_TEST_DATABASE_DSN`.
- Если менялись PostgreSQL repository, миграции, SQL или outbox/event-log storage, прогнан явный integration target
  `make test-go-postgres` с внешними DSN или `KODEX_TEST_POSTGRES_MODE=kubernetes`.
- Для полной Go-проверки окружения с тестовой БД используется `make test-go-all`: сначала hermetic tests,
  затем PostgreSQL integration tests.
- Падение `make test-go-postgres` из-за отсутствия Docker, внешних DSN и доступного Kubernetes test namespace
  не считается багом конкретного PR, но означает незапущенную обязательную integration-проверку; это явно фиксируется
  в PR/QA-отчёте.
- Прогнан `make lint-go` и исправлены нарушения.
- Прогнан `make dupl-go`; дубли устранены или выделены в отдельную задачу.
