# laravel-app (PHP/Laravel) Статус: каркас реализован (авторизация, схема БД, модели). CRUD-интерфейсы и дашборд — в процессе. Зона ответственности: - Аутентификация и роли пользователей (Sanctum: сессии для Blade-UI + токены для будущего API/мобильного клиента), owner/viewer. - Владеет схемой PostgreSQL (`database/migrations/*.php`) — users, zones, device_types, devices, automation_rules. Go-сервисы читают/пишут эти же таблицы, но не управляют их структурой. - CRUD зон/устройств/правил автоматизации через веб-интерфейс. - Просмотр истории телеметрии (запрос к ClickHouse) и текущего состояния устройств (чтение Device Shadow из Redis, который ведёт device-control-service). - Ручная отправка команд устройствам — вызов device-control-service. Не входит в зону ответственности: приём/хранение телеметрии, обработка правил в реальном времени, отправка MQTT-команд — это Go-сервисы. Laravel только читает их данные и вызывает device-control-service по gRPC/HTTP для управления. ## Архитектурные решения - **Sanctum, а не просто сессии.** Даже при том, что UI сейчас — Blade (Breeze), Sanctum используется с самого начала, чтобы токенная авторизация API была готова для будущего Vue/Flutter-клиента (этап 3) без повторной переделки авторизации. - **Роли и категории как PHP-enum, а не хардкод строк.** `App\Enums\UserRole` (owner/viewer), `App\Enums\DeviceCategory` (actuator/sensor), `App\Enums\ConditionOperator` (>,<,>=,<=,=,!=) — всё это закрытые, архитектурные множества значений. `action_type` в правилах автоматизации **намеренно остаётся обычной строкой**, не enum'ом — это открытый, расширяемый список, управляемый данными в `device_types.capabilities`, а не кодом (иначе новый тип устройства с новой командой потребовал бы правки кода — что прямо противоречит идее платформы). - **device_types — открытый реестр.** Сидер (`DeviceTypeSeeder`) заполняет типы устройств гроубокса (light, pump, fan, sensor_temp_humidity) как пример данных, а не как встроенную в код бизнес-логику. Добавление типа для другой зоны — просто новая строка. ## Docker Собирается в один контейнер (PHP-FPM + Nginx, управляются через supervisord) — см. `Dockerfile`. Образ включает `require-dev`-зависимости (в частности `fakerphp/faker`), так как сидер намеренно создаёт демо-аккаунт через `fake()`; это MVP-образ с демо-данными, а не hardened prod-сборка. ## Запуск Локально (вне Docker), с уже поднятыми `postgres`/`redis` из корневого `docker-compose.yml`: ```bash cd laravel-app composer install cp .env.example .env && php artisan key:generate php artisan migrate --seed php artisan serve ``` Через Docker — сервис `laravel-app` в корневом `docker-compose.yml`, конфигурация берётся из переменных окружения (секция Laravel app в корневом `.env.example`).