

Our Bridge는?
Our Bridge는 장거리 커플을 위한 조용한 일상 공유 앱입니다.
떨어져 있는 두 사람이 서로의 하루, 기분, 일정, 사진을 부담 없이 확인할 수 있도록 만드는 것이 목표였습니다. 메신저처럼 계속 대화를 주고받는 앱이라기보다는, 상대방의 생활 리듬과 마음을 자연스럽게 느낄 수 있는 공간에 가깝게 만들고 싶었습니다.
장거리 연애를 하다 보면 "지금 뭐 해?"라는 말을 자주 하게 됩니다. 물론 그 말 자체가 나쁜 것은 아니지만, 매번 물어봐야만 상대의 하루를 알 수 있다는 점이 조금 아쉽게 느껴졌습니다.
그래서 Our Bridge에서는 다음과 같은 경험을 중심으로 잡았습니다.
- 오늘의 기분과 현재 상태 공유
- 서로의 시간과 날씨 확인
- 다음 만남 D-day 표시
- 공유 캘린더
- 서로 챙김 목록
- 오늘의 한 장 사진 공유
- 연결된 다리 진행도
개발 환경
이번 프로젝트는 iOS 앱으로 개발했습니다.
SwiftSwiftUIiOS 18.0+CloudKitSign in with AppleOpenWeather API
처음에는 Firebase 기반 구조도 고려했지만, 최종적으로는 Apple 생태계 안에서 자연스럽게 동작하도록 Sign in with Apple과 CloudKit을 중심으로 구성했습니다.
앱의 방향성
Our Bridge를 만들면서 가장 신경 쓴 부분은 "부담 없는 공유"였습니다.
기분을 기록하거나 사진을 올리는 기능은 흔한 기능일 수 있습니다. 하지만 커플 앱에서 이 기능들이 너무 무겁게 느껴지면 오히려 사용하기 어려워진다고 생각했습니다.
그래서 홈 화면도 많은 정보를 한 번에 보여주기보다는, 두 사람이 오늘 어떤 상태인지 조용히 확인할 수 있도록 구성했습니다.
홈 화면에는 다음과 같은 카드들이 들어갑니다.
- 다음 만남
- 연결된 다리
- 시간·날씨
- 기분 공유
- 최근의 순간들
각 기능은 독립적으로 존재하지만, 결국 "오늘 두 사람이 얼마나 이어져 있는지"를 보여주는 방향으로 연결되도록 만들었습니다.
커플 연결 방식
Our Bridge는 두 사용자가 하나의 커플 공간을 공유해야 합니다.
이를 위해 초대 코드 기반 연결 방식을 사용했습니다. 한 사용자가 커플 공간을 만들면 초대 코드가 생성되고, 상대방이 해당 코드를 입력해 같은 공간에 참여하는 방식입니다.
이 과정에서 CloudKit의 공유 영역을 사용했습니다.
let share = CKShare(rootRecord: rootRecord)
share[CKShare.SystemFieldKey.title] = "Our Bridge 초대" as CKRecordValue
share.publicPermission = .readWrite
CloudKit을 사용하면서 좋았던 점은 Apple 계정 기반으로 사용자 인증과 데이터 공유 흐름을 구성할 수 있다는 점이었습니다. 다만 공유 데이터, 개인 데이터, 공개 초대 코드 데이터의 역할을 나누는 부분은 생각보다 신경 쓸 것이 많았습니다.
Our Bridge에서는 대략 다음과 같이 역할을 나눴습니다.
- 개인 사용자 정보: private database
- 커플이 함께 보는 데이터: shared database
- 초대 코드 조회용 데이터: public database
처음에는 단순히 "커플 데이터니까 같이 저장하면 되겠지"라고 생각했는데, 실제로 구현하다 보니 누가 만든 데이터인지, 누가 접근할 수 있는지, 연결이 끊겼을 때 어떤 데이터를 정리해야 하는지까지 고려해야 했습니다.
연결된 다리 진행도
Our Bridge에서 개인적으로 마음에 들었던 기능은 연결된 다리입니다.
단순히 앱에 들어와서 기능을 사용하는 것에서 끝나는 것이 아니라, 두 사람이 오늘 얼마나 서로의 하루에 참여했는지를 진행도로 보여주는 기능입니다.
진행도는 다음 요소를 기준으로 계산했습니다.
- 두 사람의 오늘 기분 공유
- 두 사람의 오늘의 한 장
- 서로 챙김 완료
- 오늘 캘린더 확인
예를 들어 기분 공유는 각자 10점, 오늘의 한 장은 각자 15점처럼 점수를 나눠 계산했습니다.
let moodPoints = (hasTodayCheckIn(userId) ? 10 : 0)
+ (hasTodayCheckIn(partnerId) ? 10 : 0)
let photoPoints = (hasTodayPhoto(userId) ? 15 : 0)
+ (hasTodayPhoto(partnerId) ? 15 : 0)
이 기능은 복잡한 알고리즘보다는 사용자의 행동을 어떻게 감성적인 피드백으로 바꿀지에 더 초점을 맞췄습니다.
진행도에 따라 문구와 이미지도 달라지도록 했습니다.
- 첫 발판을 기다리는 중
- 다리 놓기 시작
- 서로에게 가는 중
- 절반을 건너왔어요
- 거의 이어졌어요
- 오늘의 다리 완성
작은 기능이지만 앱의 이름인 Our Bridge와 가장 잘 맞는 기능이라고 생각합니다.
로컬 캐시 적용
CloudKit 기반 앱을 만들면서 가장 아쉬웠던 부분은 네트워크 상태나 응답 속도에 따라 화면이 비어 보일 수 있다는 점이었습니다.
커플 앱은 자주 열어보는 앱에 가깝기 때문에, 매번 데이터를 새로 불러오느라 기다리게 만들고 싶지 않았습니다.
그래서 커플 데이터 일부는 로컬에 캐시하도록 구성했습니다.
enum LocalCoupleDataCache {
private static func key(for userId: String) -> String {
"longdy.cachedCoupleData.\(userId)"
}
static func load(userId: String) -> CachedCoupleSnapshot? {
guard let data = UserDefaults.standard.data(forKey: key(for: userId)) else {
return nil
}
return try? JSONDecoder().decode(CachedCoupleSnapshot.self, from: data)
}
static func save(_ snapshot: CachedCoupleSnapshot) {
guard let data = try? JSONEncoder().encode(snapshot) else { return }
UserDefaults.standard.set(data, forKey: key(for: snapshot.userId))
}
}
처음부터 거창한 캐시 시스템을 만들지는 않았습니다. 현재 필요한 것은 "앱을 다시 켰을 때 마지막 데이터를 빠르게 보여주는 것"이었기 때문에 UserDefaults와 Codable을 사용했습니다.
추후 데이터가 더 커지거나 캐시 정책이 복잡해진다면 파일 저장이나 별도 저장소를 고려할 수 있겠지만, 지금 단계에서는 이 정도가 가장 단순하고 충분하다고 판단했습니다.
화면 구성
Our Bridge는 크게 네 개의 탭으로 구성했습니다.
- 홈
- 캘린더
- 챙김
- 오늘의 한 장
홈에서는 두 사람의 현재 상태를 빠르게 볼 수 있도록 했습니다. 캘린더에서는 서로의 일정과 다음 만남을 관리할 수 있고, 챙김에서는 상대방을 위해 기억하고 싶은 일을 등록할 수 있습니다. 오늘의 한 장에서는 하루에 한 장씩 사진을 공유할 수 있도록 했습니다.
각 기능을 많이 넣기보다는, 장거리 커플이 실제로 자주 확인할 만한 것들만 남기려고 했습니다.
개발하면서 배운 점
이번 프로젝트를 진행하면서 가장 크게 느낀 점은, 앱의 기능보다 데이터 흐름을 먼저 잘 잡는 것이 중요하다는 점이었습니다.
특히 커플 앱처럼 두 명의 사용자가 같은 데이터를 바라보는 구조에서는 단순 CRUD보다 고려할 부분이 많았습니다.
- 초대 코드는 누가 만들 수 있는지
- 본인이 만든 초대를 본인이 수락하지 못하게 해야 하는지
- 이미 연결된 사용자가 다른 초대를 입력하면 어떻게 처리할지
- 커플 연결을 끊으면 어떤 데이터를 유지하고 어떤 데이터를 지울지
- 공유 데이터 접근 권한이 사라졌을 때 어떻게 복구할지
이런 부분들은 화면을 만드는 것보다 더 많은 고민이 필요했습니다.
또 SwiftUI로 화면을 구성하면서 상태 관리의 중요성도 다시 느꼈습니다. 홈, 캘린더, 챙김, 사진 기능이 서로 독립되어 보이지만 실제로는 하나의 커플 상태를 공유하기 때문에, AppViewModel을 중심으로 데이터를 관리하도록 구성했습니다.
마무리
Our Bridge는 아직 개선하고 싶은 부분이 많은 프로젝트입니다.
하지만 이번 프로젝트를 통해 단순히 화면을 만드는 것보다, 사용자가 어떤 상황에서 앱을 열고 어떤 감정을 느낄지를 생각하면서 개발하는 경험을 할 수 있었습니다.
특히 CloudKit 공유 구조, Apple 로그인, 로컬 캐시, SwiftUI 상태 관리 등을 실제 앱 흐름 안에서 다뤄볼 수 있어서 많이 배웠습니다.
앞으로는 알림 경험, 사진 공유 UX, 오프라인 상태 처리 등을 더 다듬어보고 싶습니다.
장거리 커플이 매번 긴 대화를 하지 않아도, 서로의 하루를 조금 더 자연스럽게 느낄 수 있는 앱이 되었으면 좋겠습니다.
