772 lines
30 KiB
Markdown
772 lines
30 KiB
Markdown
# ⚽ VMIX Football Broadcast System
|
||
|
||
<p align="center">
|
||
<img src="https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white" alt="Python">
|
||
<img src="https://img.shields.io/badge/FastAPI-0.115+-009688?logo=fastapi&logoColor=white" alt="FastAPI">
|
||
<img src="https://img.shields.io/badge/PostgreSQL-15+-4169E1?logo=postgresql&logoColor=white" alt="PostgreSQL">
|
||
<img src="https://img.shields.io/badge/WebSocket-Realtime-7C3AED" alt="WebSocket">
|
||
<img src="https://img.shields.io/badge/vMix-Integration-FF6A00" alt="vMix">
|
||
<img src="https://img.shields.io/badge/status-active-success" alt="Status">
|
||
</p>
|
||
|
||
> Система управления футбольными трансляциями с интеграцией в **vMix**, админ-панелью, live-обновлением матчей, генерацией данных для графики и WebSocket-взаимодействием с операторскими клиентами.
|
||
|
||
---
|
||
|
||
## 📌 Что это за проект
|
||
|
||
Проект предназначен для подготовки и сопровождения футбольных трансляций. Он объединяет в одном приложении:
|
||
|
||
- администрирование матчей, команд, игроков, тренеров, судей и стадионов;
|
||
- работу с составами и формациями на матч;
|
||
- генерацию данных для эфирной графики в vMix;
|
||
- создание и выгрузку `.vmix`-проекта;
|
||
- приём и отправку команд в vMix-клиенты через WebSocket;
|
||
- фоновое отслеживание матчей и обновление live-данных;
|
||
- синхронизацию расписания, игроков, команд и турнирной таблицы.
|
||
|
||
По текущей структуре проект ориентирован на внутреннюю production/операторскую эксплуатацию, а не на публичный API-сервис.
|
||
|
||
---
|
||
|
||
## ✨ Основные возможности
|
||
|
||
### Админка и матч-центр
|
||
- авторизация администратора;
|
||
- список матчей и выбор матча для сессии;
|
||
- рабочее пространство матча;
|
||
- редактирование составов;
|
||
- редактирование формаций;
|
||
- управление судьями;
|
||
- управление событиями матча.
|
||
|
||
### База футбольных сущностей
|
||
- игроки;
|
||
- команды;
|
||
- тренеры;
|
||
- судьи;
|
||
- стадионы;
|
||
- турнирная таблица;
|
||
- составы на матч;
|
||
- матчевые сессии для операторов.
|
||
|
||
### Интеграция с vMix
|
||
- генерация `.vmix`-проекта;
|
||
- формирование имени файла проекта;
|
||
- генерация JSON-данных для графики;
|
||
- публикация команд в подключённые vMix-клиенты;
|
||
- получение динамических значений из vMix API.
|
||
|
||
### Live-логика
|
||
- планировщик, который отслеживает матчи дня;
|
||
- запуск watcher-потоков перед матчем;
|
||
- опрос live-данных каждые 60 секунд;
|
||
- обновление статуса матча и счёта;
|
||
- обновление турнирной таблицы.
|
||
|
||
### Парсинг и синхронизация
|
||
- парсинг матчей;
|
||
- парсинг игроков;
|
||
- парсинг расписания;
|
||
- парсинг таблицы;
|
||
- синхронизация сущностей в БД через сервисный слой.
|
||
|
||
---
|
||
|
||
## 🏗 Архитектура
|
||
|
||
Проект построен вокруг классической схемы:
|
||
|
||
```text
|
||
Parsers -> Services -> Repositories -> PostgreSQL
|
||
|
|
||
+-> vMix JSON / .vmix generation
|
||
+-> FastAPI admin UI
|
||
+-> WebSocket command bus
|
||
+-> Scheduler / live workers
|
||
```
|
||
|
||
### Слои проекта
|
||
|
||
#### `parsers/`
|
||
Получают данные из внешних источников. Используются для матчей, игроков, расписания, команд и таблиц.
|
||
|
||
#### `services/`
|
||
Содержат прикладную бизнес-логику: синхронизацию данных, авторизацию, подготовку JSON для vMix.
|
||
|
||
#### `repositories/`
|
||
Отвечают за доступ к PostgreSQL. Здесь собраны CRUD-операции и специализированные запросы.
|
||
|
||
#### `templates/` + `static/`
|
||
HTML-шаблоны Jinja2, CSS, JS и статические файлы интерфейса.
|
||
|
||
#### `vmix/`
|
||
Логика генерации vMix-проекта и служебные функции, связанные с эфирной интеграцией.
|
||
|
||
#### `scheduler.py`
|
||
Фоновый мониторинг матчей и обновление live-состояния.
|
||
|
||
#### `agent.py`
|
||
Отдельный клиент для связи между vMix и сервером через WebSocket.
|
||
|
||
---
|
||
|
||
## 📁 Структура проекта
|
||
|
||
```text
|
||
vmix/
|
||
├── app.py # Основной FastAPI сервер
|
||
├── agent.py # WebSocket/vMix агент
|
||
├── db.py # Подключение к PostgreSQL
|
||
├── scheduler.py # Фоновый live scheduler
|
||
├── main.py # Demo/seed сценарий
|
||
├── deploy.sh # Скрипт деплоя
|
||
├── requirements.txt # Python зависимости
|
||
├── wfl.sql # Основная схема БД
|
||
│
|
||
├── parsers/
|
||
│ ├── parser_game.py # Парсинг/обновление данных матча
|
||
│ ├── parser_players.py # Парсинг игроков
|
||
│ ├── parser_schedule.py # Парсинг расписания
|
||
│ ├── parser_standings.py # Парсинг таблицы
|
||
│ └── parser_teams.py # Парсинг команд
|
||
│
|
||
├── repositories/
|
||
│ ├── audit_log_repository.py
|
||
│ ├── auth_repository.py
|
||
│ ├── coach_repository.py
|
||
│ ├── match_clock_repository.py
|
||
│ ├── match_coach_repository.py
|
||
│ ├── match_event_repository.py
|
||
│ ├── match_formation_repository.py
|
||
│ ├── match_lineup_repository.py
|
||
│ ├── match_referee_repository.py
|
||
│ ├── match_repository.py
|
||
│ ├── match_session_repository.py
|
||
│ ├── match_view_repository.py
|
||
│ ├── player_repository.py
|
||
│ ├── referee_repository.py
|
||
│ ├── stadium_repository.py
|
||
│ ├── standings_repository.py
|
||
│ ├── team_coach_repository.py
|
||
│ ├── team_repository.py
|
||
│ └── team_squad_repository.py
|
||
│
|
||
├── services/
|
||
│ ├── auth_service.py
|
||
│ ├── game_service.py
|
||
│ ├── players_service.py
|
||
│ ├── schedule_service.py
|
||
│ ├── standings_service.py
|
||
│ ├── teams_service.py
|
||
│ └── vmix_json_service.py
|
||
│
|
||
├── sql/
|
||
│ └── 001_auth.sql # Таблицы админ-пользователей и сессий
|
||
│
|
||
├── static/
|
||
│ ├── script.js
|
||
│ ├── styles.css
|
||
│ ├── smith.ico
|
||
│ └── images/
|
||
│ └── vmix_icon.png
|
||
│
|
||
├── templates/
|
||
│ ├── login.html
|
||
│ ├── matches.html
|
||
│ ├── match_workspace.html
|
||
│ ├── download_vmix.html
|
||
│ ├── admin_db_index.html
|
||
│ ├── admin_db_players.html
|
||
│ ├── admin_db_player_edit.html
|
||
│ ├── admin_db_referees.html
|
||
│ ├── admin_db_referee_edit.html
|
||
│ ├── admin_db_coaches.html
|
||
│ ├── admin_db_coach_edit.html
|
||
│ ├── admin_db_stadiums.html
|
||
│ ├── admin_db_stadium_edit.html
|
||
│ ├── admin_db_teams.html
|
||
│ └── admin_db_team_edit.html
|
||
│
|
||
└── vmix/
|
||
├── __init__.py
|
||
└── vmix_service.py # Генерация .vmix файла
|
||
```
|
||
|
||
---
|
||
|
||
## 🧰 Технологии
|
||
|
||
| Категория | Технологии |
|
||
|---|---|
|
||
| Backend | FastAPI |
|
||
| Валидация | Pydantic |
|
||
| Шаблоны | Jinja2 |
|
||
| База данных | PostgreSQL + psycopg2 |
|
||
| Парсинг | requests + BeautifulSoup4 |
|
||
| Realtime | WebSocket |
|
||
| Интеграция с эфиром | vMix API + XML |
|
||
| Конфигурация | python-dotenv |
|
||
| Дополнительно | numpy |
|
||
|
||
### Зависимости из `requirements.txt`
|
||
|
||
```txt
|
||
fastapi>=0.115,<1.0
|
||
uvicorn[standard]>=0.30,<1.0
|
||
pydantic>=2.0,<3.0
|
||
jinja2>=3.1,<4.0
|
||
python-multipart>=0.0.9,<1.0
|
||
requests>=2.31,<3.0
|
||
websockets>=12,<16
|
||
beautifulsoup4>=4.12,<5.0
|
||
psycopg2-binary>=2.9,<3.0
|
||
python-dotenv>=1.0,<2.0
|
||
numpy>=1.26,<3.0
|
||
```
|
||
|
||
Также в файле указан дополнительный приватный индекс и пакет `nasio`, поэтому для полноценной установки в целевой среде может понадобиться доступ к внутреннему package registry.
|
||
|
||
---
|
||
|
||
## 🚀 Быстрый старт
|
||
|
||
## 1. Клонирование репозитория
|
||
|
||
```bash
|
||
git clone <YOUR_REPOSITORY_URL>
|
||
cd vmix
|
||
```
|
||
|
||
## 2. Установка зависимостей
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
## 3. Настройка переменных окружения
|
||
|
||
Создай файл `.env` в корне проекта:
|
||
|
||
```env
|
||
DB_HOST=localhost
|
||
DB_PORT=5432
|
||
DB_NAME=wfl_db
|
||
DB_USER=postgres
|
||
DB_PASSWORD=your_password
|
||
```
|
||
|
||
`db.py` загружает эти параметры через `python-dotenv` и использует их для подключения к PostgreSQL.
|
||
|
||
## 4. Инициализация базы данных
|
||
|
||
Сначала разверни основную схему:
|
||
|
||
```bash
|
||
psql -U postgres -d wfl_db -f wfl.sql
|
||
```
|
||
|
||
Затем создай таблицы авторизации:
|
||
|
||
```bash
|
||
psql -U postgres -d wfl_db -f sql/001_auth.sql
|
||
```
|
||
|
||
## 5. Создание администратора
|
||
|
||
```bash
|
||
python scripts/create_admin.py
|
||
```
|
||
|
||
Скрипт запросит:
|
||
- `Username`
|
||
- `Password`
|
||
|
||
После этого создаст запись в таблице `admin_users`.
|
||
|
||
## 6. Запуск приложения
|
||
|
||
```bash
|
||
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
|
||
После запуска приложение будет доступно по адресу:
|
||
|
||
```text
|
||
http://localhost:8000
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 Авторизация
|
||
|
||
В проекте используется сессионная авторизация для админки.
|
||
|
||
### Что есть в коде
|
||
- таблица `admin_users`;
|
||
- таблица `auth_sessions`;
|
||
- проверка пароля в `services/auth_service.py`;
|
||
- cookie/session-based доступ к админским маршрутам;
|
||
- logout с отзывом сессии.
|
||
|
||
### SQL-таблицы авторизации
|
||
Файл `sql/001_auth.sql` создаёт:
|
||
- `admin_users`
|
||
- `auth_sessions`
|
||
- индексы по токену, пользователю и активности
|
||
|
||
### Скрипт создания пользователя
|
||
`python scripts/create_admin.py`
|
||
|
||
---
|
||
|
||
## 🖥 Интерфейс и рабочие зоны
|
||
|
||
### Основные страницы
|
||
- `/login` — вход администратора;
|
||
- `/` — редирект/входная точка;
|
||
- `/admin/matches` — список матчей для администратора;
|
||
- `/admin/session/{session_token}` — рабочее пространство матча;
|
||
- `/admin/session/{session_token}/download-vmix-page` — страница выгрузки проекта;
|
||
- `/admin/db` — индекс админского раздела БД.
|
||
|
||
### Разделы админ-БД
|
||
- игроки;
|
||
- судьи;
|
||
- тренеры;
|
||
- стадионы;
|
||
- команды.
|
||
|
||
Для каждой сущности есть минимум список и форма редактирования.
|
||
|
||
---
|
||
|
||
## 📡 HTTP и WebSocket API
|
||
|
||
Ниже — маршруты, которые реально определены в `app.py`.
|
||
|
||
### Аутентификация
|
||
|
||
| Метод | Маршрут | Назначение |
|
||
|---|---|---|
|
||
| GET | `/login` | страница входа |
|
||
| POST | `/login` | авторизация |
|
||
| POST | `/logout` | выход |
|
||
|
||
### Матчи и сессии
|
||
|
||
| Метод | Маршрут | Назначение |
|
||
|---|---|---|
|
||
| GET | `/admin/matches` | список матчей |
|
||
| GET | `/admin/matches/{match_id}/select` | выбор матча и создание/открытие сессии |
|
||
| GET | `/admin/session/{session_token}` | рабочее пространство матча |
|
||
| POST | `/admin/session/{session_token}/load-match-data` | загрузка/обновление данных матча |
|
||
| POST | `/admin/session/{session_token}/close` | закрытие сессии |
|
||
| GET | `/admin/session/{session_token}/download-vmix-page` | HTML-страница выгрузки vMix |
|
||
| GET | `/admin/session/{session_token}/download-vmix` | скачивание `.vmix` |
|
||
|
||
### Формации и составы
|
||
|
||
| Метод | Маршрут | Назначение |
|
||
|---|---|---|
|
||
| POST | `/admin/session/{session_token}/formations/apply` | применить preset формации к игрокам |
|
||
| POST | `/admin/session/{session_token}/formations/save` | сохранить формации |
|
||
| GET | `/admin/session/{session_token}/squad-editor-data` | получить данные редактора состава |
|
||
| POST | `/admin/session/{session_token}/squad-editor-save` | сохранить состав |
|
||
| POST | `/admin/session/{session_token}/referees/save` | сохранить судей на матч |
|
||
|
||
### События матча
|
||
|
||
| Метод | Маршрут | Назначение |
|
||
|---|---|---|
|
||
| GET | `/admin/session/{session_token}/events` | список событий |
|
||
| POST | `/admin/session/{session_token}/event` | создать событие |
|
||
| PUT | `/admin/session/{session_token}/event/{event_id}` | обновить событие |
|
||
| DELETE | `/admin/session/{session_token}/event/{event_id}` | удалить событие |
|
||
| DELETE | `/admin/session/{session_token}/events` | очистить все события |
|
||
|
||
### Справочники БД
|
||
|
||
| Метод | Маршрут | Назначение |
|
||
|---|---|---|
|
||
| GET | `/admin/db` | главная админ-БД |
|
||
| GET/POST | `/admin/db/players` / `/admin/db/players/{player_id}/edit` | список/редактирование игроков |
|
||
| GET/POST | `/admin/db/referees` / `/admin/db/referees/{referee_id}/edit` | список/редактирование судей |
|
||
| GET/POST | `/admin/db/coaches` / `/admin/db/coaches/{coach_id}/edit` | список/редактирование тренеров |
|
||
| GET/POST | `/admin/db/stadiums` / `/admin/db/stadiums/{stadium_id}/edit` | список/редактирование стадионов |
|
||
| GET/POST | `/admin/db/teams` / `/admin/db/teams/{team_id}/edit` | список/редактирование команд |
|
||
|
||
### vMix JSON endpoints
|
||
|
||
| Метод | Маршрут | Назначение |
|
||
|---|---|---|
|
||
| GET | `/vmix/session/{session_token}/home-lineup` | стартовый состав хозяев |
|
||
| GET | `/vmix/session/{session_token}/away-lineup` | стартовый состав гостей |
|
||
| GET | `/vmix/session/{session_token}/home-bench` | запасные хозяев |
|
||
| GET | `/vmix/session/{session_token}/away-bench` | запасные гостей |
|
||
| GET | `/vmix/session/{session_token}/info` | информация о матче |
|
||
| GET | `/vmix/session/{session_token}/standings` | турнирная таблица |
|
||
| GET | `/vmix/session/{session_token}/schedule` | расписание/тур |
|
||
| GET | `/vmix/session/{session_token}/home-formations` | формация хозяев |
|
||
| GET | `/vmix/session/{session_token}/away-formations` | формация гостей |
|
||
| GET | `/vmix/session/{session_token}/scoreboard` | данные для счётчика |
|
||
| GET | `/vmix/session/{session_token}/match-events` | данные по событиям матча |
|
||
|
||
### Команды для vMix-клиентов
|
||
|
||
| Метод | Маршрут | Назначение |
|
||
|---|---|---|
|
||
| POST | `/api/vmix/publish-command` | отправить команду в vMix-клиент(ы) |
|
||
| GET | `/api/vmix/clients` | список подключённых клиентов |
|
||
| WS | `/ws/vmix-client` | WebSocket-канал клиентов |
|
||
|
||
---
|
||
|
||
## 🎬 Интеграция с vMix
|
||
|
||
### Что делает сервер
|
||
Сервер:
|
||
- создаёт матчевые сессии;
|
||
- готовит JSON для графики;
|
||
- собирает и отдаёт `.vmix`-проект;
|
||
- отправляет команды в подключённые клиентские агенты.
|
||
|
||
### Что делает агент `agent.py`
|
||
Агент — это отдельное приложение, которое запускается рядом с vMix и выполняет роль моста между сервером и локальным vMix API.
|
||
|
||
#### В коде агента есть:
|
||
- `VMIX_API = "http://127.0.0.1:8088/api"`
|
||
- `WS_BASE = "wss://wfl.tvstart.ru/ws/vmix-client"`
|
||
- чтение XML-ответа vMix;
|
||
- извлечение `dynamic/value1`, `dynamic/value2` и других значений;
|
||
- регистрация клиента в WebSocket;
|
||
- reconnect-логика.
|
||
|
||
### Как это работает в общем
|
||
1. Оператор открывает матч в админке.
|
||
2. Создаётся матчевая сессия с `session_token`.
|
||
3. Сервер отдаёт JSON и/или `.vmix`-файл.
|
||
4. Локальный агент подключается по WebSocket.
|
||
5. Сервер отправляет команды конкретному клиенту, группе или оператору.
|
||
6. Агент применяет команды в локальном vMix через HTTP API.
|
||
|
||
---
|
||
|
||
## 🧾 Генерация JSON для графики
|
||
|
||
Логика сосредоточена в `services/vmix_json_service.py`.
|
||
|
||
### По коду видно, что сервис формирует:
|
||
- стартовые составы;
|
||
- запасных;
|
||
- информацию о матче;
|
||
- турнирную таблицу;
|
||
- расписание тура;
|
||
- формации команд;
|
||
- scoreboard-информацию;
|
||
- события матча;
|
||
- данные для показа авторов голов.
|
||
|
||
### Особенности реализации
|
||
- строятся полные имена игроков;
|
||
- добавляются суффиксы капитана и вратаря;
|
||
- формируются пути к фотографиям игроков;
|
||
- используются логотипы команд и специальные варианты логотипов для некоторых клубов;
|
||
- матчевая информация собирается SQL-запросами по сессии.
|
||
|
||
---
|
||
|
||
## 📦 Генерация `.vmix` проекта
|
||
|
||
Файл `vmix/vmix_service.py` используется для:
|
||
- сборки бинарного содержимого vMix-проекта;
|
||
- генерации имени файла;
|
||
- выдачи файла пользователю через FastAPI.
|
||
|
||
В `app.py` для этого используются:
|
||
- `build_vmix_project_bytes`
|
||
- `build_vmix_filename`
|
||
|
||
Это означает, что оператор может открыть страницу сессии и скачать готовый `.vmix`-проект под конкретный матч.
|
||
|
||
---
|
||
|
||
## ⏱ Scheduler и live-мониторинг
|
||
|
||
`scheduler.py` — это фоновый процесс, который поднимается на старте приложения:
|
||
|
||
```python
|
||
@app.on_event("startup")
|
||
def start_scheduler():
|
||
import threading
|
||
thread = threading.Thread(target=run_scheduler, daemon=True)
|
||
thread.start()
|
||
```
|
||
|
||
### Ключевые интервалы
|
||
|
||
```python
|
||
MATCH_START_LEAD_MINUTES = 1
|
||
LIVE_MATCH_POLL_SECONDS = 60
|
||
MATCHES_LOOP_SECONDS = 60
|
||
STANDINGS_LOOP_SECONDS = 60
|
||
WORKER_ERROR_RETRY_SECONDS = 30
|
||
WORKER_MAX_ERRORS_IN_ROW = 20
|
||
```
|
||
|
||
### Что делает scheduler
|
||
- получает матчи на сегодня из БД;
|
||
- определяет, какие матчи уже пора мониторить;
|
||
- запускает отдельные worker-потоки;
|
||
- обновляет status/home_score/away_score в таблице матчей;
|
||
- вызывает обновление турнирной таблицы;
|
||
- ведёт реестр активных worker'ов.
|
||
|
||
### Источник live-данных
|
||
По текущему коду live-страница матча запрашивается с:
|
||
|
||
```text
|
||
https://wfl.rfs.ru/match/{match_id}
|
||
```
|
||
|
||
HTML разбирается через BeautifulSoup.
|
||
|
||
### Важное замечание
|
||
В `fetch_match_live_data()` есть незавершённая часть: функция частично реализована и в конце всё ещё содержит `NotImplementedError`. То есть scheduler уже встроен, но live-парсинг требует аккуратной доработки, чтобы считать его полностью production-ready.
|
||
|
||
---
|
||
|
||
## 🗄 Репозитории и доменные сущности
|
||
|
||
По составу `repositories/` проект работает со следующими сущностями:
|
||
|
||
### Пользователи и аудит
|
||
- `auth_repository.py`
|
||
- `audit_log_repository.py`
|
||
|
||
### Матчи
|
||
- `match_repository.py`
|
||
- `match_session_repository.py`
|
||
- `match_view_repository.py`
|
||
- `match_clock_repository.py`
|
||
- `match_event_repository.py`
|
||
|
||
### Составы и формации
|
||
- `match_lineup_repository.py`
|
||
- `match_formation_repository.py`
|
||
- `team_squad_repository.py`
|
||
|
||
### Официальные лица и стадионы
|
||
- `referee_repository.py`
|
||
- `match_referee_repository.py`
|
||
- `coach_repository.py`
|
||
- `match_coach_repository.py`
|
||
- `team_coach_repository.py`
|
||
- `stadium_repository.py`
|
||
|
||
### Команды, игроки, таблица
|
||
- `team_repository.py`
|
||
- `player_repository.py`
|
||
- `standings_repository.py`
|
||
|
||
Это хороший признак разделённой архитектуры: доступ к данным отделён от HTTP-слоя и от прикладной логики.
|
||
|
||
---
|
||
|
||
## 🔄 Сервисы синхронизации
|
||
|
||
В `services/` есть отдельные сервисы:
|
||
|
||
- `teams_service.py`
|
||
- `schedule_service.py`
|
||
- `players_service.py`
|
||
- `standings_service.py`
|
||
- `game_service.py`
|
||
- `auth_service.py`
|
||
- `vmix_json_service.py`
|
||
|
||
### Demo-режим
|
||
`main.py` показывает, как можно программно наполнить систему тестовыми данными:
|
||
|
||
- создаются 2 команды;
|
||
- создаётся матч;
|
||
- добавляются игроки;
|
||
- заполняется турнирная таблица.
|
||
|
||
Запуск:
|
||
|
||
```bash
|
||
python main.py
|
||
```
|
||
|
||
Это удобно для первичной проверки БД и шаблонного сценария разработки.
|
||
|
||
---
|
||
|
||
## 🧪 Полезные команды
|
||
|
||
### Проверка подключения к БД
|
||
|
||
```bash
|
||
python db.py
|
||
```
|
||
|
||
### Создание администратора
|
||
|
||
```bash
|
||
python scripts/create_admin.py
|
||
```
|
||
|
||
### Demo-наполнение
|
||
|
||
```bash
|
||
python main.py
|
||
```
|
||
|
||
### Запуск сервера
|
||
|
||
```bash
|
||
uvicorn app:app --reload
|
||
```
|
||
|
||
---
|
||
|
||
## 🖼 Скриншоты
|
||
|
||
Ниже заготовки под реальные скриншоты интерфейса. Когда будут реальные изображения, просто положи их в репозиторий и обнови пути.
|
||
|
||
```md
|
||

|
||

|
||

|
||

|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ Ограничения и важные замечания
|
||
|
||
### 1. Документация OpenAPI отключена
|
||
В `app.py` явно выключены:
|
||
- `/docs`
|
||
- `/redoc`
|
||
- `/openapi.json`
|
||
|
||
Это нормально для внутреннего production-режима, но неудобно для внешних интеграций.
|
||
|
||
### 2. Live scheduler требует доработки
|
||
`fetch_match_live_data()` ещё не завершена до конца и сейчас выглядит как заготовка с частичной логикой.
|
||
|
||
### 3. Есть Windows-специфичные элементы
|
||
В JSON-сервисе и агенте встречаются Windows-пути и логика работы с иконкой консоли. Это значит, что часть инфраструктуры ориентирована на Windows-машину оператора.
|
||
|
||
### 4. Есть внешняя зависимость от приватного Python registry
|
||
В `requirements.txt` указан `--extra-index-url`, поэтому разворачивание в другой среде может потребовать доступов.
|
||
|
||
### 5. Есть жёстко заданные интеграционные значения
|
||
Например:
|
||
- `http://127.0.0.1:8088/api`
|
||
- `wss://wfl.tvstart.ru/ws/vmix-client`
|
||
|
||
Для production лучше вынести их в `.env`.
|
||
|
||
---
|
||
|
||
## 🔮 Что можно улучшить
|
||
|
||
### Инфраструктура
|
||
- добавить Dockerfile и `docker-compose.yml`;
|
||
- вынести конфигурацию целиком в `.env`;
|
||
- добавить healthcheck и monitoring;
|
||
- настроить CI/CD.
|
||
|
||
### Backend
|
||
- включить структурированное логирование;
|
||
- покрыть ключевые места тестами;
|
||
- заменить часть threading-логики на более управляемый background orchestration;
|
||
- валидацию live-парсеров сделать устойчивее.
|
||
|
||
### Безопасность
|
||
- ограничить rate limit для логина;
|
||
- добавить CSRF-защиту, если нужна;
|
||
- вынести секреты и URL в окружение;
|
||
- расширить аудит действий администратора.
|
||
|
||
### API и DX
|
||
- вернуть внутреннюю OpenAPI-документацию под флагом окружения;
|
||
- добавить Postman/Insomnia collection;
|
||
- оформить контракт JSON-ответов для графики.
|
||
|
||
### UI/UX
|
||
- добавить больше навигации в админке;
|
||
- улучшить визуальный статус live-сессий;
|
||
- добавить быстрые действия в матч-центре.
|
||
|
||
---
|
||
|
||
## 🛠 Пример локального сценария запуска
|
||
|
||
```bash
|
||
# 1. установить зависимости
|
||
pip install -r requirements.txt
|
||
|
||
# 2. создать .env
|
||
cp .env.example .env # если появится шаблон
|
||
|
||
# 3. поднять БД и применить SQL
|
||
psql -U postgres -d wfl_db -f wfl.sql
|
||
psql -U postgres -d wfl_db -f sql/001_auth.sql
|
||
|
||
# 4. создать администратора
|
||
python scripts/create_admin.py
|
||
|
||
# 5. при необходимости заполнить демо-данными
|
||
python main.py
|
||
|
||
# 6. запустить сервер
|
||
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
|
||
---
|
||
|
||
## 🤝 Вклад в проект
|
||
|
||
Если проект будет развиваться дальше, рекомендуется принять минимальные правила contribution:
|
||
|
||
1. отдельная ветка на каждую фичу;
|
||
2. PR с описанием изменений;
|
||
3. проверка SQL-миграций перед merge;
|
||
4. ручная проверка vMix-сценария и матчевого workflow.
|
||
|
||
---
|
||
|
||
## 📄 Лицензия
|
||
|
||
В текущем архиве лицензия отдельно не обнаружена.
|
||
|
||
Если проект внутренний — можно оставить private/internal use only.
|
||
Если репозиторий будет публичным — добавь подходящую лицензию, например MIT, Apache-2.0 или другую нужную команде.
|
||
|
||
---
|
||
|
||
## 👨💻 Итог
|
||
|
||
Этот проект — это не просто CRUD-приложение, а полноценный операторский инструмент для футбольной трансляции:
|
||
|
||
- FastAPI-сервер с HTML-интерфейсом;
|
||
- PostgreSQL как основной источник данных;
|
||
- сессионная админ-авторизация;
|
||
- матчевые рабочие сессии;
|
||
- составы, формации, события и судьи;
|
||
- JSON и `.vmix` для эфирной графики;
|
||
- WebSocket-мост для операторских клиентов;
|
||
- scheduler для live-матчей и обновления данных.
|
||
|
||
Если нужно, следующим сообщением я могу так же сделать ещё и:
|
||
|
||
- `README_EN.md` на английском;
|
||
- `docs/API.md` с описанием всех маршрутов;
|
||
- `docker-compose.yml` для локального запуска;
|
||
- `.env.example`;
|
||
- более «маркетинговую» GitHub-версию с centered hero, anchors и navigation block.
|