Firebase_친구_기능_(1) - boostcampwm-2024/and04-Nature-Album GitHub Wiki
✅ 진행한 기능
1. Firebase Firestore 구조 설계
-
목적: 친구 요청, 친구 목록, 요청 상태 등을 관리하기 위해 NoSQL 기반 데이터베이스 구조 설계.
-
구조:
Firestore ├── USERS (Collection) │ ├── {uid} (Document) │ │ ├── displayName: String │ │ ├── email: String │ │ ├── photoUrl: String │ │ ├── FRIENDS (Sub-collection) │ │ │ ├── {friendUid} (Document) │ │ │ │ ├── user: FirestoreUser (Embedded object) │ │ │ │ │ ├── uid: String │ │ │ │ │ ├── displayName: String │ │ │ │ │ ├── email: String │ │ │ │ │ ├── photoUrl: String │ │ │ │ ├── addedAt: String (Timestamp) │ │ │ │ │ ├── FRIEND_REQUESTS (Sub-collection) │ │ │ ├── {requestUid} (Document) │ │ │ │ ├── user: FirestoreUser (Embedded object) │ │ │ │ │ ├── uid: String │ │ │ │ │ ├── displayName: String │ │ │ │ │ ├── email: String │ │ │ │ │ ├── photoUrl: String │ │ │ │ ├── requestedAt: String (Timestamp) │ │ │ │ ├── status: String ("sent" or "received") │ │ │ │ │ ├── LABEL (Sub-collection) │ │ │ ├── {labelName} (Document) │ │ │ │ ├── backgroundColor: String │ │ │ │ ├── thumbnailUri: String │ │ │ │ │ ├── PHOTOS (Sub-collection) │ │ │ ├── {photoId} (Document) │ │ │ │ ├── uri: String │ │ │ │ ├── label: String │ │ │ │ ├── latitude: Double │ │ │ │ ├── longitude: Double │ │ │ │ ├── description: String │ │ │ │ ├── datetime: String (ISO-8601)
2. Firestore 데이터 초기화 및 더미 데이터 생성
- 테스트 환경 구축을 위해 Firestore에 더미 데이터를 생성.
FriendTestScreen
에서FriendViewModel
테스트 진행.
3. 친구 관련 기능
1. 친구 요청 보내기 (sendFriendRequest
)
- 특정 사용자에게 친구 요청을 보낸다.
- 요청자와 대상자의 요청 데이터를 각각 생성하여 Firestore 트랜잭션으로 저장.
2. 친구 요청 수락하기 (acceptFriendRequest
)
- 받은 친구 요청을 수락하여 친구 관계를 형성한다.
- Firestore 트랜잭션으로 다음 작업 수행:
- 요청자와 대상자의 친구 리스트에 데이터 추가.
- 양쪽의 요청 상태 제거.
3. 친구 요청 거절하기 (rejectFriendRequest
)
- 받은 친구 요청을 거절한다.
- Firestore 트랜잭션으로 양쪽의 요청 상태를 삭제.
4. 친구 리스트 조회 (getFriends
)
- 현재 사용자의 친구 리스트를 반환한다.
- Firestore에서 친구 데이터를 가져와
FirebaseFriend
객체로 직렬화.
5. 받은 친구 요청 조회 (getFriendRequests
)
- 현재 사용자가 받은 모든 친구 요청 데이터를 반환한다.
- Firestore에서 데이터를 가져와
FirebaseFriendRequest
객체로 매핑.
6. 받은 친구 요청 중 RECEIVED
상태 조회 (getReceivedFriendRequests
)
- 받은 친구 요청 중 상태가
RECEIVED
인 요청만 반환한다. - Firestore에서 요청 데이터를 가져와 필터링 처리.
7. 모든 사용자 정보와 친구 상태 조회 (getAllUsersInfo
)
- Firestore에 저장된 모든 사용자 데이터를 가져오며, 현재 사용자와의 친구 상태를 반환.
- 상태 종류:
NORMAL
: 친구 아님.SENT
: 내가 친구 요청 보냄.RECEIVED
: 내가 친구 요청 받음.FRIEND
: 친구 관계.
💡문제 해결 과정 기록
프로젝트 구조 파악 및 Firebase NoSQL 파악
- 친구 추가 기능 진행 전 현재 프로젝트 구조와 NoSQL를 파악했다. 어떻게 구조를 짜야할지 생각해보기 위함이다.
현재 Firebase Firestore 구조
USER (Collection)
├── UID (Document)
│ ├── LABEL (Collection)
│ │ ├── [Label Name] (Document)
│ │ │ ├── BackgroundColor: String
│ │ │ ├── Thumbnail: String
│ ├── PHOTOS (Collection)
│ │ ├── [Image File Name] (Document)
│ │ │ ├── uri: String
│ │ │ ├── filename: String
│ │ │ ├── label: String
│ │ │ ├── latitude: Double
│ │ │ ├── longitude: Double
│ │ │ ├── description: String
│ │ │ ├── datetime: LocalDateTime
각 요소 설명
- USER Collection:
- 사용자 정보를 관리하는 최상위 컬렉션
- 각 사용자는 UID(고유 식별자)를 문서 이름으로 사용
- LABEL Collection:
- UID 하위에 존재하며, 사용자별 라벨 데이터를 관리
- 각 문서는 라벨 이름을 키로 가지며, 라벨의 색상(
BackgroundColor
)과 썸네일(Thumbnail
) 데이터를 저장
- PHOTOS Collection:
- UID 하위에 존재하며, 사용자가 업로드한 사진 데이터를 관리
- 각 문서는 파일 이름을 키로 가지며, 사진의 URI, 파일명, 라벨 정보, 위치, 설명, 그리고 날짜 데이터를 저장
시각화된 다이어그램
USER (Collection)
├── UID_1 (Document)
│ ├── LABEL (Collection)
│ │ ├── "Nature" (Document)
│ │ │ ├── BackgroundColor: "#00FF00"
│ │ │ ├── Thumbnail: "<https://example.com/thumbnail.jpg>"
│ │ ├── "Urban" (Document)
│ │ ├── BackgroundColor: "#FF5733"
│ │ ├── Thumbnail: "<https://example.com/urban_thumbnail.jpg>"
│ ├── PHOTOS (Collection)
│ │ ├── "photo_001.jpg" (Document)
│ │ │ ├── uri: "<https://example.com/photo_001.jpg>"
│ │ │ ├── filename: "photo_001.jpg"
│ │ │ ├── label: "Nature"
│ │ │ ├── latitude: 37.7749
│ │ │ ├── longitude: -122.4194
│ │ │ ├── description: "A beautiful forest"
│ │ │ ├── datetime: "2024-11-19T12:34:56"
│ │ ├── "photo_002.jpg" (Document)
│ │ ├── uri: "<https://example.com/photo_002.jpg>"
│ │ ├── filename: "photo_002.jpg"
│ │ ├── label: "Urban"
│ │ ├── latitude: 40.7128
│ │ ├── longitude: -74.0060
│ │ ├── description: "A bustling city street"
│ │ ├── datetime: "2024-11-20T08:00:00"
확장 계획
이 구조를 기반으로 친구 추가 및 관리 기능을 위해 다음과 같은 컬렉션/문서를 추가해볼 계획이다.
- FRIENDS Collection:
- 친구 목록과 상태 정보를 관리하는 추가 컬렉션.
- NOTIFICATIONS Collection:
- 친구 요청 등의 알림 데이터를 관리하는 추가 컬렉션.
❓ 로그인하면 UID가 어떻게 되는가?
사람들이 Firebase Authentication을 통해 로그인하면, 각 사용자의 고유 UID가 Firebase Authentication에서 생성된다. 이 UID를 기준으로 Firestore의 USER
Collection 안에 사용자별 Document를 생성하는 방식이다.
즉:
USER
는 Collection.- 각 사용자의 UID는
USER
Collection 안의 Document 이름으로 사용된다.
로그인 흐름
- 사용자가 로그인한다.
- Firebase Authentication에서 고유한 UID를 생성하거나 반환한다.
- 이 UID를 이용해
USER
Collection에 사용자 정보를 저장한다.-
예를 들어, 사용자가 처음 로그인하면:
USER Collection ├── UID_12345 (Document)
-
기존 사용자라면 해당 UID를 Document 이름으로 하여 기존 데이터를 가져온다.
-
예제
신규 사용자 로그인 시
USER (Collection)
├── UID_12345 (Document)
├── LABEL (Collection)
├── PHOTOS (Collection)
기존 사용자 로그인 시
- 이미 만들어진 UID Document에 접근하여 데이터를 읽거나 추가/수정.
UID 기반 데이터 분리의 장점
- 보안: 각 사용자는 자신의 UID로만 데이터를 관리하므로, 다른 사용자의 데이터에 접근할 수 없다.
- 확장성: Firebase에서 자동 생성된 UID는 전 세계적으로 유일하므로, 중복될 가능성이 없다.
- 관리 용이성: 데이터가 사용자별로 분리되어 있기 때문에 구조적으로 간결하고 이해하기 쉽다.
관련 코드 설명
FirebaseRepositoryImpl
클래스:
fireStore.collection("USER").document(uid).collection("LABEL").get()
이 코드에서 uid
는 Firebase Authentication에서 받은 UID이며, 해당 사용자의 LABEL
데이터를 가져오는 로직이다.
결론적으로, 로그인할 때마다 Firestore의 USER
Collection에 사용자의 UID Document가 생성되거나 업데이트된다.
Collection이름이 USER라서 잠시 혼동했다. 그래서 정리했다.
Firebase Authentication에서 제공하는 사용자 정보
Firebase auth
객체를 통해 로그인된 사용자 정보를 확인할 수 있다. 대표적으로 다음 정보를 가져올 수 있다:
사용자 정보
속성 | 설명 | 예제 |
---|---|---|
uid |
사용자 고유 식별자 | "abc123xyz456" |
displayName |
사용자의 이름 또는 별명 | "John Doe" |
email |
사용자의 이메일 주소 | "[email protected]" |
photoUrl |
사용자 프로필 사진 URL | "https://example.com/photo.jpg" |
phoneNumber |
사용자의 전화번호 (SMS 인증 시 제공) | "+1234567890" |
providerData |
로그인 제공자 정보 목록 | Google, Facebook, Email 등 |
isEmailVerified |
이메일이 인증되었는지 여부 | true 또는 false |
우리 프로젝트에서 사용할 수 있는 정보
1. 프로필 사진 (photoUrl)
- Google, Facebook 등의 소셜 로그인 제공자와 통합하면 사용자 프로필 사진을 얻을 수 있다.
Firebase.auth.currentUser?.photoUrl
로 접근.
2. 이메일 (email)
- 대부분의 로그인 제공자는 이메일을 반환한다.
Firebase.auth.currentUser?.email
로 접근.
3. 별명 / 이름 (displayName)
- Google 또는 Facebook 로그인 시 사용자 이름(별명)을 반환.
Firebase.auth.currentUser?.displayName
로 접근.
4. 고유 사용자 ID (uid)
- Firebase가 자동으로 생성한 사용자 고유 식별자.
- 각 사용자의 데이터를 식별하기 위해 활용.
Firebase.auth.currentUser?.uid
로 접근.
확인 방법
Firebase Authentication의 현재 사용자 정보는 Firebase.auth.currentUser
객체를 통해 확인할 수 있다.
사용자 정보 가져오기
import com.google.firebase.auth.ktx.auth
import com.google.firebase.ktx.Firebase
val user = Firebase.auth.currentUser
if (user != null) {
val uid = user.uid // 사용자 고유 ID
val name = user.displayName // 사용자 이름 또는 별명
val email = user.email // 사용자 이메일
val photoUrl = user.photoUrl // 사용자 프로필 사진 URL
println("UID: $uid")
println("이름: $name")
println("이메일: $email")
println("프로필 사진: $photoUrl")
} else {
println("사용자가 로그인되어 있지 않습니다.")
}
Firebase Authentication 데이터 활용
- Firestore 데이터베이스와 연동
- 로그인한 사용자의 UID를 기반으로 Firestore의 사용자 데이터를 관리.
- 예:
firestore.collection("USER").document(uid)
.
- 앱 내 프로필 정보 표시
- 사용자 이름과 프로필 사진을 앱의 UI에 표시.
- 친구 추가 기능
- 사용자 이메일이나 UID를 검색하여 친구 추가.
로그인해서 진행하려다가 트러블 슈팅
💡 친구 기능 추가에 따른 NoSQL 구조 개선
❓ 의문 사항
- Firestore 상태 저장 vs 클라이언트 계산 방식
- 친구 상태(
friend
,sent
,received
)를 클라이언트에서 계산하거나 Firestore에 저장 중 어떤 방식이 유리한가? - 현재는 클라이언트에서 계산 중이며, Firestore에 저장하는 방식으로 전환 여부 고려.
- 친구 상태(
- Cloud Functions 도입
- Firestore 쿼리 비용이 증가함에 따라 서버에서 데이터를 처리하고 반환하는 방식이 더 적합한가?
클라이언트 계산 방식 vs Firestore 상태 저장 방식
클라이언트 계산 방식
- 특징:
FRIENDS
,FRIEND_REQUESTS
Collection의 데이터를 가져온 후 클라이언트에서 상태를 계산.- 쿼리 호출이 많아질 수 있지만, 상태를 명시적으로 저장하지 않아 데이터 간 일관성 유지가 쉬움.
- 상태 계산은 클라이언트 로직에 의존.
- 장점:
- 데이터 구조가 단순하고 동적인 상태 계산 가능.
- Firestore 트랜잭션 관리가 간단.
- 단점:
- 쿼리가 많아지고 성능이 저하될 가능성.
- 클라이언트 코드 복잡도 증가.
Firestore 상태 저장 방식
- 특징:
- 상태 정보(
status
)를 Firestore에 명시적으로 기록. - 클라이언트는 상태 정보를 직접 쿼리로 가져옴.
- 상태 저장 시 데이터 동기화가 필요. ⇒ 걸리는 부분
- 상태 정보(
- 장점:
- 상태를 쿼리로 바로 가져올 수 있어 클라이언트 로직 단순화.
- 성능 최적화: 불필요한 쿼리를 줄이고 빠른 조회 가능.
- 단점:
- 상태 정보 저장 시 데이터 불일치(일관성 문제) 가능성.
- 상태 변경 시 트랜잭션이나 동기화 로직이 필요.
Firestore 상태 저장 방식 예시
Firestore 구조
USER (Collection)
├── UID (Document)
│ ├── displayName: String
│ ├── email: String
│ ├── photoUrl: String
│ ├── FRIENDS (Collection)
│ │ ├── [Friend UID] (Document)
│ │ ├── addedAt: Timestamp
│ │ ├── status: "친구" // 상태 저장
│ ├── FRIEND_REQUESTS (Collection)
│ │ ├── [Request UID] (Document)
│ │ ├── requestedAt: Timestamp
│ │ ├── status: "대기중" // 상태 저장
클라이언트 계산 vs 상태 저장 방식의 선택 기준
클라이언트 계산 방식을 선택해야 할 경우
- 프로젝트 초기 단계로 데이터 구조가 간단하고, 동적 상태 계산이 유리할 때.
- 사용자가 많지 않고, 쿼리 비용이 상대적으로 적은 경우.
Firestore 상태 저장 방식을 선택해야 할 경우
- 사용자가 많아지고 데이터베이스 쿼리 비용이 증가한 경우.
- 성능 최적화가 필요하고, 상태 확인 속도가 중요할 때.
- 상태 계산 로직을 중앙화하여 클라이언트 코드 복잡도를 줄이고 싶을 때.
커뮤니티 앱에서 상태 저장의 일반적인 방식
서버에서 상태 저장
- 서버가 사용자 간 관계(예: 친구, 팔로우, 블록 등)와 요청 상태(예: 친구 요청, 팔로우 요청 등)를 명시적으로 저장
- 클라이언트는 서버에서 상태 데이터를 읽어와 화면에 표시하고, 필요한 작업(요청, 수락, 거절 등)을 서버로 요청
왜 서버에서 상태를 저장할까?
1. 데이터 일관성 보장
- 친구 관계나 요청 상태는 다수의 클라이언트 간에 공유되는 데이터
- 상태를 서버에 저장하면 여러 클라이언트에서 같은 데이터를 일관되게 볼 수 있다.
- 예: A가 B에게 친구 요청을 보냈을 때, A와 B 모두 같은 상태("대기중")를 확인.
2. 성능 최적화
- 클라이언트에서 상태를 계산하면 불필요한 데이터 요청 및 계산 로직이 필요
- 서버에서 상태를 계산하여 저장하면, 클라이언트가 단순히 저장된 상태를 가져오는 것으로 충분.
- 예: "친구 목록", "받은 친구 요청" 등을 빠르게 쿼리 가능.
3. 클라이언트 코드 단순화
- 상태 관리 로직이 서버에 집중되므로 클라이언트 코드가 단순화
- 상태 업데이트 로직도 서버에서 처리되어 클라이언트에서 여러 케이스를 처리할 필요가 없음.
- 예: 친구 요청을 수락하면 서버에서 양쪽 사용자의 친구 목록을 업데이트.
4. 보안 관리
- 상태 정보를 클라이언트에서 관리하면 악의적인 조작 가능성이 존재
- 서버에서 상태를 저장하고 변경 작업도 서버에서만 가능하도록 제한하면, 데이터 무결성을 유지
- 예: 친구 요청 상태를 "친구"로 변경하는 작업을 클라이언트에서 수행하지 않음.
💡 의문 해결
- Firestore 상태 저장 방식 채택
- 상태를 명시적으로 저장하여 클라이언트 로직을 단순화.
- 성능 최적화를 위해 서버에서 상태를 관리하도록 변경 계획.
❓ 사용자 생성 및 Firebase Firestore 연결에 대한 고민
도윤님께 여쭤본 내용
도윤님께 여쭤본 결과, 도감에 등록할 때 Firebase와 연결한다고 하셨다. Firestore의 경우 데이터를 확인하고, 내용이 없으면 새로 만들어 쓴다고 한다. 개인적으로 NoSQL 구조가 아직 익숙하지 않아서 어렵게 느껴졌다.
사용자 생성 관련 고민
Firebase Authentication을 통해 사용자가 처음 로그인할 때, Firebase.auth.currentUser?.uid
로 uid
를 가져와야 한다는 점은 이해했다. 하지만 그 uid
를 기반으로 Firestore에 USER
컬렉션에 Document를 생성해야 하는 시점이 헷갈렸다.
고민했던 부분
- 로그인 직후 생성해야 할까?
- 사용자가 처음 로그인한 시점에서
uid
로 Firestore에 사용자 정보를 바로 만들어야 하는지 고민됐다. 도윤님 말로는 Firestore에 이미 Document가 존재하는지 확인 후 없으면 새로 생성해야 한다고 하셨다. 이 부분이 Firestore에서 데이터를 읽고 확인하는 로직을 작성해야 한다는 의미로 들렸다.
- 사용자가 처음 로그인한 시점에서
- Document 생성 여부 확인 방식
- Firestore의 구조를 보면, 컬렉션(
USER
) 안에 각 사용자의uid
로 된 Document가 존재해야 한다. 따라서 Document를 먼저 조회하고 없으면 생성해야 하는 흐름이 맞다고 생각했다. - "NoSQL은 구조를 미리 정하지 않아도 된다"는 점이 직관적으로 와닿지 않아서 계속 의문이 생겼다.
- Firestore의 구조를 보면, 컬렉션(
결론
사용자가 처음 로그인했을 때, 아래와 같은 방식으로 진행해야 한다고 정리했다:
- Firebase Authentication으로 로그인
Firebase.auth.currentUser?.uid
로uid
를 가져온다.
- Firestore에 사용자 Document 존재 여부 확인
USER
컬렉션에서 해당uid
를 조회한다.
- Document가 없을 경우 생성
- 기본 사용자 데이터를 바탕으로 Firestore에 새로운 Document를 추가한다.
느낀 점
Firestore와 NoSQL 구조를 이해하는 데 시간이 걸릴 것 같다. 도윤님이 관련 문서를 읽으라고 하셨는데, 결국 물어보면서 배우는 게 더 잘 와닿았다. 하지만 문서도 천천히 읽어볼 생각이다. Firestore에서 데이터를 가져오고 관리하는 흐름은 구현하면서 점점 익숙해질 거라고 믿는다.
로그인 할 때 Firestore에 user 정보 등록 추가
- 다른 계정으로 로그인 했을 때 screen 값은 안 바뀌는데 테스트 할 때 필요해서 작업을 진행했다.
💥 Firebase 데이터 직렬화 문제 해결
문제 상황
Firebase Firestore를 통해 친구 목록과 친구 요청 데이터를 가져오려는 과정에서 다음과 같은 에러가 발생했다:
D 친구 요청 목록을 가져오는 데 실패했습니다: Could not deserialize object. Class com.and04.naturealbum.data.dto.FirebaseFriendRequest does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped
2024-11-19 23:20:34.100 19734-19734 FriendViewModel com.and04.naturealbum D 친구 목록을 가져오는 데 실패했습니다: Could not deserialize object. Class com.and04.naturealbum.data.dto.F
문제 원인
Firebase Firestore의 객체 매핑 방식
- Firestore는 데이터를 객체로 매핑할 때 기본 생성자(no-argument constructor)를 사용한다.
FirebaseFriend
와FirebaseFriendRequest
클래스에 기본 생성자가 없었기 때문에 Firestore가 데이터를 매핑하지 못하고InstantiationException
을 발생시켰다.
해결 방안
기본 생성자 추가
Firestore의 데이터 매핑 방식을 지원하기 위해 기본 생성자를 추가했다. 기본 생성자는 모든 필드에 디폴트 값을 설정했다.
- 모든 필드에 디폴트 값을 설정하여 Firestore가 객체를 매핑할 수 있도록 구성.
결론
- 문제의 원인은 기본 생성자가 없는 상태에서 Firestore가 데이터를 직렬화/역직렬화하려다 발생한 에러였다.
FirebaseFriend
와FirebaseFriendRequest
클래스에 기본 생성자를 추가하고 필드의 디폴트 값을 설정함으로써 문제를 해결했다.- 이 수정으로 Firestore와의 데이터 매핑 문제가 정상적으로 해결되었으며, 비슷한 문제가 발생할 경우 기본 생성자와 필드의 디폴트 값 설정 여부를 우선 확인하면 된다.
💥 id 초기화 문제
현재 문제 발생 원인
-
sendFriendRequest
메서드에서FirebaseFriendRequest
를 생성할 때id
필드를 초기화하지 않고 있음. -
따라서
id
필드는 Firestore에 빈 문자열""
로 저장됨. -
하지만, 앱에서
document.id
를 사용해 데이터를 가져오므로, 앱 로직에서id
는 실제 Firestore 문서 ID를 가져오게 됨override suspend fun getFriendRequests(uid: String): List<FirebaseFriendRequest> { return try { fireStore.collection(USER) .document(uid) .collection(FRIEND_REQUESTS) .get() .await() .documents.map { document -> val request = document.toObject(FirebaseFriendRequest::class.java) request?.copy(id = document.id) ?: FirebaseFriendRequest() } } catch (e: Exception) { emptyList() } }
-
Firestore에서는 **필드 값으로 저장된
id
*와 문서 ID가 일치하지 않음.
해결 방법
sendFriendRequest
에서 FirebaseFriendRequest
를 생성할 때, id
필드를 명시적으로 문서 ID와 동일하게 설정
가져올 때도 이제는 document id로 가져오는 연산 제외하고 그대로 가져와도 됨
override suspend fun getFriendRequests(uid: String): List<FirebaseFriendRequest> {
return fireStore.collection(USER)
.document(uid)
.collection(FRIEND_REQUESTS)
.get()
.await()
.toObjects(FirebaseFriendRequest::class.java)
}
현재까지 구현된 내용 요약 (2024-11-19-화)
1. 구현된 기능
- 친구 요청 보내기
- 사용자가 다른 사용자에게 친구 요청을 보낼 수 있음.
- 요청 상태(
sent
,received
)로 각각의 상태를 Firestore에 저장.
- 친구 요청 수락/거절
- 요청을 수락하면 서로의 친구 목록에 추가되고 요청 목록에서 삭제.
- 요청을 거절하면 요청 목록에서 삭제.
- 친구 목록 보기
- Firestore에 저장된 친구 목록을 가져와 확인 가능.
- 친구 요청 목록 보기
- Firestore에서 현재 사용자에게 받은 요청 목록을 가져와 확인 가능.
- 모든 사용자 보기
- Firestore에 저장된 전체 사용자 목록을 가져옴.
- 데이터 상태 확인
- 친구 요청, 친구 목록, 요청 상태를 각각 로그로 출력하여 확인 가능.
2. 해결된 문제
- Firebase 데이터 매핑
toObjects()
로 데이터를 바로 매핑하지 않고,document.id
를id
필드에 추가해 객체에 저장.FirebaseFriend
와FirebaseFriendRequest
클래스에 기본 생성자를 추가하여 매핑 오류 해결.
- 문자열로 저장된 시간 관리
LocalDateTime
대신 문자열(String
)로 저장해 Firebase와의 직렬화 문제 해결.
- 친구 요청 처리 중 상태 오류
- 수락/거절 시, 상대방의 상태가 잘못 저장되던 문제 해결:
- 요청을 보낸 사용자와 받은 사용자 각각에 올바른 ID를 저장하도록 로직 수정.
- 수락/거절 시, 상대방의 상태가 잘못 저장되던 문제 해결:
3. 현재 살펴봐야 하는 문제
- 동시 친구 요청 처리
- 두 사용자가 서로 동시에 친구 요청을 보낼 경우:
- 최근 요청만 저장되어 한쪽 요청이 무시됨.
- Firebase 트랜잭션에서 요청 상태를 미리 확인하고 중복 요청을 방지하도록 로직 개선 필요.
- 두 사용자가 서로 동시에 친구 요청을 보낼 경우:
- 친구가 된 후에도 친구 요청 가능
- 이미 친구 관계가 형성된 사용자에게 친구 요청을 보낼 수 있음.
- UI에서 버튼 활성화 조건을 추가하여 이미 친구인 사용자에게는 요청 버튼을 비활성화하도록 처리해야 함.
- 사용자 상태 표시
- 사용자 목록을 볼 때, 각 사용자의 상태(친구, 요청 보냄, 요청 받음, 상태 없음)를 함께 보여주는 기능 필요.
- 사용자 데이터를 가져올 때, 친구 목록과 요청 목록을 병합하여 상태를 판단하는 로직이 추가되어야 함.
- 에러 처리 개선
- Firebase와 통신 실패 시 로그만 출력되고 있어, 사용자에게 명확한 에러 메시지 표시 필요.
- 네트워크 오류 시 적절한 리트라이(retry) 로직 추가 고려.
4. 앞으로 추가 구현해야 할 기능
- UI와 상태 통합
- 현재 구현된 Firebase 연동 로직을 기반으로, 친구 요청, 수락/거절, 목록 확인 기능을 UI와 연결.
- 사용자 상태에 따라 UI의 버튼 활성화/비활성화 처리.
- 추가 상태 처리
- 친구 요청 상태가
sent
또는received
일 때, 요청 목록에 추가 표시. - 친구 관계인 경우 친구 목록에서만 표시되도록 로직 구현.
- 친구 요청 상태가
- 테스트 시나리오 확장
- 동시 요청 처리, 요청 취소, 잘못된 데이터 처리 등 다양한 상황을 테스트하여 로직 안정성 확보.
현재 상태
- 기본적인 친구 요청, 수락/거절, 목록 가져오기 기능은 구현 완료.
- UI와 상태 통합, 에러 처리 및 동시 요청 문제 해결을 통해 기능 완성도를 높여야 함.
2024-11-20-수
Firestore 데이터 처리와 Cloud Functions 고민
현재 상황
- Firestore 쿼리 작업: 현재 Android에서 Firestore 쿼리를 활용해
Repository
에서 데이터를 가져오는 방식으로 구현 중이다. - Cloud Functions 발견: Firebase Cloud Functions를 통해 API를 만들 수 있다는 것을 알게 되었으나, Node.js 기반으로 TypeScript와 JavaScript를 사용해야 하는 점이 부담이 됨.
결론
- 현재 방식: Firestore 쿼리를 통해 데이터를 처리하며 진행.
- 추후 변경 가능성: Firebase Cloud Functions를 활용한 API 방식은 나중에 작업할 수 있도록 주말 이후로 검토 예정.
- 당장의 작업 방향: Firestore 쿼리를 적절히 작성해 필요한 데이터를 처리하는 방식 유지.
이로써 현재 구조에서는 Firestore 쿼리를 최대한 활용하여 진행하는 것이 효율적이다. Cloud Functions는 추가적인 작업으로 고려할 예정이다.
진행 상황 점검
- getAllUsersInfo에서 uid 기준으로 friendStatus 처리 로직 수정
- 친구 요청 상태를 "sent"와 "received"로 구분하여 UI에서 적절히 표시 가능하도록 개선
- 친구 관계 확인 및 상태 업데이트 로직 추가
- FriendTestScreen 버튼 2열 레이아웃으로 개선
- 버튼 그룹이 화면을 가리지 않도록 수정
- UI에서 사용자 상태별 정보 표시 로직 추가
- "sent", "received", "friend", "normal" 상태에 따라 화면에 반영
UI에 필요한 데이터 추가해서 구조 수정
https://github.com/user-attachments/assets/4d6182b0-914d-433e-aa47-65fe921e8910
이후 진행해야 하는 것
- 검색 기능은 안되어 있음 전체 보기로 되어 있음 ⇒ 검색 구현
- 버튼 누르고서 바로 UI 업데이트 되지는 않음 ⇒ UI 제어 필요
- 서로 동시에 친구 요청을 보낼 경우도 처리 필요: 트랜잭션 활용해보기