Перейти к содержанию

Чеклист автора PR

Пробегай этот список перед тем как запросить review. Если что-то не выполнено — либо почини, либо напиши в описании PR, почему это ОК.

Сборка и статика

  • make lint прошёл без ошибок и предупреждений.
  • make test прошёл локально (go test -race -count=1 ./...).
  • go mod tidy — diff в go.sum/go.mod только по делу (нет случайных downgrade/upgrade).
  • gofmt -l . не выводит ничего (не должно быть, если pre-commit hook настроен).

Новый код

  • Новое поведение покрыто тестами:
  • service-метод: happy-path + минимум один error-path,
  • HTTP-handler: через httptest — success + ключевой error,
  • Watermill handler: через gochannel,
  • SQL-запрос: через testcontainers-Postgres.
  • Функции в service/ принимают context.Context первым параметром.
  • Ошибки обёрнуты через fmt.Errorf("context: %w", err). Нет "error: %s".
  • Sentinel-ошибки сверяются через errors.Is, кастомные типы — через errors.As.
  • Нет panic в бизнес-коде. Нет глобальных переменных кроме var ErrX = errors.New(...).

Миграции

  • Новая миграция имеет и up, и down файлы.
  • В up-файле есть SELECT pg_advisory_xact_lock(hashtext('<svc>_migrations')); после BEGIN.
  • Breaking-изменения схемы разнесены по миграциям через expand-contract.
  • Прогнал EXPLAIN ANALYZE для новых/изменённых индексов.
  • На существующих колонках не меняется тип «на месте» без backfill.
  • Таблицы именуются во множественном числе, есть created_at/updated_at.

События и Kafka

  • Публикация — только через outbox (не напрямую в Kafka из service).
  • Envelope содержит все обязательные metadata: Event-Type, Schema-Version, Correlation-Id, Source-Service, Published-At, traceparent.
  • Для нового consumer'а middleware stack подключён в порядке: CorrelationID → Recoverer → PoisonQueue → Retry → Deduplicator.
  • Handler идемпотентен (unique constraint / upsert на БД-уровне).
  • Payload события не содержит секретов / PII в открытом виде.

Конфигурация

  • Новые env-переменные добавлены в .env.example с дефолтным (невалидным) значением.
  • Новые env-переменные описаны в README.md сервиса.
  • internal/config/ валидирует обязательные поля на старте (fail-fast).
  • Никаких секретов в docker-compose.yml кроме очевидно dev-значений (_dev_, change_me).

Логи и наблюдаемость

  • Используется log/slog (JSON handler).
  • Логи не содержат PII в открытом виде:
  • email / phone / токены / password — либо замаскировано (m***@example.com), либо не логируется вовсе,
  • в structured полях вместо emailuser_id.
  • Для операции, которая может упасть, есть slog.Error(..., "err", err) с контекстом (request_id, user_id, aggregate_id).
  • Новая метрика Prometheus зарегистрирована один раз (не в handler'е на каждый запрос).

HTTP

  • chi-middleware в нужном порядке: RequestID → RealIP → Recoverer → Logger → CORS.
  • Request body декодируется через http.MaxBytesReader + DisallowUnknownFields.
  • Все request-struct прогоняются через validator (validate:"..."-теги).
  • Ошибки из service маппятся в HTTP через mapServiceError (или аналогичный централизованный маппер) — не хардкодь http.StatusX в handler'е.
  • Для новых admin/auth endpoint'ов — подключены middleware GatewayAuth + RequireRole (или InternalToken).

Docker и runtime

  • Dockerfile не регрессирует до root: USER app (uid 10001) остался.
  • Multistage build: CGO_ENABLED=0, -ldflags="-s -w".
  • docker-compose.yml healthcheck'и на месте для postgres/redis/kafka.
  • Сервис имеет /healthz и /readyz endpoints.

Git-гигиена

  • Имя ветки — <type>/<short-description>.
  • Коммиты в Conventional Commits формате.
  • Нет случайно закоммиченных файлов: .env, bin/, .idea/, бинари.
  • Нет секретов в diff'е (проверь глазами: JWT, DB-пароли, API-ключи).
  • Нет TODO/FIXME без ссылки на issue.
  • PR-description заполнен по шаблону (цель / что сделано / как тестировать).

Размер PR

  • Diff < 400 изменённых строк (не считая генерируемых файлов).
  • Если больше — в описании PR объяснено, почему не получилось разбить.

Если всё отмечено — запрашивай review. Если что-то не получилось — опиши это в PR-описании заранее, не жди вопроса от ревьюера.