Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
b1add74
feat: insight 관련 파일 추가
enebin Mar 8, 2026
0adf431
feat: InsightViewModel 추가
enebin Mar 8, 2026
e3aae9c
feat: 인사이트 섹션 뷰 추가
enebin Mar 8, 2026
9412c99
feat: InsightViewController 리팩토링 및 DI 등록
enebin Mar 8, 2026
6a9f92c
fix: InsightKeywordsView height constraint 크래시 수정
enebin Mar 8, 2026
d1242c9
fix: 인사이트 에러 처리 개선 및 에러 알럿 추가
enebin Mar 8, 2026
b15a9dd
fix: 리뷰반영
enebin Mar 8, 2026
2b8b296
fix: CI 실패 수정
kanghun1121 Mar 8, 2026
25d2ca9
chore: blue, blueLight, primaryLight100 컬러 에셋 추가
kanghun1121 Mar 9, 2026
3cdebfc
feat: InsightPhotoStatsView UI 구현 및 컬러 익스텐션 추가
kanghun1121 Mar 9, 2026
29887c0
chore: Color Asset 이름 수정
kanghun1121 Mar 9, 2026
0a834ad
fix: 바 차트 최소높이 설정 및 감소 예외 적용
kanghun1121 Mar 9, 2026
cf9e3a0
fix: 감소, 증가에 따른 텍스트 변경
kanghun1121 Mar 10, 2026
108e83e
feat: donut chart ui구현 및 적용
kanghun1121 Mar 9, 2026
98007d8
feat: InsightDiaryTimeStatsView 디자인 변경
enebin Mar 10, 2026
3c9d9bc
feat: InsightTopMenuView 바 차트 카드로 리디자인
enebin Mar 10, 2026
d83cd89
design: 컬러 에셋 추가
kanghun1121 Mar 10, 2026
130a814
feat: 인사이트 키워드 통계 추가
kanghun1121 Mar 10, 2026
2fc0505
feat: 카테고리 FlowRow 적용
kanghun1121 Mar 12, 2026
f9c410a
feat: 인사이트 헤더 뷰 추가
kanghun1121 Mar 12, 2026
9c964f9
feat: 월간 캘린더 스와이프로 날짜 변경 추가
kanghun1121 Mar 11, 2026
07517ff
feat: 인사이트 응답 모델 변경 (keywordStats, locationStats 추가 등)
enebin Mar 12, 2026
2d3bb1b
feat: 위치 인사이트 버블 차트 추가 및 카테고리 한글 매핑
enebin Mar 12, 2026
f2f0c44
fix: 버블 차트 폰트 크기 조정 (동네 15pt, 횟수 12pt)
enebin Mar 12, 2026
252c989
API 수정
kanghun1121 Mar 12, 2026
762f9f3
fix: 리베이스 후 Insight 모델 변경에 따른 Presentation 레이어 수정
enebin Mar 12, 2026
625cfbc
chore: 행간 및 폰트 조정
kanghun1121 Mar 12, 2026
307e06a
chore: testMode 제거
kanghun1121 Mar 12, 2026
f797b5f
feat: 인사이트 주차별 막대 차트 전체 표시
enebin Mar 12, 2026
badfb73
chore: 인사이트 주차 통계 타이틀 워딩 수정
enebin Mar 12, 2026
cc7f285
feat: readme 추가
enebin Mar 21, 2026
3d75401
feat: Sentry Crashlytics & dSYM 업로드 추가
kanghun1121 Mar 28, 2026
1bace1d
feat: FoodRecordRepository에 photoURL 인메모리 캐시 추가
kanghun1121 Mar 14, 2026
460bc50
refactor: MonthlyCalendarViewModel에서 캐시 책임 제거 및 UseCase 위임
kanghun1121 Mar 14, 2026
5631b92
chore: PrefetchAdjacentMonthsUseCase, InvalidateMonthCacheUseCase DI …
kanghun1121 Mar 14, 2026
415e88f
refactor: PrefetchUseCase 삭제 및 FetchMonthlyCalendarDaysUseCase 에 Pref…
kanghun1121 Mar 18, 2026
190602d
refactor: PhotoURLCache를 NSLock 기반에서 actor LRU 캐시로 교체 및 SWR 패턴 적용
kanghun1121 Mar 23, 2026
7f97c01
chore: 파일 분리 및 로그 제거
kanghun1121 Mar 25, 2026
191e650
refactor: 작업 취소 추가
kanghun1121 Mar 28, 2026
bc4bc34
chore: 캘린더 수정
kanghun1121 Mar 28, 2026
cfedd78
TestFlight CI 에러 수정
kanghun1121 Mar 28, 2026
f380ddb
chore: archive 부분 수정
kanghun1121 Mar 28, 2026
b63e3e3
fix: PROVISIONING_PROFILE_SPECIFIER 전역 적용으로 인한 Archive 실패 수정
enebin Apr 1, 2026
aef396d
fix: App 타겟 provisioning profile을 xcconfig에서 설정하도록 변경
enebin Apr 1, 2026
6d1e530
chore: .mcp.json을 .gitignore에 추가
kanghun1121 Apr 11, 2026
d29c378
feat: Coordinator 프로토콜 및 화면별 Coordinator 파일 추가
kanghun1121 Apr 11, 2026
1a5ea09
feat: LoginSession 도입 — 로그인/로그아웃 이벤트 버스
kanghun1121 Apr 11, 2026
3c7b94e
feat: CoachmarkStoring 프로토콜 및 CoachmarkStorage 구현 추가
kanghun1121 Apr 11, 2026
805cc0b
refactor: LoginSession 기반으로 로그인 이벤트 전달 통합
kanghun1121 Apr 11, 2026
e8ef2cd
refactor: LoginSession 기반으로 로그아웃/탈퇴 이벤트 전달 통합
kanghun1121 Apr 11, 2026
2f5eaee
refactor: AppFlowController에 Coordinator 패턴 적용 및 온보딩/알림 로직 이전
kanghun1121 Apr 11, 2026
caa9ad5
refactor: RootTabBarController에서 MyPage 생성 책임을 Coordinator로 분리
kanghun1121 Apr 11, 2026
33a9cf1
feat: WeeklyCalendarViewModel에 코치마크 표시 로직 추가
kanghun1121 Apr 11, 2026
90e540b
refactor: CalendarViewController에서 팩토리 클로저를 DIContainer 직접 주입으로 교체
kanghun1121 Apr 11, 2026
5768bf7
chore: SceneDelegate DI 등록 업데이트
kanghun1121 Apr 11, 2026
3ec1d8d
feat: Presentation/Core에 Coordinator 프로토콜 및 Factories 구조체 추가
kanghun1121 Apr 11, 2026
7c4fb52
feat: ViewTransitionHandling 프로토콜 및 DefaultViewTransitionHandler 구현
kanghun1121 Apr 11, 2026
d17016e
refactor: Feature Coordinator 및 Factory를 App → Presentation 레이어로 이동
kanghun1121 Apr 11, 2026
81495ff
refactor: App 레이어 Coordinator 및 AppFlowController Presentation 구조 반영
kanghun1121 Apr 11, 2026
0f4b5f6
chore: InsightViewModel @MainActor 제거
kanghun1121 Apr 11, 2026
4a91a8d
feat: Factories에 detail, imagePicker 팩토리 추가
kanghun1121 Apr 12, 2026
1f1c023
refactor: 각 Coordinator가 개별 Factory 대신 Factories 전체를 주입받도록 통일
kanghun1121 Apr 12, 2026
012b58b
refactor: VC에서 핸들러 클로저 제거 → ImagePickerDelegate 패턴 적용
kanghun1121 Apr 12, 2026
7dd2fa3
refactor: ImagePickerViewController가 사진 로드 및 결과 처리를 내재화
kanghun1121 Apr 12, 2026
6b029f3
chore: SceneDelegate ImagePicker authUseCase 제거 및 init 업데이트
kanghun1121 Apr 12, 2026
f5bdfa5
feat: Edit/AddressSearch Coordinator, Factory, Input, Flow 파일 추가
kanghun1121 Apr 12, 2026
e815dba
refactor: Factories에 edit, addressSearch 팩토리 추가
kanghun1121 Apr 12, 2026
a29f7cc
refactor: Calendar Delegate 패턴 제거 → Combine Flow Publisher 전환
kanghun1121 Apr 12, 2026
79f5086
refactor: Detail/Edit Delegate 패턴 제거 → Combine Flow Publisher 전환
kanghun1121 Apr 12, 2026
fce0e88
chore: SceneDelegate에 EditSceneFactory, AddressSearchSceneFactory 등록
kanghun1121 Apr 12, 2026
c090481
refactor: Detail/Edit/AddressSearch Factory DIContainer 제거 → UseCase …
kanghun1121 Apr 12, 2026
1b6ce7b
refactor: CalendarSceneFactory DIContainer 제거 → UseCase 직접 주입
kanghun1121 Apr 12, 2026
9853b0e
chore: 쓰지 않는 파일 제거
kanghun1121 Apr 12, 2026
eda6bf7
refactor: FlowEmitting/SceneProducing 과도한 추상화 제거
kanghun1121 Apr 12, 2026
02583c8
chore: 코드 정리
kanghun1121 Apr 12, 2026
1a281be
fix: 메모리 누수 해결
kanghun1121 Apr 12, 2026
ee18a90
fix: 메모리 누수 해결
kanghun1121 Apr 17, 2026
e4b5575
chore: Sentry 버전 변경
kanghun1121 Apr 21, 2026
6cfd0b7
chore: Sentry 버전 변경
kanghun1121 Apr 21, 2026
1fbba6d
chore: WeeklyCalendarViewController 불필요한 Data import 제거
kanghun1121 Apr 21, 2026
009dd1a
feat: 권한 거부 안내 화면 추가 (PermissionViewController, Coordinator, SceneFac…
kanghun1121 Apr 21, 2026
6540c28
feat: 사진 권한 거부 시 안내 화면 표시 연동
kanghun1121 Apr 21, 2026
6bd6289
design: 에셋 추가
kanghun1121 Apr 21, 2026
fe2bc36
design: 권한 거부 안내 화면 디테일 추가
kanghun1121 Apr 21, 2026
71070f8
chore: 사용하지 않는 코드 제거
kanghun1121 Apr 21, 2026
ee66e9c
chore: 디버그용 코드 제거
kanghun1121 Apr 22, 2026
64ec806
feat: Gradient 적용
kanghun1121 Apr 22, 2026
9d0b5c1
feat: 분석결과 푸시 2회 수신 시 앱 스토어 리뷰 요청 기능 추가
enebin Apr 23, 2026
0494ce8
refactor: iOS 최소버전 수정
kanghun1121 Apr 27, 2026
a1d97e7
refactor: 제네릭 제거
kanghun1121 Apr 23, 2026
487958e
feat: 알림 끄기 전 확인 얼럿 추가
enebin Apr 30, 2026
10bb244
feat: 매일 식단 기록 리마인더 로컬 푸시 등록 기능 추가
kanghun1121 Apr 30, 2026
2901677
refactor: AppDelegate 알림 분기에 daily_reminder 처리 추가
kanghun1121 Apr 30, 2026
85cac77
test: 매일 리마인더 관련 단위 테스트 추가
kanghun1121 Apr 30, 2026
74b29b6
feat: 공유하기 텍스트 하단에 뭐먹었지 링크 추가
kanghun1121 Jun 11, 2026
8f8d354
feat: 주간 캘린더에 오늘로 이동 버튼 추가
enebin Jun 11, 2026
a61e52f
chore: MARKETING_VERSION 1.1.1로 범프
enebin Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions .github/workflows/deploy-testflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ jobs:
RELEASE_XCCONFIG: ${{ secrets.RELEASE_XCCONFIG }}
run: |
mkdir -p Configs
echo "$RELEASE_XCCONFIG" | grep -v -E 'CURRENT_PROJECT_VERSION|MARKETING_VERSION' > Configs/release.xcconfig
echo "$RELEASE_XCCONFIG" | grep -v -E 'CURRENT_PROJECT_VERSION|MARKETING_VERSION|PROVISIONING_PROFILE_SPECIFIER|CODE_SIGN_IDENTITY' > Configs/release.xcconfig
echo "PROVISIONING_PROFILE_SPECIFIER = FoodDiary-Distribution" >> Configs/release.xcconfig
echo "CODE_SIGN_IDENTITY = iPhone Distribution" >> Configs/release.xcconfig
echo "// Debug Configuration (CI)" > Configs/debug.xcconfig

- name: Create GoogleService-Info.plist
Expand Down Expand Up @@ -151,10 +153,17 @@ jobs:
- name: Archive
run: |
set -o pipefail

BUILD_NUMBER=$(date -u +'%y%m%d')${{ github.run_number }}

MARKETING_VERSION=$(grep 'MARKETING_VERSION' FoodDiary/App/Project.swift | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')
if [ -z "$MARKETING_VERSION" ]; then
echo "::error::MARKETING_VERSION 추출 실패"
exit 1
fi

ARCHIVE_PATH=$RUNNER_TEMP/App.xcarchive

xcodebuild archive \
-workspace Workspace.xcworkspace \
-scheme release \
Expand All @@ -169,8 +178,11 @@ jobs:
OTHER_CODE_SIGN_FLAGS="--keychain ${{ env.KEYCHAIN_PATH }}" \
2>&1 | tee "$RUNNER_TEMP/archive.log" | xcpretty --color

# 아카이브에서 버전 추출
VERSION=$(/usr/libexec/PlistBuddy -c "Print :ApplicationProperties:CFBundleShortVersionString" "$ARCHIVE_PATH/Info.plist")
if [ -z "$VERSION" ]; then
echo "::error::VERSION 추출 실패"
exit 1
fi

echo "ARCHIVE_PATH=$ARCHIVE_PATH" >> $GITHUB_ENV
echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_ENV
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ buildServer.json
.cursor/rules/
.claude/
.codex/
.mcp.json
Binary file added Assets/appicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 25 additions & 2 deletions FoodDiary/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,32 @@ let project = Project(
destinations: [.iPhone],
product: .app,
bundleId: "com.fooddiary.ios.app",
deploymentTargets: .iOS("18.0"),
deploymentTargets: .iOS("26.0"),
infoPlist: .sceneDelegateApp(),
sources: ["Sources/**"],
resources: ["Resources/**"],
entitlements: "App.entitlements",
scripts: [
.post(
script: """
if [[ "$(uname -m)" == arm64 ]]; then
export PATH="/opt/homebrew/bin:$PATH"
fi
if which sentry-cli >/dev/null; then
export SENTRY_ORG=mumuk-cs
export SENTRY_PROJECT=mumuk-ios
export SENTRY_AUTH_TOKEN="${SENTRY_AUTH_TOKEN}"
ERROR=$(sentry-cli debug-files upload "$DWARF_DSYM_FOLDER_PATH" 2>&1 >/dev/null)
if [ ! $? -eq 0 ]; then
echo "warning: sentry-cli - $ERROR"
fi
else
echo "warning: sentry-cli not installed, download from https://github.com/getsentry/sentry-cli/releases"
fi
""",
name: "Upload dSYM to Sentry"
)
],
dependencies: [
.project(target: "Data", path: "../Data"),
.project(target: "DesignSystem", path: "../DesignSystem"),
Expand All @@ -30,11 +51,13 @@ let project = Project(
.project(target: "Presentation", path: "../Presentation"),
.external(name: "FirebaseCore"),
.external(name: "FirebaseMessaging"),
.external(name: "Sentry"),
],
settings: .settings(
base: [
"MARKETING_VERSION": "1.0.0",
"MARKETING_VERSION": "1.1.1",
"BASE_URL": "$(BASE_URL)",
"SENTRY_DSN": "$(SENTRY_DSN)",
"TARGETED_DEVICE_FAMILY": "1"
],
configurations: []
Expand Down
97 changes: 97 additions & 0 deletions FoodDiary/App/Sources/AppCoordinator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//
// AppCoordinator.swift
// App
//
// Created by 강대훈 on 4/8/26.
//

import Domain
import Presentation
import UIKit

final class AppCoordinator: Coordinator {
var childCoordinators: [any Coordinator] = []

weak var sceneTransitioner: SceneTransitioning?
private let factories: Factories

init(factories: Factories) {
self.factories = factories
}
}

// MARK: - Screen Routing

extension AppCoordinator {
func pushLoginVC() {
childCoordinators.removeAll()

let loginCoordinator = LoginCoordinator(factories: factories)
loginCoordinator.sceneTransitioner = sceneTransitioner
loginCoordinator.parentCoordinator = self
addChild(loginCoordinator)

loginCoordinator.start()
}

func pushMainVC() {
childCoordinators.removeAll()

let mainCoordinator = MainCoordinator(factories: factories)
mainCoordinator.sceneTransitioner = sceneTransitioner
mainCoordinator.parentCoordinator = self
addChild(mainCoordinator)

mainCoordinator.start()
}

func navigateToDetail(diaryDateString: String) {
performDeepLinkNavigation(diaryDateString: diaryDateString)
}
}

// MARK: - Permission

extension AppCoordinator {
func presentPermissionVC(from presenter: UIViewController) {
let coord = PermissionCoordinator(factories: factories, presentingViewController: presenter)
coord.parentCoordinator = self
addChild(coord)
coord.start()
}
}

// MARK: - Deep Link Navigation

extension AppCoordinator {
private static let deepLinkDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()

private func performDeepLinkNavigation(diaryDateString: String) {
guard let date = Self.deepLinkDateFormatter.date(from: diaryDateString) else {
print("[DeepLink] 날짜 파싱 실패: \(diaryDateString)")
return
}

let navController = childCoordinators
.compactMap({ $0 as? MainCoordinator })
.last?.navigationController

let input = DetailSceneInput(date: date, records: [])
let coord = DetailCoordinator(factories: factories, navigationController: navController)
coord.parentCoordinator = self
addChild(coord)

if let presented = navController?.presentedViewController {
presented.dismiss(animated: false) {
coord.start(input: input)
}
} else {
coord.start(input: input)
}
}
}
24 changes: 20 additions & 4 deletions FoodDiary/App/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import UIKit
import UserNotifications
import FirebaseCore
import FirebaseMessaging
import Sentry
import Domain
import Data
import DI
Expand All @@ -18,13 +19,23 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
logBuildConfiguration()
configureSentry()
FirebaseApp.configure()
Messaging.messaging().delegate = self
setupAppearance()
UNUserNotificationCenter.current().delegate = self
return true
}

private func configureSentry() {
guard let dsn = Bundle.main.infoDictionary?["SENTRY_DSN"] as? String, !dsn.isEmpty else { return }
SentrySDK.start { options in
options.dsn = dsn
options.debug = false
options.tracesSampleRate = 0.2
}
}

private func logBuildConfiguration() {
#if DEBUG
print("[App] 빌드 설정: DEBUG")
Expand Down Expand Up @@ -130,8 +141,10 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
) {
let userInfo = response.notification.request.content.userInfo

if userInfo["is_local_notification"] as? Bool == true {
// 로컬 알림 탭 → 딥링크로 상세 화면 이동
if userInfo["notification_type"] as? String == "daily_reminder" {
// 매일 리마인더 탭 → 앱이 열리는 기본 동작만 수행
} else if userInfo["is_local_notification"] as? Bool == true {
// 분석 완료 로컬 알림 탭 → 딥링크로 상세 화면 이동
if let diaryDate = userInfo["diary_date"] as? String {
NotificationCenter.default.post(
name: AppNotification.Push.deepLinkToDetail,
Expand All @@ -153,8 +166,11 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
) {
let userInfo = notification.request.content.userInfo

if userInfo["is_local_notification"] as? Bool == true {
// 로컬 알림이 포그라운드에서 도착 → 배너 표시 안 함 (토스트로 이미 처리됨)
if userInfo["notification_type"] as? String == "daily_reminder" {
// 매일 리마인더가 포그라운드에 도착 → 배너 표시 안 함 (이미 앱 사용 중)
completionHandler([])
} else if userInfo["is_local_notification"] as? Bool == true {
// 분석 완료 로컬 알림이 포그라운드에서 도착 → 배너 표시 안 함 (토스트로 이미 처리됨)
completionHandler([])
} else {
handlePushNotification(userInfo)
Expand Down
Loading
Loading