# 16 · Решение проблем

[← Home](Home.md)

Первая команда при любой проблеме:

```bash
php bin/bas-ip doctor          # самодиагностика с подсказками
php bin/bas-ip logs:tail error --lines=50
php bin/bas-ip logs:tail app --lines=50
```

В UI: **Админка → Система → Диагностика** и **Журналы**. У каждого ответа
есть `X-Request-Id` — найдите его в логах (`access`/`error`) и увидите всю
цепочку запроса.

## Установка и запуск

| Симптом | Причина и решение |
|---|---|
| Белый экран | `app.debug=true` временно → смотреть ошибку; почти всегда: права на `storage/` (`chown -R www-data storage && chmod -R ug+rwX storage`) |
| «Приложение не установлено» | нет `.bas-ip.config.local.php` — откройте `/install` или создайте конфиг вручную |
| 404 на всё, кроме `/` | веб-сервер не смотрит в `public/` или не работает rewrite (nginx: `try_files $uri /index.php?$query_string`; Apache: `AllowOverride All` + mod_rewrite) |
| 500 после деплоя | `php -v` < 8.2; не хватает расширений (`php -m`: pdo, mbstring, curl, openssl); opcache — перезапустить php-fpm |
| Страница логина циклически редиректит | неверный `app.url` (http/https mismatch) или прокси без `app.behind_proxy` + `trusted_proxies` — сессия теряет Secure-cookie |
| «Не удалось подключиться к базе данных» | хост/порт/креды; для MySQL также `mysqlnd`/`pdo_mysql`; socket вместо TCP — `unix_socket`; SELinux (RHEL): `setsebool -P httpd_can_network_connect_db 1` |
| Миграции падают на MariaDB < 10.6 | collation: поставьте `utf8mb4_unicode_ci` в конфиге соединения |

## Шлагбаум

| Симптом | Причина и решение |
|---|---|
| «Устройство не отвечает» | сеть до панели (ping/telnet 80/443), VLAN/файрвол, `base_url` со схемой и `/api/v0/` |
| 401 от панели | логин/пароль панели; пароль-секрет: `secret:list`, переустановить `secret:set DEVICE_PASSWORD` |
| Открывает, но в журнале `error` | смотрите канал `device` — тело ответа панели; для не-BAS-IP железа используйте `http-relay` с корректным парсингом ответа |
| Кнопка «Открыть» неактивна | cooldown 3 с (анти-даблтап) или «тихие часы»/расписание; у жителя выключен флаг «доступ» |
| Камера не грузится | `device.camera.mode`: за панелью NAT нужен `proxy`/`mjpeg`; CSP разрешает хост устройства только для `mjpeg` |
| Всё работает, но «по-настоящему» не открывается | включён драйвер `dryrun` (эмулятор) — переключите на `basip`/`http-relay`; `doctor` это подсвечивает |

## Уведомления

| Симптом | Причина и решение |
|---|---|
| Письма не уходят | канал `mail` не включён (`notify.channels.mail.enabled`) или SMTP-креды; тест: `notify:test --channel=mail --to=you@mail`; лог: `logs:tail notify` |
| В письмах «Оплатить:» пусто | не задана ссылка оплаты — Настройки → Биллинг → `pay_link` (пустые строки-подписи удаляются автоматически) |
| Telegram молчит | `bot_token` (secret), жители должны указать @username как контакт типа telegram; служебные алерты — `admin_chat_id`; webhook — `integrations.telegram_bot.webhook_url` + секрет |
| Очередь стоит | воркер не запущен: cron `schedule:run` или `queue:work`; `queue:stats`; failed → «ретрай» в UI |
| Дубль писем | два воркера? lease защищает от двойной доставки одной строки; проверьте, что cron и systemd-воркер не запускают `queue:run` одновременно с разными лимитами (это безопасно, но дубли обычно — повторная ручная рассылка) |

## Оплаты

| Симптом | Причина и решение |
|---|---|
| Сумма счетов ≠ общей сумме | так не бывает :). Расщепление точное до копейки; если видите расхождение — `billing:balances` и проверьте, что не было перерасчёта (корректирующие счета — часть начисления) |
| Житель не попал в начисление | выключен (`is_active=0`), `is_billed=0` или удалён — фильтр «все» в списке жителей |
| Оплата «повисла» | проверьте `external_id` (идемпотентность): повтор вебхука с тем же ID игнорируется — это защита от дублей |
| Просрочка не помечается | cron `schedule:run` не работает; вручную: `billing:overdue` |

## Производительность

* Медленные списки: `EXPLAIN` через **Система → Query-log** (debug); обычно
  помогает `migrate` (индексы) и `cache:clear`.
* Большая база (10k+ жителей): MySQL/PostgreSQL вместо SQLite; `ui.per_page`
  поменьше; `prune` по политике хранения для `gate_events`/`outbox`.
* Поллинг статусов: интервалы в `ui.*_refresh_seconds`.

## Обновления

См. отдельную таблицу в [14 · Обновления](14-Updating.md#частые-проблемы).

## Куда смотреть в логах

| Канал | Содержание |
|---|---|
| `app` | общие события приложения |
| `error` | исключения со стектрейсами |
| `access` | каждый HTTP-запрос (метод, путь, статус, время, request-id) |
| `audit` | действия пользователей/API + пометки `is_security` |
| `gate` | открывания/отказы устройства |
| `device` | HTTP-вызовы панели (тайминги, коды) |
| `notify` | отправка уведомлений по каналам |
| `update` | проверки/установки обновлений |

```bash
php bin/bas-ip logs:list
php bin/bas-ip logs:tail gate --lines=100
php bin/bas-ip logs:tail audit --q=is_security   # инциденты безопасности
```

## Аварийный режим

Приложение недоступно, а ворота открывать надо:

1. Аппаратная кнопка/пульт охраны (всегда должна быть!).
2. CLI на сервере: `php bin/bas-ip gate:open --apartment=12 --access=emergency`.
3. Если упало само приложение — `maintenance --on` не помогает (оно само и
   упало): перезапустить php-fpm; данные целы (БД отдельно), `doctor` после.

Не нашли решения — [FAQ](18-FAQ.md), встроенная справка `/help` → «Решение
проблем», или создайте issue (для безопасности — [SECURITY.md](https://github.com/paulmann/BAS-IP/blob/main/SECURITY.md)).

---
Дальше: [17 · Миграция с v1](17-Migration-from-v1.md)
