| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 |
- AI
- Firestore
- offline-first
- 실내 위치
- append-only
- compose
- 보안 규칙
- 코스 공유
- Kotlin
- 오프라인 우선
- PR 리뷰
- 설계 문서
- 테스트 벡터
- 자율 루프
- claude code
- base64url
- Spark 플랜
- Android
- AI 코딩
- 로컬 저장
- App Check
- Security Rules
- 코드 리뷰
- ai 에이전트
- Core Location
- Fused Location Provider
- 산책 앱
- varint
- URL Fragment
- 산책 기록 앱
- Today
- Total
목록전체 글 (12)
웜뱃 블로그
안녕하세요.개인 프로젝트로 산책 기록 앱을 만들면서 코스 공유 기능을 Claude Code와 함께 설계부터 출시까지 진행했습니다. 오늘은 그 기능의 코드보다, 일을 어떤 순서로 나눠 맡겼는지를 정리해 보려고 합니다. AI에게 기능을 통째로 "만들어 줘"라고 하면 일단 돌아가는 코드는 금방 나옵니다. 그런데 사람이 정해야 할 것까지 AI가 조용히 정해 버리거나, Android와 iOS가 미묘하게 다르게 동작하는 상황을 만나게 됩니다.코스 공유는 특히 조심스러운 기능이었습니다. 걸은 길을 링크로 보내는 기능이라, 잘못 만들면 출발 지점, 그러니까 집 위치가 그대로 드러납니다. 그래서 아래 그림처럼 다섯 단계로 나누고, 단계마다 사람과 Claude가 맡을 일을 나눴습니다. 화면과 규칙은 사람이 먼저 확인하고,..
안녕하세요.개인 프로젝트로 산책 기록 앱을 만들고 있습니다. 오늘은 내가 걸은 코스를 친구에게 링크 하나로 보내는 기능을, 서버 없이 만든 방법을 정리해 보려고 합니다. 코스를 공유하려면 보통 서버에 코스를 저장하고, 링크에는 그 코스의 id만 담습니다. 그런데 이 앱은 Firebase 무료 플랜으로 운영하고 있어서 서버 코드를 둘 수 없습니다.설령 저장할 수 있다고 해도 걱정이 남습니다. 산책 코스는 위치 정보라서, 서버에 쌓이는 순간 그 데이터를 지키는 책임도 같이 생깁니다. 그래서 반대로 접근했습니다. 아래 그림처럼 코스 자체를 링크 안에 담아 보내고, 받는 쪽이 링크를 풀어서 지도를 그립니다.이번 포스팅에서는 좌표를 링크의 해시(#) 뒤에 담는 이유, 좌표를 짧은 글자로 바꾸는 방법, 그리고 집 ..
안녕하세요.개인 프로젝트로 산책 기록 앱을 만들면서 구현 대부분을 Claude Code에게 맡기고 있습니다. 오늘은 그 코드를 리뷰하는 쪽, 서브에이전트로 리뷰어를 세 명 만들어 PR마다 돌린 방법을 정리해 보려고 합니다. AI가 쓴 코드를 같은 대화에서 "리뷰해 줘"라고 하면 대개 비슷한 답이 돌아옵니다. 방금 자기가 쓴 코드라 의도를 이미 알고 있어서, 놓친 부분도 그대로 넘어가기 쉽습니다.보안, 성능, 스타일을 한 번에 보라고 해도 마찬가지입니다. 항목마다 얕게 훑고 "전반적으로 잘 작성되었습니다"로 끝나기 일쑤입니다. 그래서 리뷰어를 역할별로 나눴습니다. 아래 그림처럼 같은 변경 파일을 세 리뷰어가 동시에 따로 읽고, 메인 세션이 결과를 모아 심각도 순으로 정리합니다.이번 포스팅에서는 리뷰어 파일..
안녕하세요.개인 프로젝트로 산책 기록 앱을 만들면서 백엔드를 Firebase 무료 플랜(Spark)만으로 꾸렸습니다. 서버 코드를 한 줄도 두지 않고 출시 준비까지 오면서 정리한 방법과 한계를 적어 보려고 합니다. Firebase로 앱을 만들다 보면 "이건 서버에서 처리해야 하는데" 싶은 순간을 자주 만나게 됩니다. 겹치지 않는 초대 코드를 발급하거나, 사용자가 자기 계정의 정지 상태를 몰래 풀지 못하게 막거나, 다 쓴 임시 데이터를 시간이 지나면 지우는 일 같은 것들입니다. 보통은 Cloud Functions를 쓰면 되지만, Cloud Functions는 종량제 플랜(Blaze)에서만 쓸 수 있습니다. 카드 등록 없이 무료로 운영하고 싶었기 때문에 이 프로젝트에서는 서버 코드 없이 가기로 처음부터 정해..
안녕하세요.개인 프로젝트로 산책 기록 앱을 Android와 iOS로 만들고 있는데, 구현의 대부분을 AI 코딩 에이전트인 Claude Code에게 맡겼습니다. 하나씩 시키는 대신 에이전트가 스스로 다음 할 일을 골라 진행하는 "루프" 방식으로요. 오늘은 그 루프를 어떻게 만들었고, 돌려 보면서 무엇을 바꿨는지 정리해 보려고 합니다. AI 에이전트에게 코드를 맡기다 보면 금방 두 가지 고민이 생깁니다. 한 가지씩 시키면 기능 하나가 끝날 때마다 다음 할 일을 설명하고 테스트 결과를 확인하느라 결국 사람이 계속 붙어 있어야 합니다. 그렇다고 "알아서 다 만들어 줘"라고 맡기면 어디까지 진행됐는지, 왜 그렇게 만들었는지 따라가기 어렵고, 배포처럼 되돌릴 수 없는 일까지 건드릴까 봐 불안합니다. 그래서 이 프로..
안녕하세요. 오랜만에 글을 올립니다.그동안 개인 프로젝트로 산책 기록 앱을 만들고 있었는데, 만들면서 고민했던 내용들을 하나씩 정리해 보려고 합니다. 오늘은 그중에서 기록 데이터를 어떻게 저장하고 서버와 동기화했는지에 대한 이야기입니다. 산책이나 러닝 기록 앱을 만들다 보면 네트워크가 불안정한 상황을 자주 만나게 됩니다. 산길, 지하 주차장, 엘리베이터 안처럼 신호가 잠깐씩 끊기는 곳이 생각보다 많고, 데이터를 아끼려고 모바일 데이터를 꺼 두고 걷는 사용자도 있습니다. 문제는 GPS 기록은 한 번 놓치면 다시 만들 수 없다는 점입니다. 서버 저장에 실패했다고 "다시 시도해 주세요"를 띄우면 사용자는 방금 걸은 1시간을 그대로 잃게 됩니다. 그래서 이 앱에서는 처음부터 기기에 저장되면 기록은 성공이라는 원..
Compose 기반 UI 개발이 주류로 자리 잡으면서, 기존의 View 클래스 기반으로 설계된 API는 AndroidView를 사용해 Compose 환경에서 활용할 수 있었습니다. 하지만 이 접근법은 제약이 많아 완전한 Compose 개발의 장점을 누리기 어렵다는 한계가 있었습니다. Compose에 대한 지원이 확대되면서 네이버 지도 SDK에서도 naver-map-compose를 제공하여 Compose 환경에 적합한 지도 구현이 가능해졌습니다. 이번 포스팅에서는 naver-map-compose를 활용하여 Android Compose 프로젝트에서 지도를 표시하고, 맵 타입과 레이어를 동적으로 변경하는 방법을 다뤄보겠습니다. 환경 설정안드로이드 스튜디오에서 프로젝트를 생성할 때, Compose 기반의 Em..
CameraX는 Jetpack 라이브러리 중 하나로, 카메라 앱을 더욱 쉽게 개발할 수 있도록 설계되었습니다. 새로운 앱에 카메라 기능을 추가할 계획이시라면 CameraX를 활용하는 것이 좋습니다. CameraX는 대부분의 Android 기기에서 잘 작동하며, Android 5.0(API 레벨 21)까지도 호환되어 호환성 문제를 줄여줍니다. 또한, 일관성 있고 사용이 쉬운 API를 제공해 개발 효율성을 높입니다.이번 포스팅에서는 CameraX 아키텍처와 Compose로 구현된 앱에서 어떤 식으로 활용할 수 있는지 알아보겠습니다. Camera 아키텍처 CameraX를 사용하면 추상화 UseCase를 통해 장치의 카메라와 연결할 수 있습니다. 대표적으로 아래 4가지 Usecase를 활용할 수 있습니다.Pr..
앱을 개발하다 보면 백그라운드 상태에서 포어그라운드 서비스를 실행하는 상황이 생길 수 있습니다. Android OS가 점점 업그레이드되면서 사용자가 의도치 않은 상황에서 서비스가 실행되거나 또는 배터리가 소모되는 문제들을 예방하고자 특수한 예외 케이스를 제외하고는 Android 12 이상을 타겟팅하는 앱은 백그라운드 상태에서 포어그라운드 서비스를 실행이 제한됩니다. 앱이 백그라운드 상태에서 포어그라운드 서비스를 실행 할 수 있는 예외 케이스:더보기Activity와 같은 사용자에게 표시되는 상태에서 전환 Firebase Cloud를 사용하여 높은 우선순위의 메시지를 수신하는 경우 기기가 재부팅되고 broadcast receiver에서 ACTION_BOOT_COMPLETED나 ACTION_LOCKED_BOO..
오늘은 Room database Migration 방법에 대해 알아보겠습니다.Room에서 Migration은 테이블의 구조가 변경되었을 때 기존 저장된 데이터를 유지하면서변경된 테이블 구조를 적용할 수 있는 방법입니다. 아래와 같은 User Entity에서 email colmn을 추가한다고 예를 들어보겠습니다.@Entity(tableName = "user")data class UserInfoEntity( @PrimaryKey val id: Long = 0, val name: String, val password: String, val email: String //추가) room은 이미 생성된 Entity의 구조가 변경되면 Database의 버전을 높여 주어야 합니다.Entity의 정..
