'FILTERZ'는 사진의 분위기를 만드는 조정값 자체를 콘텐츠로 다루는 iOS 앱입니다. 사용자는 원하는 색감의 필터를 직접 제작해 마켓에 등록하고, 다른 크리에이터의 필터를 탐색·구매한 뒤 사진과 카메라에 바로 적용할 수 있습니다. 필터 상세 화면과 1:1 채팅을 연결해 크리에이터와의 소통도 하나의 흐름 안에서 제공합니다.
| 항목 | 내용 |
|---|---|
| 개발 기간 | 2026.04 ~ 2026.05 |
| 개발 형태 | 1인 개발 |
| 담당 역할 | UI/UX, iOS 아키텍처, API 연동, 로컬 저장소, 실시간 채팅, 인증·결제, 테스트 |
| 지원 환경 | iOS 18.6+ |
![]() 홈 · 오늘의 필터 |
![]() 피드 · 필터 탐색 |
![]() 필터 상세 · 전후 비교 |
![]() 필터 상세 · EXIF와 프리셋 |
![]() 필터 제작 · 실시간 조정 |
![]() 필터 등록 · 정보 입력 |
![]() 필터 관리 · 보유 필터 |
![]() 필터 적용 · 라이브 카메라 |
![]() 채팅 · 멀티미디어 첨부 |
![]() 채팅 · AI 대화 요약 |
- 밝기, 노출, 대비, 채도, 색온도 등 12개 조정값을 실시간 미리보기로 편집
- 카메라 촬영 또는 사진 선택 후 대표 이미지와 필터 프리셋을 함께 등록
- 필터명, 카테고리, 소개, 가격을 입력해 마켓 콘텐츠로 업로드
- 홈, 랭킹, 카테고리, 피드에서 필터를 탐색하고 상세 정보 확인
- 좋아요와 댓글·답글로 크리에이터 및 다른 사용자와 상호작용
- PortOne 결제 후 서버 검증을 거쳐 구매 필터를 필터 관리 화면에 반영
- 구매했거나 직접 제작한 필터를 사진에 적용하고 결과를 사진 보관함에 저장
- 필터가 적용된 카메라 프리뷰로 사진과 동영상 촬영
- 대표 이미지의 촬영 기기, 렌즈, 조리개, ISO, 셔터 속도, 위치 등 EXIF 정보 표시
- Socket.IO 기반 메시지 송수신과 SwiftData 기반 채팅 내역 보존
- 이미지와 PDF 첨부, 이미지 갤러리 및 PDF 미리보기 지원
- 네트워크 복구 시 소켓 재연결과 누락 메시지 동기화
- FCM 알림의 채팅방 이동, 읽지 않은 메시지 수와 앱 배지 동기화
- 대화 내용을 요약하는 AI 채팅 요약 제공
- HLS 스트리밍 재생과 화질 선택
- 플레이리스트를 분석해 자막 트랙과 세그먼트 정보를 처리
- 세로·가로 전체 화면 전환 시 재생 상태 유지
- 필터 편집 화면의 미리보기와 업로드 이미지, 구매 후 적용 결과가 서로 달라지지 않도록 하나의
FilterImageRenderer파이프라인에서 Core Image 필터를 순서대로 합성 - 12개 조정값은 도메인 모델에서 허용 범위로 보정하고 DTO와 상호 변환하며, 이전 데이터의 모든 값이
0인 프리셋은 대비·채도·색온도까지 0으로 적용되지 않도록 중립값으로 변환 - 이를 통해 생성 시점이 다른 프리셋도 현재 렌더러에서 유효한 결과로 재현
- 사진 필터링 과정에서 픽셀 방향이나 촬영 정보가 손실되지 않도록 원본 이미지의 orientation을 반영해 렌더링하고, Image I/O를 이용해 EXIF·TIFF·GPS 메타데이터를 읽고 다시 기록
- 업로드 시에는 원본과 필터 적용본을 함께 생성하며, 상세 화면에서는 카메라·렌즈·초점거리·조리개·ISO·셔터 속도·촬영 시각·위치를 구조화
- 필터가 사진의 색감만 바꾸고 촬영 맥락은 유지하도록 데이터 흐름을 분리
- 채팅방 진입 시 SwiftData의 로컬 메시지를 먼저 표시한 뒤 REST API의 이후 메시지를 병합하고, Socket.IO 이벤트는
AsyncStream<ChatSocketEvent>로 변환해 TCA Effect에서 소비 NWPathMonitor의 연결 상태 변화에 따라 소켓을 재연결하고 마지막으로 확인한 메시지를 기준으로 누락 내역을 동기화- 채팅방·메시지·읽지 않은 수를 로컬에 함께 저장해 탭 이동, 앱 재실행, 푸시 수신 이후에도 동일한 대화 상태를 이어갈 수 있게 구성
- Alamofire
RequestInterceptor에서 인증 오류가 발생하면OSAllocatedUnfairLock으로 토큰 갱신 상태를 보호하고, 갱신 중 들어온 요청의 재시도 completion을 대기열에 모음 - 한 번의 갱신 결과로 대기 중인 요청을 함께 재시도해 중복 토큰 갱신을 방지
- DEBUG 환경에서 저장하는 API 응답 fixture는 토큰, 이메일, 전화번호, 결제 식별자와 같은 필드를 치환한 뒤 기록하고, 네트워크 연결 실패 시 번들 fixture를 디코딩
- 화면별 기능을 TCA Reducer 단위로 나누고, 상태 변경과 부수 효과가 모두 Action을 거치도록 구성
- 네트워크, 인증, 저장소, 카메라, 소켓 등의 구현은
DependencyKey를 통해 주입하여 View가 인프라에 직접 의존하지 않음
flowchart LR
View[SwiftUI View] -->|send| Store[TCA Store]
Store --> Reducer[Reducer]
Reducer -->|mutate| State[State]
State -->|observe| View
Reducer -->|return| Effect[Effect]
Effect --> Client[Dependency Client]
Client --> API[REST API / Socket.IO]
Client --> Local[SwiftData / Keychain]
Client --> Platform[Camera / Photo Library / FCM]
Client -->|result| Effect
Effect -->|response Action| Store
| 구분 | 기술 | 사용 목적 |
|---|---|---|
| UI·상태 관리 | SwiftUI, The Composable Architecture | 단방향 상태 흐름, 화면 상태 및 Effect 관리 |
| 비동기 처리 | Swift Concurrency, AsyncStream | API 요청, 소켓 및 네트워크 상태 이벤트 처리 |
| 네트워크 | Alamofire | REST API, 멀티파트 업로드, 토큰 갱신 인터셉터 |
| 로컬 데이터 | SwiftData, Keychain | 채팅 데이터 영속화, 인증 토큰 보관 |
| 이미지·카메라 | Core Image, Image I/O, AVFoundation, Photos | 필터 렌더링, EXIF 처리, 촬영 및 결과 저장 |
| 실시간 통신 | Socket.IO, Firebase Messaging | 1:1 채팅, 푸시 알림과 읽지 않은 메시지 동기화 |
| 인증·결제 | Sign in with Apple, Kakao SDK, PortOne | 소셜 로그인과 필터 결제·검증 |
| 영상 | AVKit, HLS | 스트리밍 재생, 화질·자막·화면 방향 처리 |
| 테스트 | Swift Testing, XCTest | 도메인·네트워크 로직과 UI 테스트 기반 구성 |
Filterz/
├── App/ # 앱 루트 상태, 인증·메인 화면 전환
├── Features/ # Auth, Home, Feed, Upload, Detail, Chat 등 기능 모듈
├── Core/
│ ├── Dependencies/ # TCA Dependency Client 구현
│ ├── Network/ # Router, 인증 인터셉터, fixture 처리
│ └── Storage/ # Keychain, SwiftData 채팅 저장소
├── DTO/ # API 요청·응답 모델
├── Shared/ # 디자인 시스템, 공통 컴포넌트, 검증 로직
└── Assets.xcassets # 앱 에셋
각 Feature는 State, Action, Reducer와 SwiftUI View를 함께 두고, 공통 인프라는 Core, 전송 모델은 DTO, 재사용 UI는 Shared로 분리
Swift Testing을 사용해 화면 구현보다 변화에 민감한 도메인 규칙과 데이터 변환을 우선 검증
- 필터 조정값의 기본값과 허용 범위 보정
- 레거시 zero preset의 중립값 변환
- 사진 메타데이터의 파일 크기 포맷
- 댓글과 답글 요청의 parent comment 인코딩
- 영상 목록 페이지네이션 쿼리 및 스트림 URL 조합
- HLS 미디어·마스터 플레이리스트의 세그먼트와 variant URL 파싱









