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
Firefox Addon Manifest Data Collection Permissions

Firefox 확장 프로그램 AMO 제출 시 data_collection_permissions 오류 해결

Chrome 확장 프로그램을 Firefox로 포팅해서 AMO(addons.mozilla.org)에 제출하면, Chrome Web Store에서는 없던 오류들을 만난다. 특히 2025년 11월부터 필수가 된 data_collection_permissions 때문에 삽질하기 쉽다. 증상: QR 이미지가 안 보인다? 확장 프로그램 팝업에서 이미지가 깨져 보이는 문제가 있었다. 원인은 단순했다 — 패키징된 zip에 이미지 파일이 누락된 것. 로컬 개발 환경에서는 파일이 있지만, 스토어에 업로드한 빌드에는 빠져있었다. 해결: 깔끔한 zip 패키징 cd my_extension && zip -r ../extension.zip . \ -x ".*" "__MACOSX/*" "*.DS_Store" "store_assets/*" macOS에서 zip 만들면 __MACOSX/ 폴더와 .DS_Store가 들어가는데, 이걸 제외해야 한다. store_assets/ 같은 스토어 에셋 폴더도 확장 프로그램 자체에는 불필요하다. ...

2025-09-17 · 3분 소요 · Seunghan
Domain Projects Dev Guide

멀티 도메인 정적 사이트 운영 개발 가이드

개요 여러 개의 정적 사이트(랜딩 페이지 + 블로그)를 단일 디렉토리에서 관리하는 구조와 배포 워크플로우를 정리한 문서입니다. 디렉토리 구조 ~/domain/ ├── dcode/ │ └── landing/ # Static HTML 랜딩 페이지 모음 │ ├── index.html # 메인 페이지 │ ├── app-a/ # 앱별 서브 디렉토리 │ │ ├── index.html │ │ ├── privacy/ │ │ └── terms/ │ ├── app-b/ │ └── Makefile │ ├── seunghan-xyz/ # 개인 블로그 (Hugo) │ ├── content/ │ │ ├── posts/ # 기술 블로그 포스트 │ │ ├── projects/ # 프로젝트 소개 │ │ └── about/ │ ├── hugo.toml │ └── public/ # 빌드 결과물 (git 제외) │ └── blogs/ └── blog_richdada/ # Hugo 블로그 컬렉션 ├── site-a/ # 사이트 A (한국어/영어) └── site-b/ # 사이트 B 기술 스택 구분 기술 개인 블로그 Hugo + PaperMod Theme 앱 블로그 Hugo + Stack Theme v3 랜딩 페이지 Static HTML + Tailwind CSS (CDN) 호스팅 Netlify 도메인 관리 Namecheap 배포 방법 1. 개인 블로그 (Hugo → Netlify CLI) 빌드 후 Netlify CLI로 직접 배포합니다. GitHub push는 자동 배포와 연결되어 있지 않습니다. ...

2025-09-13 · 3분 소요 · 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
Rails Oauth Provider Uid Column Mismatch

Rails OAuth: PG::UndefinedColumn users.uid 에러 — 컬럼명 불일치

Apple Sign-In / Google Sign-In 연동 후 클라이언트에서는 500 에러만 보이는데, 서버 로그를 보면 실제 원인이 다른 경우가 있다. 오늘 마주친 케이스를 정리한다. SSO 연동 초기에는 클라이언트(Flutter) 쪽 설정 문제인지, 서버 쪽 문제인지 구분하기가 쉽지 않다. 이 글에서는 서버 DB 컬럼명 불일치로 인한 PG::UndefinedColumn 에러를 빠르게 진단하고 수정하는 방법을 다룬다. 에러 PG::UndefinedColumn: ERROR: column users.uid does not exist LINE 1: SELECT "users".* FROM "users" WHERE "users"."uid" = $1 ... 클라이언트(Flutter)에서는 401 Unauthorized로 보인다. ...

2025-09-06 · 2분 소요 · Seunghan
Rails Aasa Routing Proc Lambda Git

Rails AASA 라우팅 3가지 함정: proc vs lambda, 경로 누락, git 미추적

iOS 유니버설 링크(Universal Links)를 설정하려면 /.well-known/apple-app-site-association 경로에서 JSON을 반환해야 한다. Rails에서 이걸 라우팅할 때 흔히 빠지는 함정 3가지를 정리한다. 에러 ActionController::RoutingError (No route matches [GET] "/.well-known/apple-app-site-association"): ActionController::RoutingError (No route matches [GET] "/apple-app-site-association"): 배포 서버 로그에서 이 에러가 반복되고, iOS 앱에서 유니버설 링크가 동작하지 않는다. 함정 1: proc을 Rack 앱으로 사용 Rails routes에서 inline으로 파일을 반환하려고 proc을 쓰는 경우가 있다. # 동작하지 않는 코드 get "/.well-known/apple-app-site-association", to: proc { file = Rails.root.join("public/.well-known/apple-app-site-association") [200, { "Content-Type" => "application/json" }, [File.read(file)]] } Rails 라우팅에서 to: 옵션에 Rack 앱을 직접 넣을 때는 env 인자를 받는 callable이어야 한다. proc { } 블록은 인자 없이 정의되어 있어서 Rack 인터페이스를 만족하지 못한다. ...

2025-09-03 · 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
개인정보처리방침 문의