📌 앱 소개: 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