Skip to content

ACN (자동 충돌 알림) API 코드랩

개요

이 코드랩은 자동 충돌 알림(ACN) API를 구현하는 방법을 안내합니다. 이 API는 차량 사고를 자동으로 감지하고 긴급 대응을 조정합니다. 긴급 상황 처리, 사고 데이터 관리, 구조 서비스 통합 방법을 배우게 됩니다.

사전 요구 사항

  • REST API에 대한 기본 이해
  • JavaScript/TypeScript 친숙도
  • Node.js와 npm 설치
  • 긴급 대응 워크플로 이해
  • 텍스트 에디터 또는 IDE

학습 목표

  • ACN 사고 감지 및 관리 구현
  • SSE를 통한 실시간 긴급 알림 처리
  • 에이전트 워크플로 및 사고 할당 관리
  • 사고 데이터 처리 및 구조 서비스 조정
  • 긴급 대응 모범 사례 구현

설정

1. 프로젝트 초기화

bash
mkdir acn-api-demo
cd acn-api-demo
npm init -y
npm install axios node-fetch moment

2. 구성

config.js 파일을 생성하세요:

javascript
export const API_CONFIG = {
  baseURL: 'https://api.ecarus.run/api/v1/safety',
  authToken: 'sk_4f9c7b8e2d1a6c0f3e7a9b5d8c1e4f2a7c6d9e0b3f5a8c1d4e7f9b2c6a1e3d',
  sampleVIN: 'KMHSH81C7LU123456',
  sampleAgentId: 'AGENT_001',
  timeout: 10000 // 긴급 서비스용 10초
};

단계 1: ACN 시스템 상태 및 모니터링

시스템 건강 모니터링 구현

acnSystem.js를 생성하세요:

javascript
import axios from 'axios';
import { API_CONFIG } from './config.js';

class ACNSystem {
  constructor() {
    this.client = axios.create({
      baseURL: API_CONFIG.baseURL,
      headers: {
        'Authorization': `Bearer ${API_CONFIG.authToken}`,
        'Content-Type': 'application/json'
      },
      timeout: API_CONFIG.timeout
    });
  }

  async getSystemHealth() {
    try {
      const response = await this.client.get('/acn/system/health');
      console.log('ACN 시스템 건강:', response.data);
      return response.data;
    } catch (error) {
      console.error('시스템 건강 가져오기 실패:', error.response?.data || error.message);
      throw error;
    }
  }

  async getStatistics() {
    try {
      const response = await this.client.get('/acn/stats');
      console.log('ACN 통계:', response.data);
      return response.data;
    } catch (error) {
      console.error('ACN 통계 가져오기 실패:', error.response?.data || error.message);
      throw error;
    }
  }

  isSystemHealthy(healthData) {
    return healthData.status === 'HEALTHY' && 
           Object.values(healthData.services).every(service => service === 'ACTIVE');
  }

  getServiceStatus(healthData) {
    return {
      overall: healthData.status,
      services: healthData.services,
      metrics: healthData.metrics,
      isHealthy: this.isSystemHealthy(healthData)
    };
  }
}

export default ACNSystem;

시스템 모니터링 테스트

test-system.js를 생성하세요:

javascript
import ACNSystem from './acnSystem.js';

const acnSystem = new ACNSystem();

async function testSystemMonitoring() {
  try {
    console.log('🏥 ACN 시스템 모니터링 테스트 중...');
    
    // 시스템 건강 확인
    const health = await acnSystem.getSystemHealth();
    const status = acnSystem.getServiceStatus(health);
    
    console.log('📊 시스템 상태:', status);
    
    if (status.isHealthy) {
      console.log('✅ ACN 시스템이 완전히 운영 중입니다');
    } else {
      console.log('⚠️ ACN 시스템에 주의가 필요한 문제가 있습니다');
    }
    
    // 통계 가져오기
    const stats = await acnSystem.getStatistics();
    console.log('📈 ACN 통계:', stats);
    
  } catch (error) {
    console.error('❌ 시스템 모니터링 테스트 실패:', error.message);
  }
}

testSystemMonitoring();

단계 2: 사고 관리

사고 제어 구현

incidentManager.js를 생성하세요:

javascript
import axios from 'axios';
import { API_CONFIG } from './config.js';

class IncidentManager {
  constructor() {
    this.client = axios.create({
      baseURL: API_CONFIG.baseURL,
      headers: {
        'Authorization': `Bearer ${API_CONFIG.authToken}`,
        'Content-Type': 'application/json'
      },
      timeout: API_CONFIG.timeout
    });
  }

  async getIncidentStatus(vin, cid) {
    try {
      const response = await this.client.get(
        `/vehicles/${vin}/acn/status`,
        { params: { cid } }
      );

      console.log('사고 상태:', response.data);
      return response.data;
    } catch (error) {
      console.error('사고 상태 가져오기 실패:', error.response?.data || error.message);
      throw error;
    }
  }

  async getIncidentHistory(vin, options = {}) {
    try {
      const params = {
        limit: options.limit || 50,
        offset: options.offset || 0,
        startDate: options.startDate,
        endDate: options.endDate
      };

      const response = await this.client.get(
        `/vehicles/${vin}/acn/history`,
        { params }
      );

      console.log('사고 기록:', response.data);
      return response.data;
    } catch (error) {
      console.error('사고 기록 가져오기 실패:', error.response?.data || error.message);
      throw error;
    }
  }

  async closeIncident(vin, incidentData) {
    try {
      const payload = {
        cid: incidentData.cid,
        closureReason: incidentData.closureReason || 'EMERGENCY_SERVICES_DISPATCHED',
        result: incidentData.result || 'SUCCESS',
        agentId: incidentData.agentId || API_CONFIG.sampleAgentId,
        notes: incidentData.notes || ''
      };

      const response = await this.client.post(
        `/vehicles/${vin}/acn/close`,
        payload
      );

      console.log('사고 종료:', response.data);
      return response.data;
    } catch (error) {
      console.error('사고 종료 실패:', error.response?.data || error.message);
      throw error;
    }
  }

  formatIncidentLocation(location) {
    return {
      latitude: location.latitude,
      longitude: location.longitude,
      accuracy: location.accuracy || 'Unknown',
      formatted: `${location.latitude.toFixed(4)}, ${location.longitude.toFixed(4)}`
    };
  }

  assessIncidentSeverity(severity, trigger) {
    const severityLevels = {
      'LOW': { priority: 3, responseTime: '15 min', color: '🟡' },
      'MEDIUM': { priority: 2, responseTime: '10 min', color: '🟠' },
      'HIGH': { priority: 1, responseTime: '5 min', color: '🔴' },
      'CRITICAL': { priority: 0, responseTime: 'Immediate', color: '🚨' }
    };

    const triggerSeverity = {
      'AIRBAG_DEPLOYMENT': 'HIGH',
      'ROLLOVER_DETECTED': 'CRITICAL',
      'IMPACT_DETECTED': 'MEDIUM',
      'MANUAL_SOS': 'HIGH',
      'SOS_BUTTON': 'HIGH'
    };

    const assessedSeverity = severity || triggerSeverity[trigger] || 'MEDIUM';
    return severityLevels[assessedSeverity] || severityLevels['MEDIUM'];
  }
}

export default IncidentManager;

사고 관리 테스트

test-incident.js를 생성하세요:

javascript
import IncidentManager from './incidentManager.js';
import { API_CONFIG } from './config.js';

const incidentManager = new IncidentManager();

async function testIncidentManagement() {
  const vin = API_CONFIG.sampleVIN;
  const testCid = 'ACN_20260307_001';

  try {
    console.log('🚨 사고 관리 테스트 중...');
    
    // 사고 상태 가져오기
    const status = await incidentManager.getIncidentStatus(vin, testCid);
    const severity = incidentManager.assessIncidentSeverity(status.severity, status.trigger);
    
    console.log('📊 사고 평가:', {
      cid: status.cid,
      severity: severity,
      location: incidentManager.formatIncidentLocation(status.location),
      rescueStatus: status.rescueStatus
    });
    
    // 사고 기록 가져오기
    const history = await incidentManager.getIncidentHistory(vin, { limit: 10 });
    console.log('📜 사고 기록:', history.incidents.length, '건의 사고 발견');
    
    // 활성 상태인 경우 사고 종료
    if (status.status === 'ACTIVE') {
      console.log('🔒 사고 종료 중...');
      await incidentManager.closeIncident(vin, {
        cid: testCid,
        closureReason: 'EMERGENCY_SERVICES_DISPATCHED',
        result: 'SUCCESS',
        notes: '테스트 사고 종료'
      });
    }
    
  } catch (error) {
    console.error('❌ 사고 관리 테스트 실패:', error.message);
  }
}

testIncidentManagement();

단계 3: 에이전트 워크플로 관리

에이전트 관리 구현

agentManager.js를 생성하세요:

javascript
import axios from 'axios';
import { API_CONFIG } from './config.js';

class AgentManager {
  constructor() {
    this.client = axios.create({
      baseURL: API_CONFIG.baseURL,
      headers: {
        'Authorization': `Bearer ${API_CONFIG.authToken}`,
        'Content-Type': 'application/json'
      },
      timeout: API_CONFIG.timeout
    });
  }

  async getAgentStatus(agentId) {
    try {
      const response = await this.client.get(`/acn/agents/${agentId}/status`);
      console.log('에이전트 상태:', response.data);
      return response.data;
    } catch (error) {
      console.error('에이전트 상태 가져오기 실패:', error.response?.data || error.message);
      throw error;
    }
  }

  async getAgentIncidents(agentId, options = {}) {
    try {
      const params = {
        status: options.status,
        limit: options.limit || 50,
        offset: options.offset || 0
      };

      const response = await this.client.get(
        `/acn/agents/${agentId}/incidents`,
        { params }
      );

      console.log('에이전트 사고:', response.data);
      return response.data;
    } catch (error) {
      console.error('에이전트 사고 가져오기 실패:', error.response?.data || error.message);
      throw error;
    }
  }

  calculateAgentWorkload(agentStatus, agentIncidents) {
    const workload = {
      currentIncidents: agentStatus.currentIncidents,
      totalHandled: agentStatus.totalHandled,
      averageHandlingTime: agentStatus.averageHandlingTime,
      isActive: agentStatus.status === 'ACTIVE',
      capacity: this.calculateCapacity(agentStatus),
      efficiency: this.calculateEfficiency(agentStatus, agentIncidents)
    };

    return workload;
  }

  calculateCapacity(agentStatus) {
    // 현재 사고와 평균 처리 시간을 기반으로 한 간단한 용량 계산
    const maxConcurrentIncidents = 3;
    const currentLoad = agentStatus.currentIncidents / maxConcurrentIncidents;
    
    if (currentLoad >= 1) return 'FULL';
    if (currentLoad >= 0.7) return 'HIGH';
    if (currentLoad >= 0.4) return 'MEDIUM';
    return 'LOW';
  }

  calculateEfficiency(agentStatus, agentIncidents) {
    // 처리 시간과 성공률을 기반으로 효율성 계산
    const avgTime = parseFloat(agentStatus.averageHandlingTime);
    const targetTime = 10; // 10분 목표
    
    const timeEfficiency = Math.max(0, Math.min(100, (targetTime / avgTime) * 100));
    
    return {
      timeEfficiency: timeEfficiency.toFixed(1),
      grade: timeEfficiency >= 90 ? 'A' : timeEfficiency >= 75 ? 'B' : timeEfficiency >= 60 ? 'C' : 'D'
    };
  }

  async assignIncidentToAgent(agentId, incidentId) {
    try {
      // 일반적으로 내부 API 호출
      // 데모 목적으로 할당 시뮬레이션
      console.log(`사고 ${incidentId}을(를) 에이전트 ${agentId}에게 할당`);
      
      const assignment = {
        agentId,
        incidentId,
        assignedTime: new Date().toISOString(),
        status: 'ASSIGNED'
      };

      console.log('사고 할당됨:', assignment);
      return assignment;
    } catch (error) {
      console.error('에이전트에게 사고 할당 실패:', error.message);
      throw error;
    }
  }
}

export default AgentManager;

에이전트 관리 테스트

test-agent.js를 생성하세요:

javascript
import AgentManager from './agentManager.js';
import { API_CONFIG } from './config.js';

const agentManager = new AgentManager();

async function testAgentManagement() {
  const agentId = API_CONFIG.sampleAgentId;

  try {
    console.log('👮 에이전트 관리 테스트 중...');
    
    // 에이전트 상태 가져오기
    const status = await agentManager.getAgentStatus(agentId);
    
    // 에이전트 사고 가져오기
    const incidents = await agentManager.getAgentIncidents(agentId);
    
    // 워크로드 계산
    const workload = agentManager.calculateAgentWorkload(status, incidents);
    
    console.log('📊 에이전트 워크로드 분석:', {
      agentId: status.agentId,
      status: status.status,
      currentIncidents: workload.currentIncidents,
      capacity: workload.capacity,
      efficiency: workload.efficiency,
      totalHandled: workload.totalHandled
    });
    
    // 워크로드가 FULL이 아니고 활성 사고가 3개 미만인 경우 사고 할당 시뮬레이션
    if (workload.capacity !== 'FULL' && incidents.activeCount < 3) {
      await agentManager.assignIncidentToAgent(agentId, 'ACN_TEST_001');
    }
    
  } catch (error) {
    console.error('❌ 에이전트 관리 테스트 실패:', error.message);
  }
}

testAgentManagement();

단계 4: 실시간 긴급 알림

ACN용 SSE 클라이언트 구현

acnSSEClient.js를 생성하세요:

javascript
export class ACNSSEClient {
  constructor(url, authToken) {
    this.url = url;
    this.authToken = authToken;
    this.eventSource = null;
    this.listeners = new Map();
    this.incidentHandlers = new Map();
  }

  connect() {
    return new Promise((resolve, reject) => {
      try {
        this.eventSource = new EventSource(this.url, {
          headers: {
            'Authorization': `Bearer ${this.authToken}`
          }
        });

        this.eventSource.onopen = () => {
          console.log('🚨 ACN SSE 연결 열림');
          resolve();
        };

        this.eventSource.onerror = (error) => {
          console.error('ACN SSE 연결 오류:', error);
          if (this.eventSource.readyState === EventSource.CLOSED) {
            reject(new Error('ACN SSE 연결 닫힘'));
          }
        };

        this.eventSource.onmessage = (event) => {
          try {
            const data = JSON.parse(event.data);
            this.handleEvent(data);
          } catch (error) {
            console.error('ACN SSE 데이터 파싱 실패:', error);
          }
        };

      } catch (error) {
        reject(error);
      }
    });
  }

  on(eventType, callback) {
    if (!this.listeners.has(eventType)) {
      this.listeners.set(eventType, []);
    }
    this.listeners.get(eventType).push(callback);
  }

  handleEvent(data) {
    const eventType = data.type || 'default';
    const callbacks = this.listeners.get(eventType) || [];
    
    callbacks.forEach(callback => {
      try {
        callback(data);
      } catch (error) {
        console.error('ACN 이벤트 콜백에서 오류:', error);
      }
    });

    // 특정 사고 이벤트 처리
    if (eventType === 'INCIDENT_CREATED') {
      this.handleIncidentCreated(data);
    } else if (eventType === 'INCIDENT_UPDATED') {
      this.handleIncidentUpdated(data);
    }
  }

  handleIncidentCreated(data) {
    console.log('🚨 새로운 사고 생성됨:', data.data.cid);
    
    const incident = data.data;
    const severity = this.assessIncidentSeverity(incident.severity, incident.trigger);
    
    console.log(`📍 위치: ${incident.location.latitude}, ${incident.location.longitude}`);
    console.log(`🔥 심각도: ${severity.color} ${incident.severity}`);
    console.log(`⚡ 트리거: ${incident.trigger}`);
    
    // 긴급 대응 워크플로 트리거
    this.triggerEmergencyWorkflow(incident);
  }

  handleIncidentUpdated(data) {
    console.log('📝 사고 업데이트됨:', data.data.cid);
    console.log('상태:', data.data.status);
  }

  assessIncidentSeverity(severity, trigger) {
    const severityLevels = {
      'LOW': { priority: 3, responseTime: '15 min', color: '🟡' },
      'MEDIUM': { priority: 2, responseTime: '10 min', color: '🟠' },
      'HIGH': { priority: 1, responseTime: '5 min', color: '🔴' },
      'CRITICAL': { priority: 0, responseTime: 'Immediate', color: '🚨' }
    };

    const triggerSeverity = {
      'AIRBAG_DEPLOYMENT': 'HIGH',
      'ROLLOVER_DETECTED': 'CRITICAL',
      'IMPACT_DETECTED': 'MEDIUM',
      'MANUAL_SOS': 'HIGH',
      'SOS_BUTTON': 'HIGH'
    };

    const assessedSeverity = severity || triggerSeverity[trigger] || 'MEDIUM';
    return severityLevels[assessedSeverity] || severityLevels['MEDIUM'];
  }

  triggerEmergencyWorkflow(incident) {
    console.log('🚑 긴급 대응 워크플로 트리거 중...');
    
    // 긴급 대응 단계 시뮬레이션
    const workflow = [
      { step: 1, action: '사고 세부 정보 확인', delay: 1000 },
      { step: 2, action: '긴급 서비스에 연락', delay: 2000 },
      { step: 3, action: '구조 팀 파견', delay: 1500 },
      { step: 4, action: '사고 상태 업데이트', delay: 1000 }
    ];

    workflow.forEach(({ step, action, delay }) => {
      setTimeout(() => {
        console.log(`  단계 ${step}: ${action}`);
      }, delay);
    });
  }

  disconnect() {
    if (this.eventSource) {
      this.eventSource.close();
      this.eventSource = null;
      console.log('ACN SSE 연결 닫힘');
    }
  }
}

실시간 알림 테스트

test-sse.js를 생성하세요:

javascript
import { ACNSSEClient } from './acnSSEClient.js';
import { API_CONFIG } from './config.js';

async function testRealTimeNotifications() {
  const sseUrl = `${API_CONFIG.baseURL}/acn/events`;
  
  const sseClient = new ACNSSEClient(sseUrl, API_CONFIG.authToken);

  try {
    await sseClient.connect();

    // 사고 이벤트 수신
    sseClient.on('INCIDENT_CREATED', (data) => {
      console.log('🚨 새로운 사고 감지:', data.data);
    });

    sseClient.on('INCIDENT_UPDATED', (data) => {
      console.log('📝 사고 업데이트:', data.data);
    });

    sseClient.on('RESCUE_DISPATCHED', (data) => {
      console.log('🚑 구조 파견됨:', data.data);
    });

    console.log('👂 ACN 이벤트 수신 중... 중지하려면 Ctrl+C를 누르세요');

    // 연결 유지
    process.on('SIGINT', () => {
      console.log('\n연결 해제 중...');
      sseClient.disconnect();
      process.exit(0);
    });

  } catch (error) {
    console.error('ACN SSE 연결 실패:', error.message);
  }
}

testRealTimeNotifications();

단계 5: 긴급 대응 조정

긴급 대응 시스템 구현

emergencyResponse.js를 생성하세요:

javascript
import IncidentManager from './incidentManager.js';
import AgentManager from './agentManager.js';

class EmergencyResponseSystem {
  constructor() {
    this.incidentManager = new IncidentManager();
    this.agentManager = new AgentManager();
    this.activeIncidents = new Map();
    this.agentAssignments = new Map();
  }

  async handleNewIncident(incidentData) {
    try {
      console.log('🚨 새로운 사고 처리 중:', incidentData.cid);
      
      // 사고 심각도 평가
      const severity = this.incidentManager.assessIncidentSeverity(
        incidentData.severity, 
        incidentData.trigger
      );
      
      // 사용 가능한 에이전트 찾기
      const agentId = await this.findAvailableAgent(severity.priority);
      
      if (agentId) {
        // 사고를 에이전트에게 할당
        await this.assignIncidentToAgent(incidentData.cid, agentId);
        
        // 긴급 서비스 조정
        await this.coordinateEmergencyServices(incidentData, severity);
        
        // 사고 추적
        this.activeIncidents.set(incidentData.cid, {
          ...incidentData,
          assignedAgent: agentId,
          severity,
          status: 'ASSIGNED',
          timestamp: new Date().toISOString()
        });
        
        console.log(`✅ 사고 ${incidentData.cid}이(가) 에이전트 ${agentId}에게 할당됨`);
      } else {
        console.log(`⚠️ 사고 ${incidentData.cid}에 사용 가능한 에이전트가 없습니다`);
        await this.queueIncident(incidentData);
      }
      
    } catch (error) {
      console.error('새로운 사고 처리 실패:', error.message);
    }
  }

  async findAvailableAgent(priority) {
    try {
      // 데모용으로 단순화된 사용 가능한 에이전트 목록
      const agents = [API_CONFIG.sampleAgentId];
      
      for (const agentId of agents) {
        const status = await this.agentManager.getAgentStatus(agentId);
        const incidents = await this.agentManager.getAgentIncidents(agentId);
        const workload = this.agentManager.calculateAgentWorkload(status, incidents);
        
        if (workload.isActive && workload.capacity !== 'FULL') {
          return agentId;
        }
      }
      
      return null;
    } catch (error) {
      console.error('사용 가능한 에이전트 찾기 실패:', error.message);
      return null;
    }
  }

  async assignIncidentToAgent(incidentId, agentId) {
    try {
      await this.agentManager.assignIncidentToAgent(agentId, incidentId);
      this.agentAssignments.set(agentId, (this.agentAssignments.get(agentId) || 0) + 1);
    } catch (error) {
      console.error('에이전트에게 사고 할당 실패:', error.message);
    }
  }

  async coordinateEmergencyServices(incidentData, severity) {
    console.log('🚑 긴급 서비스 조정 중...');
    
    const emergencySteps = [
      { service: '경찰', priority: severity.priority <= 1 },
      { service: '소방서', priority: severity.priority <= 2 },
      { service: '의료 서비스', priority: true },
      { service: '견인 서비스', priority: severity.priority <= 2 }
    ];

    for (const { service, priority } of emergencySteps) {
      if (priority) {
        console.log(`📞 사고 ${incidentData.cid}에 ${service}에 연락 중`);
        
        // 서비스 파견 시뮬레이션
        setTimeout(() => {
          console.log(`✅ ${service}이(가) 위치: ${incidentData.location.latitude}, ${incidentData.location.longitude}로 파견됨`);
        }, Math.random() * 2000 + 1000);
      }
    }
  }

  async queueIncident(incidentData) {
    console.log(`📋 사고 ${incidentData.cid}을(를) 나중 할당을 위해 대기열에 추가`);
    // 구현 시 우선순위 큐에 추가
  }

  async updateIncidentStatus(incidentId, newStatus, details = {}) {
    try {
      const incident = this.activeIncidents.get(incidentId);
      if (incident) {
        incident.status = newStatus;
        incident.lastUpdate = new Date().toISOString();
        incident.updateDetails = details;
        
        console.log(`📝 사고 ${incidentId} 상태를 ${newStatus}로 업데이트함`);
        
        if (newStatus === 'RESOLVED') {
          await this.closeIncident(incidentId);
        }
      }
    } catch (error) {
      console.error('사고 상태 업데이트 실패:', error.message);
    }
  }

  async closeIncident(incidentId) {
    try {
      const incident = this.activeIncidents.get(incidentId);
      if (incident) {
        await this.incidentManager.closeIncident(incident.vin, {
          cid: incidentId,
          closureReason: 'EMERGENCY_SERVICES_COMPLETED',
          result: 'SUCCESS',
          agentId: incident.assignedAgent,
          notes: '긴급 대응이 성공적으로 완료되었습니다'
        });
        
        // 추적 정리
        this.activeIncidents.delete(incidentId);
        
        if (incident.assignedAgent) {
          const currentCount = this.agentAssignments.get(incident.assignedAgent) || 0;
          this.agentAssignments.set(incident.assignedAgent, Math.max(0, currentCount - 1));
        }
        
        console.log(`✅ 사고 ${incidentId}이(가) 성공적으로 종료됨`);
      }
    } catch (error) {
      console.error('사고 종료 실패:', error.message);
    }
  }

  getActiveIncidents() {
    return Array.from(this.activeIncidents.values());
  }

  getAgentWorkload() {
    const workload = {};
    for (const [agentId, count] of this.agentAssignments) {
      workload[agentId] = count;
    }
    return workload;
  }
}

export default EmergencyResponseSystem;

단계 6: 완전한 ACN 애플리케이션

완전한 ACN 시스템 생성

acnApp.js를 생성하세요:

javascript
import ACNSystem from './acnSystem.js';
import IncidentManager from './incidentManager.js';
import AgentManager from './agentManager.js';
import { ACNSSEClient } from './acnSSEClient.js';
import EmergencyResponseSystem from './emergencyResponse.js';
import { API_CONFIG } from './config.js';

class ACNApplication {
  constructor() {
    this.acnSystem = new ACNSystem();
    this.incidentManager = new IncidentManager();
    this.agentManager = new AgentManager();
    this.emergencySystem = new EmergencyResponseSystem();
    this.sseClient = null;
  }

  async initialize() {
    try {
      console.log('🚨 ACN 애플리케이션 초기화 중...');
      
      // 시스템 건강 확인
      await this.checkSystemHealth();
      
      // 실시간 이벤트 연결
      await this.connectRealTimeEvents();
      
      // 에이전트 모니터링 초기화
      await this.initializeAgentMonitoring();
      
      console.log('✅ ACN 애플리케이션이 성공적으로 초기화됨');
    } catch (error) {
      console.error('❌ ACN 애플리케이션 초기화 실패:', error.message);
    }
  }

  async checkSystemHealth() {
    console.log('🏥 ACN 시스템 건강 확인 중...');
    
    const health = await this.acnSystem.getSystemHealth();
    const status = this.acnSystem.getServiceStatus(health);
    
    if (status.isHealthy) {
      console.log('✅ ACN 시스템이 운영 중입니다');
    } else {
      console.log('⚠️ ACN 시스템에 문제가 있습니다:');
      Object.entries(status.services).forEach(([service, serviceStatus]) => {
        if (serviceStatus !== 'ACTIVE') {
          console.log(`  - ${service}: ${serviceStatus}`);
        }
      });
    }
    
    const stats = await this.acnSystem.getStatistics();
    console.log('📊 현재 통계:', stats);
  }

  async connectRealTimeEvents() {
    console.log('👂 실시간 이벤트 연결 중...');
    
    const sseUrl = `${API_CONFIG.baseURL}/acn/events`;
    this.sseClient = new ACNSSEClient(sseUrl, API_CONFIG.authToken);
    
    await this.sseClient.connect();
    
    this.sseClient.on('INCIDENT_CREATED', (data) => {
      this.handleNewIncident(data.data);
    });
    
    this.sseClient.on('INCIDENT_UPDATED', (data) => {
      this.handleIncidentUpdate(data.data);
    });
  }

  async initializeAgentMonitoring() {
    console.log('👮 에이전트 모니터링 초기화 중...');
    
    const agentId = API_CONFIG.sampleAgentId;
    const status = await this.agentManager.getAgentStatus(agentId);
    const incidents = await this.agentManager.getAgentIncidents(agentId);
    const workload = this.agentManager.calculateAgentWorkload(status, incidents);
    
    console.log('📊 에이전트 상태:', {
      agentId: status.agentId,
      status: status.status,
      currentIncidents: workload.currentIncidents,
      capacity: workload.capacity,
      efficiency: workload.efficiency
    });
  }

  async handleNewIncident(incidentData) {
    console.log('🚨 새로운 사고 처리 중:', incidentData.cid);
    
    try {
      // 자세한 사고 정보 가져오기
      const vin = incidentData.vin || API_CONFIG.sampleVIN;
      const incidentStatus = await this.incidentManager.getIncidentStatus(vin, incidentData.cid);
      
      // 긴급 대응 시스템을 통해 처리
      await this.emergencySystem.handleNewIncident(incidentStatus);
      
      // 사고 요약 표시
      this.displayIncidentSummary(incidentStatus);
      
    } catch (error) {
      console.error('새로운 사고 처리 실패:', error.message);
    }
  }

  async handleIncidentUpdate(incidentData) {
    console.log('📝 사고 업데이트 처리 중:', incidentData.cid);
    
    await this.emergencySystem.updateIncidentStatus(
      incidentData.cid,
      incidentData.status,
      incidentData
    );
  }

  displayIncidentSummary(incident) {
    const severity = this.incidentManager.assessIncidentSeverity(incident.severity, incident.trigger);
    const location = this.incidentManager.formatIncidentLocation(incident.location);
    
    console.log('\n🚨 사고 요약');
    console.log('==================');
    console.log(`🆔 ID: ${incident.cid}`);
    console.log(`🚗 차량: ${incident.vin}`);
    console.log(`🔥 심각도: ${severity.color} ${incident.severity}`);
    console.log(`⚡ 트리거: ${incident.trigger}`);
    console.log(`📍 위치: ${location.formatted}`);
    console.log(`🚑 구조 상태: ${incident.rescueStatus}`);
    console.log(`⏰ 시간: ${incident.timestamp}`);
    
    if (incident.estimatedArrival) {
      console.log(`🕐 ETA: ${incident.estimatedArrival}`);
    }
    
    console.log('==================\n');
  }

  async getSystemStatus() {
    console.log('\n📊 ACN 시스템 상태');
    console.log('==================');
    
    const activeIncidents = this.emergencySystem.getActiveIncidents();
    const agentWorkload = this.emergencySystem.getAgentWorkload();
    
    console.log(`🚨 활성 사고: ${activeIncidents.length}`);
    console.log(`👮 에이전트 워크로드:`, agentWorkload);
    
    activeIncidents.forEach(incident => {
      console.log(`  - ${incident.cid}: ${incident.status} (에이전트: ${incident.assignedAgent})`);
    });
    
    console.log('==================\n');
  }

  async shutdown() {
    console.log('🔄 ACN 애플리케이션 종료 중...');
    
    if (this.sseClient) {
      this.sseClient.disconnect();
    }
    
    console.log('✅ ACN 애플리케이션 종료 완료');
  }
}

// 사용 예제
async function main() {
  const app = new ACNApplication();
  
  try {
    await app.initialize();
    
    // 시스템 상태를 주기적으로 표시
    setInterval(async () => {
      await app.getSystemStatus();
    }, 30000); // 30초마다
    
    // 정상 종료 처리
    process.on('SIGINT', async () => {
      console.log('\n🔄 SIGINT 수신, 정상 종료 중...');
      await app.shutdown();
      process.exit(0);
    });
    
    console.log('🚨 ACN 애플리케이션이 실행 중입니다... 중지하려면 Ctrl+C를 누르세요');
    
  } catch (error) {
    console.error('애플리케이션 오류:', error.message);
    process.exit(1);
  }
}

main();

구현 테스트

완전한 ACN 애플리케이션을 실행하세요:

bash
node acnApp.js

예상 출력:

🚨 ACN 애플리케이션 초기화 중...
🏥 ACN 시스템 건강 확인 중...
✅ ACN 시스템이 운영 중입니다
📊 현재 통계: { totalIncidents: 1250, activeIncidents: 3, resolvedToday: 8, averageResponseTime: "4.5 min", successRate: 98.2 }
👂 실시간 이벤트 연결 중...
🚨 ACN SSE 연결 열림
👮 에이전트 모니터링 초기화 중...
📊 에이전트 상태: { agentId: "AGENT_001", status: "ACTIVE", currentIncidents: 2, capacity: "MEDIUM", efficiency: { timeEfficiency: "85.0", grade: "B" } }
✅ ACN 애플리케이션이 성공적으로 초기화됨
🚨 ACN 애플리케이션이 실행 중입니다... 중지하려면 Ctrl+C를 누르세요

🚨 새로운 사고 생성됨: ACN_20260307_002
📍 위치: 37.4021, 127.1023
🔥 심각도: 🔴 HIGH
⚡ 트리거: AIRBAG_DEPLOYMENT
🚑 긴급 대응 워크플로 트리거 중...
  단계 1: 사고 세부 정보 확인
  단계 2: 긴급 서비스에 연락
  단계 3: 구조 팀 파견
  단계 4: 사고 상태 업데이트
✅ 사고 ACN_20260307_002이(가) 에이전트 AGENT_001에게 할당됨

🚨 사고 요약
==================
🆔 ID: ACN_20260307_002
🚗 차량: KMHSH81C7LU123456
🔥 심각도: 🔴 HIGH
⚡ 트리거: AIRBAG_DEPLOYMENT
📍 위치: 37.4021, 127.1023
🚑 구조 상태: DISPATCHED
⏰ 시간: 2026-03-07T14:30:00Z
🕐 ETA: 2026-03-07T14:45:00Z
==================

챌린지 연습

  1. 다중 기관 조정: 서로 다른 응답 프로토콜을 가진 여러 긴급 기관 간 조정을 구현하세요.

  2. 예측 분석: 차량 텔레메트리 데이터를 기반으로 사고 심각도를 예측하는 예측 분석을 추가하세요.

  3. 모바일 통합: 사용자가 수동으로 SOS를 트리거하고 업데이트를 받을 수 있는 모바일 앱 인터페이스를 생성하세요.

  4. 사고 보고: 보험 및 법적 목적을 위한 상세한 사고 보고서를 생성하세요.

  5. 지리공간 분석: 사고 핫스팟을 식별하고 구조 자원 배치를 최적화하는 지리공간 분석을 구현하세요.

요약

이 코드랩에서 다음을 배웠습니다:

  • ✅ ACN 사고 감지 및 관리 구현
  • ✅ SSE를 통한 실시간 긴급 알림 처리
  • ✅ 에이전트 워크플로 및 사고 할당 관리
  • ✅ 긴급 대응 서비스 조정
  • ✅ 완전한 긴급 대응 시스템 구축

ACN API는 차량 사고를 처리하고 긴급 대응을 조정하는 중요한 인프라를 제공합니다. 여기서 배운 구현 패턴은 신뢰성, 실시간 처리, 생명을 구하는 조정을 강조합니다.

추가 리소스

Released under the MIT License.