# Дневник разработки

## 22 марта 2026

### Сессия 1 — Инициализация проекта

**14:41** — Прочитано ТЗ (`ТЗ_Карта_шумового_загрязнения_Flightradar24.md`)

**14:43** — Переключена модель на Claude Sonnet 4.6 (1M контекст) для работы над прототипом

**14:50** — Создана базовая структура прототипа:
- `app.py` — Flask backend
- `noise_model.py` — модель шума
- `fr24_client.py` — клиент API
- `generate_sample_data.py` — синтетические данные
- `index.html` — фронтенд (изначально Leaflet)

---

### Сессия 2 — Выбор картографической библиотеки

**15:14** — Leaflet заменён (по запросу)

**15:19** — MapLibre GL JS не заработал: `WebGL disabled (Sandboxed = yes)` в браузере

**15:23** — Переключились на **OpenLayers 10** (Canvas2D, без WebGL) ✅

**15:25** — Тайлы: CARTO Dark → OpenStreetMap (более надёжные)

---

### Сессия 3 — nginx и доступ

**14:57** — Настроен nginx проброс `/noisemap/` → Flask :5555

**15:12** — Карта открылась по адресу `https://openclaw.mva154.duckdns.org/noisemap/`

**15:16** — Исправлены пути API (`/api/` → `/noisemap/api/`) — nginx перехватывал запросы

---

### Сессия 4 — Шумовые зоны (физическая модель)

**15:29** — Первая версия зон: широкие штрихи в пикселях → неправильно

**15:39** — Обсуждение с заказчиком: зоны должны быть в реальных км

**15:53** — Добавлен **Turf.js**, реализованы буферы `turf.buffer()` + `turf.difference()`

**16:25** — Внедрена физическая модель по теореме Пифагора:
```
D = √(R² − H²)
где R — граница зоны (гипотенуза), H — высота самолёта, D — ширина на карте
```

**16:42** — Параметры модели вынесены в `noise_model.py → NOISE_ZONES` с документацией

---

### Сессия 5 — Функциональность карты

**15:35** — Добавлен градиент цвета трека по высоте (красный → жёлтый → зелёный)

**16:01** — Трек поднят поверх шумовых зон (zIndex 50)

**16:19** — Добавлена **линейка** (Haversine, мультисегментная)

**17:00** — Добавлены фильтры: высота (метры), тип рейса, период

**18:01** — Добавлен **фильтр по аэропорту** (SVO/DME/VKO/ZIA)

**18:04** — Добавлены **флажки** (несколько, с переименованием, удалением по клику)

**18:12** — Исправлена прокрутка боковой панели

**18:16** — Добавлен переключатель видимости треков (зоны остаются)

---

### Сессия 6 — Реальные данные FR24

**17:04** — Получен production API ключ

**17:05** — Обнаружена ошибка bounds: `lat_min,lon_min,lat_max,lon_max` → данные в США
           Исправлено на `lat_max,lat_min,lon_min,lon_max`

**17:15** — Первая корректная загрузка SVO 21.03: 33 рейса, 5 914 точек над МО

**17:37** — Уточнение: загружать только рейсы с вылетом или прилётом SVO (не транзит)

**17:45** — Загружены DME и VKO. Итого: 69 рейсов, 14 338 точек

**18:22** — Загружен ZIA: 1 рейс (WZ560 TBS→ZIA, SU95)

**18:29** — Запущена загрузка 20.03 со смещением +1.5ч (стратегия А+)

**18:44** — Загружены все 4 аэропорта за 20.03. Итого: 147 рейсов, 29 487 точек

---

### Сессия 7 — Обсуждение стратегии Б

**18:34** — Обсуждена стратегия "табло → треки":
- Охват ~100% vs ~10% у текущей стратегии
- Стоимость ~24 500 кредитов/день (vs ~3 100 у стратегии А)
- Ограничение: API не поддерживает временной фильтр треков (проверено)

**18:50** — Задокументированы обе стратегии в README.md, MEMORY.md и `docs/`

---

**18:52** — Добавлен словарь IATA→город (`IATA_CITIES`, ~80 аэропортов) в `index.html`

**19:07** — Обновлена карточка рейса в боковой панели:
- Тип рейса 🛫/🛬 рядом с callsign
- Названия городов: `Сочи (AER)`, `Москва (SVO)`
- Дата полёта
- Время входа/выхода из МО в МСК (UTC+3)

---

**19:15–19:52** — Исследование источников для стратегии Б:
- FR24 сайт, svo.aero, aviasales, flightaware, opensky — все недоступны для истории без ключа
- airnavradar.com — работает, 1223 рейса, но только текущий день
- **Яндекс.Расписания** — работает с историческими данными ✅
  - Ключ получен от Славы: `788c6840-...`
  - Сохранён в `.env` как `YANDEX_RASP_API_KEY`
  - Код станции SVO: `s9600213` (найден через `/nearest_stations/`)
  - Собрано: 750 рейсов (375 вылетов + 375 прилётов) за 21.03

**19:54** — Дедупликация: 66 совпавших с стратегией А, 684 новых рейсов для загрузки

**20:00** — Запущена стратегия Б v1: `fetch_strategy_b.py` — **ПРОВАЛ**
- Алгоритм искал fr24_id в снимке в момент вылета (00:05, 00:10...)
- Самолёт ещё на земле → 0 результатов из 684

**20:09** — Написан `fetch_strategy_b_v2.py` с исправленным алгоритмом:
- Вылеты: снимок через +15/+30/+45/+60 мин после вылета
- Прилёты: снимок за -30/-20/-10/0 мин до прилёта
- Расширенный bbox: 200 км вокруг SVO (57.8,53.8,33.5,41.5)
- Обнаружен баг: поле `arrival` = null в Яндекс.Расписаниях → для прилётов тоже используем `departure` + смещения 30–180 мин

**20:25–21:34** — Запуски v2, итеративные исправления:
- v2 запуск 1: стопор на 111 треков из-за кэша с null для прилётов
- Очищен кэш прилётов (`data/cache_SVO_b/id_*_arrival.json`)
- v2 запуск 2: исправлен алгоритм для прилётов (смещения 60–180 мин)
- **Итог**: 111 треков из 342 вылетов (32%)
- Прилёты = дубли вылетов из Яндекс.Расписаний, загружать не нужно

**21:34** — Обновлён лимит API: `limit=2000` в `app.py` и `index.html` (было 100)

**21:34** — Flask перезапущен, карта показывает **258 рейсов / 50 282 точки**

### Итоговые данные (22.03.2026 21:38 UTC)

| Источник | Аэропорт | Дата | Рейсов | Точек |
|----------|----------|------|--------|-------|
| Стратегия А | SVO | 21.03 | 33 | 5 914 |
| Стратегия А | SVO | 20.03+90m | 39 | 6 574 |
| Стратегия А | DME | 21.03 | 15 | 3 356 |
| Стратегия А | DME | 20.03+90m | 15 | 3 592 |
| Стратегия А | VKO | 21.03 | 21 | 5 068 |
| Стратегия А | VKO | 20.03+90m | 23 | 4 937 |
| Стратегия А | ZIA | 21.03 | 1 | 46 |
| **Стратегия Б v2** | **SVO** | **21.03** | **111** | **20 795** |
| **ИТОГО** | | | **258** | **50 282** |

Табло SVO 21.03 (Яндекс.Расписания): 375 вылетов → 111 треков найдено (32%).
Причины потерь: ночные рейсы (00:00–05:00 МСК) быстро покидают bbox, нет ADS-B у части ВС.

---

## Открытые вопросы / Бэклог

1. **Фильтр по дате в UI** — переключение между загруженными днями
2. **Производительность** — оптимизация рендеринга при >200 рейсах с зонами
3. **Модель шума v2** — учёт типа ВС (шире/тише), времени суток (ночные нормативы)
4. **Плотность шума** — тепловая карта частоты пролётов над территорией:
   - Для каждой точки земли: сколько раз в сутки над ней пролетает самолёт в зоне слышимости
   - Отображение: градиентная заливка (синий → красный) по количеству событий
   - Применение: выявить хронически шумные зоны под глиссадами и в районе набора высоты
   - Реализация: сетка ячеек (например 500×500 м), для каждого трека считать пересечения с ячейками
5. **Стратегия Б для DME/VKO** — распространить на другие аэропорты

---

## Технические долги

- [ ] `steps: 6` в Turf.js — увеличить до 8 для более гладких зон
- [ ] Зоны пересчитываются при каждом `loadData()` — кэшировать
- [ ] `fetch_svo_tracks.py` и `fetch_tracks.py` — дублирование с `fetch_airport.py`, убрать
- [ ] `IATA_CITIES` в index.html — вынести в отдельный JSON, загружать через /api/airports-dict
- [ ] Flask debug-mode включён — для production отключить
- [ ] IP контейнера (172.19.0.2) захардкожен в nginx — документировать процедуру обновления

---

## Сессия 2026-03-27 (04:24–07:48 UTC)

**Кто:** Стрим (главная сессия, session `d6e83659`)
**Контекст:** Слава открыл новую вкладку браузера → создалась новая сессия (не отдельный агент)

### Загрузка данных за 26.03.2026

**04:24–04:38** — Диагностика и загрузка Стратегией А за 26 марта:
- Обнаружена ошибка в `fetch_strategy_b_v2.py` (date_str → date_prefix несовместимость с форматом имени файла)
- Исправлена логика генерации имени файла: `flights_20260326_...`
- Данные за 26.03 загружены: SVO / DME / VKO / ZIA

### Обсуждение методик расчёта шума (04:39–04:54)

- Обсуждены NPD-кривые (Noise-Power-Distance) из открытых данных FAA AEDT/ICAO Annex 16
- Обсуждена текущая модель vs реалистичная dB-модель
- Принято решение: **сначала реализовать слой плотности пролётов**, затем улучшать шумовую модель

### БТ и ТЗ слоя плотности (04:55–05:08)

- Обсуждена концепция: сетка ячеек 500×500 м, частота пролётов = кол-во рейсов/ячейку
- Определены радиусы влияния по высоте: H<1800м→2км, H<5000м→4км, H<7000м→7км, H≥7000м→не считать
- Переключатель: показать/скрыть слой (независимо от треков и шумовых зон)
- Без фильтрации по времени суток, без ночного штрафа
- ТЗ зафиксировано: `docs/TZ_DENSITY_LAYER.md`

### Реализация слоя плотности (05:08–05:51)

- Создан `density_model.py`: сетка 500×500м, bbox по трекам, дедупликация рейсов
- Добавлен endpoint `/api/density` в `app.py` с кэшированием в `density_cache_{key}.json.gz`
- Frontend: кнопка «🔥 Показать» в панели, векторный слой OpenLayers (не Heatmap из-за Canvas2D)
- Исправлены баги: nginx 404 на `/api/density`, неправильный zIndex (скрывал треки)

### Интеграция фильтра дат с плотностью (05:56–06:53)

- Реализован единый фильтр `date_from / date_to` для треков И плотности
- Добавлен ползунок под датами: точки на шкале (без подписей), плавность анимации
- Логика: диапазон дат задаёт период, ползунок выбирает конкретную дату внутри периода
- Без ползунка = отображается весь диапазон
- При движении ползунка — мгновенный перерендер (pre-built кэш для каждой даты)

### Баги и доработки (07:07–07:48)

- Исправлено: плотность не менялась при смене даты ползунком (кэш не инвалидировался)
- Исправлено: легенда теперь показывает `макс. N рейс./ч (за X дн.)`
- Уточнена методика: `max_flights_per_hour = count / days`, нормализация по этому значению
- Добавлена легенда слоя плотности с градиентом и цифрами

### Итоговое состояние карты после сессии

| Компонент | Статус |
|-----------|--------|
| Фильтр дат (треки) | ✅ работает |
| Фильтр дат (плотность) | ✅ работает |
| Ползунок дат | ✅ мгновенный перерендер |
| Слой плотности | ✅ переключатель + легенда |
| Попап при клике на ячейку | ⚠️ частично (отображается, но без кол-ва рейс./ч) |
| Данные | 258 рейсов (20–21.03) + ~XX рейсов (26.03) |

