-- 294_dtp_incidents.sql -- ДТП (dtp-stat.ru, первоисточник — открытые данные ГИБДД), Свердловская обл. (#3410). -- -- WHY: слой ДТП нужен как радиусный "фактор безопасности" района (по образцу -- osm_poi_ekb_local / 169_osm_poi_ekb_local.sql — та же архитектура: пустая таблица + -- индексы на деплое, наполнение отдельным рефреш-джобом, никакого чтения внешнего -- источника при прогоне миграций). -- -- ИСТОЧНИК: https://dtp-stat.ru/media/opendata/sverdlovskaia-oblast.geojson.zip — открытый -- агрегатор данных ГИБДД, без auth. Дамп заморожен (Last-Modified 26.02.2026 на момент -- проверки 08.09.2026) — см. докстринг app/services/dtp_stat_loader.py, пустая дельта на -- рефреше это НЕ баг, а факт источника. -- -- ПДн (важно): properties.vehicles[].participants[] источника содержит пол/роль/нарушения -- физлиц-участников ДТП. Эта таблица их СОЗНАТЕЛЬНО НЕ хранит — ни колонкой, ни в jsonb. -- Загрузчик (dtp_stat_loader.py) участников/транспорт из парсинга просто не извлекает. -- Берём только агрегаты (dead/injured count) и не-персональные атрибуты происшествия. -- -- ИНДЕКСЫ (урок 270_houses_geog_gist_idx.sql / 134_listings_geom_geography_gist.sql): весь -- код МЕРЫ ходит радиусными запросами через ST_DWithin(geom::geography, …) — обычный GIST -- по geometry планировщик под такой предикат не берёт (прод-замер houses: 70.7 мс на -- bitmap-фильтр всех строк; после функционального индекса по geography — 38 мс на listings). -- Поэтому сразу оба индекса: geometry (на будущее/для прочих операторов) и функциональный -- по (geom::geography) — под фактический предикат dtp_index.py. -- -- Идемпотентно: CREATE TABLE/INDEX IF NOT EXISTS. Безопасно перезапускать. BEGIN; SET LOCAL lock_timeout = '5s'; CREATE TABLE IF NOT EXISTS dtp_incidents ( id bigserial PRIMARY KEY, source_id text UNIQUE, dtp_at timestamptz, category text, severity text, dead integer, injured integer, address text, light text, weather text[], nearby text[], lat double precision, lon double precision, geom geometry(Point, 4326), loaded_at timestamptz NOT NULL DEFAULT now() ); COMMENT ON TABLE dtp_incidents IS 'ДТП по Свердловской обл. (dtp-stat.ru, первоисточник — открытые данные ГИБДД, #3410). ' 'Пишет app/tasks/dtp_stat_refresh.py (TRUNCATE+INSERT, scheduler source=dtp_stat_refresh, ' 'seed 293, enabled=false — включение вручную). Читает app/services/dtp_index.py — ' 'радиусные агрегаты (число ДТП/тяжёлых/погибших/раненых) для карточки района. ' 'ПДн участников (vehicles/participants: пол, роль, нарушения физлиц) осознанно НЕ ' 'хранятся — ни колонкой, ни в jsonb; источник даёт их построчно на транспорт/участника, ' 'загрузчик их не извлекает вовсе.'; COMMENT ON COLUMN dtp_incidents.source_id IS 'properties.id из dtp-stat GeoJSON — ключ идемпотентности (UNIQUE).'; COMMENT ON COLUMN dtp_incidents.dtp_at IS 'properties.datetime, распарсено в timestamptz.'; COMMENT ON COLUMN dtp_incidents.category IS 'properties.category — тип ДТП ("Столкновение" и т.п.).'; COMMENT ON COLUMN dtp_incidents.severity IS 'properties.severity — тяжесть ("Тяжёлый"/"Лёгкий"/…).'; COMMENT ON COLUMN dtp_incidents.dead IS 'properties.dead_count — погибшие, агрегат, без ФИО/пола участников.'; COMMENT ON COLUMN dtp_incidents.injured IS 'properties.injured_count — раненые, агрегат.'; COMMENT ON COLUMN dtp_incidents.weather IS 'properties.weather — список погодных условий на момент ДТП.'; COMMENT ON COLUMN dtp_incidents.nearby IS 'properties.nearby — список объектов УДС/притяжения рядом с местом ДТП.'; COMMENT ON COLUMN dtp_incidents.geom IS 'ST_SetSRID(ST_MakePoint(lon, lat), 4326) — строится явно в загрузчике, без триггера (как osm_poi_ekb_local).'; -- GIST по geometry — на будущее / прочие geometry-операторы. CREATE INDEX IF NOT EXISTS dtp_incidents_geom_idx ON dtp_incidents USING GIST (geom); -- Функциональный GIST по (geom::geography) — под фактический предикат -- ST_DWithin(geom::geography, …) в app/services/dtp_index.py (см. WHY выше). CREATE INDEX IF NOT EXISTS dtp_incidents_geog_idx ON dtp_incidents USING GIST ((geom::geography)); CREATE INDEX IF NOT EXISTS dtp_incidents_dtp_at_idx ON dtp_incidents (dtp_at); COMMIT;