# 기술 스택 결정 문서

## 1. 개요

이 문서는 "오늘 뭐 먹Z?" 앱의 네이버 단축 URL 처리 기능 확장을 위한 기술 스택 선택 근거와 결정 사항을 설명합니다.

## 2. 현재 기술 스택 분석

### 2.1 기존 스택
- **상태 관리**: Riverpod 2.4.0
- **로컬 저장소**: Hive 2.2.3
- **네트워킹**: Dio 5.4.0, HTTP 1.1.0
- **HTML 파싱**: html 0.15.4
- **아키텍처**: Clean Architecture

### 2.2 강점 분석
- Riverpod의 강력한 의존성 주입과 상태 관리
- Hive의 빠른 성능과 간단한 사용법
- Clean Architecture로 인한 명확한 책임 분리

## 3. 네이버 URL 처리를 위한 기술 선택

### 3.1 HTTP 클라이언트

#### 선택: Dio + HTTP (하이브리드 접근)

**근거:**
- **Dio**: 인터셉터, 타임아웃, 재시도 등 고급 기능 필요한 API 호출용
- **HTTP**: 단순한 리다이렉션 처리와 기존 NaverMapParser 호환성

**구현 전략:**
```dart
// API 호출용 (Dio)
class NaverLocalApiClient {
  final Dio _dio = Dio(BaseOptions(
    connectTimeout: const Duration(seconds: 10),
    receiveTimeout: const Duration(seconds: 10),
  ))..interceptors.addAll([
    LogInterceptor(),
    RetryInterceptor(),
  ]);
}

// 단순 요청용 (HTTP)
class NaverUrlResolver {
  final http.Client _client;
}
```

### 3.2 HTML 파싱

#### 선택: html 패키지 유지

**근거:**
- 이미 프로젝트에서 사용 중
- DOM 기반 파싱으로 안정적
- 네이버 지도 페이지 구조에 적합

**대안 검토:**
- ❌ BeautifulSoup (Python 전용)
- ❌ web_scraper (기능 중복, 추가 의존성)
- ✅ html (현재 선택)

### 3.3 상태 관리

#### 선택: Riverpod 유지

**근거:**
- 이미 프로젝트 전체에서 사용 중
- 컴파일 타임 안전성
- 의존성 주입 기능 내장
- 테스트 용이성

**Provider 구조:**
```dart
// 새로운 Provider 추가
final naverUrlProcessorProvider = Provider((ref) {
  return NaverUrlProcessor(
    mapParser: ref.watch(naverMapParserProvider),
    apiClient: ref.watch(naverLocalApiClientProvider),
  );
});
```

### 3.4 로컬 캐싱

#### 선택: Hive + 메모리 캐시 조합

**근거:**
- **Hive**: 영구 저장이 필요한 식당 데이터
- **메모리 캐시**: URL 리다이렉션, API 결과 등 임시 데이터

**구현:**
```dart
class CacheManager {
  // 메모리 캐시 (LRU)
  final _urlCache = LruMap<String, String>(maximumSize: 100);
  final _apiCache = LruMap<String, dynamic>(maximumSize: 50);
  
  // Hive 박스
  late Box<Restaurant> _restaurantBox;
}
```

### 3.5 에러 처리 및 로깅

#### 선택: 계층별 예외 + 구조화된 로깅

**근거:**
- Clean Architecture의 계층 분리 원칙 준수
- 디버깅 용이성
- 프로덕션 모니터링 준비

**구현:**
```dart
// 계층별 예외
sealed class AppException implements Exception {
  final String message;
  final StackTrace? stackTrace;
}

class DataException extends AppException {}
class DomainException extends AppException {}
class PresentationException extends AppException {}

// 구조화된 로깅
class StructuredLogger {
  void log(LogLevel level, String message, {
    Map<String, dynamic>? data,
    Exception? error,
    StackTrace? stackTrace,
  });
}
```

## 4. 아키텍처 패턴 결정

### 4.1 Repository Pattern 확장

**결정**: Repository Pattern + Facade Pattern

**근거:**
- 복잡한 네이버 URL 처리 로직을 단순한 인터페이스로 제공
- 기존 Repository 구조와 일관성 유지

```dart
// Facade 패턴 적용
class NaverUrlProcessor {
  // 복잡한 내부 로직을 숨김
  Future<Restaurant> processNaverUrl(String url) {
    // 1. URL 검증
    // 2. 리다이렉션
    // 3. 스크래핑
    // 4. API 호출
    // 5. 매칭 및 병합
  }
}
```

### 4.2 의존성 주입

**결정**: Riverpod Provider 기반 DI

**근거:**
- 기존 프로젝트 구조와 일치
- 런타임 오버헤드 최소화
- 테스트 시 모킹 용이

## 5. 외부 서비스 통합

### 5.1 네이버 로컬 API

**결정**: 직접 통합

**근거:**
- 공식 SDK 없음
- REST API로 간단한 구조
- 필요한 기능만 선택적 구현 가능

**API 엔드포인트:**
```dart
class NaverApiEndpoints {
  static const String localSearch = '/v1/search/local.json';
  static const String placeDetail = '/v1/search/place/detail';
}
```

### 5.2 CORS 프록시 (웹 환경)

**결정**: allorigins.win 사용

**근거:**
- 무료 서비스
- 안정적인 가동률
- JSON 응답 지원

**대안:**
- ❌ 자체 프록시 서버 (유지보수 부담)
- ❌ cors-anywhere (제한적)
- ✅ allorigins.win (선택)

## 6. 테스트 전략

### 6.1 테스트 프레임워크

**결정**: Flutter Test + Mockito

**근거:**
- Flutter 기본 제공
- Riverpod과 호환
- 풍부한 매칭 기능

### 6.2 테스트 범위

```yaml
단위 테스트:
  - URL 파서: 90% 이상
  - API 클라이언트: 85% 이상
  - 매칭 알고리즘: 95% 이상

통합 테스트:
  - URL 처리 파이프라인: 핵심 시나리오
  - Repository 통합: 주요 플로우

E2E 테스트:
  - 실제 네이버 URL로 테스트 (CI 제외)
```

## 7. 성능 고려사항

### 7.1 네트워크 최적화

**결정:**
- Connection pooling (Dio 기본 제공)
- Request 타임아웃: 10초
- 재시도: 최대 3회

### 7.2 메모리 최적화

**결정:**
- LRU 캐시 크기 제한
- 이미지 데이터 제외
- 주기적 캐시 정리

## 8. 보안 고려사항

### 8.1 API 키 관리

**결정**: 환경 변수 + 난독화

```dart
// 컴파일 타임 주입
const String apiKey = String.fromEnvironment('NAVER_API_KEY');

// 런타임 난독화
final obfuscatedKey = base64.encode(utf8.encode(apiKey));
```

### 8.2 네트워크 보안

**결정:**
- HTTPS 전용
- Certificate pinning (선택적)
- Request 서명 검증

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

### 9.1 단계별 적용

1. **Phase 1**: 기본 구조 구현
   - NaverLocalApiClient
   - 기본 에러 처리

2. **Phase 2**: 고급 기능
   - 캐싱 레이어
   - 매칭 알고리즘

3. **Phase 3**: 최적화
   - 성능 튜닝
   - 모니터링 추가

### 9.2 롤백 계획

- Feature flag로 새 기능 제어
- 기존 NaverMapParser 유지
- 점진적 트래픽 전환

## 10. 결론

### 10.1 핵심 결정 사항

| 영역 | 선택 | 이유 |
|------|------|------|
| HTTP 클라이언트 | Dio + HTTP | 용도별 최적화 |
| 상태 관리 | Riverpod | 프로젝트 일관성 |
| 로컬 저장소 | Hive | 기존 인프라 활용 |
| 캐싱 | Hive + Memory | 성능과 영속성 균형 |
| 아키텍처 | Clean + Facade | 복잡도 관리 |

### 10.2 예상 효과

- **개발 속도**: 기존 스택 활용으로 빠른 구현
- **유지보수성**: 명확한 책임 분리로 관리 용이
- **확장성**: 다른 플랫폼 추가 시 쉬운 확장
- **성능**: 캐싱과 최적화로 빠른 응답

### 10.3 리스크 및 대응

| 리스크 | 영향도 | 대응 방안 |
|--------|--------|-----------|
| API 제한 | 중 | 캐싱 강화, Rate limiting |
| 네이버 구조 변경 | 높 | 파서 업데이트 자동화 |
| CORS 프록시 장애 | 중 | 대체 프록시 준비 |

### 10.4 향후 고려사항

- GraphQL 도입 검토 (복잡한 쿼리 증가 시)
- 자체 백엔드 구축 (사용자 증가 시)
- ML 기반 매칭 알고리즘 (정확도 개선)