/** * 오버레이/경고 시각 검증용 더미 데이터 — 김개발(DEV) 모드 전용. * * 서해 해역에 12척의 가상 선박을 배치하여 다음 시나리오를 재현: * - 정상 쌍끌이 (pair link, ~1 NM) * - 이격 쌍끌이 (pair_separation alarm, ~8 NM) * - 선단 원 (fleet circle, 5척 동일 선주) * - 환적 의심 (transshipment alarm, FC ↔ PS < 0.5 NM) * - AIS 지연 (ais_stale alarm, 2시간 전 타임스탬프) * - 수역 이탈 (zone_violation alarm, PT가 zone 4에 위치) * - closed_season은 계절(월)에 따라 자동 판정 (2월에는 미발생) * * 사용법: * DashboardPage에서 isDevMode일 때 targetsInScope + legacyHits에 병합. * 기존 computePairLinks / computeFcLinks / computeFleetCircles / * computeLegacyAlarms 파이프라인이 자동으로 오버레이/경고를 생성. */ import type { AisTarget } from '../../../entities/aisTarget/model/types'; import type { LegacyVesselInfo } from '../../../entities/legacyVessel/model/types'; // ── 타임스탬프 ────────────────────────────────────────────── const FRESH_TS = new Date().toISOString(); const STALE_TS = new Date(Date.now() - 120 * 60_000).toISOString(); // 2시간 전 → ais_stale // ── 팩토리 ────────────────────────────────────────────────── function makeAis(o: Partial & Pick): AisTarget { return { imo: 0, name: '', callsign: '', vesselType: '', heading: o.cog ?? 0, sog: 0, cog: 0, rot: 0, length: 30, width: 8, draught: 4, destination: '', eta: '', status: 'underway', messageTimestamp: FRESH_TS, receivedDate: FRESH_TS, source: 'mock', classType: 'A', ...o, }; } function makeLegacy( o: Partial & Pick, ): LegacyVesselInfo { return { shipNameRoman: '', shipNameCn: null, ton: 100, callSign: '', workSeaArea: '서해', workTerm1: '2025-01-01', workTerm2: '2025-12-31', quota: '', ownerCn: null, ownerRoman: null, pairPermitNo: null, pairShipNameCn: null, checklistSheet: null, sources: { permittedList: true, checklist: false, fleet906: false }, ...o, }; } // ── 선박 정의 (12척) ──────────────────────────────────────── /* * Group 1 — 정상 쌍끌이 (간격 ~1 NM, 경고 없음) * 위치: 서해남부(zone 3) 125.3°E 34.0°N 부근 */ const PT_01_AIS = makeAis({ mmsi: 990001, lat: 34.00, lon: 125.30, sog: 3.3, cog: 45, name: 'MOCK VESSEL 1', shipImagePath: 'https://picsum.photos/seed/ship990001v1/800/600', shipImageCount: 3 }); const PT_02_AIS = makeAis({ mmsi: 990002, lat: 34.01, lon: 125.32, sog: 3.3, cog: 45, name: 'MOCK VESSEL 2' }); const PT_01_LEG = makeLegacy({ permitNo: 'MOCK-P001', shipCode: 'PT', mmsiList: [990001], shipNameRoman: 'MOCK VESSEL 1', shipNameCn: '模拟渔船一号', pairPermitNo: 'MOCK-P002', pairShipNameCn: '模拟渔船二号', ownerRoman: 'MOCK Owner A', ownerCn: '模拟A渔业', }); const PT_02_LEG = makeLegacy({ permitNo: 'MOCK-P002', shipCode: 'PT-S', mmsiList: [990002], shipNameRoman: 'MOCK VESSEL 2', shipNameCn: '模拟渔船二号', pairPermitNo: 'MOCK-P001', pairShipNameCn: '模拟渔船一号', ownerRoman: 'MOCK Owner A', ownerCn: '模拟A渔业', }); /* * Group 2 — 이격 쌍끌이 (간격 ~8 NM → pair_separation alarm) * 위치: 서해남부(zone 3) 125.0°E 34.5°N 부근 */ const PT_03_AIS = makeAis({ mmsi: 990003, lat: 34.50, lon: 125.00, sog: 3.5, cog: 90, name: 'MOCK VESSEL 3', shipImagePath: 'https://picsum.photos/seed/ship990003v1/800/600', shipImageCount: 2 }); const PT_04_AIS = makeAis({ mmsi: 990004, lat: 34.60, lon: 125.12, sog: 3.5, cog: 90, name: 'MOCK VESSEL 4' }); const PT_03_LEG = makeLegacy({ permitNo: 'MOCK-P003', shipCode: 'PT', mmsiList: [990003], shipNameRoman: 'MOCK VESSEL 3', shipNameCn: '模拟渔船三号', pairPermitNo: 'MOCK-P004', pairShipNameCn: '模拟渔船四号', ownerRoman: 'MOCK Owner B', ownerCn: '模拟B渔业', }); const PT_04_LEG = makeLegacy({ permitNo: 'MOCK-P004', shipCode: 'PT-S', mmsiList: [990004], shipNameRoman: 'MOCK VESSEL 4', shipNameCn: '模拟渔船四号', pairPermitNo: 'MOCK-P003', pairShipNameCn: '模拟渔船三号', ownerRoman: 'MOCK Owner B', ownerCn: '模拟B渔业', }); /* * Group 3 — 선단 (동일 선주 5척 → fleet circle) * 위치: 서해중간(zone 4) 124.8°E 35.2°N 부근 * #11(GN)은 AIS 지연 2시간 → ais_stale alarm 동시 발생 */ const GN_01_AIS = makeAis({ mmsi: 990005, lat: 35.20, lon: 124.80, sog: 1.0, cog: 180, name: 'MOCK VESSEL 5', shipImagePath: 'https://picsum.photos/seed/ship990005v1/800/600', shipImageCount: 1 }); const GN_02_AIS = makeAis({ mmsi: 990006, lat: 35.22, lon: 124.85, sog: 1.2, cog: 170, name: 'MOCK VESSEL 6' }); const GN_03_AIS = makeAis({ mmsi: 990007, lat: 35.18, lon: 124.82, sog: 0.8, cog: 200, name: 'MOCK VESSEL 7' }); const OT_01_AIS = makeAis({ mmsi: 990008, lat: 35.25, lon: 124.78, sog: 3.5, cog: 160, name: 'MOCK VESSEL 8', shipImagePath: 'https://picsum.photos/seed/ship990008v1/800/600', shipImageCount: 4 }); const GN_04_AIS = makeAis({ mmsi: 990011, lat: 35.00, lon: 125.20, sog: 1.5, cog: 190, name: 'MOCK VESSEL 10', messageTimestamp: STALE_TS, receivedDate: STALE_TS, }); const GN_01_LEG = makeLegacy({ permitNo: 'MOCK-P005', shipCode: 'GN', mmsiList: [990005], shipNameRoman: 'MOCK VESSEL 5', shipNameCn: '模拟渔船五号', ownerRoman: 'MOCK Owner C', ownerCn: '模拟C渔业', }); const GN_02_LEG = makeLegacy({ permitNo: 'MOCK-P006', shipCode: 'GN', mmsiList: [990006], shipNameRoman: 'MOCK VESSEL 6', shipNameCn: '模拟渔船六号', ownerRoman: 'MOCK Owner C', ownerCn: '模拟C渔业', }); const GN_03_LEG = makeLegacy({ permitNo: 'MOCK-P007', shipCode: 'GN', mmsiList: [990007], shipNameRoman: 'MOCK VESSEL 7', shipNameCn: '模拟渔船七号', ownerRoman: 'MOCK Owner C', ownerCn: '模拟C渔业', }); const OT_01_LEG = makeLegacy({ permitNo: 'MOCK-P008', shipCode: 'OT', mmsiList: [990008], shipNameRoman: 'MOCK VESSEL 8', shipNameCn: '模拟渔船八号', ownerRoman: 'MOCK Owner C', ownerCn: '模拟C渔业', }); const GN_04_LEG = makeLegacy({ permitNo: 'MOCK-P011', shipCode: 'GN', mmsiList: [990011], shipNameRoman: 'MOCK VESSEL 10', shipNameCn: '模拟渔船十号', ownerRoman: 'MOCK Owner C', ownerCn: '模拟C渔业', }); /* * Group 4 — 환적 의심 (FC ↔ PS 거리 ~0.15 NM → transshipment alarm) * 위치: 서해남부(zone 3) 125.5°E 34.3°N 부근 */ const FC_01_AIS = makeAis({ mmsi: 990009, lat: 34.30, lon: 125.50, sog: 1.0, cog: 0, name: 'MOCK CARRIER 1', shipImagePath: 'https://picsum.photos/seed/ship990009v1/800/600', shipImageCount: 2 }); const PS_01_AIS = makeAis({ mmsi: 990010, lat: 34.302, lon: 125.502, sog: 0.5, cog: 10, name: 'MOCK VESSEL 9' }); const FC_01_LEG = makeLegacy({ permitNo: 'MOCK-P009', shipCode: 'FC', mmsiList: [990009], shipNameRoman: 'MOCK CARRIER 1', shipNameCn: '模拟运船一号', ownerRoman: 'MOCK Owner D', ownerCn: '模拟D渔业', }); const PS_01_LEG = makeLegacy({ permitNo: 'MOCK-P010', shipCode: 'PS', mmsiList: [990010], shipNameRoman: 'MOCK VESSEL 9', shipNameCn: '模拟渔船九号', ownerRoman: 'MOCK Owner E', ownerCn: '模拟E渔业', }); /* * Group 5 — 수역 이탈 (PT가 zone 4 에 위치 → zone_violation alarm) * PT는 zone 2,3만 허가. zone 4(서해중간)에 위치하면 이탈 판정. * 위치: 서해중간(zone 4) 125.0°E 36.5°N 부근 */ const PT_05_AIS = makeAis({ mmsi: 990012, lat: 36.50, lon: 125.00, sog: 3.3, cog: 270, name: 'MOCK VESSEL 11', shipImagePath: 'https://picsum.photos/seed/ship990012v1/800/600', shipImageCount: 1 }); const PT_05_LEG = makeLegacy({ permitNo: 'MOCK-P012', shipCode: 'PT', mmsiList: [990012], shipNameRoman: 'MOCK VESSEL 11', shipNameCn: '模拟渔船十一号', ownerRoman: 'MOCK Owner F', ownerCn: '模拟F渔业', }); // ── 공개 API ──────────────────────────────────────────────── /** 더미 AIS 타겟 (12척) */ export const MOCK_AIS_TARGETS: AisTarget[] = [ PT_01_AIS, PT_02_AIS, // Group 1: 정상 쌍끌이 PT_03_AIS, PT_04_AIS, // Group 2: 이격 쌍끌이 GN_01_AIS, GN_02_AIS, GN_03_AIS, OT_01_AIS, GN_04_AIS, // Group 3: 선단 + AIS 지연 FC_01_AIS, PS_01_AIS, // Group 4: 환적 의심 PT_05_AIS, // Group 5: 수역 이탈 ]; /** 더미 legacy 매칭 엔트리 (MMSI → LegacyVesselInfo) */ export const MOCK_LEGACY_ENTRIES: [number, LegacyVesselInfo][] = [ [990001, PT_01_LEG], [990002, PT_02_LEG], [990003, PT_03_LEG], [990004, PT_04_LEG], [990005, GN_01_LEG], [990006, GN_02_LEG], [990007, GN_03_LEG], [990008, OT_01_LEG], [990009, FC_01_LEG], [990010, PS_01_LEG], [990011, GN_04_LEG], [990012, PT_05_LEG], ]; /** 더미 MMSI 집합 — 필터링/하이라이팅에 활용 */ export const MOCK_MMSI_SET = new Set(MOCK_AIS_TARGETS.map((t) => t.mmsi));