feat(app): add manual entry and sharing flows
This commit is contained in:
@@ -278,12 +278,26 @@ class MockHttpClient extends Mock implements Client {}
|
||||
```dart
|
||||
// lib/core/constants/api_keys.dart
|
||||
class ApiKeys {
|
||||
static const String naverClientId = String.fromEnvironment('NAVER_CLIENT_ID');
|
||||
static const String naverClientSecret = String.fromEnvironment('NAVER_CLIENT_SECRET');
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -397,4 +411,4 @@ class ErrorReporter {
|
||||
### 10.2 하위 호환성
|
||||
- 기존 NaverMapParser는 그대로 유지
|
||||
- 새로운 기능은 옵트인 방식으로 제공
|
||||
- 점진적 마이그레이션 지원
|
||||
- 점진적 마이그레이션 지원
|
||||
|
||||
43
doc/06_testing/flutter_test_failures.md
Normal file
43
doc/06_testing/flutter_test_failures.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Flutter Test Failures – 2025-XX-XX
|
||||
|
||||
## TL;DR
|
||||
- **해결 완료**: `test/integration/naver_api_integration_test.dart`의 “NaverMapParser - 동시성 및 리소스 관리 - 리소스 정리 확인”이 dispose 이후에도 성공을 반환하던 문제가 수정되었습니다.
|
||||
- 수정 내용: `NaverMapParser`가 `dispose()` 호출 뒤 `_isDisposed` 플래그를 설정하고, 이후 `parseRestaurantFromUrl`이 호출되면 `NaverMapParseException('이미 dispose된 파서입니다')`를 던지도록 변경했습니다 (`lib/data/datasources/remote/naver_map_parser.dart`).
|
||||
- 단위 재현 테스트:
|
||||
```bash
|
||||
flutter test test/integration/naver_api_integration_test.dart \
|
||||
--plain-name '리소스 정리 확인'
|
||||
```
|
||||
- 위 명령은 정상 통과했으며, 전체 스위트는 별도로 재실행해야 합니다.
|
||||
|
||||
---
|
||||
|
||||
## Failing Spec
|
||||
|
||||
| 항목 | 내용 |
|
||||
| --- | --- |
|
||||
| 파일 | `test/integration/naver_api_integration_test.dart` |
|
||||
| 라인 | `342-355` (테스트 이름: `NaverMapParser - 동시성 및 리소스 관리 리소스 정리 확인`) |
|
||||
| 기대 | `expect(() => parser.parseRestaurantFromUrl(...), throwsAnything)` |
|
||||
| 실제 | `parseRestaurantFromUrl`가 `Restaurant` 인스턴스를 반환하여 `Future`가 성공적으로 완료됨 |
|
||||
| 로그 | `Expected: throws anything, Actual: ... emitted <Instance of 'Restaurant'>` |
|
||||
|
||||
### 의심 원인
|
||||
1. **샘플/시드 데이터 추가** – 최근 추가된 `ManualRestaurantSamples`/`SampleDataInitializer`가 지도 파서의 동작 경로를 바꾸지는 않지만, 테스트 스텁이 더 이상 에러를 내지 않고 정상 데이터를 반환하도록 수정되었을 가능성.
|
||||
2. **네이버 파서 구현 변경** – `_parseWithLocalSearch` 또는 GraphQL fallback 로직이 보강되면서, 과거에는 에러가 발생하던 케이스도 이제는 성공으로 처리되는 것으로 추정.
|
||||
|
||||
### 해야 할 일
|
||||
1. **전체 스위트 재실행**
|
||||
- 이번 수정은 특정 테스트만 확인했으므로, `flutter test` 전체를 다시 돌려 다른 회귀가 없는지 확인합니다.
|
||||
|
||||
2. **Mock/Stubs 정리 (기존 TODO 유지)**
|
||||
- `flutter analyze`가 여전히 `test/mocks/mock_naver_api_client.dart`의 override 경고를 보고하므로, 모킹 계층을 최신 구현과 맞춰 조정해야 합니다.
|
||||
|
||||
3. **회귀 방지**
|
||||
- dispose 상태 확인 로직을 다른 리소스 보유 클래스에도 적용 가능한지 검토하고, 유사 패턴의 테스트를 추가하는 것이 좋습니다.
|
||||
|
||||
---
|
||||
|
||||
## 참고 사항
|
||||
- `flutter analyze` 또한 160개의 info/warning을 내고 있으며, `test/mocks/mock_naver_api_client.dart`의 `override_on_non_overriding_member` 경고가 존재합니다. 위 이슈를 고치는 과정에서 함께 손볼 것을 권장합니다.
|
||||
- 새로 추가된 샘플 데이터가 방문 이력까지 시드하므로 테스트 환경에 영향을 줄 수 있습니다. 필요 시 테스트에서 Hive 박스를 mock하거나 초기화를 제어하세요.
|
||||
11
doc/08_pending_tasks.md
Normal file
11
doc/08_pending_tasks.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# 남은 작업 체크리스트
|
||||
|
||||
- [x] API 키를 환경 변수/난독화 전략으로 분리하고 Git에서 추적되지 않게 재구성하기 (doc/03_architecture/tech_stack_decision.md:247-256, lib/core/constants/api_keys.dart:1-20). `ApiKeys`가 `--dart-define`으로 주입된(base64 인코딩) 값을 복호화하도록 수정하고 관련 문서를 업데이트했습니다.
|
||||
- [x] AddRestaurantDialog(JSON 뷰)와 네이버 URL/검색/직접 입력 흐름 구현 및 자동 저장 제거 (doc/02_design/add_restaurant_dialog_design.md:1-137, doc/01_requirements/오늘 뭐 먹Z? 완전한 개발 가이드.md:1491-1605, lib/presentation/pages/restaurant_list/widgets/add_restaurant_dialog.dart:108-177, lib/presentation/view_models/add_restaurant_view_model.dart:171-224). FAB → 바텀시트(링크/검색/직접 입력) 흐름을 추가하고, 링크·검색 다이얼로그에는 JSON 필드 에디터를 구성하여 데이터 확인 후 저장하도록 변경했으며 `ManualRestaurantInputScreen`에서 직접 입력을 처리합니다.
|
||||
- [ ] 광고보고 추천받기 플로우에서 광고 게이팅, 조건 필터링, 추천 팝업, 방문 처리, 재추천, 알림 연동까지 완성하기 (doc/01_requirements/오늘 뭐 먹Z? 완전한 개발 가이드.md:820-920, lib/presentation/pages/random_selection/random_selection_screen.dart:1-400, lib/presentation/providers/recommendation_provider.dart:1-220, lib/core/services/notification_service.dart:1-260). 현재 광고 버튼을 눌러도 조건에 맞는 식당이 제시되지 않으며, 광고·추천 다이얼로그·재추천 버튼·알림 예약 로직이 모두 누락되어 있다. 임시 광고 화면(닫기 이벤트 포함)을 띄운 뒤 n일/거리 조건을 만족하는 식당을 찾으면 팝업으로 노출하고, 다시 추천받기/닫기 버튼을 제공하며, 닫거나 추가 행동 없이 유지되면 방문 처리 및 옵션으로 지정한 시간 이후 푸시 알림을 예약해야 한다. 조건에 맞는 식당이 없으면 광고 없이 “조건에 맞는 식당이 존재하지 않습니다” 토스트만 출력한다.
|
||||
- [ ] P2P 리스트 공유 기능(광고 시청(임시화면만 제공) → 코드 생성 → Bluetooth 스캔/수신 → JSON 병합)을 서비스 계층(bluetoothServiceProvider, adServiceProvider, PermissionService 등)과 함께 완성하기 (doc/01_requirements/오늘 뭐 먹Z? 완전한 개발 가이드.md:1874-1978, lib/presentation/pages/share/share_screen.dart:13-218). 현재 화면은 단순 토글과 더미 코드만 제공하며 요구된 광고 게이팅·기기 리스트·데이터 병합 로직이 없습니다.
|
||||
- [ ] 실시간 날씨 API(기상청) 연동 및 캐시 무효화 로직 구현하기 (doc/01_requirements/오늘 뭐 먹Z? 완전한 개발 가이드.md:306-329, lib/data/repositories/weather_repository_impl.dart:16-92). 지금은 더미 WeatherInfo를 반환하고 있어 추천 화면의 날씨 카드가 실제 데이터를 사용하지 못합니다.
|
||||
- [ ] 방문 캘린더에서 추천 이력(`recommendationHistoryProvider`)과 방문 기록을 함께 로딩하고 카드 액션(방문 확인)까지 연결하기 (doc/01_requirements/오늘 뭐 먹Z? 완전한 개발 가이드.md:2055-2127, lib/presentation/pages/calendar/calendar_screen.dart:18-210). 구현본은 `visitRecordsProvider`만 사용하며 추천 기록, 방문 확인 버튼, 추천 이벤트 마커가 모두 빠져 있습니다.
|
||||
- [ ] 문서에서 요구한 NaverUrlProcessor/NaverLocalApiClient 파이프라인을 별도 데이터 소스로 구축하고 캐싱·병렬 처리·에러 복구를 담당하도록 리팩터링하기 (doc/03_architecture/naver_url_processing_architecture.md:29-90,392-400, lib/data/datasources/remote/naver_map_parser.dart:32-640, lib/data/datasources/remote/naver_search_service.dart:19-210). 현재 구조에는 `naver_url_processor.dart`가 없고, 파싱·API 호출이 Parser와 SearchService에 산재해 있어 요구된 책임 분리가 이뤄지지 않습니다.
|
||||
- [ ] `print` 기반 디버그 출력을 공통 Logger로 치환하고 lints가 지적한 100+개 로그를 정리하기 (doc/06_testing/2025-07-30_update_summary.md:42-45, lib/core/services/notification_service.dart:209-214, lib/data/repositories/weather_repository_impl.dart:59-133, lib/presentation/providers/notification_handler_provider.dart:55-154 등). 현재 analyze 단계에서 warning을 유발하고 프로덕션 빌드에 불필요한 로그가 남습니다.
|
||||
- [ ] RestaurantRepositoryImpl 단위 테스트를 복구하고 `path_provider` 초기화 문제를 해결하기 (doc/07_test_report_lunchpick.md:52-57, test/unit/data/repositories/restaurant_repository_impl_test.dart). 관련 테스트 파일이 삭제된 상태라 7건 실패를 수정하지 못했고, Hive 경로 세팅도 검증되지 않습니다.
|
||||
156
doc/sample_data/manual_entry_samples.md
Normal file
156
doc/sample_data/manual_entry_samples.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# 수동 입력 샘플 맛집 데이터
|
||||
|
||||
직접 입력 탭에서 곧바로 붙여 넣을 수 있는 참조 데이터를 10개 제공합니다. 모든 사례는 `RestaurantFormData`의 필드를 그대로 나열했으며, `naverUrl`은 비워 둔 상태(네이버 연동 없이 사용자 입력으로만 추가)입니다. 위도/경도는 소수점 5자리 이상으로 기록해 지도를 바로 사용할 수 있습니다. 초기 부트스트랩 시에는 동일한 데이터가 Hive 박스에 저장되며, 각 항목은 최근 방문 히스토리(visit records)까지 포함하므로 추천/통계 화면에서 즉시 재방문 로직을 검증할 수 있습니다.
|
||||
|
||||
## 필드 구성
|
||||
- `name`: 매장명
|
||||
- `category`: 대분류 (앱의 필터와 동일한 영문/국문 조합 사용)
|
||||
- `subCategory`: 세부 카테고리
|
||||
- `description`: 소개 문구
|
||||
- `phoneNumber`: 지역번호가 포함된 숫자/하이픈 형식
|
||||
- `roadAddress`: 도로명 주소
|
||||
- `jibunAddress`: 지번 주소
|
||||
- `latitude`, `longitude`: WGS84 좌표(십진수)
|
||||
- `naverUrl`: 수동 입력이면 빈 문자열로 둠
|
||||
|
||||
## 샘플 세트
|
||||
|
||||
### 1. 을지로 진미식당
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 을지로 진미식당 |
|
||||
| category | 한식 |
|
||||
| subCategory | 백반/한정식 |
|
||||
| description | 50년 전통의 정갈한 백반집으로 제철 반찬과 명란구이가 유명합니다. 점심 회전율이 빨라 예약 없이 방문 가능. |
|
||||
| phoneNumber | 02-777-1234 |
|
||||
| roadAddress | 서울 중구 을지로12길 34 |
|
||||
| jibunAddress | 서울 중구 수표동 67-1 |
|
||||
| latitude | 37.56698 |
|
||||
| longitude | 127.00531 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 2. 성수연방 버터
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 성수연방 버터 |
|
||||
| category | 카페 |
|
||||
| subCategory | 디저트 카페 |
|
||||
| description | 버터 향이 진한 크루아상과 라즈베리 타르트를 파는 성수연방 내 디저트 카페. 아침 9시에 오픈. |
|
||||
| phoneNumber | 02-6204-1231 |
|
||||
| roadAddress | 서울 성동구 성수이로14길 14 |
|
||||
| jibunAddress | 서울 성동구 성수동2가 320-10 |
|
||||
| latitude | 37.54465 |
|
||||
| longitude | 127.05692 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 3. 망원 라라멘
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 망원 라라멘 |
|
||||
| category | 일식 |
|
||||
| subCategory | 라멘 |
|
||||
| description | 돼지뼈 육수에 유자 오일을 더한 하카타 스타일 라멘. 저녁에는 한정 교자도 제공. |
|
||||
| phoneNumber | 02-333-9086 |
|
||||
| roadAddress | 서울 마포구 포은로 78-1 |
|
||||
| jibunAddress | 서울 마포구 망원동 389-50 |
|
||||
| latitude | 37.55721 |
|
||||
| longitude | 126.90763 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 4. 해방촌 살사포차
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 해방촌 살사포차 |
|
||||
| category | 세계요리 |
|
||||
| subCategory | 멕시칸/타코 |
|
||||
| description | 직접 구운 토르티야 위에 매콤한 살사를 얹어주는 캐주얼 타코펍. 주말에는 살사 댄스 클래스 운영. |
|
||||
| phoneNumber | 02-792-7764 |
|
||||
| roadAddress | 서울 용산구 신흥로 68 |
|
||||
| jibunAddress | 서울 용산구 용산동2가 22-16 |
|
||||
| latitude | 37.54241 |
|
||||
| longitude | 126.98620 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 5. 연남 그로서리 포케
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 연남 그로서리 포케 |
|
||||
| category | 세계요리 |
|
||||
| subCategory | 포케/샐러드 |
|
||||
| description | 직접 고른 토핑으로 만드는 하와이안 포케 볼 전문점. 비건 토핑과 현미밥 선택 가능. |
|
||||
| phoneNumber | 02-336-0214 |
|
||||
| roadAddress | 서울 마포구 동교로38길 33 |
|
||||
| jibunAddress | 서울 마포구 연남동 229-54 |
|
||||
| latitude | 37.55955 |
|
||||
| longitude | 126.92579 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 6. 정동 브루어리
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 정동 브루어리 |
|
||||
| category | 주점 |
|
||||
| subCategory | 수제맥주펍 |
|
||||
| description | 소규모 양조 탱크를 갖춘 다운타운 브루펍. 시즈널 IPA와 훈제 플래터를 함께 즐길 수 있습니다. |
|
||||
| phoneNumber | 02-720-8183 |
|
||||
| roadAddress | 서울 중구 정동길 21-15 |
|
||||
| jibunAddress | 서울 중구 정동 1-18 |
|
||||
| latitude | 37.56605 |
|
||||
| longitude | 126.97013 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 7. 목동 참숯 양꼬치
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 목동 참숯 양꼬치 |
|
||||
| category | 중식 |
|
||||
| subCategory | 양꼬치/바비큐 |
|
||||
| description | 매장에서 직접 손질한 어린양 꼬치를 참숯에 구워내는 곳. 마라볶음과 칭다오 생맥 조합 추천. |
|
||||
| phoneNumber | 02-2653-4411 |
|
||||
| roadAddress | 서울 양천구 목동동로 377 |
|
||||
| jibunAddress | 서울 양천구 목동 907-2 |
|
||||
| latitude | 37.52974 |
|
||||
| longitude | 126.86455 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 8. 부산 민락 수제버거
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 부산 민락 수제버거 |
|
||||
| category | 패스트푸드 |
|
||||
| subCategory | 수제버거 |
|
||||
| description | 광안리 바다가 내려다보이는 루프탑 버거 전문점. 패티를 미디엄으로 구워 치즈와 구운 파인애플을 올립니다. |
|
||||
| phoneNumber | 051-754-2278 |
|
||||
| roadAddress | 부산 수영구 광안해변로 141 |
|
||||
| jibunAddress | 부산 수영구 민락동 181-5 |
|
||||
| latitude | 35.15302 |
|
||||
| longitude | 129.11830 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 9. 제주 동문 파스타바
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 제주 동문 파스타바 |
|
||||
| category | 양식 |
|
||||
| subCategory | 파스타/와인바 |
|
||||
| description | 동문시장 골목의 오픈키친 파스타바. 한치 크림 파스타와 제주산 와인을 코스로 제공. |
|
||||
| phoneNumber | 064-723-9012 |
|
||||
| roadAddress | 제주 제주시 관덕로14길 18 |
|
||||
| jibunAddress | 제주 제주시 일도일동 1113-4 |
|
||||
| latitude | 33.51227 |
|
||||
| longitude | 126.52686 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
|
||||
### 10. 대구 중앙시장 샌드
|
||||
| 필드 | 값 |
|
||||
| --- | --- |
|
||||
| name | 대구 중앙시장 샌드 |
|
||||
| category | 카페 |
|
||||
| subCategory | 샌드위치/브런치 |
|
||||
| description | 직접 구운 식빵과 사과 절임으로 만드는 시그니처 에그샐러드 샌드. 평일 오전 8시부터 테이크아웃 가능. |
|
||||
| phoneNumber | 053-256-8874 |
|
||||
| roadAddress | 대구 중구 중앙대로 363-1 |
|
||||
| jibunAddress | 대구 중구 남일동 135-1 |
|
||||
| latitude | 35.87053 |
|
||||
| longitude | 128.59404 |
|
||||
| naverUrl | (직접 입력 - 비움) |
|
||||
Reference in New Issue
Block a user