На ВМ выполните: cd /opt/han-chat/backend umask 077 read -r -p "Тестовый номер в E.164 (+79...): " TEST_PHONE CHALLENGE_ID=$(python3 -c 'import uuid; print(uuid.uuid4())') OTP_CODE=$(python3 -c 'import secrets; print(f"{secrets.randbelow(1000000):06d}")') SMS_TOKEN=$(python3 - <<'PY' from pathlib import Path for line in Path(".env").read_text().splitlines(): if line.startswith("SMS_SERVICE_TOKEN="): print(line.split("=", 1)[1].strip().strip("\"'")) break else: raise SystemExit("SMS_SERVICE_TOKEN отсутствует") PY ) export TEST_PHONE CHALLENGE_ID OTP_CODE SMS_TOKEN REQUEST_FILE=$(mktemp) python3 - "$REQUEST_FILE" <<'PY' import json import os import sys payload = { "idempotency_key": f"ops:smoke:{os.environ['CHALLENGE_ID']}", "template_code": "auth_otp", "locale": "ru", "phone_e164": os.environ["TEST_PHONE"], "substitutions": { "code": os.environ["OTP_CODE"], "ttl_min": "1", }, "customer_ref": os.environ["CHALLENGE_ID"], "message_ttl_sec": 60, } with open(sys.argv[1], "w", encoding="utf-8") as file: json.dump(payload, file, ensure_ascii=False) PY Создайте функцию отправки: send_sms_smoke() { docker compose --env-file .env --profile ops run --rm --no-deps \ --user 0:0 \ --entrypoint sh \ -e SMS_TOKEN \ -v "$REQUEST_FILE:/tmp/sms-request.json:ro" \ toolbox -ec ' curl -sS \ -w "\nHTTP %{http_code}\n" \ -X POST \ -H "Authorization: Bearer $SMS_TOKEN" \ -H "Content-Type: application/json" \ -H "X-Request-ID: ops-sms-smoke" \ --data-binary @/tmp/sms-request.json \ http://sms-service:8080/internal/sms/v1/send ' } Отправка: send_sms_smoke Ожидается: HTTP 202 и JSON с sms_message_id. Проверьте журнал: SELECT id, phone_masked, send_status, delivery_status, provider_message_id, provider_error_code, attempt_count, created_at FROM sms.sms_outbound_message ORDER BY created_at DESC LIMIT 5; После проверки удалите секретные данные: shred -u "$REQUEST_FILE" 2>/dev/null || rm -f "$REQUEST_FILE" unset SMS_TOKEN OTP_CODE TEST_PHONE CHALLENGE_ID REQUEST_FILE