-- +goose Up -- Per-language AI prompts + multi-language product content. -- ASSUMPTION (backfill): existing single prompts/content map to companies.language -- (fallback "en" when unset/invalid). Primary language columns on processed_products -- remain the denormalized view of localized_content[primary]. ALTER TABLE companies ADD COLUMN IF NOT EXISTS content_languages TEXT[] NOT NULL DEFAULT '{}'; UPDATE companies SET content_languages = ARRAY[COALESCE(NULLIF(lower(trim(language)), ''), 'en')] WHERE content_languages = '{}' OR content_languages IS NULL; ALTER TABLE categories ADD COLUMN IF NOT EXISTS prompts_lang JSONB NOT NULL DEFAULT '{}'::jsonb; UPDATE categories c SET prompts_lang = CASE WHEN COALESCE(c.prompt, '') = '' THEN '{}'::jsonb ELSE jsonb_build_object( COALESCE(NULLIF(lower(trim(co.language)), ''), 'en'), c.prompt ) END FROM companies co WHERE co.id = c.company_id AND c.prompts_lang = '{}'::jsonb AND COALESCE(c.prompt, '') <> ''; ALTER TABLE categories DROP COLUMN IF EXISTS prompt; ALTER TABLE categories RENAME COLUMN prompts_lang TO prompt; ALTER TABLE categories DROP CONSTRAINT IF EXISTS categories_prompt_is_object; ALTER TABLE categories ADD CONSTRAINT categories_prompt_is_object CHECK (jsonb_typeof(prompt) = 'object'); ALTER TABLE ai_prompt_templates ADD COLUMN IF NOT EXISTS language TEXT NOT NULL DEFAULT ''; UPDATE ai_prompt_templates t SET language = COALESCE(NULLIF(lower(trim(c.language)), ''), 'en') FROM companies c WHERE c.id = t.company_id AND (t.language IS NULL OR t.language = ''); ALTER TABLE ai_prompt_templates DROP CONSTRAINT IF EXISTS ai_prompt_templates_company_id_prompt_key_key; ALTER TABLE ai_prompt_templates DROP CONSTRAINT IF EXISTS ai_prompt_templates_company_key_lang_uidx; ALTER TABLE ai_prompt_templates ADD CONSTRAINT ai_prompt_templates_company_key_lang_uidx UNIQUE (company_id, prompt_key, language); ALTER TABLE ai_prompt_templates DROP CONSTRAINT IF EXISTS ai_prompt_templates_language_fmt; ALTER TABLE ai_prompt_templates ADD CONSTRAINT ai_prompt_templates_language_fmt CHECK (language ~ '^[a-z]{2}$'); ALTER TABLE processed_products ADD COLUMN IF NOT EXISTS localized_content JSONB NOT NULL DEFAULT '{}'::jsonb; UPDATE processed_products pp SET localized_content = jsonb_build_object( COALESCE(NULLIF(lower(trim(co.language)), ''), 'en'), jsonb_strip_nulls(jsonb_build_object( 'processed_name', NULLIF(pp.processed_name, ''), 'processed_description', NULLIF(pp.processed_description, ''), 'meta_title', NULLIF(pp.meta_title, ''), 'meta_description', NULLIF(pp.meta_description, '') )) ) FROM companies co WHERE co.id = pp.company_id AND pp.localized_content = '{}'::jsonb AND ( COALESCE(pp.processed_name, '') <> '' OR COALESCE(pp.processed_description, '') <> '' OR COALESCE(pp.meta_title, '') <> '' OR COALESCE(pp.meta_description, '') <> '' ); ALTER TABLE processed_products DROP CONSTRAINT IF EXISTS processed_products_localized_content_is_object; ALTER TABLE processed_products ADD CONSTRAINT processed_products_localized_content_is_object CHECK (jsonb_typeof(localized_content) = 'object'); -- +goose Down ALTER TABLE processed_products DROP CONSTRAINT IF EXISTS processed_products_localized_content_is_object; ALTER TABLE processed_products DROP COLUMN IF EXISTS localized_content; ALTER TABLE ai_prompt_templates DROP CONSTRAINT IF EXISTS ai_prompt_templates_language_fmt; ALTER TABLE ai_prompt_templates DROP CONSTRAINT IF EXISTS ai_prompt_templates_company_key_lang_uidx; ALTER TABLE ai_prompt_templates DROP COLUMN IF EXISTS language; ALTER TABLE ai_prompt_templates ADD CONSTRAINT ai_prompt_templates_company_id_prompt_key_key UNIQUE (company_id, prompt_key); ALTER TABLE categories DROP CONSTRAINT IF EXISTS categories_prompt_is_object; ALTER TABLE categories ADD COLUMN IF NOT EXISTS prompt_text TEXT; UPDATE categories SET prompt_text = ( SELECT trim(value) FROM jsonb_each_text(COALESCE(prompt, '{}'::jsonb)) WHERE trim(value) <> '' LIMIT 1 ); ALTER TABLE categories DROP COLUMN IF EXISTS prompt; ALTER TABLE categories RENAME COLUMN prompt_text TO prompt; ALTER TABLE companies DROP COLUMN IF EXISTS content_languages;