📌 앱 소개: TMDB API를 활용한 영화 정보 조회 및 추천 앱
🕒 기간: 2025.05.13 ~ 2025.05.15 (3일)
📱 플랫폼: Flutter 크로스 플랫폼 앱 (iOS, Android)
👥 개발 인원: 1명 (개인 프로젝트)
💼 역할: 앱 전체 설계 및 개발, API 연동, 성능 최적화
🛠️ 주요 사용 기술: Flutter Dart TMDB API Riverpod Clean Architecture Dio GitHub Actions Hero Animation Shimmer  
🔗 GitHub: daehan-lim/flutter-film-mind-app
  
  
  
  
  
  
  
  
FilmMind는 TMDB API를 활용하여 현재 상영작, 인기 영화, 평점 높은 영화, 개봉 예정작 등 다양한 카테고리의 영화 정보를 제공하는 Flutter 기반 모바일 애플리케이션입니다. Clean Architecture 패턴과 MVVM 구조를 적용하여 확장 가능하고 유지보수가 용이하도록 설계되었으며, Hero Animation을 통한 자연스러운 화면 전환과 Google/Naver 검색 연동 기능을 통해 사용자가 영화 정보를 직관적으로 탐색하고 추가 정보를 조회할 수 있는 환경을 제공합니다.
├── app/                               # 앱 전체에서 설정 및 공통 상수, 테마 등  
│   ├── constants/                     # 앱 상수 정의  
│   │   ├── app_colors.dart            # 색상 정의  
│   │   ├── app_constants.dart         # 상수 값 정의  
│   │   └── app_styles.dart            # 스타일 정의  
│   └── theme.dart                     # 앱 테마 설정  
├── core/                              # 앱 전체에서 사용되는 핵심 기능 및 유틸리티  
│   ├── exceptions/                    # 앱 전체에서 사용되는 예외 클래스  
│   │   └── data_exceptions.dart       # 데이터 관련 예외 클래스  
│   ├── extensions/                    # 확장 메서드 정의  
│   │   ├── date_extensions.dart       # 날짜 관련 확장 메서드  
│   │   └── number_extensions.dart     # 숫자 관련 확장 메서드  
│   ├── providers/                     # 공통 프로바이더  
│   │   └── repository_providers.dart  # 리포지토리 프로바이더  
│   └── utils/                         # 유틸리티 함수  
│       ├── navigation_util.dart       # 네비게이션 관련 유틸리티  
│       ├── snackbar_util.dart         # 스낵바 관련 유틸리티  
│       └── dialogue_util.dart         # 다이얼로그 관련 유틸리티  
├── data/                              # 데이터 관련 클래스 및 데이터 액세스 계층  
│   ├── data_source/                   # 데이터 소스 클래스 
│   ├── dto/                           # 데이터 전송 객체 
│   └── repository/                    # 리포지토리 구현체 
├── domain/                            # 비즈니스 로직 및 엔티티 정의  
│   ├── entity/                        # 도메인 엔티티 
│   ├── repository/                    # 리포지토리 인터페이스
│   └── usecase/                       # 유스케이스 
├── presentation/                      # UI 관련 코드  
│   ├── pages/                         # 앱 화면  
│   │   ├── home/                      # 홈 화면  
│   │   │   ├── home_page.dart         # 홈 페이지 위젯  
│   │   │   ├── home_view_model.dart   # 홈 화면 뷰모델  
│   │   │   └── widgets/               # 홈 화면 관련 위젯 
│   │   └── detail/                    # 상세 화면 
│   └── widgets/                       # 공통 위젯 
└── main.dart                          # 앱 진입점  
Domain, Data, Presentation 계층 분리를 통한 관심사 분리 및 의존성 역전 원칙 적용Riverpod을 활용한 전역 상태 관리와 Provider 기반 의존성 주입 구현MVVM 패턴 적용으로 UI와 비즈니스 로직 분리 및 단방향 데이터 플로우 구축Repository 패턴과 UseCase 계층으로 비즈니스 로직 캡슐화 및 테스트 가능한 코드 구조 구축Dio HTTP 클라이언트와 Bearer Token 인증을 통한 안정적인 API 통신 구현Extension을 활용한 예산/수익 정보의 가독성 있는 표시Hero Animation 구현으로 영화 포스터 클릭 시 자연스러운 화면 전환 효과 제공Hero 태그 매칭으로 애니메이션 충돌 방지CachedNetworkImage를 활용한 이미지 캐싱으로 반복 로딩 시간 단축 및 데이터 사용량 절약Shimmer 로딩 애니메이션 구현으로 데이터 로딩 중 인지된 성능 향상 및 사용자 대기 경험 개선Transform.translate를 활용한 인기 영화 랭킹 숫자 오버레이 디자인으로 시각적 임팩트 강화ListView와 카테고리별 차별화된 레이아웃으로 효율적인 공간 활용DataSource부터 ViewModel까지 모든 계층에 대한 단위 테스트 작성으로 비즈니스 로직 안정성 확보Mocktail을 활용한 의존성 모킹과 Provider 오버라이드로 외부 API 의존성 없는 격리된 테스트 환경 구축Pull Request 및 Push 이벤트 기반 자동화된 테스트 실행 및 코드 품질 검증으로 수동 검수 시간 단축GitHub Secrets를 통한 민감 정보 보호Extension 메서드를 활용한 코드 가독성 향상Entity와 DTO 분리를 통한 외부 API 의존성 최소화 및 도메인 모델 보호1. Hero Animation 태그 중복 충돌 문제
문제 상황
Flutter로 영화 정보 앱을 개발하면서 Hero Animation을 사용하여 영화 포스터 클릭 시 홈 화면에서 상세 화면으로 자연스럽게 전환되도록 구현했으나, There are multiple heroes that share the same tag within a subtree 오류가 발생하며 애니메이션이 제대로 작동하지 않는 문제 발생
'movie-image-${movie.id}' 형태의 Hero 태그를 생성Hero 태그가 한 화면에 여러 개 존재Hero 태그가 고유해야 한다는 제약 조건을 위반'movie-image-${movie.id}-$categoryName' 형태의 고유 태그 생성 시스템 구현Hero Animation 매칭Hero 태그를 가지도록 하여 중복 문제 완전 해결// 수정된 Hero 태그 생성
Hero(
  tag: 'movie-image-${movie.id}-$categoryName',
  child: AppCachedImage(imageUrl: movie.getPosterUrl()),
)
Hero 태그를 가지게 되어 충돌 없이 자연스러운 애니메이션 전환 구현2. GitHub Actions에서 TMDB API 키 보안 관리
문제 상황
CI 파이프라인에서 TMDB Bearer Token이 필요하지만 코드에 하드코딩할 수 없어 빌드 시 환경 변수 부재로 실패하는 문제 발생
flutter_dotenv 패키지가 런타임에 .env (환경 변수) 파일을 요구함을 파악GitHub Secrets를 활용한 안전한 환경 변수 관리 방법 검토TMDB_BEARER_TOKEN을 Secret으로 등록GitHub Actions 워크플로우에서 Secret을 환경 변수로 주입하여 .env 파일 동적 생성- name: Create .env file
  run: |
    echo "TMDB_BEARER_TOKEN=$" > .env
- name: Install dependencies
  run: flutter pub get
- name: Run tests
  run: flutter test