Компоненты системы
Backend компоненты
FastAPI приложение
Главный модуль приложения находится в src/main.py.
app = FastAPI(title="TVIP Provisioning Service")
Включает:
CORS middleware для frontend
Регистрацию роутеров из presentation слоя
Инициализацию БД при старте
Uvicorn сервер
ASGI сервер для запуска FastAPI приложения. Конфигурация в supervisord.conf:
[program:uvicorn]
command=uvicorn main:app --host 0.0.0.0 --port 8000
directory=/app/src
PostgreSQL
База данных для хранения:
Устройств (devices)
Конфигураций (provision_configs)
Схема БД:
CREATE TABLE devices (
id SERIAL PRIMARY KEY,
mac_address VARCHAR(17) UNIQUE NOT NULL,
ip_address VARCHAR(45),
model VARCHAR(100),
custom_config_id INTEGER,
created_at TIMESTAMP DEFAULT NOW(),
last_seen_at TIMESTAMP
);
CREATE TABLE provision_configs (
id SERIAL PRIMARY KEY,
config_type VARCHAR(20) NOT NULL,
config_data JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP
);
Nginx
Reverse proxy для:
Проксирование запросов к FastAPI
Установка заголовков X-Real-IP
Отдача статических файлов (опционально)
Supervisord
Управление процессами внутри контейнера:
uvicorn (FastAPI)
nginx
Frontend компоненты
React приложение
SPA приложение для администрирования:
Layout — общий layout с навигацией
DevicesList — список устройств с фильтрацией
DeviceConfig — редактирование конфигурации устройства
DefaultConfig — управление дефолтной конфигурацией
Vite dev server
Development сервер с hot reload для разработки.
API клиент (Axios)
Модуль services/api.js для взаимодействия с backend:
const api = axios.create({
baseURL: API_BASE_URL,
headers: { 'Content-Type': 'application/json' }
});
Nginx (production)
Для production используется отдельный nginx контейнер, отдающий собранные статические файлы.
Доменные компоненты
Entities (Сущности)
Device
Представляет TVIP-приставку.
Атрибуты:
mac_address: MacAddress— MAC-адрес устройстваip_address: Optional[IpAddress]— IP-адресmodel: Optional[str]— модель приставкиcustom_config_id: Optional[int]— ID кастомной конфигурацииcreated_at: datetime— время регистрацииlast_seen_at: Optional[datetime]— время последнего обращения
ProvisionConfig
Представляет конфигурацию.
Атрибуты:
id: int— идентификаторconfig_type: ProvisionConfigType— тип (DEFAULT или CUSTOM)config_data: ConfigData— данные конфигурацииcreated_at: datetime— время созданияupdated_at: Optional[datetime]— время обновления
Value Objects
MacAddress
Валидация и нормализация MAC-адресов.
mac = MacAddress("00:11:22:33:44:55")
assert mac.value == "00:11:22:33:44:55"
IpAddress
Валидация IP-адресов (IPv4/IPv6).
ConfigData
Работа с конфигурацией в формате dot notation.
config = ConfigData({"provision.@reload": "3600"})
config.set("provision.operator.@name", "MyOperator")
xml = config.to_dict() # Преобразование в иерархический dict
ProvisionConfigType
Enum для типа конфигурации (DEFAULT, CUSTOM).
Repositories (Репозитории)
DeviceRepository
Интерфейс для работы с устройствами:
get_by_mac(mac: str) -> Optional[Device]create(device: Device) -> Deviceupdate(device: Device) -> Deviceget_all(filters) -> List[Device]
ProvisionRepository
Интерфейс для работы с конфигурациями:
get_default_config() -> ProvisionConfigget_by_id(id: int) -> Optional[ProvisionConfig]update(config: ProvisionConfig) -> ProvisionConfigcreate(config: ProvisionConfig) -> ProvisionConfig
Services (Доменные сервисы)
XmlSerializer
Интерфейс для сериализации конфигураций в XML:
serialize(data: dict) -> str— преобразование dict в XML строку
DefaultConfigService
Сервис для работы с дефолтной конфигурацией:
get_default_config()— получение дефолтной конфигурацииensure_default_exists()— создание дефолтной конфигурации при отсутствии
Прикладные компоненты
Use Cases
HandleProvisionRequestUseCase
Обработка запроса от TVIP-приставки:
Проверка существования устройства
Создание нового устройства при необходимости
Обновление метаданных (IP, модель, время)
Получение конфигурации (кастомной или дефолтной)
Сериализация в XML
GetDevicesListUseCase
Получение списка устройств с фильтрацией по:
IP-адресу
Модели
Времени последней активности
Pagination (limit/offset)
UpdateDeviceConfigUseCase
Частичное обновление конфигурации устройства через dot notation.
ReplaceDeviceConfigUseCase
Полная замена конфигурации устройства.
ResetDeviceConfigUseCase
Сброс конфигурации устройства к дефолтной (удаление кастомной конфигурации).
UpdateDefaultConfigUseCase
Частичное обновление дефолтной конфигурации.
ReplaceDefaultConfigUseCase
Полная замена дефолтной конфигурации.
GetDefaultConfigUseCase
Получение дефолтной конфигурации.
Инфраструктурные компоненты
SQLAlchemy модели
DeviceModel
ORM модель для таблицы devices.
ProvisionConfigModel
ORM модель для таблицы provision_configs. Использует JSONB для хранения конфигурации.
Репозитории
SQLDeviceRepository
Реализация DeviceRepository через SQLAlchemy.
SQLProvisionRepository
Реализация ProvisionRepository через SQLAlchemy.
Сериализаторы
XmlToDictSerializer
Реализация XmlSerializer через библиотеку xmltodict.
Value Objects
PydashConfigData
Реализация ConfigData через библиотеку pydash для работы с dot notation.
Dependency Injection
Модуль infrastructure/di/injection.py содержит провайдеры для всех use cases:
def get_handle_provision_use_case(
device_repo: DeviceRepository = Depends(get_device_repository),
provision_repo: ProvisionRepository = Depends(get_provision_repository),
serializer: XmlSerializer = Depends(get_xml_serializer)
) -> HandleProvisionRequestUseCase:
return HandleProvisionRequestUseCase(device_repo, provision_repo, serializer)
Фабрики
ConfigDataFactory
Создание экземпляров ConfigData (использует PydashConfigData).
Взаимодействие компонентов
Поток запроса от TVIP
Nginx получает запрос от приставки
Nginx устанавливает заголовок
X-Real-IPи проксирует в FastAPIEndpoint (
provision.py) извлекаетMac-Addressиз заголовковUse Case (
HandleProvisionRequestUseCase) выполняет бизнес-логику:Запрашивает устройство через DeviceRepository
Создаёт новое устройство при отсутствии
Получает конфигурацию через ProvisionRepository
Сериализует в XML через XmlSerializer
Endpoint возвращает XML с
Content-Type: application/xml
Поток API запроса
Frontend отправляет запрос через Axios
Nginx проксирует в FastAPI
Endpoint (
devices_management.py) вызывает соответствующий Use CaseUse Case работает с репозиториями
Repository выполняет SQL запрос через SQLAlchemy
Результат возвращается обратно через слои