You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/db/migrate/20250103000005_backfill_ins...

87 lines
2.9 KiB

# frozen_string_literal: true
# Migration 5: Backfill institution data
# Part of Winston's 4-layer data isolation foundation
# This migration backfills existing data and makes institution_id non-nullable
class BackfillInstitutionData < ActiveRecord::Migration[7.0]
def up
# For existing installations, we need to:
# 1. Create default institutions for each account
# 2. Link existing users to their institutions via account_access
# 3. Make institution_id non-nullable
# Note: This is a data migration that should be run carefully in production
# We'll use raw SQL for performance on large datasets
execute <<-SQL
-- Step 1: Create default institutions for accounts that don't have them
INSERT INTO institutions (
account_id,
super_admin_id,
name,
registration_number,
address,
contact_email,
contact_phone,
settings,
created_at,
updated_at
)
SELECT DISTINCT
a.id as account_id,
(
SELECT u.id
FROM users u
WHERE u.account_id = a.id
AND u.role = 'admin'
ORDER BY u.created_at
LIMIT 1
) as super_admin_id,
COALESCE(a.name, 'Default Institution') as name,
NULL as registration_number,
NULL as address,
NULL as contact_email,
NULL as contact_phone,
'{}'::jsonb as settings,
NOW() as created_at,
NOW() as updated_at
FROM accounts a
LEFT JOIN institutions i ON a.id = i.account_id
WHERE i.id IS NULL;
-- Step 2: Update account_accesses with institution_id
UPDATE account_accesses aa
SET institution_id = i.id
FROM institutions i
WHERE aa.account_id = i.account_id;
-- Step 3: Add default role for existing records
UPDATE account_accesses
SET role = 'cohort_super_admin'
WHERE institution_id IS NOT NULL;
-- Step 4: Add unique index for [user_id, institution_id]
-- This will prevent duplicate roles
CREATE UNIQUE INDEX index_account_accesses_on_user_id_and_institution_id
ON account_accesses(user_id, institution_id)
WHERE institution_id IS NOT NULL;
SQL
# Step 5: Make institution_id non-nullable
change_column_null :account_accesses, :institution_id, false
# Step 6: Add foreign key constraint
add_foreign_key :account_accesses, :institutions, name: 'fk_account_accesses_to_institutions'
end
def down
# Reverse operations
remove_foreign_key :account_accesses, name: 'fk_account_accesses_to_institutions'
change_column_null :account_accesses, :institution_id, true
remove_index :account_accesses, name: 'index_account_accesses_on_user_id_and_institution_id'
# Don't delete institutions as they may contain important data
# Instead, just nullify the institution_id in account_accesses
execute 'UPDATE account_accesses SET institution_id = NULL'
end
end