From e351d1f8ff4fd46e5115ab998d1407e8a3d650ae Mon Sep 17 00:00:00 2001 From: opficdev <162981733+opficdev@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:08:02 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20u?= =?UTF-8?q?psert=EC=97=90=20Firestore=20transaction=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Service/UserServiceImpl.swift | 137 +++++++++++------- 1 file changed, 82 insertions(+), 55 deletions(-) diff --git a/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift b/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift index 8e1c827a..5888cade 100644 --- a/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift @@ -36,12 +36,6 @@ final class UserServiceImpl: UserService { } do { - let userRef = store.document(FirestorePath.user(user.uid)) - let infoRef = store.document(FirestorePath.userData(user.uid, document: .info)) - let tokensRef = store.document(FirestorePath.userData(user.uid, document: .tokens)) - let settingsRef = store.document(FirestorePath.userData(user.uid, document: .settings)) - let todoCounterRef = store.document(FirestorePath.counter(user.uid, document: .todo)) - // 사용자 기본 정보 var userField: [String: Any] = [ "currentProvider": response.providerID @@ -62,64 +56,22 @@ final class UserServiceImpl: UserService { userField["appleName"] = user.displayName } - let userDocument = try await userRef.getDocument() - if !userDocument.exists { - userField["statusMsg"] = "" - userField["createdAt"] = FieldValue.serverTimestamp() - } - - var settingField: [String: Any] = [:] + var tokenField: [String: Any] = [:] if let fcmToken = response.fcmToken { - settingField["fcmToken"] = fcmToken + tokenField["fcmToken"] = fcmToken } // 깃헙 로그인 시 추가 정보 저장 if response.providerID == "github.com", let accessToken = response.accessToken { - settingField["githubAccessToken"] = accessToken + tokenField["githubAccessToken"] = accessToken } - // Reference to capture ~ in concurrently-executing code; Swift 6 lang mode의 경고 해결 - let userFieldSnapshot = userField - let settingFieldSnapshot = settingField - // ----------------------------------------------------- - - async let userUpdate: Void = userRef.setData( - ["updatedAt": FieldValue.serverTimestamp()], - merge: true + try await upsertUserDocuments( + uid: user.uid, + userField: userField, + tokenField: tokenField ) - async let infoUpdate: Void = infoRef.setData(userFieldSnapshot, merge: true) - async let tokensUpdate: Void = { - guard !settingFieldSnapshot.isEmpty else { return } - try await tokensRef.setData(settingFieldSnapshot, merge: true) - }() - - let settingsDocument = try await settingsRef.getDocument() - var settingsField: [String: Any] = [ - "timeZone": TimeZone.autoupdatingCurrent.identifier - ] - if !settingsDocument.exists { - settingsField["allowPushNotification"] = true - settingsField["pushNotificationHour"] = 9 - settingsField["pushNotificationMinute"] = 0 - } - - let settingsFieldSnapshot = settingsField - async let settingsUpdate: Void = settingsRef.setData(settingsFieldSnapshot, merge: true) - async let todoCounterUpdate: Void? = { // 옵셔널이 포함된 이유: 신규 사용자일 때만 할 작업 - guard !userDocument.exists else { return nil } - - try await todoCounterRef.setData( - [ - "nextNumber": 1, - "updatedAt": FieldValue.serverTimestamp() - ], - merge: true - ) - return nil - }() - - _ = try await (userUpdate, infoUpdate, tokensUpdate, settingsUpdate, todoCounterUpdate) logger.info("Successfully upserted user: \(user.uid)") } catch { @@ -241,4 +193,79 @@ private extension UserServiceImpl { private func record(_ error: Error, code: CrashlyticsError.Code) { Self.record(error, code: code) } + + func upsertUserDocuments( + uid: String, + userField: [String: Any], + tokenField: [String: Any] + ) async throws { + let userRef = store.document(FirestorePath.user(uid)) + let infoRef = store.document(FirestorePath.userData(uid, document: .info)) + let tokensRef = store.document(FirestorePath.userData(uid, document: .tokens)) + let settingsRef = store.document(FirestorePath.userData(uid, document: .settings)) + let todoCounterRef = store.document(FirestorePath.counter(uid, document: .todo)) + + try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in + store.runTransaction({ transaction, errorPointer in + let userDocument: DocumentSnapshot + let settingsDocument: DocumentSnapshot + + do { + userDocument = try transaction.getDocument(userRef) + settingsDocument = try transaction.getDocument(settingsRef) + } catch let error as NSError { + errorPointer?.pointee = error + return nil + } + + var infoField = userField + if !userDocument.exists { + infoField["statusMsg"] = "" + infoField["createdAt"] = FieldValue.serverTimestamp() + } + + var settingsField: [String: Any] = [ + "timeZone": TimeZone.autoupdatingCurrent.identifier + ] + if !settingsDocument.exists { + settingsField["allowPushNotification"] = true + settingsField["pushNotificationHour"] = 9 + settingsField["pushNotificationMinute"] = 0 + } + + transaction.setData( + ["updatedAt": FieldValue.serverTimestamp()], + forDocument: userRef, + merge: true + ) + transaction.setData(infoField, forDocument: infoRef, merge: true) + + if !tokenField.isEmpty { + transaction.setData(tokenField, forDocument: tokensRef, merge: true) + } + + transaction.setData(settingsField, forDocument: settingsRef, merge: true) + + if !userDocument.exists { + transaction.setData( + [ + "nextNumber": 1, + "updatedAt": FieldValue.serverTimestamp() + ], + forDocument: todoCounterRef, + merge: true + ) + } + + return nil + }) { _, error in + if let error { + continuation.resume(throwing: error) + return + } + + continuation.resume(returning: ()) + } + } + } } From a97dd2e53f5de42e6ffdb91975e4b9cee4cc5a4c Mon Sep 17 00:00:00 2001 From: opficdev <162981733+opficdev@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:08:54 +0900 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20=EC=95=8C=EB=A6=BC=20=EC=9D=BD?= =?UTF-8?q?=EC=9D=8C=20=ED=86=A0=EA=B8=80=EC=97=90=20Firestore=20transacti?= =?UTF-8?q?on=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Service/PushNotificationServiceImpl.swift | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift b/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift index ece2ad88..fee81b11 100644 --- a/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift @@ -274,12 +274,7 @@ final class PushNotificationServiceImpl: PushNotificationService { throw FirestoreError.dataNotFound("notification") } - guard let currentValue = document.data()["isRead"] as? Bool else { - logger.error("isRead not found for notification: \(document.documentID)") - throw FirestoreError.dataNotFound("isRead") - } - - try await document.reference.updateData(["isRead": !currentValue]) + try await toggleReadValue(for: document.reference) logger.info("Successfully toggled notification read") } catch { logger.error("Failed to toggle notification read", error: error) @@ -302,6 +297,32 @@ private extension PushNotificationServiceImpl { Self.record(error, code: code) } + func toggleReadValue(for notificationRef: DocumentReference) async throws { + try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in + store.runTransaction({ transaction, errorPointer in + do { + let snapshot = try transaction.getDocument(notificationRef) + guard let currentValue = snapshot.data()?["isRead"] as? Bool else { + throw FirestoreError.dataNotFound("isRead") + } + + transaction.updateData(["isRead": !currentValue], forDocument: notificationRef) + } catch let error as NSError { + errorPointer?.pointee = error + } + + return nil + }) { _, error in + if let error { + continuation.resume(throwing: error) + return + } + + continuation.resume(returning: ()) + } + } + } + func makeQuery( uid: String, query: PushNotificationQuery From 10759ebfed87f665654d219f10a29cac029c0297 Mon Sep 17 00:00:00 2001 From: opficdev <162981733+opficdev@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:09:13 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor:=20Apple=20refresh=20token=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=EC=97=90=20Firestore=20transaction=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppleAuthenticationServiceImpl.swift | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift b/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift index 40e394b6..64b12d66 100644 --- a/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift @@ -197,15 +197,8 @@ final class AppleAuthenticationServiceImpl: AuthenticationService { let tokensRef = store.document(FirestorePath.userData(uid, document: .tokens)) - logger.info("Starting Apple token document fetch for unlink. uid: \(uid)") - let doc = try await tokensRef.getDocument() - - if doc.exists { - logger.info("Starting Apple refresh token deletion from Firestore for unlink. uid: \(uid)") - try await tokensRef.updateData([ - "appleRefreshToken": FieldValue.delete() - ]) - } + logger.info("Starting Apple refresh token deletion from Firestore for unlink. uid: \(uid)") + try await deleteAppleRefreshToken(from: tokensRef) logger.info("Starting Firebase Apple provider unlink. uid: \(uid)") _ = try await user?.unlink(fromProvider: providerID.rawValue) @@ -337,6 +330,37 @@ final class AppleAuthenticationServiceImpl: AuthenticationService { } private extension AppleAuthenticationServiceImpl { + func deleteAppleRefreshToken(from tokensRef: DocumentReference) async throws { + try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in + store.runTransaction({ transaction, errorPointer in + let snapshot: DocumentSnapshot + + do { + snapshot = try transaction.getDocument(tokensRef) + } catch let error as NSError { + errorPointer?.pointee = error + return nil + } + + if snapshot.exists { + transaction.updateData( + ["appleRefreshToken": FieldValue.delete()], + forDocument: tokensRef + ) + } + + return nil + }) { _, error in + if let error { + continuation.resume(throwing: error) + return + } + + continuation.resume(returning: ()) + } + } + } + private static func record(_ error: Error, code: CrashlyticsError.Code) { FirebaseCrashlyticsHelper.record( error, From 3e22f40fa07d5a2f66754046b45b5cf21c5cd3df Mon Sep 17 00:00:00 2001 From: opficdev <162981733+opficdev@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:21:07 +0900 Subject: [PATCH 4/6] =?UTF-8?q?chore:=20=EC=BB=A4=EB=B0=8B=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=ED=99=95=EC=9D=B8=20=EC=A7=80=EC=B9=A8?= =?UTF-8?q?=EC=9D=84=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../references/devlog-workflow-rules.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.hermes/skills/devlog-architecture-harness/references/devlog-workflow-rules.md b/.hermes/skills/devlog-architecture-harness/references/devlog-workflow-rules.md index 095d22e6..071d1501 100644 --- a/.hermes/skills/devlog-architecture-harness/references/devlog-workflow-rules.md +++ b/.hermes/skills/devlog-architecture-harness/references/devlog-workflow-rules.md @@ -45,6 +45,7 @@ This reference holds DevLog-specific working rules that should live with the pro - If the user says they will commit or asks only for a commit message, provide commit-message guidance instead of committing. - Before proposing a commit message, inspect the actual diff and recent `git log`. +- When recent history contains GitHub merge commits, do not infer commit-message style from merge subjects such as `[#123] ... (#456)`. Open the merge commit with `git show --no-patch --format=full ` and use the individual commit messages in the body, or inspect nearby non-merge commits. - Match the repository's current Korean style and prefix pattern. - If the user explicitly specifies a prefix or noun-phrase ending, follow it exactly. - For broad architecture refactors, split commits by layer when the user asks for staged commits. From 396864dc007fd496eca8970602f63a963a9bd40b Mon Sep 17 00:00:00 2001 From: opficdev <162981733+opficdev@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:34:43 +0900 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20Firestore=20transaction=20?= =?UTF-8?q?=EB=B9=84=EB=8F=99=EA=B8=B0=20=EC=B2=98=EB=A6=AC=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Service/PushNotificationServiceImpl.swift | 29 ++---- .../AppleAuthenticationServiceImpl.swift | 37 +++---- .../Sources/Service/TodoServiceImpl.swift | 87 ++++++++-------- .../Sources/Service/UserServiceImpl.swift | 99 +++++++++---------- 4 files changed, 108 insertions(+), 144 deletions(-) diff --git a/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift b/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift index fee81b11..7d5a9740 100644 --- a/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift @@ -298,28 +298,19 @@ private extension PushNotificationServiceImpl { } func toggleReadValue(for notificationRef: DocumentReference) async throws { - try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - store.runTransaction({ transaction, errorPointer in - do { - let snapshot = try transaction.getDocument(notificationRef) - guard let currentValue = snapshot.data()?["isRead"] as? Bool else { - throw FirestoreError.dataNotFound("isRead") - } - - transaction.updateData(["isRead": !currentValue], forDocument: notificationRef) - } catch let error as NSError { - errorPointer?.pointee = error + _ = try await store.runTransaction { transaction, errorPointer in + do { + let snapshot = try transaction.getDocument(notificationRef) + guard let currentValue = snapshot.data()?["isRead"] as? Bool else { + throw FirestoreError.dataNotFound("isRead") } - return nil - }) { _, error in - if let error { - continuation.resume(throwing: error) - return - } - - continuation.resume(returning: ()) + transaction.updateData(["isRead": !currentValue], forDocument: notificationRef) + } catch let error as NSError { + errorPointer?.pointee = error } + + return nil } } diff --git a/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift b/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift index 64b12d66..2ed89436 100644 --- a/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/SocialLogin/AppleAuthenticationServiceImpl.swift @@ -331,33 +331,24 @@ final class AppleAuthenticationServiceImpl: AuthenticationService { private extension AppleAuthenticationServiceImpl { func deleteAppleRefreshToken(from tokensRef: DocumentReference) async throws { - try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - store.runTransaction({ transaction, errorPointer in - let snapshot: DocumentSnapshot - - do { - snapshot = try transaction.getDocument(tokensRef) - } catch let error as NSError { - errorPointer?.pointee = error - return nil - } - - if snapshot.exists { - transaction.updateData( - ["appleRefreshToken": FieldValue.delete()], - forDocument: tokensRef - ) - } + _ = try await store.runTransaction { transaction, errorPointer in + let snapshot: DocumentSnapshot + do { + snapshot = try transaction.getDocument(tokensRef) + } catch let error as NSError { + errorPointer?.pointee = error return nil - }) { _, error in - if let error { - continuation.resume(throwing: error) - return - } + } - continuation.resume(returning: ()) + if snapshot.exists { + transaction.updateData( + ["appleRefreshToken": FieldValue.delete()], + forDocument: tokensRef + ) } + + return nil } } diff --git a/Application/DevLogInfra/Sources/Service/TodoServiceImpl.swift b/Application/DevLogInfra/Sources/Service/TodoServiceImpl.swift index 12aae818..9fea958d 100644 --- a/Application/DevLogInfra/Sources/Service/TodoServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/TodoServiceImpl.swift @@ -348,66 +348,57 @@ private extension TodoServiceImpl { for todoRef: DocumentReference, counterRef: DocumentReference ) async throws { - try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - store.runTransaction({ transaction, errorPointer in - let todoSnapshot: DocumentSnapshot + _ = try await store.runTransaction { transaction, errorPointer in + let todoSnapshot: DocumentSnapshot + + do { + todoSnapshot = try transaction.getDocument(todoRef) + } catch let error as NSError { + errorPointer?.pointee = error + return nil + } + + var todoData = data + + if !todoSnapshot.exists { + let counterSnapshot: DocumentSnapshot do { - todoSnapshot = try transaction.getDocument(todoRef) + counterSnapshot = try transaction.getDocument(counterRef) } catch let error as NSError { errorPointer?.pointee = error return nil } - var todoData = data - - if !todoSnapshot.exists { - let counterSnapshot: DocumentSnapshot - - do { - counterSnapshot = try transaction.getDocument(counterRef) - } catch let error as NSError { - errorPointer?.pointee = error - return nil - } - - let nextNumberValue = counterSnapshot.data()?[CounterFieldKey.nextNumber.rawValue] - let nextNumber: Int - - if let storedNextNumber = nextNumberValue as? Int { - nextNumber = storedNextNumber - } else if counterSnapshot.exists { - errorPointer?.pointee = NSError( - domain: "TodoServiceImpl", - code: 1, - userInfo: [NSLocalizedDescriptionKey: "Todo counter is invalid."] - ) - return nil - } else { - nextNumber = 1 - } + let nextNumberValue = counterSnapshot.data()?[CounterFieldKey.nextNumber.rawValue] + let nextNumber: Int - todoData[TodoFieldKey.number.rawValue] = nextNumber - transaction.setData( - [ - CounterFieldKey.nextNumber.rawValue: nextNumber + 1, - CounterFieldKey.updatedAt.rawValue: FieldValue.serverTimestamp() - ], - forDocument: counterRef, - merge: true + if let storedNextNumber = nextNumberValue as? Int { + nextNumber = storedNextNumber + } else if counterSnapshot.exists { + errorPointer?.pointee = NSError( + domain: "TodoServiceImpl", + code: 1, + userInfo: [NSLocalizedDescriptionKey: "Todo counter is invalid."] ) + return nil + } else { + nextNumber = 1 } - transaction.setData(todoData, forDocument: todoRef, merge: true) - return nil - }) { _, error in - if let error { - continuation.resume(throwing: error) - return - } - - continuation.resume(returning: ()) + todoData[TodoFieldKey.number.rawValue] = nextNumber + transaction.setData( + [ + CounterFieldKey.nextNumber.rawValue: nextNumber + 1, + CounterFieldKey.updatedAt.rawValue: FieldValue.serverTimestamp() + ], + forDocument: counterRef, + merge: true + ) } + + transaction.setData(todoData, forDocument: todoRef, merge: true) + return nil } } diff --git a/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift b/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift index 5888cade..0cf2df5c 100644 --- a/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/UserServiceImpl.swift @@ -205,67 +205,58 @@ private extension UserServiceImpl { let settingsRef = store.document(FirestorePath.userData(uid, document: .settings)) let todoCounterRef = store.document(FirestorePath.counter(uid, document: .todo)) - try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in - store.runTransaction({ transaction, errorPointer in - let userDocument: DocumentSnapshot - let settingsDocument: DocumentSnapshot - - do { - userDocument = try transaction.getDocument(userRef) - settingsDocument = try transaction.getDocument(settingsRef) - } catch let error as NSError { - errorPointer?.pointee = error - return nil - } - - var infoField = userField - if !userDocument.exists { - infoField["statusMsg"] = "" - infoField["createdAt"] = FieldValue.serverTimestamp() - } - - var settingsField: [String: Any] = [ - "timeZone": TimeZone.autoupdatingCurrent.identifier - ] - if !settingsDocument.exists { - settingsField["allowPushNotification"] = true - settingsField["pushNotificationHour"] = 9 - settingsField["pushNotificationMinute"] = 0 - } + _ = try await store.runTransaction { transaction, errorPointer in + let userDocument: DocumentSnapshot + let settingsDocument: DocumentSnapshot + + do { + userDocument = try transaction.getDocument(userRef) + settingsDocument = try transaction.getDocument(settingsRef) + } catch let error as NSError { + errorPointer?.pointee = error + return nil + } - transaction.setData( - ["updatedAt": FieldValue.serverTimestamp()], - forDocument: userRef, - merge: true - ) - transaction.setData(infoField, forDocument: infoRef, merge: true) + var infoField = userField + if !userDocument.exists { + infoField["statusMsg"] = "" + infoField["createdAt"] = FieldValue.serverTimestamp() + } - if !tokenField.isEmpty { - transaction.setData(tokenField, forDocument: tokensRef, merge: true) - } + var settingsField: [String: Any] = [ + "timeZone": TimeZone.autoupdatingCurrent.identifier + ] + if !settingsDocument.exists { + settingsField["allowPushNotification"] = true + settingsField["pushNotificationHour"] = 9 + settingsField["pushNotificationMinute"] = 0 + } - transaction.setData(settingsField, forDocument: settingsRef, merge: true) + transaction.setData( + ["updatedAt": FieldValue.serverTimestamp()], + forDocument: userRef, + merge: true + ) + transaction.setData(infoField, forDocument: infoRef, merge: true) - if !userDocument.exists { - transaction.setData( - [ - "nextNumber": 1, - "updatedAt": FieldValue.serverTimestamp() - ], - forDocument: todoCounterRef, - merge: true - ) - } + if !tokenField.isEmpty { + transaction.setData(tokenField, forDocument: tokensRef, merge: true) + } - return nil - }) { _, error in - if let error { - continuation.resume(throwing: error) - return - } + transaction.setData(settingsField, forDocument: settingsRef, merge: true) - continuation.resume(returning: ()) + if !userDocument.exists { + transaction.setData( + [ + "nextNumber": 1, + "updatedAt": FieldValue.serverTimestamp() + ], + forDocument: todoCounterRef, + merge: true + ) } + + return nil } } } From f7239186cdc81f49fe9a34de1803896e426c6d51 Mon Sep 17 00:00:00 2001 From: opficdev <162981733+opficdev@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:48:36 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20=EC=95=8C=EB=A6=BC=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=20=EC=97=90=EB=9F=AC=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=ED=9D=90=EB=A6=84=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Service/PushNotificationServiceImpl.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift b/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift index 7d5a9740..7b37318b 100644 --- a/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift +++ b/Application/DevLogInfra/Sources/Service/PushNotificationServiceImpl.swift @@ -308,6 +308,7 @@ private extension PushNotificationServiceImpl { transaction.updateData(["isRead": !currentValue], forDocument: notificationRef) } catch let error as NSError { errorPointer?.pointee = error + return nil } return nil