Skip to content

[#272] Todo를 제거한 후 해당 Todo에 대한 푸시알림 데이터가 일정 시간 그대로 유지되는 이슈를 해결한다#274

Merged
opficdev merged 10 commits intodevelopfrom
fix/#272-delay-after-delete-todo
Mar 15, 2026
Merged

[#272] Todo를 제거한 후 해당 Todo에 대한 푸시알림 데이터가 일정 시간 그대로 유지되는 이슈를 해결한다#274
opficdev merged 10 commits intodevelopfrom
fix/#272-delay-after-delete-todo

Conversation

@opficdev
Copy link
Copy Markdown
Owner

@opficdev opficdev self-assigned this Mar 15, 2026
@opficdev opficdev marked this pull request as ready for review March 15, 2026 11:35
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 풀 리퀘스트는 Todo를 삭제한 후에도 해당 Todo에 대한 푸시 알림 데이터가 일정 시간 동안 그대로 유지되어 사용자에게 혼란을 줄 수 있었던 문제를 해결합니다. Todo 삭제 시 5초의 유예 기간을 두어 사용자가 삭제를 취소할 수 있도록 하는 소프트 삭제 메커니즘을 도입했으며, 이 과정에서 푸시 알림 데이터도 즉시 업데이트되도록 개선했습니다. 핵심 로직은 Firebase Cloud Functions를 통해 구현되어 서버 측에서 안전하고 효율적으로 처리됩니다.

Highlights

  • 지연된 Todo 삭제 및 취소 기능 구현: Todo 삭제 시 즉시 삭제되지 않고 일정 시간(5초) 동안 유예되며, 이 기간 동안 삭제를 취소할 수 있는 기능이 추가되었습니다. 이는 사용자 경험을 개선하고 실수로 인한 데이터 손실을 방지합니다.
  • 푸시 알림 데이터 동기화 개선: Todo가 삭제 유예 상태일 때 해당 Todo와 관련된 푸시 알림 데이터가 즉시 비활성화되도록 로직이 변경되었습니다. 이를 통해 삭제된 Todo에 대한 알림이 잘못 전송되는 문제를 해결합니다.
  • Firebase Cloud Functions 활용: Todo 삭제 및 삭제 취소 로직이 Firebase Cloud Functions를 통해 서버리스 방식으로 처리되도록 변경되었습니다. 이는 클라이언트의 부담을 줄이고 데이터 일관성을 강화합니다.
  • 의존성 주입 구조 리팩토링: 영속성(Persistence) 관련 서비스들의 의존성 주입을 위한 PersistenceAssembler가 새로 추가되어, DI 컨테이너의 역할 분담이 명확해지고 코드의 모듈성이 향상되었습니다.
  • 불필요한 Xcode 유닛 테스트 타겟 제거: 사용되지 않는 DevLog_Unit 유닛 테스트 타겟 및 관련 파일들이 Xcode 프로젝트에서 제거되어 프로젝트 설정이 간소화되었습니다.
Changelog
  • DevLog.xcodeproj/project.pbxproj
    • Firebase functions, TypeScript 파일, 그리고 DevLog_Unit 테스트 타겟에 대한 참조를 제거했습니다.
    • Xcode 프로젝트 파일에서 불필요한 빌드 파일 및 파일 참조를 정리했습니다.
    • PBXFileSystemSynchronizedRootGroup, PBXFrameworksBuildPhase, PBXGroup, PBXNativeTarget, PBXResourcesBuildPhase, PBXSourcesBuildPhase, XCBuildConfiguration, XCConfigurationList 섹션에서 DevLog_Unit 관련 항목을 삭제했습니다.
  • DevLog/App/Assembler/Assembler.swift
    • 애플리케이션의 의존성 주입 설정에 PersistenceAssembler를 추가했습니다.
  • DevLog/App/Assembler/DomainAssembler.swift
    • 도메인 레이어에 UndoDeleteTodoUseCase를 등록했습니다.
  • DevLog/App/Assembler/InfraAssembler.swift
    • 영속성 관련 서비스 등록을 제거하고, 이를 새로운 PersistenceAssembler로 위임했습니다.
  • DevLog/App/Assembler/PersistenceAssembler.swift
    • UserDefaultsStore 및 ThemeStore와 같은 영속성 관련 서비스들을 위한 새로운 어셈블러를 추가했습니다.
  • DevLog/Data/Repository/TodoRepositoryImpl.swift
    • Todo 서비스와 상호작용하는 undoDeleteTodo 메서드를 구현했습니다.
  • DevLog/Domain/Protocol/TodoRepository.swift
    • TodoRepository 프로토콜에 undoDeleteTodo 메서드를 추가했습니다.
  • DevLog/Domain/UseCase/Todo/Delete/UndoDeleteTodoUseCase.swift
    • UndoDeleteTodoUseCase에 대한 프로토콜을 정의했습니다.
  • DevLog/Domain/UseCase/Todo/Delete/UndoDeleteTodoUseCaseImpl.swift
    • UndoDeleteTodoUseCase의 구현을 제공했습니다.
  • DevLog/Infra/Service/PushNotificationService.swift
    • 알림 처리 로직을 업데이트하여 삭제 보류 중인 항목에 대한 알림을 필터링하고 'deletingAt' 키를 추가했습니다.
  • DevLog/Infra/Service/TodoService.swift
    • 지연된 Todo 삭제 및 취소 기능을 위해 Firebase Functions를 통합하고, 삭제 보류 중인 Todo를 필터링했습니다.
    • FirebaseFunctions를 임포트하고 FirebaseFunctions 인스턴스를 초기화했습니다.
    • deleteTodo 메서드를 Firebase Cloud Function 'requestTodoDeletion'을 호출하도록 변경했습니다.
    • undoDeleteTodo 메서드를 추가하여 Firebase Cloud Function 'undoTodoDeletion'을 호출하도록 했습니다.
    • makeResponse 메서드를 수정하여 'deletingAt' 타임스탬프가 있는 Todo는 응답에서 제외하도록 했습니다.
    • TodoFieldKey 열거형에 'deletingAt' 케이스를 추가했습니다.
  • DevLog/Presentation/ViewModel/TodoListViewModel.swift
    • 지연된 Todo 삭제, 취소 기능, 그리고 이러한 작업에 대한 UI 상태 관리 로직을 구현했습니다.
    • Action 열거형에 'restoreTodo'와 'undoDelete' 케이스를 추가했습니다.
    • SideEffect 열거형에 'restoreTodo'와 'undoDelete' 케이스를 추가했습니다.
    • UndoDeleteTodoUseCase를 의존성으로 주입받도록 생성자를 업데이트했습니다.
    • reduceByRun 메서드에서 'undoDelete' SideEffect를 처리하는 로직을 추가했습니다.
    • reduceByView 메서드에서 'swipeTodo' 시 'delete' SideEffect를 발생시키도록 변경했습니다.
    • reduceByRun 메서드에서 'restoreTodo' SideEffect를 처리하는 로직을 추가했습니다.
    • confirmDelete 액션에서 직접 삭제 SideEffect를 발생시키지 않도록 수정했습니다.
  • DevLog/UI/Home/HomeView.swift
    • Todo 목록 관리를 위해 새로운 UndoDeleteTodoUseCase를 TodoListViewModel에 주입했습니다.
  • DevLog_Unit/DevLog_Unit.swift
    • DevLog_Unit 테스트 파일을 제거했습니다.
  • Firebase/functions/src/fcm/notification.ts
    • 푸시 알림 전송 로직에 주석을 추가하여 가독성을 높였습니다.
  • Firebase/functions/src/index.ts
    • Todo 삭제와 관련된 새로운 Firebase Cloud Functions를 임포트하고 익스포트했습니다.
  • Firebase/functions/src/todo/deletion.ts
    • Todo 삭제 요청, 취소, 그리고 지연된 Todo 삭제 완료를 위한 Firebase Cloud Functions를 추가했습니다.
    • requestTodoDeletion: Todo 삭제를 요청하고 'deletingAt' 필드를 설정하며, 지연된 삭제 태스크를 큐에 추가합니다.
    • undoTodoDeletion: Todo 삭제 요청을 취소하고 'deletingAt' 필드를 제거하며, 관련 태스크를 삭제합니다.
    • completeTodoDeletion: 지연된 삭제 태스크에 의해 호출되어 Todo를 최종적으로 삭제합니다.
    • updateNotificationsDeletingAt: Todo와 관련된 알림 문서의 'deletingAt' 필드를 업데이트하는 헬퍼 함수를 추가했습니다.
Activity
  • 이 풀 리퀘스트는 제목에 명시된 이슈를 해결하며, 이슈 #272를 닫습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

이번 PR은 Todo 삭제 시 잠시 동안 삭제를 취소할 수 있는 기능을 추가하고, 이와 관련된 푸시 알림 데이터가 즉시 반영되지 않는 문제를 해결했습니다. 클라이언트(Swift)에서는 TodoListViewModel을 중심으로 상태 관리를 수정하여 삭제 취소 UI를 구현했고, 백엔드(Firebase Functions)에서는 deletingAt 필드를 이용한 'soft delete'와 지연된 최종 삭제 로직을 추가했습니다. 전체적으로 기능 구현이 잘 이루어졌으며, 몇 가지 유지보수성 및 잠재적 오류 개선을 위한 제안 사항을 코드 리뷰에 남겼습니다.

state.todos.insert(todo, at: index)
}
pendingTask = nil
return [.undoDelete(todo.id)]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

undoDelete 사이드 이펙트를 반환하는 것은 올바르지만, 바로 앞의 UI 상태 복원 로직에 잠재적인 버그가 있습니다. if index <= state.todos.count 조건문에서 indexstate.todos.count를 초과하는 경우에 대한 처리가 없습니다. 이 경우 todo 항목이 UI에 다시 표시되지 않게 됩니다. 예를 들어, 삭제 취소 토스트가 표시된 상태에서 목록이 새로고침되어 todos 배열의 크기가 변경되면 발생할 수 있습니다. else 블록을 추가하여 state.todos.append(todo)를 호출하는 것을 고려해 보세요.

Comment thread DevLog/Infra/Service/TodoService.swift Outdated
Comment on lines +181 to +198
let function = functions.httpsCallable("requestTodoDeletion")
_ = try await function.call(["todoId": todoId])

logger.info("Successfully deleted todo")
logger.info("Successfully requested todo deletion")
} catch {
logger.error("Failed to delete todo", error: error)
logger.error("Failed to request todo deletion", error: error)
throw error
}
}

func undoDeleteTodo(todoId: String) async throws {
guard Auth.auth().currentUser?.uid != nil else { throw AuthError.notAuthenticated }

logger.info("Undoing todo deletion: \(todoId)")

do {
let function = functions.httpsCallable("undoTodoDeletion")
_ = try await function.call(["todoId": todoId])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Firebase function 이름인 "requestTodoDeletion""undoTodoDeletion"이 문자열로 하드코딩되어 있습니다. 오타의 위험을 줄이고 유지보수성을 높이기 위해, 이 이름들을 별도의 상수로 정의하여 사용하는 것이 좋습니다. 예를 들어, private enum FunctionName { static let requestTodoDeletion = "requestTodoDeletion"; static let undoTodoDeletion = "undoTodoDeletion" } 와 같이 정의하고 사용할 수 있습니다.

guard let (item, _) = pendingTask else {
return []
}
pendingTask = nil
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

swipeTodo 시점에 삭제 요청이 시작되도록 로직이 변경되면서, .confirmDelete 액션의 역할도 변경되었습니다. 이제는 삭제를 '확인'하는 것이 아니라, 삭제 취소(undo)가 가능한 시간이 초과되었음을 처리하는 역할만 합니다. 이름이 현재 동작과 맞지 않아 혼란을 줄 수 있으니, commitDeletion 또는 undoTimedOut 과 같이 역할을 더 명확하게 나타내는 이름으로 변경하는 것을 고려해보세요.

Comment thread Firebase/functions/src/todo/deletion.ts Outdated

try {
await taskRef.set(taskData);
const todoRef = admin.firestore().doc(`users/${userId}/todoLists/${todoId}`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

requestTodoDeletion 함수 내에서 todoRef 상수가 여러 번 선언되고 있습니다(L34, L50, L81). 이는 변수 섀도잉(variable shadowing)을 유발하여 코드를 읽고 이해하기 어렵게 만들 수 있습니다. 함수 상단에서 한 번만 선언하고 계속 재사용하는 방식으로 리팩토링하는 것을 권장합니다.

@opficdev opficdev merged commit 88f88a3 into develop Mar 15, 2026
2 checks passed
@opficdev opficdev deleted the fix/#272-delay-after-delete-todo branch March 15, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Todo를 제거한 후 해당 Todo에 대한 푸시알림 데이터가 일정 시간 그대로 유지되는 이슈를 해결한다

1 participant