Flutter Sync Queue Aggressive Error Handling

Flutter Sync Queue에서 불필요한 에러가 반복 노출되는 문제 해결

모바일 앱에서 오프라인 동기화를 위해 Transactional Outbox 패턴을 구현하던 중, 동기화가 실제로는 정상 완료되었는데도 “동기화 실패” 에러가 반복적으로 사용자에게 노출되는 문제를 발견했다. 현상 앱에서 다음과 같은 에러가 반복적으로 발생했다: AppException: Failed to push changes: AppException: Push completed with failures; retry count: 2, pending changes remain in queue. 서버 로그를 확인하면 동기화 pull은 정상 동작하고, 실제 데이터도 이미 동기화된 상태였다. 구조 파악: Transactional Outbox 패턴 앱의 동기화 구조는 다음과 같다: ┌────────────────┐ ┌──────────────┐ ┌────────────────┐ │ Local DB │────▶│ Sync Queue │────▶│ Remote API │ │ (Drift/SQLite)│ │ (Outbox) │ │ (Rails) │ └────────────────┘ └──────────────┘ └────────────────┘ 로컬에서 데이터 변경 → sync queue에 pending 아이템 추가 performFullSync() 호출 시 pull → push 순서로 동기화 push 단계에서 queue의 각 아이템을 서버에 전송 성공하면 queue에서 제거, 실패하면 retry count 증가 원인 분석 _pushChanges() 메서드의 에러 처리 로직에 문제가 있었다: ...

2025-10-04 · 4분 소요 · Seunghan
Flutter Sso Localhost Rails Uninitialized Constant Debug

Flutter SSO 로그인 실패 + Rails 서버 크래시 동시 디버깅 기록

TestFlight에서 소셜 로그인(Apple, Google)이 전부 실패하는 버그를 잡다가 서버도 크래시되고 있다는 걸 같이 발견했다. 각각 원인이 달랐고 둘 다 잡아야 앱이 정상 동작했다. 증상 실기기(TestFlight)에서 Apple 로그인, Google 로그인 버튼을 누르면 다음 에러가 표시됐다: Apple 로그인 실패: DioException [connection error]: The connection errored: Connection refused This indicates an error which most likely cannot be solved by the library. Error: SocketException: Connection refused (OS Error: Connection refused, errno = 61), address = localhost, port = 56837 Google 로그인 실패: DioException [connection error]: ... address = localhost, port = 56839 두 가지가 이상했다: ...

2025-10-01 · 3분 소요 · Seunghan
Flutter Rails Auth Session Persistence Debugging

Flutter + Rails 인증 세션이 계속 풀리는 문제 - 3가지 원인과 해결

Flutter BLoC 앱에서 로그인을 해도 세션이 자꾸 풀린다. 분명 SecureStorage에 토큰도 저장하고, Dio 인터셉터로 401 시 자동 갱신도 구현했는데 왜? 서버 로그부터 시작해서 원인 3개를 찾고 모두 고친 과정을 정리한다. 기술 스택 모바일: Flutter + BLoC 패턴 + Dio HTTP + SecureStorage 서버: Rails 8 API + ActionCable WebSocket 인증: SHA-256 digest 기반 access token + JTI refresh token (90일) 실시간: ActionCable WebSocket (토큰 기반 인증) 증상 로그인 직후는 정상 동작 시간이 지나면 API 요청이 401로 실패 토큰 갱신은 되는 것 같은데 WebSocket이 끊어짐 결국 앱이 미인증 상태로 전환 원인 1: 레거시 코드의 유령 - DTA 잔존 메서드 발견 서버 로그에서 토큰 갱신 시 user.tokens 관련 에러가 간헐적으로 보였다. 이전에 devise_token_auth(DTA)를 사용하다가 자체 토큰 시스템으로 마이그레이션했는데, token_refresh_service.rb에 DTA 시절 코드가 남아 있었다. ...

2025-09-27 · 4분 소요 · Seunghan
Flutter Glassappbar Tabbar Overflow Colors White Lightmode

Flutter UI 전수조사 — GlassAppBar TabBar overflow와 Colors.white 라이트모드 버그

Flutter 앱을 어느 정도 만들다 보면 꼭 한 번씩 마주치는 두 가지 버그가 있다. 하나는 bottom overflowed by N pixels 에러, 다른 하나는 라이트모드에서 텍스트가 배경에 묻혀 보이지 않는 현상이다. 둘 다 원인은 단순한데, 전체 화면을 대상으로 전수조사하기 전까지는 “일부 화면에서 이상하다” 수준으로만 인식하기 쉽다. 이번에 앱 전체 50개 페이지를 한 번 훑어보고 나서야 패턴이 보였다. GlassAppBar + TabBar overflow의 진짜 원인 커스텀 GlassAppBar를 만들어서 쓰고 있었다. bottom: TabBar(...) 를 붙이면 AppBar 아래에 탭이 생기는 구조다. ...

2025-09-24 · 3분 소요 · Seunghan
Flutter Bloc Infinite Scroll Pagination

Flutter BLoC 무한스크롤 구현 — 외부 패키지 없이 레이어별로 설계하기

목록을 처음에 전부 로드하면 느리다. 사용자가 스크롤할수록 자연스럽게 다음 데이터를 불러오는 무한스크롤이 필요했다. infinite_scroll_pagination 같은 패키지도 있지만, 기존 BLoC 구조에 그대로 얹으려면 상태 설계를 패키지 방식에 맞춰야 해서 오히려 복잡해지는 경우가 있다. 외부 의존 없이 ScrollController만으로도 충분히 만들 수 있어서 그 방향으로 구현했다. 왜 Offset 기반인가 페이지네이션 방식은 두 가지다. Offset 기반 (page 번호) GET /items?page=1&per_page=20 GET /items?page=2&per_page=20 Cursor 기반 (마지막 아이템 ID) GET /items?cursor=abc123&per_page=20 Cursor 방식이 “데이터가 중간에 삽입/삭제돼도 중복/누락 없다"는 점에서 이론적으로 더 우수하다. 하지만 대상 데이터가 법령/규정처럼 자주 바뀌지 않는 정적 문서라면 Offset 방식으로 충분하다. ...

2025-09-20 · 5분 소요 · Seunghan
Sign In With Apple Testflight Entitlement Errors

Sign In with Apple 추가 후 TestFlight 빌드 에러 2연타 해결

Flutter iOS 앱에 Sign In with Apple을 추가하면서 TestFlight 빌드까지 두 가지 에러를 연달아 만났다. 각각 원인이 달라서 정리해둔다. 배경 Sign In with Apple을 활성화하려면 코드만 짜면 되는 게 아니다. Apple Developer Portal에서 App ID에 capability를 추가하고, 프로비저닝 프로파일을 반드시 재생성해야 한다. 기존 프로파일은 Sign In with Apple entitlement를 포함하지 않으므로 그냥 빌드하면 실패한다. 순서대로 하면: developer.apple.com → Identifiers → App ID 선택 Sign In with Apple 체크 → Edit → “Enable as a primary App ID” 선택 → Save Profiles → 기존 App Store 프로파일 Edit → Generate → Download 다운받은 .mobileprovision 파일을 ~/Library/MobileDevice/Provisioning Profiles/ 에 복사 여기까지 하면 준비 완료처럼 보이는데, 막상 flutter build ipa 를 돌리면 에러가 나온다. ...

2025-09-10 · 2분 소요 · Seunghan
Ios Sso Entitlements Testflight Errors

iOS TestFlight 배포 삽질 모음: SSO 에러부터 entitlements mismatch까지

Flutter 앱 여러 개를 TestFlight에 올리면서 반복적으로 마주친 에러들을 정리했다. 1. Apple Sign-In 에러 1000 SignInWithAppleAuthorizationException(AuthorizationErrorCode.unknown, The operation couldn't be completed. (com.apple.AuthenticationServices.AuthorizationError error 1000.)) 원인 Runner.entitlements에 Sign in with Apple capability가 없어서 발생한다. 해결 두 곳 모두 설정해야 한다. ① ios/Runner/Runner.entitlements <key>com.apple.developer.applesignin</key> <array> <string>Default</string> </array> ② Apple Developer Console developer.apple.com → Identifiers → 앱 Bundle ID 선택 → Sign in with Apple 체크 → Save 프로비저닝 프로파일이 이미 있다면 재생성이 필요하다. ...

2025-08-30 · 4분 소요 · Seunghan
Ios Itms 90683 Permission Strings

App Store Connect ITMS-90683: Info.plist 권한 purpose string 누락 오류 해결

TestFlight에 IPA를 업로드하고 몇 분 후 App Store Connect에서 메일이 온다. ITMS-90683: Missing purpose string in Info.plist The app's Info.plist file is missing a required purpose string for one or more of the following API categories: NSPhotoLibraryUsageDescription 업로드 자체는 성공했지만 앱 배포 전 Apple이 자동으로 검사해서 이 메일을 보낸다. 수정하지 않으면 App Store 심사 제출 시 거절된다. 왜 이 오류가 발생하는가 iOS는 카메라, 사진 라이브러리, 마이크 등 민감한 API에 접근할 때 사용자에게 권한 팝업을 보여준다. 이 팝업에 표시되는 설명 문구가 Info.plist에 없으면 Apple이 오류로 처리한다. ...

2025-08-27 · 3분 소요 · Seunghan
Ios Gidclientid Info Plist Missing

Flutter iOS Google Sign-In: GIDClientID가 Info.plist에 없을 때

Flutter iOS 앱에서 Google Sign-In을 구현할 때 Firebase를 쓰지 않고 Google Cloud Console에서 직접 OAuth 클라이언트 ID를 발급받는 경우가 있다. 이때 GIDClientID를 Info.plist에 명시적으로 추가하지 않으면 런타임에 에러가 발생한다. Firebase 프로젝트를 쓰는 경우 GoogleService-Info.plist가 이 역할을 자동으로 대신해주기 때문에 의식하지 못하고 지나치기 쉬운 설정이다. 이 글에서는 에러 원인과 해결 방법을 정리한다. 에러 메시지 PlatformException(google_sign_in, No active configuration. Make sure GIDClientID is set in Info.plist., null, null) 원인 google_sign_in iOS SDK는 초기화 시 Info.plist에서 GIDClientID 키를 읽는다. ...

2025-08-23 · 2분 소요 · Seunghan
Flutter Testflight Makefile Automation

Flutter TestFlight 업로드 자동화 - Makefile로 한 줄에 끝내기

Flutter iOS 앱을 TestFlight에 올리는 과정은 단계가 많다. flutter build ipa, Xcode 아카이브, altool 업로드… Makefile로 묶어두면 make testflight 한 줄로 끝난다. 최종 Makefile .PHONY: build-ipa testflight clean EXPORT_OPTIONS = ios/ExportOptions.plist API_KEY = YOUR_API_KEY_ID API_ISSUER = YOUR_ISSUER_ID IPA_DIR = build/ios/ipa IPA_FILE = $(IPA_DIR)/Talkk.ipa # ← 앱 Display Name과 일치해야 함 build-ipa: flutter build ipa --release --export-options-plist=$(EXPORT_OPTIONS) testflight: build-ipa @echo "📦 TestFlight 업로드 중..." xcrun altool --upload-app \ --type ios \ --file "$(IPA_FILE)" \ --apiKey $(API_KEY) \ --apiIssuer $(API_ISSUER) \ --verbose @echo "✅ TestFlight 업로드 완료!" clean: flutter clean && flutter pub get ExportOptions.plist 설정 flutter build ipa는 내부적으로 Xcode 아카이브 후 IPA를 만든다. 이 과정에서 서명 방식, 팀 ID, App Store Connect API 키 등을 지정하는 파일이 필요하다. ...

2025-08-20 · 3분 소요 · Seunghan
개인정보처리방침 문의