From 0c78ad8bb853323e3743eb3c5c3da4513c375216 Mon Sep 17 00:00:00 2001 From: htlee Date: Wed, 18 Mar 2026 02:59:54 +0900 Subject: [PATCH] =?UTF-8?q?feat(db):=20ships/osint/satellites=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20=EC=83=9D=EC=84=B1=20+=20=EC=83=98?= =?UTF-8?q?=ED=94=8C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=81=EC=9E=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ship_positions: AIS/signal-batch 선박 위치 이력 (PostGIS) - osint_feeds: GDELT/Google News/CENTCOM 피드 (UNIQUE 중복방지) - satellite_tle: CelesTrak TLE 위성 궤도 데이터 - 샘플: 중동 함정 16척, 한국 해역 8척, OSINT 17건, 위성 11기 --- .../migration/003_ships_osint_satellites.sql | 79 +++++++++++++++++++ database/seed/001_sample_ships.sql | 60 ++++++++++++++ database/seed/002_sample_osint.sql | 31 ++++++++ database/seed/003_sample_satellites.sql | 36 +++++++++ 4 files changed, 206 insertions(+) create mode 100644 database/migration/003_ships_osint_satellites.sql create mode 100644 database/seed/001_sample_ships.sql create mode 100644 database/seed/002_sample_osint.sql create mode 100644 database/seed/003_sample_satellites.sql diff --git a/database/migration/003_ships_osint_satellites.sql b/database/migration/003_ships_osint_satellites.sql new file mode 100644 index 0000000..0c58763 --- /dev/null +++ b/database/migration/003_ships_osint_satellites.sql @@ -0,0 +1,79 @@ +-- 003: 선박 위치 이력 + OSINT 피드 + 위성 TLE 테이블 +-- 리플레이 및 분석용 시계열 데이터 저장 + +SET search_path TO kcg, public; + +-- ═══════════════════════════════════════════ +-- 선박 위치 이력 (AIS / signal-batch) +-- ═══════════════════════════════════════════ +CREATE TABLE IF NOT EXISTS ship_positions ( + id BIGSERIAL PRIMARY KEY, + mmsi VARCHAR(9) NOT NULL, + name VARCHAR(128), + position geometry(Point, 4326) NOT NULL, + heading DOUBLE PRECISION, + speed DOUBLE PRECISION, -- knots + course DOUBLE PRECISION, -- COG + category VARCHAR(16), -- warship, carrier, destroyer, tanker, cargo, ... + flag VARCHAR(4), -- ISO 국가코드 + typecode VARCHAR(16), + type_desc VARCHAR(128), + imo VARCHAR(16), + call_sign VARCHAR(16), + status VARCHAR(64), -- Under way, Anchored, ... + destination VARCHAR(128), + draught DOUBLE PRECISION, + length DOUBLE PRECISION, + width DOUBLE PRECISION, + source VARCHAR(16) NOT NULL, -- spg, signal-batch, sample + region VARCHAR(16) NOT NULL, -- middleeast, korea + collected_at TIMESTAMP NOT NULL DEFAULT NOW(), + last_seen TIMESTAMP +); + +CREATE INDEX IF NOT EXISTS idx_ship_pos_geom ON ship_positions USING GIST (position); +CREATE INDEX IF NOT EXISTS idx_ship_pos_collected ON ship_positions (collected_at); +CREATE INDEX IF NOT EXISTS idx_ship_pos_region_time ON ship_positions (region, collected_at); +CREATE INDEX IF NOT EXISTS idx_ship_pos_mmsi ON ship_positions (mmsi, collected_at); + +-- ═══════════════════════════════════════════ +-- OSINT 피드 (GDELT, Google News, CENTCOM) +-- ═══════════════════════════════════════════ +CREATE TABLE IF NOT EXISTS osint_feeds ( + id BIGSERIAL PRIMARY KEY, + title TEXT NOT NULL, + source VARCHAR(64) NOT NULL, -- gdelt, google-news-ko, google-news-en, centcom + source_url TEXT, + category VARCHAR(32), -- military, oil, diplomacy, shipping, nuclear, ... + language VARCHAR(8), -- ko, en + focus VARCHAR(16), -- iran, korea + image_url TEXT, + position geometry(Point, 4326), -- nullable (위치 추출 가능 시) + published_at TIMESTAMP, -- 원본 기사 발행 시각 + collected_at TIMESTAMP NOT NULL DEFAULT NOW(), + UNIQUE(source, source_url) -- 중복 방지 +); + +CREATE INDEX IF NOT EXISTS idx_osint_feeds_collected ON osint_feeds (collected_at); +CREATE INDEX IF NOT EXISTS idx_osint_feeds_focus ON osint_feeds (focus, collected_at); +CREATE INDEX IF NOT EXISTS idx_osint_feeds_category ON osint_feeds (category); +CREATE INDEX IF NOT EXISTS idx_osint_feeds_geom ON osint_feeds USING GIST (position); + +-- ═══════════════════════════════════════════ +-- 위성 TLE (CelesTrak) +-- ═══════════════════════════════════════════ +CREATE TABLE IF NOT EXISTS satellite_tle ( + id BIGSERIAL PRIMARY KEY, + norad_id INTEGER NOT NULL, + name VARCHAR(128) NOT NULL, + tle_line1 VARCHAR(70) NOT NULL, + tle_line2 VARCHAR(70) NOT NULL, + category VARCHAR(20), -- reconnaissance, communications, navigation, weather, other + tle_group VARCHAR(32), -- military, gps-ops, geo, weather, stations + epoch TIMESTAMP, -- TLE epoch (궤도 기준 시각) + collected_at TIMESTAMP NOT NULL DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_satellite_tle_norad ON satellite_tle (norad_id, collected_at); +CREATE INDEX IF NOT EXISTS idx_satellite_tle_collected ON satellite_tle (collected_at); +CREATE INDEX IF NOT EXISTS idx_satellite_tle_category ON satellite_tle (category); diff --git a/database/seed/001_sample_ships.sql b/database/seed/001_sample_ships.sql new file mode 100644 index 0000000..aa1628d --- /dev/null +++ b/database/seed/001_sample_ships.sql @@ -0,0 +1,60 @@ +-- 샘플 선박 데이터 적재 +-- 리플레이 시나리오: 2026-03-01 이란 공습 당시 중동 해역 주요 함정 + +SET search_path TO kcg, public; + +-- ═══════════════════════════════════════════ +-- 중동 해역 (region: middleeast) +-- ═══════════════════════════════════════════ + +-- USS Abraham Lincoln CSG (CVN-72) — 아라비아해 +INSERT INTO ship_positions (mmsi, name, position, heading, speed, course, category, flag, typecode, type_desc, source, region, last_seen) +VALUES +('369970072', 'USS ABRAHAM LINCOLN (CVN-72)', ST_SetSRID(ST_MakePoint(61.5, 23.5), 4326), 315, 18, 315, 'carrier', 'US', 'CVN', 'Aircraft Carrier', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('369970073', 'USS SPRUANCE (DDG-111)', ST_SetSRID(ST_MakePoint(61.3, 23.7), 4326), 310, 20, 310, 'destroyer', 'US', 'DDG', 'Destroyer', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('369970074', 'USS STERETT (DDG-104)', ST_SetSRID(ST_MakePoint(61.7, 23.3), 4326), 320, 19, 320, 'destroyer', 'US', 'DDG', 'Destroyer', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('369970075', 'USS MOBILE BAY (CG-53)', ST_SetSRID(ST_MakePoint(61.4, 23.6), 4326), 315, 18, 315, 'warship', 'US', 'CG', 'Cruiser', 'sample', 'middleeast', '2026-03-01 12:01:00'), + +-- USS Gerald R. Ford CSG (CVN-78) — 동지중해 +('369970078', 'USS GERALD R. FORD (CVN-78)', ST_SetSRID(ST_MakePoint(33.5, 34.0), 4326), 90, 15, 90, 'carrier', 'US', 'CVN', 'Aircraft Carrier', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('369970079', 'USS RAMAGE (DDG-61)', ST_SetSRID(ST_MakePoint(33.3, 34.2), 4326), 85, 17, 85, 'destroyer', 'US', 'DDG', 'Destroyer', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('369970080', 'USS THOMAS HUDNER (DDG-116)', ST_SetSRID(ST_MakePoint(33.7, 33.8), 4326), 95, 16, 95, 'destroyer', 'US', 'DDG', 'Destroyer', 'sample', 'middleeast', '2026-03-01 12:01:00'), + +-- 호르무즈 해협 IRGCN 쾌속정 +('422100001', 'IRGCN PATROL-1', ST_SetSRID(ST_MakePoint(56.3, 26.5), 4326), 180, 25, 180, 'patrol', 'IR', 'FAC', 'Fast Attack Craft', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('422100002', 'IRGCN PATROL-2', ST_SetSRID(ST_MakePoint(56.1, 26.7), 4326), 200, 22, 200, 'patrol', 'IR', 'FAC', 'Fast Attack Craft', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('422100003', 'IRGCN PATROL-3', ST_SetSRID(ST_MakePoint(56.5, 26.3), 4326), 170, 28, 170, 'patrol', 'IR', 'FAC', 'Fast Attack Craft', 'sample', 'middleeast', '2026-03-01 12:01:00'), + +-- 영국 HMS Queen Elizabeth CSG +('232009001', 'HMS QUEEN ELIZABETH (R08)', ST_SetSRID(ST_MakePoint(58.0, 25.0), 4326), 0, 16, 0, 'carrier', 'GB', 'CV', 'Aircraft Carrier', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('232009002', 'HMS DIAMOND (D34)', ST_SetSRID(ST_MakePoint(58.2, 25.2), 4326), 5, 18, 5, 'destroyer', 'GB', 'DDG', 'Destroyer', 'sample', 'middleeast', '2026-03-01 12:01:00'), + +-- 프랑스 FS Charles de Gaulle +('227000001', 'FS CHARLES DE GAULLE (R91)', ST_SetSRID(ST_MakePoint(32.0, 34.5), 4326), 90, 14, 90, 'carrier', 'FR', 'CV', 'Aircraft Carrier', 'sample', 'middleeast', '2026-03-01 12:01:00'), + +-- 민간 유조선 / 화물선 (호르무즈 해협) +('538007001', 'FRONT ALTA (VLCC)', ST_SetSRID(ST_MakePoint(56.0, 26.0), 4326), 150, 12, 150, 'tanker', 'MH', 'VLCC', 'Very Large Crude Carrier', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('538007002', 'SEAVIGOUR', ST_SetSRID(ST_MakePoint(55.5, 26.2), 4326), 330, 11, 330, 'tanker', 'MH', 'VLCC', 'Very Large Crude Carrier', 'sample', 'middleeast', '2026-03-01 12:01:00'), +('477000001', 'EVER GIVEN', ST_SetSRID(ST_MakePoint(56.8, 25.8), 4326), 120, 14, 120, 'cargo', 'HK', 'CONT', 'Container Ship', 'sample', 'middleeast', '2026-03-01 12:01:00'); + +-- ═══════════════════════════════════════════ +-- 한국 해역 (region: korea) +-- ═══════════════════════════════════════════ + +INSERT INTO ship_positions (mmsi, name, position, heading, speed, course, category, flag, typecode, type_desc, source, region, last_seen) +VALUES +-- ROKN 제7기동전단 +('440100001', 'ROKS CHOI YOUNG (DDH-981)', ST_SetSRID(ST_MakePoint(129.0, 35.0), 4326), 180, 16, 180, 'destroyer', 'KR', 'DDH', 'Destroyer', 'sample', 'korea', '2026-03-01 12:01:00'), +('440100002', 'ROKS SEJONG THE GREAT (DDG-991)', ST_SetSRID(ST_MakePoint(129.2, 35.2), 4326), 175, 18, 175, 'destroyer', 'KR', 'DDG', 'Aegis Destroyer', 'sample', 'korea', '2026-03-01 12:01:00'), +('440100003', 'ROKS DOKDO (LPH-6111)', ST_SetSRID(ST_MakePoint(128.8, 34.8), 4326), 190, 14, 190, 'warship', 'KR', 'LPH', 'Amphibious Assault Ship', 'sample', 'korea', '2026-03-01 12:01:00'), + +-- 동해 해경 순시선 +('440200001', 'SAMBONGHO (3000톤급)', ST_SetSRID(ST_MakePoint(129.5, 37.0), 4326), 0, 12, 0, 'patrol', 'KR', 'PCG', 'Coast Guard', 'sample', 'korea', '2026-03-01 12:01:00'), + +-- 부산항 민간선박 +('440300001', 'HMM ALGECIRAS', ST_SetSRID(ST_MakePoint(129.05, 35.1), 4326), 270, 8, 270, 'cargo', 'KR', 'CONT', 'Container Ship 24000TEU', 'sample', 'korea', '2026-03-01 12:01:00'), +('440300002', 'SK INNOVATION', ST_SetSRID(ST_MakePoint(129.3, 35.4), 4326), 90, 10, 90, 'tanker', 'KR', 'VLCC', 'VLCC Tanker', 'sample', 'korea', '2026-03-01 12:01:00'), + +-- 미 제7함대 CVN-76 +('369970076', 'USS RONALD REAGAN (CVN-76)', ST_SetSRID(ST_MakePoint(129.8, 35.1), 4326), 90, 15, 90, 'carrier', 'US', 'CVN', 'Aircraft Carrier', 'sample', 'korea', '2026-03-01 12:01:00'), +('369970077', 'USS BARRY (DDG-52)', ST_SetSRID(ST_MakePoint(130.0, 35.3), 4326), 85, 17, 85, 'destroyer', 'US', 'DDG', 'Destroyer', 'sample', 'korea', '2026-03-01 12:01:00'); diff --git a/database/seed/002_sample_osint.sql b/database/seed/002_sample_osint.sql new file mode 100644 index 0000000..2eb1133 --- /dev/null +++ b/database/seed/002_sample_osint.sql @@ -0,0 +1,31 @@ +-- 샘플 OSINT 피드 데이터 적재 +-- 리플레이 시나리오: 2026-03-01 이란 공습 관련 주요 뉴스 + +SET search_path TO kcg, public; + +INSERT INTO osint_feeds (title, source, source_url, category, language, focus, position, published_at) +VALUES +-- 이란 관련 주요 뉴스 (한국어) +('미국·이스라엘, 이란 핵시설 정밀타격… 이스파한·나탄즈 동시 공습', 'google-news-ko', 'https://example.com/news/iran-strike-1', 'military', 'ko', 'iran', ST_SetSRID(ST_MakePoint(51.7, 32.6), 4326), '2026-03-01 12:30:00'), +('이란 혁명수비대, 호르무즈 해협 봉쇄 위협… 유가 급등', 'google-news-ko', 'https://example.com/news/hormuz-1', 'oil', 'ko', 'iran', ST_SetSRID(ST_MakePoint(56.3, 26.5), 4326), '2026-03-01 13:00:00'), +('한국 정부, 호르무즈 해역 한국 선박 안전 확보 비상 대책 가동', 'google-news-ko', 'https://example.com/news/korea-response-1', 'shipping', 'ko', 'iran', NULL, '2026-03-01 14:00:00'), +('이란 탄도미사일, 알 다프라 공군기지 타격… 미군 피해 현황 미확인', 'google-news-ko', 'https://example.com/news/al-dhafra-1', 'military', 'ko', 'iran', ST_SetSRID(ST_MakePoint(54.55, 24.25), 4326), '2026-03-01 13:30:00'), +('국제 유가, 브렌트유 120달러 돌파… 2022년 이후 최고', 'google-news-ko', 'https://example.com/news/oil-price-1', 'oil', 'ko', 'iran', NULL, '2026-03-01 15:00:00'), +('UN 안보리, 이란 사태 긴급 회의 소집', 'google-news-ko', 'https://example.com/news/unsc-1', 'diplomacy', 'ko', 'iran', NULL, '2026-03-01 16:00:00'), + +-- 이란 관련 주요 뉴스 (영어) +('CENTCOM confirms strikes on Iranian nuclear facilities at Isfahan and Natanz', 'gdelt', 'https://example.com/news/centcom-confirm-1', 'military', 'en', 'iran', ST_SetSRID(ST_MakePoint(51.7, 32.6), 4326), '2026-03-01 12:15:00'), +('Iran retaliates with ballistic missiles targeting US bases in Gulf', 'gdelt', 'https://example.com/news/iran-retaliation-1', 'military', 'en', 'iran', ST_SetSRID(ST_MakePoint(54.55, 24.25), 4326), '2026-03-01 13:00:00'), +('Strait of Hormuz shipping disrupted as IRGCN deploys fast boats', 'gdelt', 'https://example.com/news/hormuz-shipping-1', 'shipping', 'en', 'iran', ST_SetSRID(ST_MakePoint(56.3, 26.5), 4326), '2026-03-01 14:30:00'), +('Brent crude surges past $120 on Middle East escalation fears', 'gdelt', 'https://example.com/news/oil-surge-1', 'oil', 'en', 'iran', NULL, '2026-03-01 15:00:00'), + +-- CENTCOM 공식 발표 +('CENTCOM: US and coalition forces conducted precision strikes on Iranian military targets', 'centcom', 'https://example.com/centcom/statement-1', 'military', 'en', 'iran', NULL, '2026-03-01 12:10:00'), +('CENTCOM: Iranian ballistic missile attack on Al Dhafra Air Base; damage assessment underway', 'centcom', 'https://example.com/centcom/statement-2', 'military', 'en', 'iran', ST_SetSRID(ST_MakePoint(54.55, 24.25), 4326), '2026-03-01 13:15:00'), + +-- 한국 해역 관련 뉴스 +('해경, 독도 인근 일본 순시선 접근 경고 조치', 'google-news-ko', 'https://example.com/news/dokdo-1', 'maritime_traffic', 'ko', 'korea', ST_SetSRID(ST_MakePoint(131.87, 37.24), 4326), '2026-03-15 09:00:00'), +('부산항 입출항 컨테이너선 1만 TEU 돌파… 물동량 회복세', 'google-news-ko', 'https://example.com/news/busan-port-1', 'shipping', 'ko', 'korea', ST_SetSRID(ST_MakePoint(129.05, 35.1), 4326), '2026-03-14 10:00:00'), +('서해 NLL 인근 중국 어선 불법조업 단속 강화', 'google-news-ko', 'https://example.com/news/nll-fishing-1', 'fishing', 'ko', 'korea', ST_SetSRID(ST_MakePoint(124.5, 37.5), 4326), '2026-03-13 11:00:00'), +('해군 제7기동전단, 동해 대잠수함 훈련 실시', 'google-news-ko', 'https://example.com/news/rokn-asw-1', 'military', 'ko', 'korea', ST_SetSRID(ST_MakePoint(130.0, 36.0), 4326), '2026-03-12 08:00:00'), +('여수 해상에서 유조선-화물선 충돌사고… 기름 유출 우려', 'google-news-ko', 'https://example.com/news/yeosu-accident-1', 'maritime_accident', 'ko', 'korea', ST_SetSRID(ST_MakePoint(127.7, 34.7), 4326), '2026-03-11 14:00:00'); diff --git a/database/seed/003_sample_satellites.sql b/database/seed/003_sample_satellites.sql new file mode 100644 index 0000000..5508125 --- /dev/null +++ b/database/seed/003_sample_satellites.sql @@ -0,0 +1,36 @@ +-- 샘플 위성 TLE 데이터 적재 +-- 주요 정찰/통신/GPS 위성 TLE (CelesTrak 2026년 3월 기준) + +SET search_path TO kcg, public; + +INSERT INTO satellite_tle (norad_id, name, tle_line1, tle_line2, category, tle_group, epoch) +VALUES +-- ═══ 정찰/군사 위성 ═══ +(25544, 'ISS (ZARYA)', '1 25544U 98067A 26060.54166667 .00016717 00000-0 29461-3 0 9991', '2 25544 51.6414 247.4627 0006703 130.5360 229.6130 15.50238364470812', 'other', 'stations', '2026-03-01 13:00:00'), + +-- SBIRS GEO-1 (미사일 조기경보 위성) +(37481, 'SBIRS GEO-1', '1 37481U 11019A 26060.00000000 .00000088 00000-0 00000-0 0 9998', '2 37481 3.2500 75.1000 0003500 270.0000 90.0000 1.00274000 50001', 'reconnaissance', 'military', '2026-03-01 00:00:00'), + +-- USA-224 (KH-11 광학 정찰위성) +(37348, 'USA-224 (KH-11)', '1 37348U 11002A 26060.50000000 .00000700 00000-0 30000-4 0 9996', '2 37348 97.9000 120.0000 0006000 250.0000 110.0000 14.56000000 50001', 'reconnaissance', 'military', '2026-03-01 12:00:00'), + +-- USA-245 (합성개구레이더 위성) +(40258, 'USA-245 (TOPAZ)', '1 40258U 14068A 26060.50000000 .00002000 00000-0 60000-4 0 9994', '2 40258 97.4000 50.0000 0012000 200.0000 160.0000 15.19000000 40001', 'reconnaissance', 'military', '2026-03-01 12:00:00'), + +-- Lacrosse-5 (SAR 정찰위성) +(28646, 'LACROSSE 5', '1 28646U 05016A 26060.50000000 .00001500 00000-0 40000-4 0 9993', '2 28646 57.0000 300.0000 0010000 180.0000 180.0000 14.98000000 50001', 'reconnaissance', 'military', '2026-03-01 12:00:00'), + +-- ═══ GPS/항법 위성 ═══ +(48859, 'GPS III-06 (SVN-79)', '1 48859U 21054A 26060.00000000 .00000010 00000-0 00000-0 0 9997', '2 48859 55.0200 175.5000 0050000 30.0000 330.0000 2.00565000 30001', 'navigation', 'gps-ops', '2026-03-01 00:00:00'), + +(28874, 'GPS IIR-M 03 (SVN-58)', '1 28874U 05038A 26060.00000000 .00000005 00000-0 00000-0 0 9998', '2 28874 56.1000 60.0000 0060000 90.0000 270.0000 2.00570000 40001', 'navigation', 'gps-ops', '2026-03-01 00:00:00'), + +-- ═══ 통신 위성 (GEO) ═══ +(44479, 'WGS-10', '1 44479U 19052A 26060.00000000 .00000088 00000-0 00000-0 0 9995', '2 44479 0.0500 60.0000 0002000 270.0000 90.0000 1.00274000 20001', 'communications', 'geo', '2026-03-01 00:00:00'), + +(36032, 'AEHF-1', '1 36032U 10039A 26060.00000000 .00000088 00000-0 00000-0 0 9996', '2 36032 3.0000 75.0000 0003000 270.0000 90.0000 1.00274000 30001', 'communications', 'geo', '2026-03-01 00:00:00'), + +-- ═══ 기상 위성 ═══ +(43689, 'METOP-C', '1 43689U 18087A 26060.50000000 .00000200 00000-0 50000-4 0 9992', '2 43689 98.7100 30.0000 0010000 300.0000 60.0000 14.21500000 30001', 'weather', 'weather', '2026-03-01 12:00:00'), + +(37849, 'SUOMI NPP', '1 37849U 11061A 26060.50000000 .00000150 00000-0 40000-4 0 9991', '2 37849 98.7400 50.0000 0008000 280.0000 80.0000 14.19500000 50001', 'weather', 'weather', '2026-03-01 12:00:00');