feat(migrations): UNIQUE constraints on account_artist_ids + artist_organization_ids pairs
What
Adds supabase/migrations/20260708200000_join_row_unique_constraints.sql:
account_artist_ids—UNIQUE (account_id, artist_id). The table has only a bigint PK onidtoday, so nothing prevents duplicate pairs and the join row can't serve as a deterministic key.artist_organization_ids—UNIQUE (artist_id, organization_id).
Each constraint is preceded by a defensive dedupe (keep the lowest id per pair, delete the rest) so the migration applies cleanly against prod data even if duplicate pairs exist — none are known today. Constraint adds are guarded by pg_constraint existence checks, so the migration is idempotent.
Why
P1 prerequisite for re-keying Composio connection ownership on the join row (connector-connection scoping): recoupable/chat#1860.
Cross-reference: this closes the same check-then-insert race class tracked in recoupable/chat#1844 for these two sibling tables — concurrent duplicate inserts now fail at the database instead of minting duplicate rows. It does not fix #1844 itself (different tables).
Status
Not yet applied to any environment — migration apply + verification pending, tracked in chat#1860.
🤖 Generated with Claude Code
Summary by cubic
Add UNIQUE constraints to account_artist_ids and artist_organization_ids so each pair is stored once and the join row can serve as a deterministic key. This prevents duplicate inserts and enables connector-connection scoping needed for chat#1860.
- Migration
- Dedupes existing rows first (keeps lowest id per pair).
- Adds
UNIQUE(account_id, artist_id)andUNIQUE(artist_id, organization_id)if missing (idempotent). - Safe to run on prod; no app changes required.
Summary by CodeRabbit
- Bug Fixes
- Prevented duplicate link records in artist/account and artist/organization relationships.
- Improved data consistency by cleaning up existing duplicates before enforcing uniqueness.
- Reduced the chance of duplicate entries appearing from repeated or concurrent actions.