# Техническое задание
## Веб-приложение: Карта шумового загрязнения от самолётов (Московская область)

**Дата:** 23 марта 2026 (обновлено по итогам прототипа v0.2)  
**Заказчик:** Слава  
**Исполнитель:** Стрим (ИИ-ассистент)  
**Статус:** Прототип v0.2 реализован и работает в production

---

## Реализованный прототип v0.2 (23 марта 2026)

### 🚀 Текущее состояние
- **Рабочий прототип доступен по адресу:** https://openclaw.mva154.duckdns.org/noisemap/
- **Стек:** Flask (бэкенд) + OpenLayers (Canvas2D) + Turf.js (геометрия)
- **Данные:** 258 рейсов / 50 282 точки (4 аэропорта: SVO, DME, VKO, ZIA; период 20–21 марта 2026)
- **Модель шума:** физическая модель на основе теоремы Пифагора (D = √(R² − H²))
- **Шумовые зоны:** 4 уровня (0–2 км, 2–5 км, 5–7 км, 7–11 км) с реальными географическими полигонами
- **Функциональность:** треки с градиентом по высоте, интерактивные фильтры, карточка рейса, флажки, линейка измерений, боковая панель с прокруткой

### 📊 Стратегии загрузки данных

**Стратегия А (реализована):** снимки каждые 3 часа → треки
- Охват: ~10–20% рейсов за день
- Стоимость: ~3 100 кредитов/день на аэропорт
- Данные: 147 рейсов, 29 487 точек (все 4 аэропорта за 2 дня)

**Стратегия Б v2 (реализована частично):** табло Яндекс.Расписаний + FR24 треки
- Охват: ~32% рейсов (ночные рейсы и рейсы без ADS-B не находятся)
- Стоимость: ~24 500 кредитов/день на аэропорт (при полном охвате)
- Добавлено: +111 рейсов SVO 21.03.2026

### ⚙️ Технические особенности
- **Картографическая библиотека:** OpenLayers 10 (Canvas2D) — совместимость с sandbox-браузерами (без WebGL)
- **Геометрия шумовых зон:** Turf.js `buffer()` + `difference()` — построение реальных полигонов на земной поверхности
- **Фильтры:** аэропорт (SVO/DME/VKO/ZIA/все), тип рейса (вылет/прилёт), высота (0–13 000 м), период (дата начала/окончания)
- **Дополнительные инструменты:** 
  - Флажки (маркеры) с переименованием и удалением
  - Линейка измерений с разбивкой по сегментам (Haversine формула)
  - Переключатель видимости треков (шумовые зоны остаются)
- **Детали рейса:** тип (🛫/🛬), callsign, номер рейса, тип ВС, маршрут с названиями городов, время входа/выхода из Московской области, высота, скорость, уровень шума

### 💳 Использование кредитов FR24
- **Потрачено на прототип:** ~16 161 кредитов из 120 000 промо-лимита (~13.5%)
- **Остаток:** ~103 839 кредитов (до 31.05.2026)

### 📁 Архитектура прототипа
```
prototype/
├── app.py                      # Flask backend + REST API
├── noise_model.py              # Модель шума (калибровочные параметры)
├── fr24_client.py              # Клиент Flightradar24 API с кэшированием
├── fetch_airport.py            # Загрузка треков по аэропорту (стратегия А)
├── fetch_strategy_b_v2.py      # Загрузка треков через табло Яндекс.Расписаний (стратегия Б)
├── index.html                  # Фронтенд (OpenLayers + Turf.js)
├── requirements.txt            # Зависимости Python
├── .env.example                # Шаблон конфигурации
└── data/                       # Кэшированные данные и файлы рейсов
```

### ✅ Выполненные критерии приемки (из раздела 6)
- [x] Веб-страница открывается и загружает карту
- [x] На карте отображаются траектории полётов за выбранный период
- [x] Шумовые границы отображаются корректно (зависят от высоты)
- [x] Работают фильтры по времени и области
- [x] При наведении отображается информация о рейсе
- [x] Система отслеживает использование кредитов API

---

## 1. Общие сведения

### 1.1. Цель проекта
Создание веб-приложения для визуализации шумового загрязнения от воздушных судов на территории Московской области на основе исторических данных Flightradar24.

### 1.2. Исходные данные
- **API:** Flightradar24, тариф Explorer (60,000 кредитов/месяц, промо до 120,000 до 31.05.2026)
- **География:** Московская область
- **Период анализа:** до одного года (начать с 6-12 месяцев в зависимости от доступности данных)
- **Типы воздушных судов:** все доступные в Flightradar24
- **Ключ API:** уже имеется у Заказчика

### 1.3. Основная концепция
Веб-страница с интерактивной картой, на которой отображаются:
1. **Траектории полётов** за выбранный период
2. **Шумовые границы** вокруг траекторий, зависящие от высоты полёта
3. **Интерактивные элементы:** зум, фильтры, всплывающая информация о рейсах

---

## 2. Функциональные требования

### 2.1. Основной функционал (реализованный в прототипе v0.2)
- [x] **Загрузка и обработка исторических данных** за период 2 дня (20–21 марта 2026)
- [x] **Расчёт шумового воздействия** на основе высоты полёта (модель Пифагора)
- [x] **Визуализация на карте:**
  - Траектории полётов (линии с градиентом по высоте: 🔴 0 м → 🟡 4 250 м → 🟢 8 500+ м)
  - Шумовые границы (реальные полигоны, построенные через Turf.js buffer/difference)
  - Цветовая градация в зависимости от высоты (4 зоны: красный, оранжевый, жёлтый, зелёный)
- [x] **Интерактивность:**
  - Масштабирование карты (зум) — OpenLayers стандартный контрол
  - Фильтрация по временным интервалам (date_from/date_to), аэропорту, типу рейса, высоте
  - При наведении на траекторию — tooltip с информацией о точке
  - При клике на трек — детали рейса в боковой панели
- [x] **Информационная панель:**
  - Основные параметры рейса при выборе (callsign, номер рейса, тип ВС, маршрут, высота, скорость, время входа/выхода из МО)
  - Статистика по выбранной области (количество рейсов, точек)
  - Контроль использования кредитов API (отдельный endpoint `/api/usage`)

#### Дополнительный функционал, реализованный в прототипе:
- **Флажки (маркеры):** добавление, удаление, переименование, разные цвета
- **Линейка измерений:** мультисегментная, расчёт расстояний по Haversine, разбивка по сегментам
- **Переключатель видимости треков:** возможность скрыть треки, оставив шумовые зоны
- **Чекбоксы шумовых зон:** включение/отключение каждой из четырёх зон независимо
- **Прокручиваемая боковая панель** с поддержкой большого количества рейсов

### 2.2. Детализация функционала

#### 2.2.1. Данные о рейсах (реализованные в прототипе)
- **Номер рейса / Callsign** — отображается в карточке рейса и tooltip
- **Авиакомпания** — из данных FR24 (поле `airline.name`)
- **Тип воздушного судна** — модель (`aircraft.model`)
- **Высота полёта** — в метрах (конвертировано из футов), отображается в карточке и влияет на цвет трека
- **Скорость** — в км/ч (конвертировано из узлов)
- **Аэропорт вылета** — код ICAO (`airport.origin.code.icao`) и название города
- **Аэропорт прибытия** — код ICAO (`airport.destination.code.icao`) и название города
- **Время вылета/прибытия** — расчётное время на основе данных трека (первая/последняя точка в МО)
- **Длительность полёта над Московской областью** — вычисляется по времени входа/выхода
- **Дополнительно:** время входа/выхода из МО (в МСК), уровень шума (дБ) — расчётный

#### 2.2.2. Фильтры (реализованные)
- **Временные:** фильтр по периоду (date_from / date_to) — работает на стороне бэкенда
- **Высотные:** слайдеры минимальной и максимальной высоты (0–13 000 м) — фильтрация на стороне фронтенда
- **По аэропорту:** выбор SVO / DME / VKO / ZIA / все — фильтрация на стороне бэкенда
- **По типу рейса:** вылеты / прилёты / все — определяется по отношению к аэропорту назначения
- **Географические:** пока не реализованы (планируется фильтр по bounding box)

#### 2.2.3. Модель шумового воздействия (v1.0 — реализована)
- **Фактор:** только высота полёта (физическая модель на основе теоремы Пифагора)
- **Формула:** D = √(R² − H²), где R — радиус сферы шума (2, 5, 7, 11 км), H — высота самолёта, D — ширина зоны на карте
- **Визуализация:** четыре концентрические зоны (0–2 км, 2–5 км, 5–7 км, 7–11 км) с разным цветом и прозрачностью
- **Бэклог для v2.0:** 
  - Учёт типа воздушного судна (разный уровень шума)
  - Учёт времени суток (ночные полёты имеют больший вес)
  - Учёт направления ветра (распространение шума)
  - Привязка к санитарным нормам (СН 2.2.4/2.1.8.562-96)
  - **Плотность шума** (частота пролётов над местностью) — сетка ячеек, количество событий в сутки

### 2.3. Технические требования к данным (реализованные)
- **Источник:** Flightradar24 API (тариф Explorer) + Яндекс.Расписания (для стратегии Б)
- **Формат:** JSON через REST API, кэширование в локальных файлах
- **Частота обновления:** раз в день (в зависимости от лимитов кредитов), ручной запуск скриптов
- **Хранение:** локальные файлы JSON (`data/flights_*.json`) для обработанных данных; кэш API в папках `data/cache/` и `data/cache_*/`
- **Обработка:** Python-скрипты (`fetch_airport.py`, `fetch_strategy_b_v2.py`) для загрузки и обработки данных
- **Объём данных:** 258 рейсов, 50 282 точки (на текущий момент)

---

## 3. Технические требования

### 3.1. Технологический стек (реализованный в прототипе v0.2)

#### Бэкенд
- **Язык:** Python 3.8+
- **Фреймворк:** Flask (выбран для простоты и быстрой разработки)
- **Библиотеки:**
  - `requests` - работа с Flightradar24 API и Яндекс.Расписаниями
  - `python-dotenv` - управление конфигурацией через `.env`
  - `geojson` - работа с геоданными
  - `shapely` - геопространственные операции (опционально, для будущих улучшений)
- **Кэширование:** локальные файлы JSON в папке `data/cache_*/` для экономии кредитов API

#### Фронтенд
- **Карты:** OpenLayers 10 (Canvas2D) — выбран из-за совместимости с sandbox-браузерами (без WebGL)
- **Геометрия:** Turf.js — построение буферов, разность полигонов, расчёт расстояний
- **Визуализация:** встроенные возможности OpenLayers (векторные слои, стилизация)
- **Интерфейс:** чистый HTML/CSS/JavaScript (без фреймворков) для максимальной простоты
- **Стили:** кастомный CSS (без Bootstrap/Tailwind) для минимального размера

#### Хранение данных
- **Первичное:** локальные файлы JSON (`data/flights_*.json`) — простота развёртывания
- **Кэш API:** папки `data/cache/` и `data/cache_*/` для сырых ответов FR24
- **Конфигурация:** `.env` файл для API ключей (FR24, Яндекс.Расписания)

### 3.2. Архитектура решения (реализованная в прототипе)
```
tasks/flightradar24/prototype/
├── app.py                      # Flask backend + REST API
├── noise_model.py              # ⚙️  Модель шума (калибровочные параметры)
├── fr24_client.py              # Клиент Flightradar24 API (с кэшированием)
├── generate_sample_data.py     # Генератор синтетических треков
├── fetch_airport.py            # Загрузка треков по аэропорту (стратегия А)
├── fetch_airport_offset.py     # Загрузка со смещением времени (стратегия А+)
├── fetch_svo_tracks.py         # Загрузка только SVO треков
├── fetch_tracks.py             # Загрузка треков (общий скрипт)
├── fetch_strategy_b_v2.py      # Загрузка треков через табло Яндекс.Расписаний (стратегия Б v2)
├── index.html                  # Фронтенд (OpenLayers + Turf.js)
├── requirements.txt            # Зависимости Python
├── .env.example                # Шаблон конфигурации
└── data/                       # Кэшированные данные и файлы рейсов
    ├── flights_SVO_2026-03-21.json       # Реальные данные SVO 21.03
    ├── flights_DME_2026-03-21.json       # Реальные данные DME 21.03
    ├── flights_VKO_2026-03-21.json       # Реальные данные VKO 21.03
    ├── flights_ZIA_2026-03-21.json       # Реальные данные ZIA 21.03
    ├── flights_*_offset90m.json          # Данные со смещением времени
    ├── sample_flights.json               # Fallback (синтетика или последняя загрузка)
    ├── cache_SVO/                        # Кэш треков SVO
    ├── cache_DME/                        # Кэш треков DME
    ├── cache_VKO/                        # Кэш треков VKO
    ├── cache_ZIA/                        # Кэш треков ZIA
    └── cache/                            # Общий кэш API запросов
```

### 3.3. Требования к коду
- Чистый, документированный код (PEP8 для Python, ESLint для JS)
- Модульность и возможность расширения
- Обработка ошибок и логирование
- Кэширование запросов к API для экономии кредитов
- Оптимизация производительности при работе с большими объёмами данных

---

## 4. Ограничения и риски (актуальные по итогам прототипа)

### 4.1. Ограничения тарифа Explorer (подтверждённые)
- **Кредиты:** 60,000/месяц, промо-лимит 120,000 до 31.05.2026 (потрачено ~16 161, осталось ~103 839)
- **Endpoints:** нет доступа к airports full, count endpoints; доступны historic/flight-positions, flight-tracks, live
- **Исторические данные:** доступны за несколько месяцев (точный лимит не установлен), но каждый запрос стоит кредиты
- **Важные ограничения API:**
  - Формат bounds: `lat_max,lat_min,lon_min,lon_max` (не `lat_min,lon_min`!)
  - `flight-tracks` не поддерживает фильтр по времени — возвращает весь маршрут (~700 точек/10 сек)
  - Rate limit: ~684 запросов в час (эмпирически), после чего API возвращает 429

### 4.2. Технические ограничения (выявленные в прототипе)
- **Объём данных:** 258 рейсов / 50 282 точек уже создают нагрузку на браузер (отрисовка тормозит при включении всех зон)
- **Производительность:** OpenLayers Canvas2D справляется, но при >500 рейсов потребуется агрегация или Level-of-Detail
- **Точность модели:** текущая модель шума (Пифагор) учитывает только высоту, не учитывает тип ВС, время суток, погоду
- **Охват данных:** стратегия А даёт только 10–20% рейсов; стратегия Б v2 даёт ~32% (ночные рейсы и рейсы без ADS-B не находятся)
- **Sandbox-браузеры:** WebGL заблокирован (`Sandboxed = yes`), поэтому выбран Canvas2D рендеринг OpenLayers

### 4.3. Риски и меры минимизации (обновлённые)
| Риск | Вероятность | Влияние | Меры минимизации (реализованные/планируемые) |
|------|-------------|---------|------------------|
| Превышение лимита кредитов | Высокая | Высокое | ✅ Кэширование запросов, ✅ мониторинг использования, ⏳ оптимизация стратегий загрузки |
| Недостаток исторических данных | Средняя | Среднее | ✅ Поэтапный сбор данных, ✅ проверка доступности через sandbox, ⏳ поиск альтернативных источников (Яндекс.Расписания) |
| Низкая производительность визуализации | Средняя | Среднее | ✅ Агрегация данных на бэкенде, ⏳ Level-of-Detail, ⏳ Web Workers для тяжёлых вычислений |
| Сложность модели шума | Низкая | Низкое | ✅ Начата с простой модели (Пифагор), ⏳ постепенное усложнение (тип ВС, время суток, санитарные нормы) |
| Низкий охват рейсов | Высокая | Высокое | ⏳ Стратегия Б v3 (парсинг табло аэропортов), ⏳ комбинирование нескольких источников данных |
| Ограничения sandbox-браузеров | Высокая | Среднее | ✅ Выбор OpenLayers Canvas2D, ✅ отказ от WebGL, ✅ тестирование в sandbox-окружении |

---

## 5. План реализации (обновлён по итогам прототипа)

### ✅ Завершённые этапы

#### Этап 0 — Исследование и выбор технологий (22 марта 2026)
- Проверка FR24 sandbox API, тестирование endpoints
- Выбор картографической библиотеки: Leaflet ❌ → MapLibre GL ❌ (WebGL заблокирован) → **OpenLayers Canvas2D ✅**
- Выбор бэкенд-фреймворка: **Flask ✅**
- Составление ТЗ v1, очистка структуры проекта

#### Этап 1 — Прототип (синтетика + модель шума) (22 марта 2026)
- Физическая модель шума: D = √(R² − H²), 4 зоны (0–2 / 2–5 / 5–7 / 7–11 км)
- Генератор 50 синтетических рейсов
- Фронтенд: треки с градиентом по высоте, шумовые зоны, боковая панель, флажки, линейка
- Деплой: nginx → Flask :5555 → https://openclaw.mva154.duckdns.org/noisemap/

#### Этап 2 — Реальные данные, стратегия А (22 марта 2026)
- Интеграция с FR24 Production API
- Загрузка: 4 аэропорта (SVO/DME/VKO/ZIA), 2 дня (20–21.03.2026), **147 рейсов / 29 487 точек**
- Исправление баги с bounds (`lat_max,lat_min,lon_min,lon_max`)
- Фильтры в UI: аэропорт, тип рейса, высота, период

#### Этап 3 — Стратегия Б v2 (Яндекс.Расписания) (22 марта 2026)
- Интеграция с Яндекс.Расписаниями (ключ `788c6840-...`)
- Табло SVO 21.03: 750 рейсов → поиск fr24_id через live API со смещением +15/+30/+45 мин
- Результат: +111 рейсов SVO, итого **258 рейсов / 50 282 точки**
- Ограничение: охват ~32% (ночные и рейсы без ADS-B не находятся)

---

### 🔄 Планируемые этапы

#### Этап 4 — Расширение охвата данных (стратегия Б v3)
**Приоритет: высокий**
- Парсинг табло для остальных аэропортов (DME, VKO, ZIA)
- Улучшение алгоритма поиска fr24_id (расширенный временной интервал, fallback по callsign)
- Сбор данных за 7–14 дней (в рамках лимита кредитов ~103 839 осталось)
- Цель охвата: 60–80% рейсов

#### Этап 5 — Улучшения UI и визуализации
**Приоритет: высокий**
- Фильтр по дате в интерфейсе (переключение между загруженными днями без перезагрузки)
- Тепловая карта плотности шума: сетка ячеек, частота пролётов над точкой в сутки
- Фильтр по авиакомпании и типу ВС
- Оптимизация производительности при > 500 рейсов (агрегация, Level-of-Detail)

#### Этап 6 — Улучшение модели шума (v2)
**Приоритет: средний**
- Учёт типа воздушного судна (тяжёлые ВС — бо́льший радиус)
- Учёт времени суток (ночные полёты, коэффициент ×1.5)
- Привязка к санитарным нормам СН 2.2.4/2.1.8.562-96
- Расчёт накопленного шума (Lden/Lnight)

#### Этап 7 — Дополнительный функционал
**Приоритет: низкий**
- Экспорт зон в GeoJSON / KML
- Сравнение периодов (наложение данных за разные дни)
- Статистика по часам суток и авиакомпаниям
- Мобильная адаптация

#### Этап 8 — Финальное тестирование и документация
- Нагрузочное тестирование (1 000+ рейсов)
- Инструкция по развёртыванию
- Финальная версия документации API
- Резервное копирование данных

---

## 6. Критерии приемки (обновлены)

### 6.1. Функциональные критерии
- [x] Веб-страница открывается и загружает карту *(выполнено)*
- [x] На карте отображаются траектории полётов за выбранный период *(выполнено)*
- [x] Шумовые границы отображаются корректно (зависят от высоты) *(выполнено)*
- [x] Работают фильтры по времени и области *(выполнено)*
- [x] При наведении отображается информация о рейсе *(выполнено)*
- [x] Система отслеживает использование кредитов API *(выполнено)*
- [ ] Фильтр по дате работает непосредственно в UI *(в планах)*
- [ ] Тепловая карта плотности шума отображается корректно *(в планах)*
- [ ] Экспорт зон в GeoJSON/KML работает *(в планах)*

### 6.2. Технические критерии
- [x] Flask-бэкенд запущен и отвечает на запросы *(выполнено)*
- [x] Кэширование запросов к FR24 API реализовано *(выполнено)*
- [x] Обработка ошибок предотвращает сбои приложения *(базовая реализована)*
- [x] Расход кредитов API оптимизирован и не превышает лимитов *(~16 161 / 120 000)*
- [ ] Производительность сохраняется при 1 000+ рейсов *(не тестировалось)*
- [ ] Система масштабируема для будущих расширений *(частично — файловое хранилище)*

### 6.3. Пользовательские критерии
- [x] Карта реагирует на действия пользователя без задержек (при ≤ 258 рейсах) *(выполнено)*
- [x] Информация о рейсе отображается понятно (карточка + tooltip) *(выполнено)*
- [x] Доступ по постоянному публичному URL *(https://openclaw.mva154.duckdns.org/noisemap/)*
- [ ] Система работает стабильно при длительном использовании *(требует наблюдения)*
- [ ] Интерфейс корректно отображается на мобильных устройствах *(не адаптирован)*

---

## 7. Дальнейшее развитие (бэклог)

### 7.1. Данные
- [ ] Охват рейсов 60–80% (стратегия Б v3: все аэропорты, улучшенный алгоритм)
- [ ] Сбор данных за 7–30 дней в рамках лимита кредитов
- [ ] Автоматический ежедневный сбор данных (cron-задача)

### 7.2. Модель шума
- [ ] Учёт типа воздушного судна
- [ ] Учёт времени суток (ночные полёты)
- [ ] Привязка к санитарным нормам (СН 2.2.4/2.1.8.562-96)
- [ ] Расчёт накопленного шума (Lden/Lnight)

### 7.3. Визуализация
- [ ] Тепловая карта плотности шума (частота пролётов над ячейкой)
- [ ] Фильтр по дате непосредственно в UI
- [ ] Фильтр по авиакомпании и типу ВС
- [ ] Сравнение двух временных периодов

### 7.4. Производительность
- [ ] Level-of-Detail (упрощение треков при отдалении)
- [ ] Постраничная загрузка / кластеризация треков
- [ ] Web Workers для вычисления шумовых зон

### 7.5. Экспорт и масштабирование
- [ ] Экспорт зон в GeoJSON / KML
- [ ] Поддержка других регионов
- [ ] Публичный доступ / embed-карта

---

## 8. Контакты и коммуникация

### 8.1. Ответственные лица
- **Заказчик:** Слава
- **Исполнитель:** Стрим (ИИ-ассистент)
- **Канал связи:** Telegram / веб-чат через OpenClaw

### 8.2. Документация проекта
- [Flightradar24 API Documentation](https://fr24api.flightradar24.com/)
- [OpenLayers Documentation](https://openlayers.org/en/latest/apidoc/)
- [Turf.js Documentation](https://turfjs.org/)
- [Внутренняя документация прототипа](../prototype/docs/)

---

**Приложения:**
1. [README прототипа](../prototype/README.md)
2. [Архитектура системы](../prototype/docs/ARCHITECTURE.md)
3. [Модель шума](../prototype/docs/NOISE_MODEL.md)
4. [Стратегии загрузки данных](../prototype/docs/DATA_LOADING.md)
5. [FR24 API — особенности](../prototype/docs/FR24_API.md)

**Дата составления:** 22 марта 2026  
**Последнее обновление:** 23 марта 2026 (по итогам прототипа v0.2)

---

*ТЗ обновлено по результатам реализованного прототипа v0.2. Прототип доступен по адресу: https://openclaw.mva154.duckdns.org/noisemap/*