Skip to content

refactor(persistence): normalize UserProfile into a shared user_profiles table - #1210

Merged
bmc08gt merged 1 commit into
code/cashfrom
refactor/normalize-user-profile-table
Aug 10, 2026
Merged

refactor(persistence): normalize UserProfile into a shared user_profiles table#1210
bmc08gt merged 1 commit into
code/cashfrom
refactor/normalize-user-profile-table

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

What

The full UserProfile was serialized as a JSON blob and duplicated onto every chat_members row (once per membership) and onto blocked_users. This normalizes it into a single user_profiles table keyed by user_id_hex, joined back via @Relation — mirroring the existing TokenWithBalanceRelation pattern.

Changes

  • New user_profiles table with decomposed scalar columns (display_name, phone_value/verified, email_value/verified). The two inherently-nested values (social_accounts_json, profile_picture_json) stay serialized — modelling them as columns would need child tables for no query benefit.
  • chat_members / blocked_users drop user_profile_json; they now join the shared profile via ChatMemberWithProfile / BlockedUserWithProfile.
  • v25 to v26 manual migration: stages each user's legacy blob once (dedups the same user across chats; the full chat blob is preferred over the blocklist's name+avatar-only one), then table-recreates both tables to drop the column. Column drops avoid ALTER TABLE ... DROP COLUMN for minSdk-29 SQLite compatibility.
  • Preserve via backfill: a one-shot pass (fired from PersistenceProvider) decomposes the staged blobs into columns and clears the staging field. Reads also fall back to parsing a not-yet-backfilled blob, so correctness never depends on backfill timing.
  • Two-writer safety: chat sync writes the authoritative full profile (upsertFull); blocklist sync writes only name+avatar via an INSERT OR REPLACE + correlated-subquery merge that never downgrades a richer cached profile (avoids ON CONFLICT DO UPDATE, which minSdk-29 SQLite lacks).

Testing

:apps:flipcash:app:assembleDebug green. New unit tests (Robolectric) cover: migration dedup + column-drop + blob staging, backfill decomposition, partial-write-preserves-richer-profile, and the chat-member relation join. Full :db + :sources suites pass.

…les table

The full UserProfile was serialized as a JSON blob and duplicated onto every
chat_members row (once per membership) and onto blocked_users. This normalizes it
into a single user_profiles table keyed by user_id_hex, joined back via @relation.

- New UserProfileEntity with decomposed scalar columns (display name, phone, email);
  the two inherently-nested values (social accounts, profile picture) stay serialized.
- chat_members / blocked_users drop user_profile_json and join the shared profile
  via ChatMemberWithProfile / BlockedUserWithProfile.
- v25->v26 manual migration: stages each user's legacy blob once (dedup across chats,
  chat's full blob preferred over the blocklist's name+avatar-only one), then
  table-recreates both tables to drop the column. Column drops avoid ALTER TABLE DROP
  COLUMN for minSdk-29 SQLite compatibility.
- Preserve via backfill: a one-shot pass decomposes the staged blobs; reads also fall
  back to parsing a not-yet-backfilled blob, so correctness never depends on timing.
- Two-writer safety: chat sync writes the authoritative full profile; blocklist sync
  writes only name+avatar via an INSERT OR REPLACE + correlated-subquery merge that
  never downgrades a richer cached profile (avoids ON CONFLICT DO UPDATE, absent on
  minSdk-29 SQLite).

Tests: migration dedup + column-drop, backfill decomposition, partial-write
preservation, and the chat-member relation join.
@github-actions github-actions Bot added the type: refactor Code restructuring, no behavior change label Aug 10, 2026
@bmc08gt
bmc08gt merged commit 512e76e into code/cash Aug 10, 2026
2 of 4 checks passed
@bmc08gt
bmc08gt deleted the refactor/normalize-user-profile-table branch August 10, 2026 23:33
bmc08gt added a commit that referenced this pull request Aug 11, 2026
…ipcash-protos

* origin/code/cash:
  refactor(persistence): normalize UserProfile into a shared user_profiles table (#1210)
  fix(tests): repair unit tests broken by the new-ui v2 merge (#1212)
  feat(kmp/ed25519): in-place KMP module (JNI on Android, cinterop on iOS) + mnemonic Kotlin rewrite (#1204)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: refactor Code restructuring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant