auto-sync: 2026-04-19 14:20:01

This commit is contained in:
Stream
2026-04-19 14:20:01 +03:00
parent 69099c1ee5
commit 81be6ea8c1
10 changed files with 407 additions and 581 deletions

View File

@@ -6,13 +6,18 @@
- **noisemap / FR24-прототип** — визуализация и расчёт шумовой плотности на базе исторических данных Flightradar24
- **RTL-SDR ingest-контур** — локальный приём ADS-B, хранение в PostgreSQL/PostGIS и recovery после сбоев
## Текущий курс
- ingest-контур строится как набор отдельных контейнеров: `capture`, `preprocess`, `api`, `monitoring`
- `raw_packets` хранят base64 payload + метаданные, retention 3 дня
- ingest и API связаны через схему PostgreSQL, а не через файловый контракт
## Куда смотреть
- `tasks/flightradar24/PROJECT.md` — общий статус проекта
- `tasks/flightradar24/docs/INDEX.md` — карта документации
- `tasks/flightradar24/docs/ARCHITECTURE.md` — контейнерная архитектура ingest-контура
- `tasks/flightradar24/docs/RTL-SDR_TZ.md`ТЗ на RTL-SDR ingest
- `tasks/flightradar24/docs/VM_SETUP.md` — инструкция по созданию VM в PVE
- `tasks/flightradar24/docs/DEV_AGENT_HANDOFF.md` — пакет передачи Dev-агенту
- `tasks/flightradar24/compose/README.md` — compose skeleton и контракт API
## Текущий статус
- FR24-прототип жив и остаётся в проекте как историческая и визуальная база
@@ -29,182 +34,3 @@
- **Траектории полётов** за выбранный период (до 12 месяцев)
- **Шумовые границы** вокруг траекторий, рассчитанные на основе высоты полёта
- **Интерактивные элементы**: зум, фильтры по времени, всплывающая информация о рейсах
## 🎯 Цели проекта
1. **Визуализация**: Наглядно показать распределение шумового загрязнения от авиации
2. **Анализ**: Выявить наиболее загруженные воздушные коридоры
3. **Информирование**: Предоставить данные для исследований и принятия решений
4. **Оптимизация**: Эффективное использование данных Flightradar24 API в рамках тарифа Explorer
## 🛠 Технологический стек
### Бэкенд
- **Язык**: Python 3.8+
- **Фреймворк**: FastAPI (лёгкий, асинхронный)
- **Библиотеки**:
- `requests` - работа с Flightradar24 API
- `sqlalchemy` / `sqlite3` - работа с базой данных
- `pandas` / `numpy` - обработка данных
- `python-dotenv` - управление конфигурацией
### Фронтенд
- **Карты**: Leaflet.js с OpenStreetMap
- **Интерфейс**: Bootstrap 5 + чистый JavaScript
- **Визуализация**: встроенные возможности Leaflet + D3.js (опционально)
### Хранение данных
- **База данных**: SQLite (разработка) / PostgreSQL (production)
- **Кэш**: файловая система (JSON/CSV)
- **Конфигурация**: `.env` файл + `config.json`
## 📊 Модель шумового воздействия (v1.0)
### Основные допущения
- **Фактор**: только высота полёта
- **Зависимость**: уровень шума обратно пропорционален высоте
- **Формула**:
```
noise_radius_km = base_radius * (min_height / actual_height) * factor
```
где:
- `base_radius` = 5.0 км (базовый радиус шума)
- `min_height` = 300 м (минимальная высота для расчёта)
- `factor` = 0.01 (коэффициент масштабирования)
### Параметры (config.json)
```json
"noise_model": {
"base_noise_radius_km": 5.0,
"height_factor": 0.01,
"min_height_m": 300,
"max_height_m": 12000,
"min_radius_km": 0.5,
"max_radius_km": 10.0
}
```
### Бэклог для v2.0
- Учёт типа воздушного судна
- Учёт времени суток (ночные полёты)
- Учёт направления и скорости ветра
- Привязка к санитарным нормам
## 🚀 Быстрый старт
### 1. Установка зависимостей
```bash
pip install -r requirements.txt
```
### 2. Настройка API ключа
```bash
export FLIGHTRADAR24_API_KEY="your_api_key_here"
```
Или создайте файл `.env`:
```
FLIGHTRADAR24_API_KEY=your_api_key_here
```
### 3. Проверка подключения
```bash
python scripts/check_api.py
```
### 4. Запуск тестового сбора данных
```bash
python scripts/flightradar24_explorer.py
```
## 📁 Структура проекта
```
flightradar24/
├── README.md # Эта документация
├── requirements.txt # Зависимости Python
├── config.json # Конфигурация проекта
├── scripts/ # Вспомогательные скрипты
│ ├── check_api.py # Проверка API ключа
│ └── flightradar24_explorer.py # Базовый клиент API
├── reports/ # Отчёты и документация
│ └── ТЗ_Картаумовогоагрязнения_Flightradar24.md
├── data/ # Данные (будет создано)
│ ├── cache/ # Кэшированные данные API
│ ├── processed/ # Обработанные данные
│ └── exports/ # Экспортированные файлы
├── backend/ # Бэкенд приложения (будет создано)
├── frontend/ # Фронтенд приложения (будет создано)
└── docs/ # Документация (будет создано)
```
## 🔧 Конфигурация
Основные параметры настройки в `config.json`:
| Параметр | Описание | Значение по умолчанию |
|----------|----------|----------------------|
| `geography.region` | Регион исследования | Московская область |
| `geography.bounds` | Границы региона | 54.5-56.5°N, 35.5-39.5°E |
| `data_collection.target_period_months` | Целевой период данных | 12 месяцев |
| `data_collection.initial_period_days` | Начальный период для тестирования | 30 дней |
| `visualization.default_center` | Центр карты | [55.7558, 37.6173] (Москва) |
| `visualization.default_zoom` | Увеличение карты | 9 |
## 💳 Использование кредитов Flightradar24 API
### Тариф Explorer
- **Базовый лимит**: 60,000 кредитов/месяц
- **Промо-период**: до 120,000 кредитов/месяц (до 31.05.2026)
- **Обновление**: раз в неделю/месяц в зависимости от лимитов
### Примерная стоимость запросов
| Endpoint | Кредитов/запрос | Примерное использование |
|----------|-----------------|-------------------------|
| `flight/list` (live) | 5 | 100 запросов = 500 кредитов |
| `flight/{id}/history` | 20 | 50 рейсов = 1,000 кредитов |
| `flight/{id}/playback` | 30 | 30 треков = 900 кредитов |
### Стратегия оптимизации
1. **Кэширование**: Сохранять полученные данные локально
2. **Пакетная обработка**: Собирать данные партиями
3. **Приоритизация**: Сначала ключевые маршруты и периоды
4. **Мониторинг**: Регулярно проверять остаток кредитов
## 📈 План разработки
### Этап 1: Подготовка и прототип (23-25 марта 2026)
- [ ] Проверка доступности исторических данных
- [ ] Создание proof-of-concept с 10-50 траекториями
- [ ] Согласование визуализации с Заказчиком
### Этап 2: Разработка бэкенда (26-28 марта 2026)
- [ ] Архитектура FastAPI приложения
- [ ] Система сбора и обработки данных
- [ ] API для фронтенда
### Этап 3: Разработка фронтенда (29-31 марта 2026)
- [ ] Интерфейс карты (Leaflet)
- [ ] Панель управления и фильтры
- [ ] Интеграция с бэкендом
### Этап 4: Тестирование и оптимизация (1-2 апреля 2026)
- [ ] Функциональное тестирование
- [ ] Оптимизация производительности
- [ ] Документация и развёртывание
## 🔗 Полезные ссылки
- [Flightradar24 API Documentation](https://fr24api.flightradar24.com/)
- [Leaflet.js Documentation](https://leafletjs.com/)
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
- [Полное ТЗ проекта](reports/ТЗ_Картаумовогоагрязнения_Flightradar24.md)
## 📞 Контакты
- **Заказчик**: Слава
- **Исполнитель**: Стрим (ИИ-ассистент)
- **Канал связи**: Telegram через OpenClaw
---
*Проект находится в активной разработке. Последнее обновление: 22 марта 2026.*

View File

@@ -9,8 +9,16 @@ POSTGRES_PUBLISHED_PORT=5432
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
# Ingest scaffold
INGEST_MODE=placeholder
RAW_RETENTION_DAYS=3
OVERLAP_MINUTES=10
API_PUBLISHED_PORT=8080
MONITORING_PUBLISHED_PORT=9090
# Capture / preprocess
CAPTURE_SOURCE=rtl-sdr
RTLSDR_DEVICE_INDEX=0
RTLSDR_SAMPLE_RATE=2000000
RTLSDR_CENTER_FREQUENCY=1090000000
RTLSDR_GAIN=auto
RAW_RETENTION_DAYS=3
PARTITION_RETENTION_DAYS=3
OVERLAP_MINUTES=10
MONITORING_INTERVAL_SECONDS=30

View File

@@ -1,21 +1,51 @@
# Compose scaffold for FR24 ingest
# FR24 ingest compose skeleton
This directory contains the baseline Docker Compose skeleton for the RTL-SDR ingest contour.
This directory contains the Docker Compose skeleton for the RTL-SDR ingest contour.
## Services
- `postgres` — PostgreSQL 16 + PostGIS
- `ingest` — placeholder for capture/preprocess wiring
- `status` — simple heartbeat/status scaffold
- `postgres` — PostgreSQL 16 + PostGIS, single source of truth for ingest and API
- `capture` — RTL-SDR access and `raw_packets` writer
- `preprocess` — normalization, flights/tracks/track_points builder, recovery
- `api` — reader for noisemap UI and future viewer endpoints
- `monitoring` — separate container for healthchecks, disk/DB/capture status, alerts
## Layout
- `../db/postgres` — PostgreSQL data directory
- `../db/init`init SQL scripts for schema/bootstrap
- `../ingest`ingest service code placeholder
- `../logs/ingest` — ingest logs
- `../logs/status` — status heartbeat files
- `../backup`backup artifacts
- `../db/init`bootstrap SQL for extensions and schema
- `../ingest`capture and preprocess implementation
- `../frontend` — API/viewer implementation
- `../logs/*` — service logs
- `../backup`pg_dump / restore artifacts
## Architecture notes
- `raw_packets` stores binary payloads as base64 plus metadata: timestamp, frequency, RSSI, SNR, samplerate.
- Raw retention is 3 days.
- Raw data is partitioned by date.
- `capture` and `preprocess` are separate containers.
- `api` is included now so the ingest↔API contract is fixed early.
- The contract between ingest and API is the PostgreSQL schema itself: ingest writes tables, API reads the same tables.
## API / data contract
The API reads:
- `captures`
- `raw_packets`
- `aircraft`
- `flights`
- `track_points`
- `tracks`
- `processing_state`
- `noise_results`
Planned endpoints:
- `GET /health` — service status
- `GET /captures` — capture sessions
- `GET /aircraft` — aircraft list and search
- `GET /flights` — flights with filters
- `GET /tracks/{track_id}` — a single track with points
- `GET /noise-results` — noise polygons and summaries
- `GET /dashboard/status` — ingest / recovery / backlog status for UI
- `GET /viewer/config` — map/UI bootstrap metadata
## Notes
- No destructive migrations are included.
- The `ingest` service is a placeholder; wire real capture/preprocess logic later.
- No runtime is started from this repository during preparation.
- The stack expects a `.env` file copied from `.env.example` in this directory.

View File

@@ -4,12 +4,20 @@ name: fr24-ingest
x-common-env: &common-env
TZ: ${TZ:-UTC}
APP_ENV: ${APP_ENV:-dev}
POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
POSTGRES_PORT: ${POSTGRES_PORT:-5432}
POSTGRES_DB: ${POSTGRES_DB:-fr24}
POSTGRES_USER: ${POSTGRES_USER:-fr24}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me}
APP_ENV: ${APP_ENV:-dev}
RAW_RETENTION_DAYS: ${RAW_RETENTION_DAYS:-3}
PARTITION_RETENTION_DAYS: ${PARTITION_RETENTION_DAYS:-3}
OVERLAP_MINUTES: ${OVERLAP_MINUTES:-10}
CAPTURE_SOURCE: ${CAPTURE_SOURCE:-rtl-sdr}
RTLSDR_DEVICE_INDEX: ${RTLSDR_DEVICE_INDEX:-0}
RTLSDR_SAMPLE_RATE: ${RTLSDR_SAMPLE_RATE:-2000000}
RTLSDR_CENTER_FREQUENCY: ${RTLSDR_CENTER_FREQUENCY:-1090000000}
RTLSDR_GAIN: ${RTLSDR_GAIN:-auto}
services:
postgres:
@@ -35,25 +43,24 @@ services:
networks:
- fr24-net
ingest:
capture:
image: alpine:3.20
container_name: fr24-ingest
command: ["sh", "-c", "echo 'ingest placeholder: wire capture/preprocess here'; tail -f /dev/null"]
container_name: fr24-capture
command: ["sh", "-c", "echo 'capture placeholder: read RTL-SDR and write raw_packets'; tail -f /dev/null"]
environment:
<<: *common-env
INGEST_MODE: ${INGEST_MODE:-placeholder}
RAW_RETENTION_DAYS: ${RAW_RETENTION_DAYS:-3}
OVERLAP_MINUTES: ${OVERLAP_MINUTES:-10}
CAPTURE_SOURCE: ${CAPTURE_SOURCE:-rtl-sdr}
SERVICE_ROLE: capture
devices:
- "/dev/bus/usb:/dev/bus/usb"
volumes:
- ../ingest:/app
- ../logs/ingest:/var/log/fr24
- ../logs/capture:/var/log/fr24
- ../backup:/backup
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "test -f /tmp/ingest-ready && echo ok || exit 1"]
test: ["CMD-SHELL", "test -f /tmp/capture-ready || exit 1"]
interval: 30s
timeout: 5s
retries: 3
@@ -62,17 +69,89 @@ services:
networks:
- fr24-net
status:
preprocess:
image: alpine:3.20
container_name: fr24-status
command: ["sh", "-c", "while true; do date -u +'%Y-%m-%dT%H:%M:%SZ' > /status/heartbeat; sleep 30; done"]
container_name: fr24-preprocess
command: ["sh", "-c", "echo 'preprocess placeholder: normalize data and build flights/tracks'; tail -f /dev/null"]
environment:
<<: *common-env
SERVICE_ROLE: preprocess
volumes:
- ../logs/status:/status
- ../ingest:/app
- ../logs/preprocess:/var/log/fr24
- ../backup:/backup
depends_on:
postgres:
condition: service_healthy
capture:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "test -f /status/heartbeat"]
test: ["CMD-SHELL", "test -f /tmp/preprocess-ready || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
networks:
- fr24-net
api:
image: alpine:3.20
container_name: fr24-api
command: ["sh", "-c", "echo 'api placeholder: noisemap reader and UI endpoints'; tail -f /dev/null"]
environment:
<<: *common-env
SERVICE_ROLE: api
API_PORT: ${API_PORT:-8080}
ports:
- "${API_PUBLISHED_PORT:-8080}:8080"
volumes:
- ../frontend:/app
- ../logs/api:/var/log/fr24
depends_on:
postgres:
condition: service_healthy
preprocess:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "test -f /tmp/api-ready || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
networks:
- fr24-net
monitoring:
image: alpine:3.20
container_name: fr24-monitoring
command: ["sh", "-c", "echo 'monitoring placeholder: disk, db, capture status, alerts'; tail -f /dev/null"]
environment:
<<: *common-env
SERVICE_ROLE: monitoring
MONITORING_INTERVAL_SECONDS: ${MONITORING_INTERVAL_SECONDS:-30}
ports:
- "${MONITORING_PUBLISHED_PORT:-9090}:9090"
volumes:
- ../logs/monitoring:/var/log/fr24
- ../backup:/backup
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
postgres:
condition: service_healthy
capture:
condition: service_started
preprocess:
condition: service_started
api:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "test -f /tmp/monitoring-ready || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
networks:
- fr24-net
@@ -81,8 +160,3 @@ networks:
fr24-net:
name: fr24-net
driver: bridge
volumes:
postgres-data:
ingest-logs:
backups:

View File

@@ -1,7 +1,24 @@
# Database layout
- `postgres/` — PostgreSQL persistent data volume
- `init/` — bootstrap SQL for extensions and initial schema
- `init/` — bootstrap SQL for extensions, schema, and retention helpers
Current bootstrap only enables `postgis` and `pgcrypto`.
No irreversible migrations are included.
Bootstrap now enables:
- `postgis`
- `pgcrypto`
- core FR24 ingest schema under `fr24`
Schema objects:
- `captures`
- `raw_packets`
- `aircraft`
- `flights`
- `tracks`
- `track_points`
- `processing_state`
- `noise_results`
Notes:
- `raw_packets` is partitioned by `partition_date`
- raw retention target is 3 days
- no runtime is started from this repository during preparation

View File

@@ -0,0 +1,124 @@
CREATE SCHEMA IF NOT EXISTS fr24;
CREATE TABLE IF NOT EXISTS fr24.captures (
capture_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
started_at TIMESTAMPTZ NOT NULL,
ended_at TIMESTAMPTZ,
source TEXT NOT NULL DEFAULT 'rtl-sdr',
device_index INTEGER NOT NULL DEFAULT 0,
center_frequency_hz BIGINT NOT NULL,
sample_rate_hz INTEGER NOT NULL,
gain_db NUMERIC(6,2),
status TEXT NOT NULL DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
notes TEXT
);
CREATE TABLE IF NOT EXISTS fr24.raw_packets (
raw_packet_id BIGSERIAL PRIMARY KEY,
capture_id UUID NOT NULL REFERENCES fr24.captures(capture_id) ON DELETE CASCADE,
observed_at TIMESTAMPTZ NOT NULL,
partition_date DATE NOT NULL DEFAULT (CURRENT_DATE),
frequency_hz BIGINT NOT NULL,
rssi_dbm NUMERIC(8,3),
snr_db NUMERIC(8,3),
samplerate_hz INTEGER NOT NULL,
payload_base64 TEXT NOT NULL,
payload_bytes INTEGER,
decoded_format TEXT,
message_type TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
) PARTITION BY RANGE (partition_date);
CREATE TABLE IF NOT EXISTS fr24.raw_packets_default
PARTITION OF fr24.raw_packets DEFAULT;
CREATE TABLE IF NOT EXISTS fr24.aircraft (
aircraft_id BIGSERIAL PRIMARY KEY,
icao24 TEXT NOT NULL UNIQUE,
callsign TEXT,
registration TEXT,
aircraft_type TEXT,
operator_name TEXT,
first_seen_at TIMESTAMPTZ,
last_seen_at TIMESTAMPTZ,
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS fr24.flights (
flight_id BIGSERIAL PRIMARY KEY,
aircraft_id BIGINT NOT NULL REFERENCES fr24.aircraft(aircraft_id) ON DELETE CASCADE,
departure_airport TEXT,
arrival_airport TEXT,
callsign TEXT,
flight_number TEXT,
started_at TIMESTAMPTZ NOT NULL,
ended_at TIMESTAMPTZ,
status TEXT NOT NULL DEFAULT 'active',
source TEXT NOT NULL DEFAULT 'rtl-sdr',
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS fr24.tracks (
track_id BIGSERIAL PRIMARY KEY,
flight_id BIGINT NOT NULL REFERENCES fr24.flights(flight_id) ON DELETE CASCADE,
geometry GEOMETRY(LineString, 4326),
point_count INTEGER NOT NULL DEFAULT 0,
min_altitude_m NUMERIC(10,2),
max_altitude_m NUMERIC(10,2),
distance_m NUMERIC(14,2),
duration_seconds INTEGER,
last_point_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS fr24.track_points (
track_point_id BIGSERIAL PRIMARY KEY,
track_id BIGINT NOT NULL REFERENCES fr24.tracks(track_id) ON DELETE CASCADE,
flight_id BIGINT NOT NULL REFERENCES fr24.flights(flight_id) ON DELETE CASCADE,
observed_at TIMESTAMPTZ NOT NULL,
point_order INTEGER NOT NULL,
geom GEOMETRY(Point, 4326) NOT NULL,
altitude_m NUMERIC(10,2),
ground_speed_kt NUMERIC(10,2),
vertical_rate_fpm NUMERIC(10,2),
heading_deg NUMERIC(10,2),
source_packet_id BIGINT REFERENCES fr24.raw_packets(raw_packet_id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (track_id, point_order)
);
CREATE TABLE IF NOT EXISTS fr24.processing_state (
state_key TEXT PRIMARY KEY,
state_value JSONB NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
note TEXT
);
CREATE TABLE IF NOT EXISTS fr24.noise_results (
noise_result_id BIGSERIAL PRIMARY KEY,
flight_id BIGINT REFERENCES fr24.flights(flight_id) ON DELETE CASCADE,
track_id BIGINT REFERENCES fr24.tracks(track_id) ON DELETE CASCADE,
computed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
period_start TIMESTAMPTZ,
period_end TIMESTAMPTZ,
noise_model TEXT NOT NULL DEFAULT 'v1',
geometry GEOMETRY(Polygon, 4326),
summary JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_raw_packets_capture_time ON fr24.raw_packets (capture_id, observed_at DESC);
CREATE INDEX IF NOT EXISTS idx_raw_packets_partition_date ON fr24.raw_packets (partition_date);
CREATE INDEX IF NOT EXISTS idx_aircraft_last_seen ON fr24.aircraft (last_seen_at DESC);
CREATE INDEX IF NOT EXISTS idx_flights_aircraft_started ON fr24.flights (aircraft_id, started_at DESC);
CREATE INDEX IF NOT EXISTS idx_track_points_track_time ON fr24.track_points (track_id, observed_at);
CREATE INDEX IF NOT EXISTS idx_track_points_flight_time ON fr24.track_points (flight_id, observed_at);
CREATE INDEX IF NOT EXISTS idx_tracks_flight ON fr24.tracks (flight_id);
CREATE INDEX IF NOT EXISTS idx_noise_results_computed_at ON fr24.noise_results (computed_at DESC);

View File

@@ -0,0 +1,23 @@
CREATE OR REPLACE FUNCTION fr24.drop_raw_partitions_older_than(retention_days INTEGER)
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
partition_record RECORD;
cutoff_date DATE := CURRENT_DATE - retention_days;
BEGIN
FOR partition_record IN
SELECT inhrelid::regclass::text AS partition_name
FROM pg_inherits
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
WHERE parent.relname = 'raw_packets'
AND parent.relnamespace = 'fr24'::regnamespace
LOOP
IF partition_record.partition_name <> 'fr24.raw_packets_default' THEN
EXECUTE format('ALTER TABLE %s DETACH PARTITION %s', 'fr24.raw_packets', partition_record.partition_name);
END IF;
END LOOP;
END;
$$;
COMMENT ON FUNCTION fr24.drop_raw_partitions_older_than(INTEGER) IS 'Retention helper placeholder; actual cleanup is driven by monitoring/preprocess scheduler.';

View File

@@ -10,169 +10,46 @@
- хранить данные в PostgreSQL/PostGIS
- отдавать данные в noisemap / карту
## 2. Ограничения среды
- 1 VM в PVE
- USB RTL-SDR проброшен в VM
- ресурсы VM ограничены:
- CPU: до 6 vCPU
- RAM: 1012 GB
- SSD: 80100 GB max
- развёртывание через Docker Compose
## 2. Контейнеры
## 3. Логическая схема
```text
RTL-SDR USB
capture
raw_packets / captures (PostgreSQL)
preprocess
flights / tracks / track_points / processing_state
noise_results
noisemap / UI / API
```
## 4. Контейнеры
### 4.1 `postgres`
**Назначение:** хранение всех данных проекта.
Содержит:
### 2.1 `postgres`
Хранит:
- `captures`
- `raw_packets`
- `aircraft`
- `flights`
- `track_points`
- `tracks`
- `track_points`
- `processing_state`
- `noise_results`
Требования:
- PostgreSQL
- PostGIS enabled
- volume для данных
- регулярные backup/restore процедуры
### 2.2 `capture`
- читает USB RTL-SDR
- пишет `captures` и `raw_packets`
- не занимается нормализацией
### 4.2 `capture`
**Назначение:** приём ADS-B потока с RTL-SDR.
### 2.3 `preprocess`
- читает `raw_packets`
- строит `aircraft`, `flights`, `tracks`, `track_points`
- управляет `processing_state`
- поддерживает recovery
Функции:
- чтение USB-устройства
- получение live-потока
- запись сырья в PostgreSQL
- фиксация `captures`
- маркировка границ сессий приёма
### 2.4 `api`
- читает те же таблицы
- отдаёт данные для noisemap UI
- не пересчитывает геометрию на лету
Требования:
- лёгкий CPU footprint
- устойчивость к временной потере downstream
- healthcheck
- автоматический рестарт
### 2.5 `monitoring`
- отдельный контейнер
- healthchecks, disk/DB/capture status, alerts
### 4.3 `preprocess`
**Назначение:** нормализация и догоняющая обработка.
Функции:
- обработка live-потока
- разбор `raw_packets`
- построение `aircraft`
- построение `flights`
- построение `tracks` и `track_points`
- обновление `processing_state`
- recovery с overlap при сбоях
Требования:
- инкрементальная обработка
- дедупликация на границах overlap
- ограничение по памяти
- возможность догонять пропуски автоматически
### 4.4 `api` / `viewer`
**Назначение:** отдача данных для noisemap.
Функции:
- чтение обработанных данных из PostgreSQL
- отдача треков, точек и шумовых результатов
- фильтрация по периоду и зоне
- API для карты/визуализации
Требования:
- лёгкие запросы
- минимальная логика в рантайме
- кэширование только при реальной необходимости
### 4.5 `monitoring` (optional)
**Назначение:** наблюдение за здоровьем контура.
Функции:
- healthcheck контейнеров
- мониторинг задержки обработки
- мониторинг заполнения диска
- мониторинг статуса RTL-SDR
- алерты при деградации
## 5. Docker Compose структура
Минимальный compose должен поднимать:
## 3. Docker Compose порядок
Минимальный состав:
- `postgres`
- `capture`
- `preprocess`
- `api`
Опционально:
- `monitoring`
### Сетевое правило
- контейнеры общаются внутри одной docker network
- наружу публикуется только `api` и, если нужно, `monitoring`
- `postgres` не публикуется наружу
## 6. Данные и потоки
### 6.1 Live flow
1. RTL-SDR → `capture`
2. `capture` пишет сырьё в `raw_packets`
3. `preprocess` читает сырьё
4. `preprocess` обновляет `flights`, `tracks`, `track_points`
5. `api` отдаёт данные на карту
### 6.2 Recovery flow
1. `preprocess` обнаруживает отставание
2. ищет недостающий диапазон в `raw_packets`
3. добирает пропущенные записи
4. обрабатывает с небольшим overlap
5. обновляет `processing_state`
## 7. Автозапуск и устойчивость
- контейнеры стартуют после reboot VM
- каждый контейнер имеет healthcheck
- сбой одного контейнера не должен валить всю VM
- `capture` должен уметь переживать временный разрыв downstream
- `preprocess` должен уметь догонять запись после восстановления
## 8. Производительность
С учётом ограничений VM:
- минимизировать число контейнеров и лишних сервисов
- не тащить тяжёлые брокеры очередей без необходимости
- не строить много промежуточных копий данных
- хранить сырьё коротко и чистить автоматически
- тяжёлые вычисления держать инкрементальными
## 9. Что должно быть детализировано дальше
Следующие документы/итерации должны закрыть:
- схему БД и индексы
- backup/restore
- мониторинг и алерты
- контракт между `preprocess` и `api`
- точный формат `raw_packets`
- стратегию партиционирования
## 10. Связь с проектом
Этот документ — техническая основа для:
- `tasks/flightradar24/PROJECT.md`
- `tasks/flightradar24/docs/RTL-SDR_TZ.md`
## 4. Контракт ingest↔API
Контрактом является схема PostgreSQL. Детали — в `docs/INGEST_API_CONTRACT.md`.

View File

@@ -0,0 +1,44 @@
# Ingest ↔ API contract
## Principle
The contract between ingest and API is the PostgreSQL schema.
Ingest writes rows; API reads the same rows.
No file exchange is required for the core data path.
## API read model
The API reads these tables:
- `fr24.captures` — capture sessions and source metadata
- `fr24.raw_packets` — raw base64 packets with radio metadata
- `fr24.aircraft` — aircraft identity and enrichment
- `fr24.flights` — flight sessions and state
- `fr24.tracks` — track aggregates
- `fr24.track_points` — ordered track geometry points
- `fr24.processing_state` — recovery cursors and pipeline state
- `fr24.noise_results` — computed noise polygons and summaries
## Ingest write model
- `capture` writes `captures` and `raw_packets`
- `preprocess` writes `aircraft`, `flights`, `tracks`, `track_points`, `processing_state`, `noise_results`
- `monitoring` does not own core data; it reports status and alerts
## Planned endpoints
- `GET /health`
- `GET /captures`
- `GET /raw-packets` with pagination and time filters
- `GET /aircraft`
- `GET /flights`
- `GET /tracks/{track_id}`
- `GET /track-points?track_id=...`
- `GET /noise-results`
- `GET /dashboard/status`
- `GET /viewer/config`
## Query expectations
- API should prefer indexed filters by time, flight, aircraft, and partition date.
- API should not reconstruct track geometry from raw packets at request time.
- API should read prebuilt aggregates from `tracks` and `track_points`.
## Retention expectations
- `raw_packets` keep 3 days by default.
- Cleanup is partition-based by date.
- Aggregated tables may retain longer, depending on UI needs.

View File

@@ -1,219 +1,22 @@
# ТЗ: Приём, хранение и обработка данных с RTL-SDR для FR24 / noisemap
# ТЗ: RTL-SDR ingest-контур
## 1. Цель
Построить локальный контур приёма ADS-B данных с RTL-SDR, их предобработки, хранения в PostgreSQL/PostGIS и дальнейшего использования для:
- восстановления данных после сбоев без потерь,
- формирования сущностей рейсов и треков,
- расчёта производных шумовых данных,
- визуализации на карте в рамках проекта FR24 / noisemap.
## Цель
Построить локальный ADS-B ingest-контур на RTL-SDR с PostgreSQL/PostGIS, recovery и API для noisemap UI.
## 2. Целевой контур
Система разворачивается на одной VM в PVE.
## Обязательные сервисы
- `postgres`
- `capture`
- `preprocess`
- `api`
- `monitoring`
### Ограничения VM
- CPU: до 6 vCPU
- RAM: 1012 GB
- SSD: 80100 GB max
## Требования к данным
- raw packets хранятся как base64 payload + radio metadata
- retention raw: 3 дня
- partitioning: по дате
- схема БД — контракт между ingest и API
### Аппаратный вход
- RTL-SDR подключён к физической машине по USB
- PVE-хост пробрасывает USB в VM
### Развёртывание
- Docker Compose
- каждый компонент в отдельном контейнере
## 3. Архитектура
### Компоненты внутри VM
- postgres + postgis
- capture
- preprocess
- api/viewer
- optional: monitoring
### Принцип
- одна VM
- одна PostgreSQL база
- сырьё и обработанные данные живут в одной БД, но логически разделены
- сырьё хранится с небольшим retention и используется для догоняющей обработки
## 4. Режимы работы
### 4.1 Live mode
- система принимает поток в реальном времени
- записи сохраняются в сырьевой слой
- данные сразу уходят в предобработку
### 4.2 Recovery mode
- если обработка отстала или упала,
- но сырьё ещё доступно,
- система автоматически догоняет пропущенный диапазон
### 4.3 Overlap mode
- при догоняющей обработке допускается небольшой перекрывающийся участок
- это нужно, чтобы не терять данные на границах и компенсировать сбои
## 5. Хранение данных
### 5.1 Retention
- сырьё хранится 3 дня
- после этого raw-слой чистится автоматически
- 3 дня — минимальный гарантированный горизонт для восстановления
### 5.2 База
- PostgreSQL
- PostGIS обязателен
### 5.3 Принцип хранения
- raw-данные отделены от core-данных
- core-данные очищены и оптимизированы под запросы карты и расчётов
- схема должна быть компактной, без лишних таблиц и тяжёлой нормализации
## 6. Объекты хранения
Минимальный набор сущностей:
### `captures`
Сессии приёма.
Хранят:
- старт и конец сессии
- источник приёма
- статус
- покрытый диапазон времени
- признаки сбоя / восстановления
### `raw_packets`
Сырой поток.
Хранят:
- timestamp
- payload/packet data
- signal metadata при наличии
- привязку к capture/session
### `aircraft`
Справочник бортов.
Хранят:
- ICAO24
- callsign
- тип/категорию при наличии
- оператор/авиакомпанию при наличии
### `flights`
Сущность рейса.
Хранят:
- flight id / number
- aircraft
- время начала и конца
- маршрут / аэропорты при наличии
- состояние заполненности
### `track_points`
Точки трека.
Хранят:
- время
- координаты
- высоту
- скорость
- курс
- принадлежность к flight/track
### `tracks`
Сводка трека.
Хранят:
- bbox
- длительность
- min/max altitude
- количество точек
- краткое описание маршрута
### `processing_state`
Состояние пайплайна.
Хранят:
- последний успешный checkpoint
- обработанный диапазон
- отставание
- состояние recovery
### `noise_results`
Производные данные для карты.
Хранят:
- расчётные зоны/радиусы
- интенсивность/плотность
- геометрию для визуализации
- привязку к рейсу/треку/времени
## 7. Основные требования к обработке
### 7.1 Приём
- принимать ADS-B поток от RTL-SDR
- сохранять сырьё до обработки
- не терять данные при временном сбое downstream
### 7.2 Предобработка
- нормализовать записи
- выделять рейсы
- строить треки
- обновлять state обработки
### 7.3 Восстановление
- после сбоя искать недостающий диапазон
- добирать пропущенные записи из raw-слоя
- допускается overlap
### 7.4 Оптимизация
- обработка должна быть лёгкой по CPU и памяти
- БД и схема должны быть компактными
- лишних промежуточных слоёв не заводить
## 8. Карта и визуализация
Система должна поддерживать данные, нужные для:
- отображения треков рейсов
- отображения шумовых зон
- анализа плотности пролётов
- фильтрации по времени
- отрисовки результатов на карте
## 9. Требования к инфраструктуре
- запуск через Docker Compose
- отдельные контейнеры для ключевых частей
- автозапуск после ребута VM
- возможность мониторить состояние приёма и БД
- логирование по каждому компоненту отдельно
## 10. Критерии приёмки
Система считается готовой, если:
- RTL-SDR отдаёт поток в VM через USB passthrough
- raw-данные сохраняются в PostgreSQL
- raw retention работает на 3 дня
- при сбое система может догнать пропущенный диапазон
- в БД присутствуют рейсы, треки и точки треков
- PostGIS используется для геоданных
- данные доступны для визуализации на карте
- контейнеры поднимаются через Docker Compose
## 11. Открытые вопросы, которые ещё стоит уточнить позже
- точный формат сырьевых пакетов
- нужен ли отдельный UI мониторинга
- нужен ли архив beyond 3 days
- какие индексы и партиционирование делать на старте
- где именно будет жить API noisemap после переноса
## 12. Итерация 2 — обязательный список улучшений
Следующая итерация ТЗ должна включать:
- мониторинг отвалившегося RTL-SDR и автоперезапуск capture
- healthcheck контейнеров и БД
- политика ротации логов и объёма диска
- схема индексов и партиционирования raw/track tables
- unique key / dedup стратегия для overlapping recovery
- экспорт/импорт исторических данных при миграции
- резервное копирование PostgreSQL и восстановление
- уведомления о деградации приёма или заполнении диска
- контракт между ingest-слоем и noisemap UI, если они остаются раздельными
## 13. Анализ: ничего ли не упущено
Дополнительно стоит проверить перед реализацией:
- нужен ли отдельный UI мониторинга
- где живёт API после переноса
- как именно партиционируются `raw_packets` и `track_points`
- нужен ли отдельный архив после 3 дней
- какую политику дедупликации выбрать для overlap на границах
- как восстанавливать БД после полного падения VM
---
Подготовлено на основе текущей архитектуры FR24/noisemap и согласованных ограничений VM.
## Нефункциональные требования
- `capture` и `preprocess` должны быть отдельными контейнерами
- `monitoring` должен быть отдельным контейнером
- API нужен в первой compose-итерации