From 415200d8f092b2746a985f93cdb3585b3e518759 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 26 May 2026 14:01:21 -0400 Subject: [PATCH] feat(android): persist client_id for play-event reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a stable client_id column to auth_session for the upcoming PlayEventsReporter. Lazily generated on first read by the reporter; deliberately survives sign-out since it's a device install identity, not a session value. DB version bump 3→4 (destructive migration per the pre-release policy). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../com/fabledsword/minstrel/auth/AuthStore.kt | 18 ++++++++++++++++++ .../minstrel/cache/db/AppDatabase.kt | 2 +- .../minstrel/cache/db/dao/AuthSessionDao.kt | 4 ++++ .../cache/db/entities/AuthSessionEntity.kt | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/fabledsword/minstrel/auth/AuthStore.kt b/android/app/src/main/java/com/fabledsword/minstrel/auth/AuthStore.kt index cc1ae149..5a7753b2 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/auth/AuthStore.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/auth/AuthStore.kt @@ -43,6 +43,9 @@ class AuthStore @Inject constructor( private val themeModeState = MutableStateFlow(null) val themeMode: StateFlow = themeModeState.asStateFlow() + private val clientIdState = MutableStateFlow(null) + val clientId: StateFlow = clientIdState.asStateFlow() + init { scope.launch { dao.observe().collect { row -> @@ -50,6 +53,7 @@ class AuthStore @Inject constructor( baseUrlState.value = row?.baseUrl ?: DEFAULT_BASE_URL userJsonState.value = row?.userJson themeModeState.value = row?.themeMode + clientIdState.value = row?.clientId } } } @@ -74,6 +78,11 @@ class AuthStore @Inject constructor( scope.launch { persistThemeMode(value) } } + fun setClientId(value: String?) { + clientIdState.value = value + scope.launch { persistClientId(value) } + } + private suspend fun persistCookie(value: String?) { if (dao.get() == null) { dao.upsert(currentEntity().copy(sessionCookie = value)) @@ -106,12 +115,21 @@ class AuthStore @Inject constructor( } } + private suspend fun persistClientId(value: String?) { + if (dao.get() == null) { + dao.upsert(currentEntity().copy(clientId = value)) + } else { + dao.setClientId(value) + } + } + private fun currentEntity(): AuthSessionEntity = AuthSessionEntity( id = ROW_ID, sessionCookie = sessionCookieState.value, baseUrl = baseUrlState.value, userJson = userJsonState.value, themeMode = themeModeState.value, + clientId = clientIdState.value, ) companion object { diff --git a/android/app/src/main/java/com/fabledsword/minstrel/cache/db/AppDatabase.kt b/android/app/src/main/java/com/fabledsword/minstrel/cache/db/AppDatabase.kt index 819cd2e8..0a473095 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/cache/db/AppDatabase.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/cache/db/AppDatabase.kt @@ -59,7 +59,7 @@ import com.fabledsword.minstrel.cache.db.entities.SyncMetadataEntity CachedHomeIndexEntity::class, AuthSessionEntity::class, ], - version = 3, + version = 4, exportSchema = true, ) @TypeConverters(MinstrelTypeConverters::class) diff --git a/android/app/src/main/java/com/fabledsword/minstrel/cache/db/dao/AuthSessionDao.kt b/android/app/src/main/java/com/fabledsword/minstrel/cache/db/dao/AuthSessionDao.kt index 683564cd..6901490d 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/cache/db/dao/AuthSessionDao.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/cache/db/dao/AuthSessionDao.kt @@ -34,4 +34,8 @@ interface AuthSessionDao { /** Partial update: change only the theme override ("light"/"dark"/null=system). */ @Query("UPDATE auth_session SET themeMode = :themeMode WHERE id = 0") suspend fun setThemeMode(themeMode: String?) + + /** Partial update: change only the stable client install id. */ + @Query("UPDATE auth_session SET clientId = :clientId WHERE id = 0") + suspend fun setClientId(clientId: String?) } diff --git a/android/app/src/main/java/com/fabledsword/minstrel/cache/db/entities/AuthSessionEntity.kt b/android/app/src/main/java/com/fabledsword/minstrel/cache/db/entities/AuthSessionEntity.kt index 42e1cce1..81528c6e 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/cache/db/entities/AuthSessionEntity.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/cache/db/entities/AuthSessionEntity.kt @@ -28,4 +28,5 @@ data class AuthSessionEntity( val baseUrl: String, val userJson: String? = null, val themeMode: String? = null, + val clientId: String? = null, )