diff --git a/app/src/main/java/app/closer/core/billing/FirestoreEntitlementChecker.kt b/app/src/main/java/app/closer/core/billing/FirestoreEntitlementChecker.kt index 996badd8..7fe2f824 100644 --- a/app/src/main/java/app/closer/core/billing/FirestoreEntitlementChecker.kt +++ b/app/src/main/java/app/closer/core/billing/FirestoreEntitlementChecker.kt @@ -1,5 +1,6 @@ package app.closer.core.billing +import app.closer.data.remote.FirestoreCollections import app.closer.domain.model.AuthState import app.closer.domain.repository.AuthRepository import com.google.firebase.firestore.DocumentSnapshot @@ -125,7 +126,9 @@ class FirestoreEntitlementChecker @Inject constructor( } private fun entitlementsRef(userId: String) = - firestore.collection("users").document(userId).collection("entitlements").document("premium") + firestore.collection(FirestoreCollections.USERS).document(userId) + .collection(FirestoreCollections.Users.ENTITLEMENTS) + .document(FirestoreCollections.Users.ENTITLEMENT_PREMIUM_DOC) companion object { private const val PREMIUM_ENTITLEMENT_ID = "closer_premium" diff --git a/app/src/main/java/app/closer/data/remote/FirestoreBucketListDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreBucketListDataSource.kt index dd6107b4..fb5a149a 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreBucketListDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreBucketListDataSource.kt @@ -26,7 +26,8 @@ class FirestoreBucketListDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() private fun itemsRef(coupleId: String) = - db.collection("couples").document(coupleId).collection("bucket_list") + db.collection(FirestoreCollections.COUPLES).document(coupleId) + .collection(FirestoreCollections.Couples.BUCKET_LIST) // ─── CRUD methods ──────────────────────────────────────────────────────── diff --git a/app/src/main/java/app/closer/data/remote/FirestoreCollections.kt b/app/src/main/java/app/closer/data/remote/FirestoreCollections.kt new file mode 100644 index 00000000..349c9cc4 --- /dev/null +++ b/app/src/main/java/app/closer/data/remote/FirestoreCollections.kt @@ -0,0 +1,40 @@ +package app.closer.data.remote + +/** + * Single source of truth for all Firestore collection and fixed document-ID names. + * + * Use these constants everywhere instead of inline string literals so that a path + * rename requires a change in exactly one place and the compiler catches every caller. + */ +object FirestoreCollections { + + // ── Top-level collections ───────────────────────────────────────────────── + const val USERS = "users" + const val COUPLES = "couples" + const val INVITES = "invites" + + // ── Subcollections under users/{uid} ────────────────────────────────────── + object Users { + const val ENTITLEMENTS = "entitlements" + const val FCM_TOKENS = "fcmTokens" + const val ENTITLEMENT_PREMIUM_DOC = "premium" + } + + // ── Subcollections under couples/{coupleId} ─────────────────────────────── + object Couples { + const val SESSIONS = "sessions" + const val QUESTION_THREADS = "question_threads" + const val DATE_SWIPES = "date_swipes" + const val DATE_MATCHES = "date_matches" + const val DATE_PLAN_PREFERENCES = "date_plan_preferences" + const val DATE_PLANS = "date_plans" + const val BUCKET_LIST = "bucket_list" + } + + // ── Subcollections under …/question_threads/{threadId} ──────────────────── + object QuestionThreads { + const val ANSWERS = "answers" + const val MESSAGES = "messages" + const val REACTIONS = "reactions" + } +} diff --git a/app/src/main/java/app/closer/data/remote/FirestoreCoupleDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreCoupleDataSource.kt index bfed2307..bf3cb5e7 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreCoupleDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreCoupleDataSource.kt @@ -15,8 +15,8 @@ import kotlin.coroutines.resumeWithException class FirestoreCoupleDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() - private fun coupleRef(coupleId: String) = db.collection("couples").document(coupleId) - private fun userRef(uid: String) = db.collection("users").document(uid) + private fun coupleRef(coupleId: String) = db.collection(FirestoreCollections.COUPLES).document(coupleId) + private fun userRef(uid: String) = db.collection(FirestoreCollections.USERS).document(uid) suspend fun createCouple(inviterUserId: String, acceptorUserId: String, inviteCode: String): String { val coupleId = UUID.randomUUID().toString() @@ -89,7 +89,7 @@ class FirestoreCoupleDataSource @Inject constructor() { suspend fun leaveCouple(userId: String) { val userSnap = suspendCancellableCoroutine { cont -> - db.collection("users").document(userId).get() + userRef(userId).get() .addOnSuccessListener { cont.resume(it) } .addOnFailureListener { cont.resumeWithException(it) } } @@ -104,7 +104,7 @@ class FirestoreCoupleDataSource @Inject constructor() { suspendCancellableCoroutine { cont -> val batch = db.batch() allUserIds.forEach { uid -> - batch.update(db.collection("users").document(uid), "coupleId", null) + batch.update(userRef(uid), "coupleId", null) } batch.commit() .addOnSuccessListener { cont.resume(Unit) } diff --git a/app/src/main/java/app/closer/data/remote/FirestoreDateMatchDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreDateMatchDataSource.kt index f85ed90a..db3c138d 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreDateMatchDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreDateMatchDataSource.kt @@ -36,7 +36,8 @@ class FirestoreDateMatchDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() private fun matchesRef(coupleId: String) = - db.collection("couples").document(coupleId).collection("date_matches") + db.collection(FirestoreCollections.COUPLES).document(coupleId) + .collection(FirestoreCollections.Couples.DATE_MATCHES) suspend fun createMatch(coupleId: String, dateIdeaId: String, matchedBy: List): String { val doc = matchesRef(coupleId).document() diff --git a/app/src/main/java/app/closer/data/remote/FirestoreDatePlanDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreDatePlanDataSource.kt index 8c97b288..15846eb1 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreDatePlanDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreDatePlanDataSource.kt @@ -29,10 +29,12 @@ class FirestoreDatePlanDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() private fun preferencesRef(coupleId: String) = - db.collection("couples").document(coupleId).collection("date_plan_preferences") + db.collection(FirestoreCollections.COUPLES).document(coupleId) + .collection(FirestoreCollections.Couples.DATE_PLAN_PREFERENCES) private fun plansRef(coupleId: String) = - db.collection("couples").document(coupleId).collection("date_plans") + db.collection(FirestoreCollections.COUPLES).document(coupleId) + .collection(FirestoreCollections.Couples.DATE_PLANS) // ─── Preference methods ────────────────────────────────────────────────── diff --git a/app/src/main/java/app/closer/data/remote/FirestoreDateSwipeDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreDateSwipeDataSource.kt index 066166ce..b31ebbb0 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreDateSwipeDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreDateSwipeDataSource.kt @@ -37,7 +37,8 @@ class FirestoreDateSwipeDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() private fun swipesRef(coupleId: String) = - db.collection("couples").document(coupleId).collection("date_swipes") + db.collection(FirestoreCollections.COUPLES).document(coupleId) + .collection(FirestoreCollections.Couples.DATE_SWIPES) suspend fun recordSwipe(coupleId: String, swipe: DateSwipe) { val path = swipesRef(coupleId).document(swipe.dateIdeaId) diff --git a/app/src/main/java/app/closer/data/remote/FirestoreInviteDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreInviteDataSource.kt index 4c3b984d..ec7b2ea6 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreInviteDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreInviteDataSource.kt @@ -14,7 +14,7 @@ import kotlin.random.Random class FirestoreInviteDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() - private fun inviteRef(code: String) = db.collection("invites").document(code) + private fun inviteRef(code: String) = db.collection(FirestoreCollections.INVITES).document(code) fun generateCode(): String = (1..6) .map { CODE_CHARS[Random.nextInt(CODE_CHARS.length)] } diff --git a/app/src/main/java/app/closer/data/remote/FirestoreQuestionThreadDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreQuestionThreadDataSource.kt index abf33671..0a5e0726 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreQuestionThreadDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreQuestionThreadDataSource.kt @@ -24,7 +24,8 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() private fun threadsRef(coupleId: String) = - db.collection("couples").document(coupleId).collection("question_threads") + db.collection(FirestoreCollections.COUPLES).document(coupleId) + .collection(FirestoreCollections.Couples.QUESTION_THREADS) // ─── Thread ───────────────────────────────────────────────────────────────── @@ -77,7 +78,7 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { val now = FieldValue.serverTimestamp() threadsRef(coupleId) .document(threadId) - .collection("answers") + .collection(FirestoreCollections.QuestionThreads.ANSWERS) .document(userId) .set( mapOf( @@ -96,7 +97,7 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { suspend fun getAnswerCount(coupleId: String, threadId: String): Int { val snap = threadsRef(coupleId) .document(threadId) - .collection("answers") + .collection(FirestoreCollections.QuestionThreads.ANSWERS) .getAwait() return snap.size() } @@ -104,7 +105,7 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { fun observeAnswers(coupleId: String, threadId: String): Flow> = callbackFlow { val listener = threadsRef(coupleId) .document(threadId) - .collection("answers") + .collection(FirestoreCollections.QuestionThreads.ANSWERS) .addSnapshotListener { snap, err -> if (err != null || snap == null) return@addSnapshotListener trySend(snap.documents.mapNotNull { it.toQuestionAnswer() }) @@ -117,7 +118,7 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { suspend fun sendMessage(coupleId: String, threadId: String, message: QuestionMessage) { threadsRef(coupleId) .document(threadId) - .collection("messages") + .collection(FirestoreCollections.QuestionThreads.MESSAGES) .add( mapOf( "userId" to message.userId, @@ -130,7 +131,7 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { fun observeMessages(coupleId: String, threadId: String): Flow> = callbackFlow { val listener = threadsRef(coupleId) .document(threadId) - .collection("messages") + .collection(FirestoreCollections.QuestionThreads.MESSAGES) .orderBy("createdAt", Query.Direction.ASCENDING) .addSnapshotListener { snap, err -> if (err != null || snap == null) return@addSnapshotListener @@ -145,7 +146,7 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { val docId = "${reaction.userId}_${reaction.targetUserId}" threadsRef(coupleId) .document(threadId) - .collection("reactions") + .collection(FirestoreCollections.QuestionThreads.REACTIONS) .document(docId) .set( mapOf( @@ -160,7 +161,7 @@ class FirestoreQuestionThreadDataSource @Inject constructor() { fun observeReactions(coupleId: String, threadId: String): Flow> = callbackFlow { val listener = threadsRef(coupleId) .document(threadId) - .collection("reactions") + .collection(FirestoreCollections.QuestionThreads.REACTIONS) .addSnapshotListener { snap, err -> if (err != null || snap == null) return@addSnapshotListener trySend(snap.documents.mapNotNull { it.toQuestionReaction() }) diff --git a/app/src/main/java/app/closer/data/remote/FirestoreUserDataSource.kt b/app/src/main/java/app/closer/data/remote/FirestoreUserDataSource.kt index 6505722a..d2b5bff8 100644 --- a/app/src/main/java/app/closer/data/remote/FirestoreUserDataSource.kt +++ b/app/src/main/java/app/closer/data/remote/FirestoreUserDataSource.kt @@ -14,7 +14,7 @@ import kotlin.coroutines.resumeWithException class FirestoreUserDataSource @Inject constructor() { private val db = FirebaseFirestore.getInstance() - private fun userRef(uid: String) = db.collection("users").document(uid) + private fun userRef(uid: String) = db.collection(FirestoreCollections.USERS).document(uid) suspend fun getUser(uid: String): User? = suspendCancellableCoroutine { cont -> @@ -89,7 +89,7 @@ class FirestoreUserDataSource @Inject constructor() { token: String, metadata: DeviceMetadata ): Unit = suspendCancellableCoroutine { cont -> - userRef(uid).collection("fcmTokens").document(token) + userRef(uid).collection(FirestoreCollections.Users.FCM_TOKENS).document(token) .set( mapOf( "token" to token, diff --git a/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt b/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt index 79edeff7..52f48372 100644 --- a/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt +++ b/app/src/main/java/app/closer/data/repository/QuestionSessionRepositoryImpl.kt @@ -1,5 +1,6 @@ package app.closer.data.repository +import app.closer.data.remote.FirestoreCollections import app.closer.domain.model.QuestionSession import app.closer.domain.repository.QuestionSessionRepository import com.google.firebase.firestore.FirebaseFirestore @@ -14,14 +15,14 @@ class QuestionSessionRepositoryImpl @Inject constructor( override suspend fun saveSession(session: QuestionSession): Result = runCatching { val doc = if (session.id.isBlank()) { - firestore.collection("couples") + firestore.collection(FirestoreCollections.COUPLES) .document(session.coupleId) - .collection("sessions") + .collection(FirestoreCollections.Couples.SESSIONS) .document() } else { - firestore.collection("couples") + firestore.collection(FirestoreCollections.COUPLES) .document(session.coupleId) - .collection("sessions") + .collection(FirestoreCollections.Couples.SESSIONS) .document(session.id) } @@ -41,9 +42,9 @@ class QuestionSessionRepositoryImpl @Inject constructor( override suspend fun getSessionsForCouple(coupleId: String): Result> = runCatching { - firestore.collection("couples") + firestore.collection(FirestoreCollections.COUPLES) .document(coupleId) - .collection("sessions") + .collection(FirestoreCollections.Couples.SESSIONS) .orderBy("completedAt", com.google.firebase.firestore.Query.Direction.DESCENDING) .limit(50) .get()