From d787e583415694720c4b204adffa1d110a15e3d4 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Mon, 9 Mar 2026 15:06:06 +0100 Subject: [PATCH] fix(migration): handle missing sdk_states table in migration 039 The sdk_states table may not exist yet if no state has been saved via the frontend. Wrap sdk_states alterations in a conditional DO block. Co-Authored-By: Claude Opus 4.6 --- .../migrations/039_compliance_projects.sql | 117 +++++++++--------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/backend-compliance/migrations/039_compliance_projects.sql b/backend-compliance/migrations/039_compliance_projects.sql index 27abdfc..84a0c8e 100644 --- a/backend-compliance/migrations/039_compliance_projects.sql +++ b/backend-compliance/migrations/039_compliance_projects.sql @@ -29,67 +29,72 @@ CREATE INDEX IF NOT EXISTS idx_compliance_projects_status ON compliance_projects -- ============================================================================= -- 2. sdk_states: Add project_id, adjust constraints +-- Only runs if sdk_states table exists (it may not yet exist if no state +-- has been saved via the frontend state API) -- ============================================================================= --- Drop the old UNIQUE constraint on tenant_id (allows multiple states per tenant) -ALTER TABLE sdk_states DROP CONSTRAINT IF EXISTS sdk_states_tenant_id_key; - --- Add project_id column (nullable initially for migration) -ALTER TABLE sdk_states ADD COLUMN IF NOT EXISTS project_id UUID; - --- ============================================================================= --- 3. Data migration: Create default projects for existing states --- ============================================================================= - --- For each existing sdk_states row without a project, create a default project -INSERT INTO compliance_projects (id, tenant_id, name, customer_type, status) -SELECT - gen_random_uuid(), - s.tenant_id, - COALESCE(s.state->'companyProfile'->>'companyName', 'Projekt 1'), - COALESCE(s.state->>'customerType', 'new'), - 'active' -FROM sdk_states s -WHERE s.project_id IS NULL -ON CONFLICT DO NOTHING; - --- Link existing states to their newly created projects -UPDATE sdk_states s -SET project_id = p.id -FROM compliance_projects p -WHERE s.tenant_id = p.tenant_id AND s.project_id IS NULL; - --- ============================================================================= --- 4. Add constraints after migration --- ============================================================================= - --- Make project_id NOT NULL now that all rows have a value --- (Only if there are no NULL values remaining — safe guard) DO $$ BEGIN - IF NOT EXISTS (SELECT 1 FROM sdk_states WHERE project_id IS NULL) THEN - ALTER TABLE sdk_states ALTER COLUMN project_id SET NOT NULL; - END IF; -END $$; - --- Unique constraint: one state per (tenant, project) -DO $$ -BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'uq_sdk_states_tenant_project' + -- Check if sdk_states exists + IF EXISTS ( + SELECT 1 FROM information_schema.tables + WHERE table_name = 'sdk_states' ) THEN - ALTER TABLE sdk_states ADD CONSTRAINT uq_sdk_states_tenant_project - UNIQUE (tenant_id, project_id); - END IF; -END $$; + -- Drop the old UNIQUE constraint on tenant_id (allows multiple states per tenant) + ALTER TABLE sdk_states DROP CONSTRAINT IF EXISTS sdk_states_tenant_id_key; --- Foreign key to compliance_projects -DO $$ -BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'fk_sdk_states_project' - ) THEN - ALTER TABLE sdk_states ADD CONSTRAINT fk_sdk_states_project - FOREIGN KEY (project_id) REFERENCES compliance_projects(id) ON DELETE CASCADE; + -- Add project_id column (nullable initially for migration) + ALTER TABLE sdk_states ADD COLUMN IF NOT EXISTS project_id UUID; + + -- ===================================================================== + -- 3. Data migration: Create default projects for existing states + -- ===================================================================== + + -- For each existing sdk_states row without a project, create a default project + INSERT INTO compliance_projects (id, tenant_id, name, customer_type, status) + SELECT + gen_random_uuid(), + s.tenant_id, + COALESCE(s.state->'companyProfile'->>'companyName', 'Projekt 1'), + COALESCE(s.state->>'customerType', 'new'), + 'active' + FROM sdk_states s + WHERE s.project_id IS NULL + ON CONFLICT DO NOTHING; + + -- Link existing states to their newly created projects + UPDATE sdk_states s + SET project_id = p.id + FROM compliance_projects p + WHERE s.tenant_id = p.tenant_id AND s.project_id IS NULL; + + -- ===================================================================== + -- 4. Add constraints after migration + -- ===================================================================== + + -- Make project_id NOT NULL if all rows have a value + IF NOT EXISTS (SELECT 1 FROM sdk_states WHERE project_id IS NULL) THEN + ALTER TABLE sdk_states ALTER COLUMN project_id SET NOT NULL; + END IF; + + -- Unique constraint: one state per (tenant, project) + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'uq_sdk_states_tenant_project' + ) THEN + ALTER TABLE sdk_states ADD CONSTRAINT uq_sdk_states_tenant_project + UNIQUE (tenant_id, project_id); + END IF; + + -- Foreign key to compliance_projects + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'fk_sdk_states_project' + ) THEN + ALTER TABLE sdk_states ADD CONSTRAINT fk_sdk_states_project + FOREIGN KEY (project_id) REFERENCES compliance_projects(id) ON DELETE CASCADE; + END IF; + + RAISE NOTICE 'sdk_states migration completed successfully'; + ELSE + RAISE NOTICE 'sdk_states table does not exist yet — skipping sdk_states migration (will be applied on first state save)'; END IF; END $$;