# 네이버 단축 URL 처리 아키텍처 설계

## 1. 개요

### 1.1 목적
네이버 단축 URL(naver.me)을 처리하여 식당 정보를 추출하고, 네이버 로컬 API를 통해 상세 정보를 보강하는 시스템을 설계합니다.

### 1.2 핵심 요구사항
- 네이버 단축 URL 리다이렉션 처리
- HTML 스크래핑을 통한 기본 정보 추출
- 네이버 로컬 API를 통한 상세 정보 검색
- 기존 Clean Architecture 패턴 유지
- 사이드이펙트 방지 및 테스트 가능성 확보

## 2. 아키텍처 구조

### 2.1 계층 구조
```
Presentation Layer
    ↓
Domain Layer (Use Cases)
    ↓
Data Layer
    ├── Repository Implementation
    ├── Data Sources
    │   ├── Remote
    │   │   ├── NaverMapParser (기존)
    │   │   ├── NaverLocalApiClient (신규)
    │   │   └── NaverUrlProcessor (신규)
    │   └── Local
    │       └── Hive Database
    └── Models/DTOs
```

### 2.2 주요 컴포넌트

#### 2.2.1 Data Layer - Remote Data Sources

**NaverUrlProcessor (신규)**
```dart
// lib/data/datasources/remote/naver_url_processor.dart
class NaverUrlProcessor {
  final NaverMapParser _mapParser;
  final NaverLocalApiClient _apiClient;
  
  // 단축 URL 처리 파이프라인
  Future<Restaurant> processNaverUrl(String url);
  
  // URL 유효성 검증
  bool isValidNaverUrl(String url);
  
  // 단축 URL → 실제 URL 변환
  Future<String> resolveShortUrl(String shortUrl);
}
```

**NaverLocalApiClient (신규)**
```dart
// lib/data/datasources/remote/naver_local_api_client.dart
class NaverLocalApiClient {
  final Dio _dio;
  
  // 네이버 로컬 API 검색
  Future<List<NaverLocalSearchResult>> searchLocal({
    required String query,
    String? category,
    int display = 5,
  });
  
  // 상세 정보 조회 (Place ID 기반)
  Future<NaverPlaceDetail?> getPlaceDetail(String placeId);
}
```

**NaverMapParser (기존 확장)**
- 기존 HTML 스크래핑 기능 유지
- 새로운 메서드 추가:
  - `extractSearchQuery()`: HTML에서 검색 가능한 키워드 추출
  - `extractPlaceMetadata()`: 메타 정보 추출 강화

#### 2.2.2 Data Layer - Models

**NaverLocalSearchResult (신규)**
```dart
// lib/data/models/naver_local_search_result.dart
class NaverLocalSearchResult {
  final String title;
  final String link;
  final String category;
  final String description;
  final String telephone;
  final String address;
  final String roadAddress;
  final int mapx;  // 경도 * 10,000,000
  final int mapy;  // 위도 * 10,000,000
}
```

**NaverPlaceDetail (신규)**
```dart
// lib/data/models/naver_place_detail.dart
class NaverPlaceDetail {
  final String id;
  final String name;
  final String category;
  final Map<String, dynamic> businessHours;
  final List<String> menuItems;
  final String? homePage;
  final List<String> images;
}
```

#### 2.2.3 Repository Layer

**RestaurantRepositoryImpl (확장)**
```dart
// 기존 메서드 확장
@override
Future<Restaurant> addRestaurantFromUrl(String url) async {
  try {
    // NaverUrlProcessor 사용
    final processor = NaverUrlProcessor(
      mapParser: _naverMapParser,
      apiClient: _naverLocalApiClient,
    );
    
    final restaurant = await processor.processNaverUrl(url);
    
    // 중복 체크 및 저장 로직 (기존 유지)
    // ...
  } catch (e) {
    // 에러 처리
  }
}
```

### 2.3 처리 흐름

```mermaid
sequenceDiagram
    participant User
    participant UI
    participant Repository
    participant UrlProcessor
    participant MapParser
    participant ApiClient
    participant Hive

    User->>UI: 네이버 단축 URL 입력
    UI->>Repository: addRestaurantFromUrl(url)
    Repository->>UrlProcessor: processNaverUrl(url)
    
    UrlProcessor->>UrlProcessor: isValidNaverUrl(url)
    UrlProcessor->>MapParser: resolveShortUrl(url)
    MapParser-->>UrlProcessor: 실제 URL
    
    UrlProcessor->>MapParser: parseRestaurantFromUrl(url)
    MapParser-->>UrlProcessor: 기본 정보 (HTML 스크래핑)
    
    UrlProcessor->>MapParser: extractSearchQuery()
    MapParser-->>UrlProcessor: 검색 키워드
    
    UrlProcessor->>ApiClient: searchLocal(query)
    ApiClient-->>UrlProcessor: 검색 결과 리스트
    
    UrlProcessor->>UrlProcessor: 매칭 및 병합
    UrlProcessor-->>Repository: 완성된 Restaurant 객체
    
    Repository->>Hive: 중복 체크
    Repository->>Hive: 저장
    Repository-->>UI: 결과 반환
    UI-->>User: 성공/실패 표시
```

## 3. 상세 설계

### 3.1 URL 처리 파이프라인

1. **URL 유효성 검증**
   - 네이버 도메인 확인 (naver.com, naver.me)
   - URL 형식 검증

2. **단축 URL 리다이렉션**
   - HTTP HEAD/GET 요청으로 실제 URL 획득
   - 웹 환경에서는 CORS 프록시 사용

3. **HTML 스크래핑 (기존 NaverMapParser)**
   - 기본 정보 추출: 이름, 주소, 카테고리
   - Place ID 추출 시도

4. **네이버 로컬 API 검색**
   - 추출된 이름과 주소로 검색
   - 결과 매칭 알고리즘 적용

5. **정보 병합**
   - HTML 스크래핑 데이터 + API 데이터 병합
   - 우선순위: API 데이터 > 스크래핑 데이터

### 3.2 에러 처리 전략

```dart
// 계층별 예외 정의
abstract class NaverException implements Exception {
  final String message;
  NaverException(this.message);
}

class NaverUrlException extends NaverException {
  NaverUrlException(String message) : super(message);
}

class NaverApiException extends NaverException {
  final int? statusCode;
  NaverApiException(String message, {this.statusCode}) : super(message);
}

class NaverParseException extends NaverException {
  NaverParseException(String message) : super(message);
}
```

### 3.3 매칭 알고리즘

```dart
class RestaurantMatcher {
  // 스크래핑 데이터와 API 결과 매칭
  static NaverLocalSearchResult? findBestMatch(
    Restaurant scrapedData,
    List<NaverLocalSearchResult> apiResults,
  ) {
    // 1. 이름 유사도 계산 (Levenshtein distance)
    // 2. 주소 유사도 계산
    // 3. 카테고리 일치 여부
    // 4. 거리 계산 (좌표 기반)
    // 5. 종합 점수로 최적 매칭 선택
  }
}
```

## 4. 테스트 전략

### 4.1 단위 테스트

```dart
// test/data/datasources/remote/naver_url_processor_test.dart
- URL 유효성 검증 테스트
- 단축 URL 리다이렉션 테스트
- 정보 병합 로직 테스트

// test/data/datasources/remote/naver_local_api_client_test.dart
- API 호출 성공/실패 테스트
- 응답 파싱 테스트
- 에러 처리 테스트
```

### 4.2 통합 테스트

```dart
// test/integration/naver_url_processing_test.dart
- 전체 파이프라인 테스트
- 실제 URL로 E2E 테스트
- 에러 시나리오 테스트
```

### 4.3 모킹 전략

```dart
// Mock 객체 사용
class MockNaverMapParser extends Mock implements NaverMapParser {}
class MockNaverLocalApiClient extends Mock implements NaverLocalApiClient {}
class MockHttpClient extends Mock implements Client {}
```

## 5. 설정 및 환경 변수

### 5.1 API 키 관리

```dart
// lib/core/constants/api_keys.dart
class ApiKeys {
  static const String _encodedClientId =
      String.fromEnvironment('NAVER_CLIENT_ID', defaultValue: '');
  static const String _encodedClientSecret =
      String.fromEnvironment('NAVER_CLIENT_SECRET', defaultValue: '');

  static String get naverClientId => _decode(_encodedClientId);
  static String get naverClientSecret => _decode(_encodedClientSecret);

  static bool areKeysConfigured() {
    return naverClientId.isNotEmpty && naverClientSecret.isNotEmpty;
  }

  static String _decode(String value) {
    if (value.isEmpty) return '';
    try {
      return utf8.decode(base64.decode(value));
    } on FormatException {
      return value;
    }
  }
}
```

### 5.2 환경별 설정

```dart
// lib/core/config/environment.dart
abstract class Environment {
  static const bool isProduction = bool.fromEnvironment('dart.vm.product');
  
  static String get corsProxyUrl {
    return isProduction
      ? 'https://api.allorigins.win/get?url='
      : 'http://localhost:8080/proxy?url=';
  }
}
```

## 6. 성능 최적화

### 6.1 캐싱 전략

```dart
class CacheManager {
  // URL 리다이렉션 캐시 (TTL: 1시간)
  final Map<String, CachedUrl> _urlCache = {};
  
  // API 검색 결과 캐시 (TTL: 30분)
  final Map<String, CachedSearchResult> _searchCache = {};
}
```

### 6.2 동시성 제어

```dart
class RateLimiter {
  // 네이버 API 호출 제한 (초당 10회)
  static const int maxRequestsPerSecond = 10;
  
  // 동시 요청 수 제한
  static const int maxConcurrentRequests = 3;
}
```

## 7. 보안 고려사항

### 7.1 API 키 보호
- 환경 변수 사용
- 클라이언트 사이드에서 직접 노출 방지
- ProGuard/R8 난독화 적용

### 7.2 입력 검증
- URL 인젝션 방지
- XSS 방지를 위한 HTML 이스케이핑
- SQL 인젝션 방지 (Hive는 NoSQL이므로 해당 없음)

## 8. 모니터링 및 로깅

### 8.1 로깅 전략

```dart
class NaverUrlLogger {
  static void logUrlProcessing(String url, ProcessingStep step, {dynamic data}) {
    // 구조화된 로그 기록
    // - 타임스탬프
    // - 처리 단계
    // - 성공/실패 여부
    // - 소요 시간
  }
}
```

### 8.2 에러 추적

```dart
class ErrorReporter {
  static void reportError(Exception error, StackTrace stackTrace, {
    Map<String, dynamic>? extra,
  }) {
    // Crashlytics 또는 Sentry로 에러 전송
  }
}
```

## 9. 향후 확장 고려사항

### 9.1 다른 플랫폼 지원
- 카카오맵 URL 처리
- 구글맵 URL 처리
- 배달앱 공유 링크 처리

### 9.2 기능 확장
- 메뉴 정보 수집
- 리뷰 데이터 수집
- 영업시간 실시간 업데이트

### 9.3 성능 개선
- 백그라운드 프리페칭
- 예측 기반 캐싱
- CDN 활용

## 10. 마이그레이션 계획

### 10.1 단계별 적용
1. NaverLocalApiClient 구현 및 테스트
2. NaverUrlProcessor 구현
3. 기존 addRestaurantFromUrl 메서드 리팩토링
4. UI 업데이트 (로딩 상태, 에러 처리)
5. 프로덕션 배포

### 10.2 하위 호환성
- 기존 NaverMapParser는 그대로 유지
- 새로운 기능은 옵트인 방식으로 제공
- 점진적 마이그레이션 지원
