# backend-structured-logging Specification ## Purpose Определяет безопасные структурированные backend-логи, позволяющие связать HTTP-запрос, его ответ и вызовы T-Bank при диагностике инцидентов. ## Requirements ### Requirement: Backend публикует единообразные структурированные события Backend SHALL записывать lifecycle-, HTTP-, authentication-, domain- и T-Bank-события в stdout как Pino JSON-записи с time, level, message и безопасным context. Записи MUST поддерживать уровни debug, info, warn и error; уровень вывода MUST настраиваться валидируемой конфигурацией `LOG_LEVEL` с production-значением по умолчанию `info`. #### Scenario: Приложение успешно запускается - **WHEN** backend завершает запуск - **THEN** stdout содержит info JSON-событие запуска с безопасными service и environment #### Scenario: Выбран уровень debug - **WHEN** backend запущен с допустимым `LOG_LEVEL=debug` - **THEN** stdout содержит debug-события наряду с событиями более высоких уровней #### Scenario: Указан недопустимый уровень логирования - **WHEN** backend запущен с недопустимым значением `LOG_LEVEL` - **THEN** запуск завершается ошибкой валидации конфигурации ### Requirement: HTTP-запросы имеют сквозной идентификатор Backend SHALL создавать server-generated request ID для каждого HTTP-запроса, включать его в связанные с запросом log-события и возвращать его в response header `X-Request-ID`. CORS MUST разрешать browser-клиенту прочитать этот header. Входящий request ID MAY быть записан отдельным недоверенным полем, но MUST NOT заменять server-generated request ID и MUST NOT влиять на авторизацию или обработку запроса. #### Scenario: Клиент получает идентификатор запроса - **WHEN** browser-клиент получает HTTP-ответ backend - **THEN** ответ содержит `X-Request-ID`, доступный через CORS, и этот же ID присутствует в HTTP log-событии #### Scenario: Клиент передаёт собственный идентификатор - **WHEN** HTTP-запрос содержит client-provided request ID - **THEN** backend использует другой server-generated request ID для обработки и логирования запроса ### Requirement: Backend фиксирует итог каждого HTTP-запроса Backend SHALL записывать ровно одно completion-событие для каждого HTTP-запроса с request ID, HTTP method, route template, status и duration. Completion-событие MUST иметь level info для обычных ответов, warn для authentication failures и status 429, error для status 5xx. События с ошибкой MUST включать стабильный public error code; error-события для status 5xx MUST включать stack trace. #### Scenario: Запрос завершается успешно - **WHEN** backend возвращает ответ со status 2xx - **THEN** stdout содержит одно info completion-событие с route template без query string и длительностью обработки #### Scenario: T-Bank недоступен во время запроса - **WHEN** backend возвращает клиенту status 503 с public error code `TBANK_UNAVAILABLE` - **THEN** stdout содержит одно error completion-событие с этим code, request ID и stack trace #### Scenario: Запрос не проходит аутентификацию - **WHEN** backend возвращает status 401 или 403 - **THEN** stdout содержит одно warn completion-событие без отдельного дублирующего события ошибки ### Requirement: События T-Bank позволяют диагностировать интеграцию Backend SHALL записывать события вызовов T-Bank с request ID, именем операции и duration, когда вызов выполняется в контексте HTTP-запроса. Успешный вызов MUST иметь level debug, повтор вызова MUST иметь level warn, а окончательный сбой MUST иметь level error и содержать gRPC code и число попыток. #### Scenario: Вызов T-Bank успешен с первой попытки - **WHEN** вызов T-Bank завершается успешно без повтора - **THEN** stdout содержит debug-событие операции с её duration и request ID #### Scenario: Вызов T-Bank повторяется и затем завершается ошибкой - **WHEN** вызов T-Bank исчерпывает разрешённые попытки - **THEN** stdout содержит warn-событие повтора и error-событие окончательного сбоя с gRPC code и числом попыток ### Requirement: Логи не раскрывают секретные и чувствительные данные Backend MUST NOT записывать в логи token, cookie, JWT, пароль, полный HTTP header, HTTP body, email, IP-адрес, финансовые значения или payload T-Bank. В production-логах MAY присутствовать только внутренние user ID и brokerage account ID, если они известны при формировании события. Ошибка формирования или вывода log-события MUST NOT менять HTTP-ответ или результат доменной операции. #### Scenario: Запрос содержит секретные данные - **WHEN** HTTP-запрос содержит authentication cookie, JWT или тело с паролем - **THEN** связанные log-события не содержат эти значения #### Scenario: Событие не сериализуется - **WHEN** backend не может сериализовать поле log-события - **THEN** backend завершает обработку исходного запроса без ошибки, вызванной логированием