Browse Source

Update documentation: BACKEND.md and BACKEND_NOTES.md

- BACKEND.md: Complete API documentation, installation guide, configuration
- BACKEND_NOTES.md: Technical implementation details, critical decisions, known issues

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
root 1 month ago
parent
commit
07863cde63
2 changed files with 761 additions and 432 deletions
  1. 306 432
      BACKEND.md
  2. 455 0
      BACKEND_NOTES.md

+ 306 - 432
BACKEND.md

@@ -1,437 +1,311 @@
-# MyBeacon - Техническое задание
+# MyBeacon Backend
 
 
-## О проекте
-
-MyBeacon - это платформа для работы с BLE и WiFi сканерами. Платформа **модульная** - можно подключать разные продукты независимо друг от друга. Сейчас планируются два продукта:
+Модульная платформа BLE/WiFi мониторинга с multi-tenant архитектурой.
 
 
-1. **WiFi Analytics** - сбор данных о WiFi устройствах для рекламной аналитики
-2. **BLE Tracking** - отслеживание BLE меток для контроля персонала и активов
-
-В будущем могут появиться другие продукты (например, мониторинг температуры, счетчики посетителей и т.д.). Вся админка и демон железки должны легко расширяться под новые продукты.
-
-## Кто пользуется системой
-
-### 1. Супер-админ
-- Полный доступ ко всему
-- Управляет клиентами (организациями)
-- Управляет железками (может отвязать от клиента, поменять настройки)
-- Видит все данные
+## Стек технологий
 
 
-### 2. Клиент (организация)
-- Это компания, которая покупает услугу
-- У клиента может быть **несколько пользователей** (сотрудников)
-- Видит только свои железки и свои данные
-- Доступ к продуктам включает админ (WiFi, BLE или оба)
+- **Backend**: Python 3.11+, FastAPI, SQLAlchemy (async)
+- **Database**: PostgreSQL 16 (metadata), Redis (cache)
+- **Authentication**: JWT (python-jose), bcrypt
+- **Development**: Poetry, uvicorn --reload
 
 
-### 3. Пользователь клиента
-- Сотрудник компании-клиента
-- Имеет **права доступа** (может быть read-only или полный доступ)
-- Права настраиваются **для каждого объекта** (например: может смотреть данные, но не менять настройки)
-- Все действия **логируются** (кто, когда, что делал)
+## Архитектура
 
 
-## Многопользовательский доступ в организации
-
-У одного клиента может работать много людей:
-- Директор (полный доступ)
-- Менеджеры (read-only по аналитике)
-- Техники (доступ к настройкам железок)
-- Охранники (только просмотр BLE меток на картах)
-
-**Требования:**
-- Владелец организации может добавлять пользователей
-- Каждому пользователю назначаются роли/права
-- Права на уровне объектов (может смотреть эту локацию, но не ту)
-- Логи всех действий: кто куда ходил, что смотрел, что нажимал
-- Возможность ограничить только чтением (read-only mode)
-
-**Роли пользователей в организации:**
-- **Владелец** (Owner) - полный доступ, управление пользователями
-- **Администратор** (Admin) - полный доступ к функционалу, но не может управлять пользователями
-- **Менеджер** (Manager) - доступ к аналитике и отчетам (read-only)
-- **Оператор** (Operator) - доступ к конкретным локациям/объектам
-- **Наблюдатель** (Viewer) - только просмотр, ничего не может менять
-
-## Регистрация и управление клиентами
-
-### Вариант 1: Самостоятельная регистрация
-
-1. Клиент заходит на сайт, жмет "Зарегистрироваться"
-2. Заполняет форму: email, пароль, название компании, телефон
-3. Ему приходит письмо с подтверждением email
-4. Кликает по ссылке - email подтвержден
-5. Логинится в личный кабинет - видит сообщение "Ожидается активация администратором"
-6. **По умолчанию доступа к продуктам НЕТ** (wifi_enabled=false, ble_enabled=false)
-7. Админ видит нового клиента в списке "Ожидают активации"
-8. Админ включает нужные продукты (WiFi, BLE или оба) - клиенту приходит уведомление
-9. Клиент заходит - видит активированные продукты
-
-### Вариант 2: Создание админом
-
-1. Админ создает клиента: email, название, телефон
-2. Выбирает какие продукты доступны (WiFi, BLE)
-3. Система генерирует пароль, отправляет на email клиента
-4. Клиент получает письмо с логином и паролем
-5. Логинится - сразу видит активные продукты
-
-## Железки (устройства)
-
-### Простой ID для общения с клиентами
-
-Железки имеют MAC адрес (например `38:54:39:4b:1b:ac`), но клиентам так общаться неудобно.
-
-**Решение:** Каждой железке присваивается **простой ID** начиная с 1:
-- Приемник #1
-- Приемник #2
-- Приемник #3
-- ...
-
-Когда клиент звонит в поддержку: "У нас проблема с приемником номер 5" - админ по фильтру легко находит его в базе.
-
-**Как работает:**
-- ID назначается автоматически при регистрации железки
-- ID уникальный в рамках всей системы (не сбрасывается)
-- В админке можно искать как по MAC, так и по простому ID
-- Клиенту показывается "Приемник #5", но можно раскрыть и увидеть MAC
-
-### Управление железками
-
-**Админ может:**
-- Видеть все железки (все клиенты)
-- Фильтровать: по клиенту, по статусу (онлайн/офлайн), по MAC, по простому ID
-- Привязывать/отвязывать железку к клиенту
-- Менять настройки любой железки
-- Открыть SSH терминал (через туннель)
-- Открыть dashboard железки (через туннель)
-
-**Клиент может:**
-- Видеть только свои железки
-- Менять настройки (если есть права)
-- Видеть статус (онлайн/офлайн)
-- Видеть последнюю активность
-- Назначать железку на конкретную локацию (для BLE)
-
-## Продукт 1: WiFi Analytics
-
-**Для кого:** рекламные агентства, торговые центры, аэропорты - всем кто хочет знать сколько людей проходит мимо.
-
-**Что делает:**
-- Собирает данные о WiFi устройствах (MAC адреса)
-- Фильтрует фейковые (рандомизированные) MAC адреса
-- Показывает статистику: уникальные посетители, повторные визиты, время нахождения
-- Экспортирует данные для рекламщиков
-
-**Личный кабинет клиента:**
-
-1. **Dashboard**
-   - Общая статистика за период (сегодня/неделя/месяц)
-   - Уникальные MAC адреса
-   - Фейковые vs настоящие
-   - График по дням/часам
-   - Топ производителей устройств (Apple, Samsung и т.д.)
-
-2. **Мои железки**
-   - Список своих сканеров
-   - Статус (онлайн/офлайн)
-   - Сколько событий собрали за период
-   - Простой ID + MAC адрес
-
-3. **Экспорт данных**
-   - Выбрать период
-   - Выбрать формат (CSV, JSON)
-   - Опции: исключить фейковые MAC
-   - Скачать файл
-   - История экспортов (когда, кто скачал)
-
-## Продукт 2: BLE Tracking
-
-**Для кого:** магазины, склады, больницы, офисы - где нужно отслеживать людей или объекты.
-
-**Что делает:**
-- Отслеживает BLE метки (iBeacon)
-- Показывает на карте где находятся метки
-- Привязывает метки к людям/объектам ("Марья Ивановна", "Велосипед №5")
-- История перемещений
-
-**Личный кабинет клиента:**
-
-### 1. Локации (объекты)
-
-Клиент может иметь несколько объектов:
-- Магазин на Ленина
-- Магазин на Пушкина
-- Склад №3
-
-Для каждой локации:
-- Название
-- Адрес
-- Свои приемники
-- Свои планы помещений
-
-### 2. Планы помещений
-
-**Загрузка плана:**
-1. Клиент загружает картинку (JPG/PNG) - растровый план
-2. Система автоматически конвертирует в вектор (SVG)
-3. Клиент в редакторе может:
-   - Подправить контуры стен
-   - Выделить зоны/комнаты
-   - Добавить подписи
-   - Указать масштаб (сколько метров в одном пикселе)
-
-**Цветовая схема (светлая тема):**
-- Фон: светло-зеленый `#E5F2E5`
-- Стены/контуры: серо-бежевый `#D4CFC4`
-- Комнаты: пастельные тона
-  - Бежевый `#F5EFE0`
-  - Персиковый `#FFE8D6`
-  - Голубой `#E0F7FA`
-- Выделенные зоны: оранжевый контур `#FF9800`
-- Подписи: черный текст `#000000`
-
-*(Для темной темы - потом придумаем)*
-
-### 3. Размещение приемников на плане
-
-**Как работает:**
-1. Клиент открывает план помещения
-2. Видит список своих приемников (по простым ID: Приемник #1, #2, #3...)
-3. Перетаскивает иконку приемника на нужное место на карте
-4. Приемник показывается как **прямоугольная иконка с логотипом** (logo.svg)
-5. Можно повернуть иконку (если направление важно)
-6. Сохраняет расположение
-
-**Логотип приемника:**
-- Использовать `logo.svg` (beacon с концентрическими кругами)
-- Размер: ~32x32px на карте
-- Цвет: голубой `#1CB5D5`
-- При наведении - показывает: "Приемник #5 (онлайн)"
-
-### 4. Зоны на плане
-
-**Зачем нужны зоны:**
-С таким железом точная навигация не получится - только определение зоны нахождения. Этого достаточно в большинстве случаев: понять что человек в столовой, на складе или в туалете.
-
-**Как рисовать зоны:**
-1. Клиент открывает редактор плана
-2. Выбирает инструмент "Нарисовать зону"
-3. Рисует полигон (многоугольник) поверх плана
-4. Зона показывается **полупрозрачной** (например, синий с прозрачностью 30%)
-5. Зоне автоматически присваивается номер: Зона #1, Зона #2, Зона #3...
-6. Клиент может дать зоне название: "Столовая", "Зал", "Склад", "Туалет", "Задний вход"
-7. Сохраняет
-
-**Свойства зоны:**
-- Номер (автоматический, уникальный на плане)
-- Название (задает клиент)
-- Цвет (можно выбрать из палитры)
-- Полигон (координаты вершин)
-
-**Примеры зон:**
-- Зона #1: "Столовая" (голубой)
-- Зона #2: "Торговый зал" (зеленый)
-- Зона #3: "Склад" (желтый)
-- Зона #4: "Туалет" (розовый)
-- Зона #5: "Задний вход" (оранжевый)
-
-**Определение принадлежности метки к зоне:**
-- Бэк по координатам метки определяет в какой зоне она находится (point-in-polygon)
-- Если метка видна несколькими приемниками - берется среднее положение
-- Если не попала ни в одну зону - показывается "Вне зон"
-
-**Аналитика по зонам:**
-- Сколько времени метка провела в каждой зоне
-- Сколько меток сейчас в каждой зоне
-- Тепловая карта по зонам (какие зоны самые посещаемые)
-- Маршруты: Зона #1 → Зона #3 → Зона #2
-
-### 5. Управление метками (Beacons)
-
-**Добавление метки:**
-- UUID, Major, Minor (технические идентификаторы iBeacon)
-- Привязать к объекту:
-  - Тип: Человек / Актив / Транспорт
-  - Имя: "Марья Ивановна", "Велосипед №5", "Погрузчик ПГ-12"
-  - Фото (опционально)
-  - Описание
-
-**Список меток:**
-- Поиск по имени
-- Фильтр по типу
-- Статус: активна / не видна >10 минут
-- Последнее местоположение
-
-### 5. Real-time карта
-
-**Что видит клиент:**
-- План помещения
-- Иконки приемников (с логотипами) на своих местах
-- **Метки на карте:**
-  - Показываются иконкой (точка или аватарка)
-  - Рядом с меткой: "Марья Ивановна, -65dB"
-  - RSSI показывает силу сигнала (близость к приемнику)
-  - Если метка видна несколькими приемниками - показывается примерная позиция
-
-**Обновление:**
-- Каждые 5-10 секунд карта обновляется
-- Можно включить автообновление (polling) или WebSocket
-
-**История:**
-- Можно включить "воспроизведение" - как двигалась метка за последний час/день
-- Тепловая карта (где метка проводила больше времени)
-
-## Туннели (удаленный доступ)
-
-### SSH туннель
-
-**Зачем:** админ может подключиться к терминалу железки удаленно (даже если она за NAT).
-
-**Как работает:**
-1. Админ в списке железок жмет кнопку **[Открыть SSH]**
-2. Открывается новая страница с сообщением "Подключение к устройству..."
-3. Система:
-   - Включает SSH туннель на железке
-   - Ждет пока железка подключится (до 60 секунд)
-   - Запускает ttyd (веб-терминал)
-4. В браузере открывается терминал - админ работает как в SSH
-5. При закрытии вкладки - терминал убивается (через 60 секунд grace period)
-6. Туннель остается активным (можно переоткрыть терминал)
-
-### Dashboard туннель
-
-**Зачем:** админ или клиент может открыть веб-интерфейс железки.
-
-**Как работает:**
-1. Жмет кнопку **[Открыть Dashboard]**
-2. Ожидание подключения...
-3. Открывается iframe с dashboard железки
-4. Можно смотреть статус, логи, менять настройки прямо на железке
-
-## Права доступа и логирование
-
-### Система прав
-
-**На уровне организации:**
-- Владелец может добавлять/удалять пользователей
-- Владелец назначает роли
-- Администратор не может управлять пользователями, но может все остальное
-
-**На уровне объектов (для BLE):**
-- Пользователь может иметь доступ только к определенным локациям
-- Пример: охранник видит только "Магазин на Ленина", но не видит "Склад №3"
-- Права: read-only (только смотреть) или read-write (менять настройки)
-
-**Матрица прав:**
-```
-Действие                 | Owner | Admin | Manager | Operator | Viewer
--------------------------|-------|-------|---------|----------|-------
-Просмотр аналитики       |   ✓   |   ✓   |    ✓    |    ✓     |   ✓
-Экспорт данных           |   ✓   |   ✓   |    ✓    |    ✗     |   ✗
-Настройки железок        |   ✓   |   ✓   |    ✗    |    ✓     |   ✗
-Управление метками       |   ✓   |   ✓   |    ✗    |    ✓     |   ✗
-Управление пользователями|   ✓   |   ✗   |    ✗    |    ✗     |   ✗
-Изменение планов         |   ✓   |   ✓   |    ✗    |    ✓     |   ✗
-```
-
-### Детальное логирование
-
-**Что логируется:**
-- Вход/выход пользователя (timestamp, IP адрес)
-- Переходы по страницам ("открыл страницу локации X")
-- Просмотр данных ("посмотрел аналитику за период Y")
-- Изменения ("изменил настройки железки #5", "привязал метку к человеку")
-- Экспорты ("скачал CSV с данными за месяц")
-- Действия с пользователями ("добавил пользователя", "изменил права")
-
-**Формат лога:**
-```
-2024-01-15 10:30:45 | user@example.com | Просмотр | Локация "Магазин на Ленина" | IP: 192.168.1.100
-2024-01-15 10:31:12 | user@example.com | Изменение | Метка #42: "Велосипед №5" → "Велосипед №6" | IP: 192.168.1.100
-2024-01-15 10:35:00 | user@example.com | Экспорт | WiFi Analytics, 2024-01-01 - 2024-01-15, CSV | IP: 192.168.1.100
-```
-
-**Где смотреть логи:**
-- Владелец и Админ видят все логи своей организации
-- Фильтры: по пользователю, по действию, по дате
-- Экспорт логов в CSV
-
-## Модульность системы
-
-Система должна легко расширяться новыми продуктами.
-
-**Принципы:**
-- Каждый продукт - независимый модуль
-- Админка - общая (управление клиентами, железками, пользователями)
-- Демон железки универсальный (можно включать/выключать модули в конфиге)
-- API универсальное (endpoints группируются по продуктам)
-
-**Пример добавления нового продукта "Temperature Monitoring":**
-1. В клиентах добавляется флаг `temperature_enabled`
-2. В API добавляется группа `/api/v1/client/temperature/*`
-3. В демоне железки добавляется модуль сбора температуры
-4. Во frontend добавляется раздел "Температура"
-5. Админ включает продукт клиенту - тот видит новый раздел
-
-**Переиспользование в других проектах:**
-- Можно взять только админку и использовать для управления любыми IoT устройствами
-- Можно взять демон железки и адаптировать под другое железо (Raspberry Pi, ESP32)
-- API спроектировано универсально
-
-## Технический стек
-
-### Backend
-- **Python + FastAPI**
-- **PostgreSQL** - клиенты, пользователи, железки, права
-- **ClickHouse** - события (BLE/WiFi), аналитика
-- **Redis** - очереди, кеш
-
-### Frontend
-- **Vue 3 + Vite**
-- **Vue Router** + **Pinia**
-- **TailwindCSS** (или Vuetify)
-
-### Деплой
-- **БЕЗ Docker** (обычный Linux + systemd)
-- Скрипт установки всех зависимостей
-- PostgreSQL, ClickHouse, Redis, Nginx
-- Автоматические миграции БД
-
-## План разработки
-
-### Этап 1: Фундамент (2-3 недели)
-- Auth (многопользовательский, роли)
-- Админка: клиенты + пользователи в организациях
-- Device API (регистрация, конфиг)
-- Управление железками (с простыми ID)
-- Background worker: буфер → ClickHouse
-
-### Этап 2: WiFi Analytics (1-2 недели)
-- WiFi события в ClickHouse
-- Аналитика (уникальные MAC, фейковые)
-- Клиентский кабинет WiFi
-- Экспорт данных
-
-### Этап 3: Tunnels (1 неделя)
-- SSH + Dashboard туннели
-- ttyd для веб-терминала
-- UI: кнопки + ожидание подключения
-
-### Этап 4: BLE Tracking (2-3 недели)
-- Локации, планы, метки
-- Загрузка и редактирование планов
-- Размещение приемников на карте
-- Real-time отображение меток
-
-### Этап 5: Права и логи (1 неделя)
-- Детальная система прав
-- Логирование всех действий
-- UI для просмотра логов
-
-## Открытые вопросы
-
-1. **Домен**: какой? mybeacon.ru?
-2. **Email**: SMTP настройки? Свой сервер или SendGrid?
-3. **File storage**: где хранить планы и фото? `/uploads` на сервере?
-4. **Real-time BLE**: polling каждые 5 сек или WebSocket?
-5. **Экспорт WiFi**: какой формат CSV нужен? Какие поля?
-6. **Хранение событий**: сколько хранить в ClickHouse? Год?
-7. **Ресурсы сервера**: сколько RAM/CPU? Сколько железок планируется?
+### Multi-tenant
+
+Полная изоляция данных между организациями:
+- Каждый пользователь принадлежит организации
+- Устройства назначаются организациям
+- API автоматически фильтрует данные по organization_id
+
+### Роли (RBAC)
+
+1. **superadmin** - полный доступ ко всем организациям и устройствам
+2. **owner** - управление своей организацией (создание/удаление пользователей, устройств)
+3. **admin** - управление пользователями в организации
+4. **manager** - просмотр и частичное управление
+5. **operator** - только просмотр устройств
+6. **viewer** - минимальный доступ (только чтение)
+
+### Автоматическая регистрация устройств
+
+- Superadmin включает авторегистрацию через API
+- Новые устройства регистрируются автоматически при первом подключении
+- Авторегистрация автоматически отключается через 1 час после последнего зарегистрированного устройства
+- Незарегистрированные устройства (organization_id = NULL) назначаются superadmin'ом
+
+## API Endpoints
+
+### Authentication (`/api/v1/auth/*`)
+
+```
+POST /auth/register      - Регистрация нового пользователя
+POST /auth/login         - Вход (получение JWT токенов)
+POST /auth/refresh       - Обновление access token
+GET  /auth/me            - Информация о текущем пользователе
+```
+
+### Superadmin API (`/api/v1/superadmin/*`)
+
+**Organizations:**
+```
+GET    /superadmin/organizations       - Список всех организаций
+POST   /superadmin/organizations       - Создание организации
+GET    /superadmin/organizations/:id   - Просмотр организации
+PATCH  /superadmin/organizations/:id   - Обновление (статус, модули)
+DELETE /superadmin/organizations/:id   - Удаление организации
+```
+
+**Users:**
+```
+GET    /superadmin/users                - Список всех пользователей
+POST   /superadmin/users                - Создание пользователя
+GET    /superadmin/users/:id            - Просмотр пользователя
+PATCH  /superadmin/users/:id            - Обновление пользователя
+DELETE /superadmin/users/:id            - Удаление пользователя
+POST   /superadmin/users/:id/change-password - Смена пароля
+```
+
+**Devices:**
+```
+GET    /superadmin/devices              - Список всех устройств
+POST   /superadmin/devices              - Регистрация устройства
+GET    /superadmin/devices/:id          - Просмотр устройства
+PATCH  /superadmin/devices/:id          - Обновление (назначение организации)
+DELETE /superadmin/devices/:id          - Удаление устройства
+```
+
+**Settings:**
+```
+GET  /superadmin/settings/auto-registration  - Статус авторегистрации
+POST /superadmin/settings/auto-registration  - Включить/выключить авторегистрацию
+```
+
+### Client API (`/api/v1/client/*`)
+
+**Organization:**
+```
+GET /client/organization/me - Информация о своей организации
+```
+
+**Users (owner/admin only):**
+```
+GET    /client/users                    - Пользователи в организации
+POST   /client/users                    - Создать пользователя
+GET    /client/users/:id                - Просмотр пользователя
+PATCH  /client/users/:id                - Обновление пользователя
+DELETE /client/users/:id                - Удаление пользователя
+POST   /client/users/:id/change-password - Смена пароля
+```
+
+**Devices:**
+```
+GET /client/devices     - Устройства организации
+GET /client/devices/:id - Просмотр устройства
+```
+
+### Device API (для железок)
+
+**Registration:**
+```
+POST /api/v1/registration
+Body: {"device_id": "MAC_ADDRESS", "ssh_public_key": "..."}
+Response: {"device_token": "...", "device_password": "..."}
+```
+
+**Configuration:**
+```
+GET /api/v1/config?device_id=MAC_ADDRESS
+Headers: Authorization: Bearer DEVICE_TOKEN
+Response: {config object with BLE/WiFi settings}
+```
+
+**Events:**
+```
+POST /api/v1/ble   - BLE scan events batch
+POST /api/v1/wifi  - WiFi probe events batch
+Headers: Authorization: Bearer DEVICE_TOKEN
+Headers: Content-Encoding: gzip (optional)
+Body: {"count": N, "events": [...]}
+```
+
+## Database Schema
+
+### Основные таблицы
+
+**users** - Пользователи (superadmin + org users)
+```sql
+id, email, hashed_password, full_name, phone,
+role, status, organization_id, email_verified,
+last_login_at, created_at
+```
+
+**organizations** - Организации (клиенты)
+```sql
+id, name, contact_email, contact_phone,
+wifi_enabled, ble_enabled, status, notes, created_at
+```
+
+**devices** - Устройства (receivers)
+```sql
+id, simple_id, mac_address, organization_id,
+device_token, device_password, status, last_seen_at,
+config (JSONB), created_at
+```
+
+**settings** - Системные настройки
+```sql
+id, key, value (JSONB), updated_at
+```
+
+**refresh_tokens** - JWT refresh tokens
+```sql
+id, user_id, token, expires_at, created_at
+```
+
+### Simple ID
+
+Устройства получают автоинкрементный simple_id для отображения:
+- Устройство #1, #2, #3... вместо MAC-адресов
+- PostgreSQL sequence гарантирует уникальность
+- Используется для customer support
+
+## Установка и запуск
+
+### Требования
+
+- Python 3.11+
+- PostgreSQL 16+
+- Redis 7+
+- Poetry
+
+### Установка
+
+```bash
+cd backend
+
+# Установка зависимостей
+poetry install
+
+# Копирование .env
+cp .env.example .env
+# Редактировать .env (DATABASE_URL, SECRET_KEY)
+
+# Миграции
+poetry run alembic upgrade head
+
+# Создание superadmin (вручную или через скрипт)
+poetry run python -c "
+from app.core.security import hash_password
+print(hash_password('YOUR_PASSWORD'))
+"
+# Вставить в БД:
+# INSERT INTO users (email, hashed_password, role, status, email_verified)
+# VALUES ('admin@example.com', 'HASHED_PASSWORD', 'superadmin', 'active', true);
+```
+
+### Запуск
+
+**Development:**
+```bash
+poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
+```
+
+**Production:**
+```bash
+poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
+```
+
+**Swagger UI:** http://localhost:8000/docs
+
+## Тестирование
+
+### Включение авторегистрации
+
+```bash
+curl -X POST http://localhost:8000/api/v1/superadmin/settings/auto-registration \
+  -H "Authorization: Bearer SUPERADMIN_TOKEN" \
+  -H "Content-Type: application/json" \
+  -d '{"enabled": true}'
+```
+
+### Проверка регистрации устройства
+
+```bash
+# На устройстве (автоматически при старте):
+# POST /api/v1/registration с MAC-адресом
+
+# Проверка в базе:
+psql -U mybeacon -d mybeacon -c "SELECT simple_id, mac_address, status FROM devices;"
+```
+
+### Назначение устройства организации
+
+```bash
+curl -X PATCH http://localhost:8000/api/v1/superadmin/devices/DEVICE_ID \
+  -H "Authorization: Bearer SUPERADMIN_TOKEN" \
+  -H "Content-Type: application/json" \
+  -d '{"organization_id": ORG_ID}'
+```
+
+## Конфигурация
+
+### Environment Variables (.env)
+
+```env
+# Database
+DATABASE_URL=postgresql+asyncpg://mybeacon:password@localhost/mybeacon
+
+# Security
+SECRET_KEY=your-secret-key-here-minimum-32-chars
+ALGORITHM=HS256
+ACCESS_TOKEN_EXPIRE_MINUTES=15
+REFRESH_TOKEN_EXPIRE_DAYS=30
+
+# Redis (optional)
+REDIS_URL=redis://localhost:6379/0
+
+# Server
+HOST=0.0.0.0
+PORT=8000
+```
+
+### Device Default Config
+
+Дефолтная конфигурация для устройств (см. `app/api/v1/config.py`):
+- BLE enabled, batch_interval_ms: 2500
+- WiFi monitor disabled по умолчанию
+- SSH/Dashboard tunnels disabled
+- NTP servers: pool.ntp.org, time.google.com
+
+Конфигурация перезаписывается через `device.config` (JSONB).
+
+## Безопасность
+
+- JWT токены с expiration (15 мин access, 30 дней refresh)
+- Device tokens уникальные, хранятся в БД
+- Bcrypt для паролей (cost factor 12)
+- HTTPS рекомендуется (nginx reverse proxy)
+- RBAC на уровне endpoints
+- Multi-tenant изоляция в SQL queries
+
+## Мониторинг
+
+События логируются в консоль:
+```
+[REGISTRATION] device=MAC simple_id=N
+[BLE BATCH] device=MAC simple_id=N count=X
+[WIFI BATCH] device=MAC simple_id=N count=X
+```
+
+ClickHouse для хранения событий будет добавлен позже.
+
+## Roadmap
+
+- [ ] ClickHouse интеграция для событий
+- [ ] WebSocket для real-time BLE карты
+- [ ] Frontend (Vue 3)
+- [ ] Email notifications
+- [ ] Audit logs middleware
+- [ ] Rate limiting
+- [ ] Grafana dashboards

+ 455 - 0
BACKEND_NOTES.md

@@ -0,0 +1,455 @@
+# MyBeacon Backend - Технические заметки
+
+Технические детали и особенности реализации.
+
+## Критические решения
+
+### 1. JWT Subject как string
+
+**Проблема:** python-jose требует JWT `sub` поле как string, но мы используем integer ID.
+
+**Решение:**
+```python
+# При создании токена
+if "sub" in to_encode and isinstance(to_encode["sub"], int):
+    to_encode["sub"] = str(to_encode["sub"])
+
+# При парсинге
+user_id_str: str = payload.get("sub")
+user_id = int(user_id_str)
+```
+
+**Файлы:**
+- `app/core/security.py:26-27` - конвертация при создании
+- `app/api/deps.py:48-62` - парсинг обратно в int
+
+### 2. JWT type field для разных токенов
+
+**Проблема:** Нужны разные типы токенов (access, refresh, device).
+
+**Решение:** Добавлено поле `type` в JWT payload:
+```python
+# Access token для пользователей
+{"sub": "user_id", "type": "access", "exp": ...}
+
+# Refresh token
+{"sub": "user_id", "type": "refresh", "exp": ...}
+
+# Device token
+{"sub": "device_id", "type": "device", "mac": "...", "org_id": ..., "exp": ...}
+```
+
+**Важно:** При создании токена НЕ перезаписываем `type` если он уже есть:
+```python
+# app/core/security.py:31-34
+if "type" not in to_encode:
+    to_encode["type"] = "access"
+to_encode["exp"] = expire
+```
+
+**Файлы:**
+- `app/core/security.py:31-34` - не перезаписываем type
+- `app/api/deps.py:182-187` - проверка type="device"
+
+### 3. Device simple_id auto-increment
+
+**Проблема:** NULL constraint violation при создании Device без simple_id.
+
+**Решение:** Добавить `server_default` в SQLAlchemy модель:
+```python
+simple_id: Mapped[int] = mapped_column(
+    Integer,
+    unique=True,
+    nullable=False,
+    server_default=text("nextval('device_simple_id_seq')"),
+)
+```
+
+**Критично:** `server_default` должен быть в модели, даже если sequence создан в миграции!
+
+**Файлы:**
+- `alembic/versions/001_initial_schema.py` - создание sequence
+- `app/models/device.py:23-28` - server_default в модели
+
+### 4. Bcrypt vs Passlib
+
+**Проблема:** Passlib с bcrypt backend имеет compatibility issues:
+```
+ValueError: password cannot be longer than 72 bytes
+```
+
+**Решение:** Использовать bcrypt напрямую, убрать passlib:
+```python
+import bcrypt
+
+def hash_password(password: str) -> str:
+    salt = bcrypt.gensalt()
+    hashed = bcrypt.hashpw(password.encode("utf-8"), salt)
+    return hashed.decode("utf-8")
+
+def verify_password(plain_password: str, hashed_password: str) -> bool:
+    return bcrypt.checkpw(
+        plain_password.encode("utf-8"),
+        hashed_password.encode("utf-8")
+    )
+```
+
+**Файлы:**
+- `app/core/security.py:83-103` - прямой bcrypt
+- `pyproject.toml` - только bcrypt, без passlib
+
+### 5. Stub-compatible Device API
+
+**Проблема:** Демон на железке ожидает stub API (192.168.5.2:5000).
+
+**Решение:** Реализованы endpoints полностью совместимые со stub:
+```
+POST /api/v1/registration
+GET  /api/v1/config?device_id=MAC
+POST /api/v1/ble
+POST /api/v1/wifi
+```
+
+**Важно:**
+- `device_id` передаётся как query parameter в GET /config
+- Authorization header с Bearer token обязателен (кроме /registration)
+- Content-Encoding: gzip поддерживается для events
+
+**Файлы:**
+- `app/api/v1/registration.py` - POST /registration
+- `app/api/v1/config.py` - GET /config
+- `app/api/v1/events.py` - POST /ble, POST /wifi
+
+### 6. Автоматическая регистрация устройств
+
+**Проблема:** Каждое новое устройство регистрировать руками неудобно.
+
+**Решение:** Settings table с JSON value + toggle в superadmin API:
+```python
+# settings table
+{
+  "key": "auto_registration",
+  "value": {
+    "enabled": true,
+    "last_device_at": "2025-12-27T11:39:14Z"
+  }
+}
+```
+
+**Механизм:**
+1. Superadmin включает авторегистрацию через API
+2. Устройство отправляет POST /registration
+3. Если enabled=true, создаётся Device с organization_id=NULL
+4. При создании обновляется last_device_at
+5. Автоотключение через 1 час после last_device_at (проверяется в GET /auto-registration)
+
+**Файлы:**
+- `app/models/settings.py` - модель Settings
+- `app/services/device_auth_service.py:36-62` - авторегистрация
+- `app/api/v1/superadmin/settings.py` - toggle API
+
+### 7. FastAPI Depends в Annotated
+
+**Проблема:**
+```python
+db: Annotated[AsyncSession, Depends(get_db)] = Depends(get_db)
+# AssertionError: Cannot specify Depends in Annotated and default value
+```
+
+**Решение:** Параметры БЕЗ default value должны идти ПЕРЕД параметрами с default:
+```python
+# Правильно
+async def endpoint(
+    db: Annotated[AsyncSession, Depends(get_db)],  # БЕЗ default
+    param: str = Query(None),  # С default
+):
+    pass
+
+# Неправильно
+async def endpoint(
+    param: str = Query(None),
+    db: Annotated[AsyncSession, Depends(get_db)],  # ОШИБКА!
+):
+    pass
+```
+
+**Файлы:** Все endpoints с Depends
+
+### 8. Device token vs Device password
+
+**Два поля в devices:**
+- `device_token` - Bearer token для API (base64, 32 bytes)
+- `device_password` - 8-digit password для dashboard admin
+
+**device_token** - используется в Authorization header
+**device_password** - для POST /admin/update_device в будущем
+
+**Генерация:**
+```python
+def _generate_token() -> str:
+    return b64encode(secrets.token_bytes(32)).decode("ascii")
+
+def _generate_password() -> str:
+    n = secrets.randbelow(10**8)
+    return f"{n:08d}"
+```
+
+**Файлы:**
+- `app/api/v1/registration.py:29-37` - генерация
+- `app/models/device.py:61-62` - поля в модели
+
+## Особенности архитектуры
+
+### Multi-tenant isolation
+
+**SQL уровень:**
+```python
+# Автоматическая фильтрация по organization_id
+result = await db.execute(
+    select(Device).where(
+        Device.organization_id == current_user.organization_id
+    )
+)
+```
+
+**Проверки:**
+```python
+# Проверка принадлежности к организации
+if device.organization_id != current_user.organization_id:
+    raise HTTPException(status_code=403, detail="...")
+```
+
+**Файлы:**
+- `app/api/v1/client/devices.py:72-76` - проверка organization_id
+- `app/api/v1/client/users.py:81-85` - multi-tenant для users
+
+### RBAC Dependencies
+
+**Иерархия:**
+```python
+get_current_user()                # Любой авторизованный
+  └─ get_current_owner()          # owner или superadmin
+       └─ get_current_superadmin() # только superadmin
+```
+
+**Использование:**
+```python
+@router.post("/users")
+async def create_user(
+    current_user: Annotated[User, Depends(get_current_owner)],  # owner/admin only
+):
+    pass
+```
+
+**Файлы:**
+- `app/api/deps.py:83-127` - все dependencies
+
+### Config JSONB merge
+
+Device config - это JSONB поле для гибких настроек:
+```python
+# Default config (hardcoded)
+default_config = {
+    "ble": {"enabled": True, "batch_interval_ms": 2500},
+    "wifi": {"monitor_enabled": False}
+}
+
+# Device-specific overrides (в БД)
+device.config = {
+    "wifi": {"monitor_enabled": True}  # override
+}
+
+# Merged config (отправляется устройству)
+merged = {
+    "ble": {"enabled": True, "batch_interval_ms": 2500},
+    "wifi": {"monitor_enabled": True}  # OVERRIDDEN
+}
+```
+
+**Файлы:**
+- `app/api/v1/config.py:56-95` - merge logic
+
+## Database особенности
+
+### Async SQLAlchemy
+
+```python
+# asyncpg driver
+DATABASE_URL = "postgresql+asyncpg://user:password@host/db"
+
+# async session
+async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
+
+# usage
+async with async_session() as session:
+    result = await session.execute(select(User))
+    user = result.scalar_one_or_none()
+```
+
+**Важно:** `expire_on_commit=False` чтобы можно было использовать объекты после commit.
+
+**Файлы:**
+- `app/core/database.py:11-14` - async session config
+
+### JSONB columns
+
+PostgreSQL JSONB для гибких данных:
+- `devices.config` - конфигурация устройства
+- `settings.value` - системные настройки
+
+**Преимущества:**
+- Можно добавлять новые поля без миграций
+- Можно делать partial updates
+- Можно query по содержимому (GIN индексы)
+
+**Файлы:**
+- `app/models/device.py:58` - config JSONB
+- `app/models/settings.py:14` - value JSONB
+
+### Sequences
+
+PostgreSQL sequence для simple_id:
+```sql
+CREATE SEQUENCE device_simple_id_seq START 1;
+ALTER TABLE devices
+  ALTER COLUMN simple_id
+  SET DEFAULT nextval('device_simple_id_seq');
+```
+
+**Важно:** SQLAlchemy модель ДОЛЖНА иметь `server_default`!
+
+**Файлы:**
+- `alembic/versions/001_initial_schema.py` - CREATE SEQUENCE
+- `app/models/device.py:23-28` - server_default
+
+## Тестирование
+
+### Тестовые данные в БД
+
+**Superadmin:**
+- email: superadmin@mybeacon.com
+- password: Admin123!
+- role: superadmin
+
+**Owner:**
+- email: admin@mybeacon.com
+- password: Admin123!
+- role: owner
+- organization_id: 4
+
+**Devices:**
+- #2 (AA:BB:CC:DD:EE:02) - тестовое
+- #4 (38:54:39:4b:1b:ac) - реальное железо на 192.168.5.244
+
+### Тестовые скрипты
+
+```bash
+/tmp/test_client.sh       # Client API test
+/tmp/test_device_api.sh   # Device API test
+/tmp/demo_hardware.sh     # Hardware integration demo
+/tmp/enable_autoreg.sh    # Enable auto-registration
+/tmp/assign_device.sh     # Assign device to org
+```
+
+## Deployment
+
+### Environment
+
+- **Server:** 192.168.5.4:8000
+- **Database:** PostgreSQL на localhost
+- **Redis:** localhost:6379 (optional)
+
+### Hardware
+
+- **Device:** Luckfox Pico Ultra W (192.168.5.244)
+- **Daemon:** /etc/init.d/S98mybeacon
+- **Server URL:** обновлён на http://192.168.5.4:8000
+
+### Startup
+
+```bash
+cd /home/user/work/luckfox/alpine/mybeacon-backend/backend
+poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000
+```
+
+**Production:** Добавить systemd service + nginx reverse proxy.
+
+## Known Issues
+
+### Resolved
+
+✅ JWT Subject must be string - конвертируем int → str
+✅ Device simple_id NULL - добавлен server_default
+✅ Bcrypt/passlib compatibility - используем прямой bcrypt
+✅ Device token type - не перезаписываем type в create_access_token
+✅ FastAPI Depends ordering - параметры без default идут первыми
+
+### TODO
+
+- [ ] ClickHouse для хранения событий (BLE/WiFi)
+- [ ] Audit logs middleware
+- [ ] Email verification
+- [ ] Password reset flow
+- [ ] Rate limiting на login
+- [ ] WebSocket для real-time
+- [ ] Frontend (Vue 3)
+
+## Performance
+
+### Текущее состояние
+
+- BLE events: 2-46 событий в батче
+- Logging: только в консоль (print)
+- Database: PostgreSQL без индексов (пока)
+
+### Оптимизации (when needed)
+
+1. ClickHouse для событий (миллионы records)
+2. Redis для кеширования config
+3. PostgreSQL индексы (organization_id, mac_address, created_at)
+4. Connection pooling (asyncpg имеет встроенный)
+5. Batch inserts для событий
+
+## Monitoring
+
+### Logs
+
+```
+[REGISTRATION] device=38:54:39:4b:1b:ac simple_id=4
+[BLE BATCH] device=38:54:39:4b:1b:ac simple_id=4 count=46
+[WIFI BATCH] device=38:54:39:4b:1b:ac simple_id=4 count=10
+```
+
+### Metrics (future)
+
+- Prometheus + Grafana
+- Device online/offline count
+- Events per second
+- API latency
+
+## Security
+
+### JWT Security
+
+- **Access token:** 15 minutes (короткий срок)
+- **Refresh token:** 30 days (хранится в БД с возможностью отзыва)
+- **Device token:** не expire (можно добавить rotation)
+
+### Password Security
+
+- **Bcrypt** с default cost factor (12)
+- **Min length:** 8 символов (в Pydantic schema)
+- **Strength:** рекомендуется uppercase + lowercase + digit + special
+
+### API Security
+
+- **HTTPS:** рекомендуется в production (nginx SSL termination)
+- **CORS:** настроить allowed origins
+- **Rate limiting:** добавить для /auth/login
+- **SQL injection:** защищено через SQLAlchemy ORM
+
+## Git
+
+**Repository:** https://h2.e-bash.ru/root/mybeacon-backend.git
+**Branch:** master
+**Latest commit:** Implement complete MyBeacon backend MVP