# Автоматический запуск SMS-обработчика

Планировщик работает независимо от посещений сайта. Реальная отправка управляется приватными настройками RocketSMS и по умолчанию выключена. Установка задания не включает провайдера и не подтверждает доставку SMS.

## Windows / OSPanel

Из корня проекта под обычной учётной записью владельца:

```powershell
.\tools\install-sms-task.ps1 -StartNow
```

При необходимости передайте `-PhpPath` с абсолютным путём к PHP 8.1+. Установщик создаёт или обновляет только своё задание `LaFleur-SMS-flowers.local`, проверяя точные пути и владельца существующего задания. Одноимённое чужое задание не изменяется. Системная политика выполнения PowerShell сохраняется; повышенные права и обход ограничений не запрашиваются.

Задание запускается каждую минуту без срока окончания, под текущим пользователем с уровнем `Limited`, в скрытом окне. `IgnoreNew` запрещает наложение запусков; дополнительно обработчик защищён блокировкой MariaDB. Режим `Interactive` не сохраняет пароль Windows и работает, пока этот пользователь вошёл в систему, в том числе при заблокированном экране. После выхода пользователя обработка возобновляется при следующем входе. Компьютер, MariaDB и интернет должны работать.

Для постоянной работы production без пользовательского сеанса администратор сервера отдельно настраивает ограниченную служебную учётную запись или cron. Не переводите задачу на `SYSTEM` и не сохраняйте пользовательский пароль в исходном коде.

Проверка фактического состояния:

```powershell
Get-ScheduledTask -TaskName 'LaFleur-SMS-flowers.local'
Get-ScheduledTaskInfo -TaskName 'LaFleur-SMS-flowers.local'
Get-Content -LiteralPath '.\storage\sms-worker-status.json'
```

`LastTaskResult=0` означает завершение процесса без ошибки; время в heartbeat должно обновляться. Это не доказательство отправки или доставки SMS. Если установка отклонена системным API, устранением прав занимается администратор; установщик не обходит запрет.

Остановка и удаление задания по решению владельца:

```powershell
Disable-ScheduledTask -TaskName 'LaFleur-SMS-flowers.local'
# Удалять задание только после проверки имени и путей:
Unregister-ScheduledTask -TaskName 'LaFleur-SMS-flowers.local' -Confirm
```

## Heartbeat и журналы

`tools/sms-worker.php` атомарно обновляет `storage/sms-worker-status.json`: время Europe/Minsk, статус `running/success/skipped/error`, режим `run/queue/poll`, числовые счётчики и безопасный код ошибки. `skipped` означает, что отправляющий обработчик уже удерживает блокировку. Файл не содержит телефонов, текстов сообщений, OTP, реквизитов API и исключений. Он закрыт от HTTP вместе с каталогом `storage`.

Скрытый runner сохраняет только текущий технический вывод в `storage/sms-worker-output.log` и `storage/sms-worker-error.log`, перезаписывая их при следующем запуске. Чувствительные данные не выводятся обработчиком. Heartbeat показывает последний запуск, включая ручной; наличие файла само по себе не доказывает исправность расписания — проверяйте свежесть времени.

## Linux / production

Настройте cron от ограниченного пользователя сервиса, проверив абсолютные пути и доступ к приватной конфигурации/хранилищу:

```cron
* * * * * cd /absolute/path/to/shop && /usr/bin/php /absolute/path/to/shop/tools/sms-worker.php run >/dev/null 2>&1
```

После установки проверьте обновление heartbeat как минимум на двух последовательных минутах. При `error` изучите соединение с БД, миграции и права записи. Для немедленного прекращения внешней отправки установите `ROCKETSMS_ENABLED=false`; календарь и кабинет продолжат работать. Подключение провайдера, доказательство контролируемой доставки и юридические проверки описаны в [sms-setup.md](sms-setup.md).
