Живой дашборд информационной безопасности с графиками в реальном времени, метриками и аналитикой угроз. Данные обновляются каждую секунду через polling (легко заменяется на SSE/WebSocket).
flowchart LR
A[Frontend: SvelteKit + Chart.js] -->|Polling every 1 sec| B[Backend: Django + Django-Ninja]
B --> C[(PostgreSQL / SQLite)]
B --> D[Генератор случайных инцидентов<br>в памяти за последнюю минуту]
/live-stats), имитируя поток событий безопасности (0-5 событий в секунду со случайными типами и критичностью).liveDataStore), который управляет опросом, ошибками и reconnect. Компоненты (LiveStatsDisplay, LiveLineChartDisplay, LiveTopTypesChartDisplay) являются «чистыми» – они только подписываются на данные из стора и не содержат собственных интервалов. Это обеспечивает предсказуемость и облегчает тестирование.BackendStatus, который также предоставляет кнопку Retry. Автоматический reconnect таймер пытается восстановить соединение каждые 5 секунд.| Компонент | Технологии |
|---|---|
| Бэкенд | Django, Django-Ninja, PostgreSQL (SQLite для разработки) |
| Фронтенд | SvelteKit, TypeScript, Chart.js, Tailwind CSS |
| Деплой | Render (бэкенд), Vercel (фронтенд) |
Клонирование репозитория
git clone https://github.com/ВАШ_НИК/security-dashboard.git
cd security-dashboard
Бэкенд (Django)
cd backend
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
python manage.py migrate
python manage.py generate_incidents --count=500 # генерация тестовых данных
python manage.py runserver
Сервер запустится на http://localhost:8000.
API документация: http://localhost:8000/api/docs
Фронтенд (SvelteKit)
cd frontend
npm install
npm run dev
Откройте http://localhost:5173
Проверка работы
django-cors-headers).security-dashboard/
├── backend/ # Django проект
│ ├── incidents/ # приложение с моделью, API, генератором
│ ├── config/ # настройки Django
│ └── manage.py
├── frontend/ # SvelteKit проект
│ ├── src/
│ │ ├── routes/ # страницы (главная дашборда)
│ │ ├── lib/
│ │ │ ├── components/ # чистые компоненты (LiveStatsDisplay, LiveLineChartDisplay, LiveTopTypesChartDisplay, BackendStatus)
│ │ │ ├── stores/ # liveDataStore (централизованный стор)
│ │ │ └── api/ # API-клиент
│ │ └── app.css # Tailwind
│ ├── package.json
│ └── tailwind.config.js
├── README.md
└── .gitignore
/live-stats генерируется 0–5 новых случайных инцидентов (тип, критичность).Создайте .env в frontend/:
VITE_API_BASE_URL=http://localhost:8000/api
Для продакшена измените на реальный URL бэкенда.
cd backend && gunicorn config.wsgi:applicationSECRET_KEY, DEBUG=False, ALLOWED_HOSTS=..., CORS_ALLOWED_ORIGINS=https://frontend.vercel.appnpm i -g vercelfrontend выполните vercel --prodVITE_API_BASE_URL=https://your-backend.onrender.com/apiВ проекте реализованы модульные тесты для ключевых компонентов бэкенда с использованием встроенного unittest Django.
SecurityIncident — создание инцидента, строковое представление./summary — подсчёт общего количества инцидентов и распределение по критичности./timeline — временной ряд (группировка по дням)./top-types — топ типов угроз с лимитом./list — пагинация списка инцидентов./live-stats — структура ответа и работа с глобальным состоянием (имитация скользящего окна).generate_incidents создаёт заданное количество записей.cd backend
python manage.py test incidents
Ожидаемый результат: все тесты проходят (10+ успешных проверок). Тесты используют отдельную тестовую БД и не влияют на разработческие данные.
В проекте используется Pydantic для автоматической сериализации (превращение объектов Python в JSON) и десериализации (обратное преобразование). Это один из ключевых принципов Django‑Ninja.
Schema). В ней указываются поля и их типы.response=SomeSchema.from ninja import Router, Schema
from typing import Optional
from .models import SecurityIncident
class IncidentListItemSchema(Schema):
id: int
timestamp: str
incident_type: str
severity: str
source_country: str
status: str
cve_id: Optional[str] = None # может быть None
description: Optional[str] = None
@router.get("/list", response=list[IncidentListItemSchema])
def get_incidents(request, page: int = 1, limit: int = 20):
offset = (page-1)*limit
incidents = SecurityIncident.objects.all().order_by("-timestamp")[offset:offset+limit]
# возвращаем список словарей или моделей — Ninja сам преобразует
return incidents
id, timestamp).severity, status).MIT
[Константин Кононенко] – https://github.com/kalikrit/security-dashboard