Чеклист автора 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 полях вместо
email—user_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.ymlhealthcheck'и на месте для postgres/redis/kafka. - Сервис имеет
/healthzи/readyzendpoints.
Git-гигиена¶
- Имя ветки —
<type>/<short-description>. - Коммиты в Conventional Commits формате.
- Нет случайно закоммиченных файлов:
.env,bin/,.idea/, бинари. - Нет секретов в diff'е (проверь глазами: JWT, DB-пароли, API-ключи).
- Нет
TODO/FIXMEбез ссылки на issue. - PR-description заполнен по шаблону (цель / что сделано / как тестировать).
Размер PR¶
- Diff < 400 изменённых строк (не считая генерируемых файлов).
- Если больше — в описании PR объяснено, почему не получилось разбить.
Если всё отмечено — запрашивай review. Если что-то не получилось — опиши это в PR-описании заранее, не жди вопроса от ревьюера.