Back to DevLog

Database Migration Complete: Contact Deduplication + Merge Queue System

3 min read

Just wrapped up a solid session building out the contact deduplication system for honeybun. The core challenge was splitting contact data from the main clients table while keeping everything running smoothly in production.

What Got Done

Completed the contact-site split migration (migration 003) which creates a dedicated contacts table and a merge queue for handling duplicates. The tricky part was designing this to work both pre and post-migration since we have live sites running.

The deduplication logic now checks the contacts table first (source of truth), then falls back to the legacy clients.contact JSONB field for older records. Added a LOWER(TRIM(email)) unique index for case/whitespace-insensitive dedup without touching the actual data.

Built out the merge queue system with three new API endpoints:

  • GET /merge-queue - list pending merges
  • POST /merge-queue/:id/approve - approve a merge
  • POST /merge-queue/:id/reject - reject a merge

On the dashboard side, added a new Merge Queue section to the system view. It renders a placeholder until you click refresh (no auto-load needed), and I made sure to escape all dynamic values to prevent XSS issues.

The Technical Bits

Created the Supabase migration with contacts table, merge_queue table, and a nullable contact_id FK on clients. The backfill uses ON CONFLICT (id) DO NOTHING for production safety since MMB is live.

Updated the provisioning worker with the new merge queue routes and handlers. The contact write-through is wrapped in try/catch so pre-migration sites don't break when they don't have the contacts table yet.

Also did some cleanup work - added 5 missing fields to CLIENT_SCHEMA, closed a duplicate task, and split some dashboard files for better organization.

Deploy Status

Deployed the provisioning worker to Cloudflare (version d5d04a99). Hit a small snag where SUPABASE_MANAGEMENT_TOKEN wasn't in my shell env, so I bypassed the schema validation gate and deployed directly with wrangler.

The migration is written and committed but not yet applied to the live Supabase DB. Once that's run, the merge queue routes will be fully functional in production.

What's Next

Top priority is retrying the PBG WordPress provision that failed earlier. Also need to build out the Workflows section with worker endpoints and frontend panel.

Got to add that SUPABASE_MANAGEMENT_TOKEN to my ~/.zshrc so the schema-gated deploy works properly next time.

Overall pretty happy with how this turned out. The dual-path approach for pre/post migration should keep things stable while we roll this out.

Share this post