# Спецификация: go-live инварианты безопасности публичных точек входа Лидерры

## Цель

Зафиксировать проверяемые инварианты безопасности портала перед публикацией в
интернет и дать критерий приёмки для отчёта доменного аудита (threat-model +
pdn-152fz + billing). Предмет — авторизация чувствительных API-маршрутов, защита
исходящих webhook от SSRF, полнота удаления персональных данных по 152-ФЗ и
денежная корректность списаний.

## Авторизация чувствительных маршрутов {#D1}

Контракт: каждый маршрут, отдающий данные тенанта или выполняющий привилегированное
действие, несёт middleware `auth:sanctum` + `tenant`; зона `/api/admin/*` обязана
иметь application-layer гейт авторизации, а не полагаться только на сетевой периметр
(reverse-proxy). Привилегированные действия привязываются к личности исполнителя в
audit-trail (идентификатор берётся из аутентифицированной сессии, не из параметра
запроса). Edge-case: маршруты auth-flow (login/register/2fa/forgot/reset) публичны
намеренно; скачивание готового отчёта — capability-token (`signed`). Критерий
приёмки: нет чувствительного маршрута без авторизации; админ-действие невозможно
выполнить, минуя application-гейт; исполнитель действия достоверно зафиксирован.

## SSRF-поверхность исходящих webhook {#D2}

Контракт: целевой URL исходящего webhook задаёт администратор тенанта; перед каждым
исходящим запросом адрес проходит guard, блокирующий приватные и зарезервированные
сети и cloud-metadata-эндпоинты; HTTP-клиент не следует за редиректами во внутреннюю
сеть. Edge-case: публичный хост, переразрешающийся позже в приватный IP
(DNS-rebinding), и ответ `3xx` с Location во внутреннюю сеть. Критерий приёмки: ни
pre-flight guard, ни фактический запрос не дают обратиться к внутреннему адресу ни
одним из перечисленных путей.

## Полнота удаления ПДн по 152-ФЗ {#D3}

Контракт: операция удаления субъекта анонимизирует ВСЕ копии телефона и почты во всех
таблицах текущей версии схемы — скалярные колонки, JSON-массивы дополнительных
телефонов, журналы и производные региональные данные. Сервис удаления синхронизирован
с актуальной версией схемы: при добавлении новой таблицы или колонки с ПДн он
расширяется. Edge-case: вторичные телефоны в JSON-массиве; таблицы, добавленные после
написания сервиса. Критерий приёмки: после удаления ни одна таблица не содержит
исходный телефон субъекта.

## Денежная корректность списаний {#D4}

Контракт: денежные величины считаются в копейках через `bcmath`, без PHP-float;
списание за лид идемпотентно — один доставленный лид порождает ровно одно списание
даже при повторном запуске фоновой задачи; источник списания (`charge_source`)
фиксируется в журнале. Edge-case: повтор фоновой задачи доставки; гонка двух доставок
одного лида одному тенанту. Критерий приёмки: на деньгах нет float-арифметики; двойное
списание невозможно на уровне приложения, желательно подкреплено ограничением БД.

## Критерий приёмки отчёта {#D5}

Отчёт доменного аудита перечисляет по каждому инварианту статус (закрыт / остаточный
риск / открыт) с указанием файла и строки, классом приоритета и рекомендацией; в конце
— вердикт готовности к публикации GO / NO-GO. Открытые вопросы проекта не закрываются
без явного решения владельца.

```verified-context-json
[
  {"id":"D2","kind":"EXTRACTED","ref":"app/app/Support/WebhookUrlGuard.php","anchor":"final class WebhookUrlGuard"},
  {"id":"D3","kind":"EXTRACTED","ref":"app/app/Services/Pd/PdErasureService.php","anchor":"class PdErasureService"},
  {"id":"D4","kind":"EXTRACTED","ref":"app/app/Services/Billing/LedgerService.php","anchor":"final class LedgerService"}
]
```
