-- AI / manual catalog translations (EN, AR) for products and categories. -- Source text stays on the entity; extra locales live here, one row per entity + locale. DO $$ BEGIN CREATE TYPE translation_entity_type AS ENUM ('product', 'category'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; DO $$ BEGIN CREATE TYPE translation_locale AS ENUM ('en', 'ar'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; DO $$ BEGIN CREATE TYPE translation_status AS ENUM ('pending', 'ready', 'stale', 'failed'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; CREATE TABLE IF NOT EXISTS entity_translations ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, business_id BIGINT NOT NULL, entity_type translation_entity_type NOT NULL, entity_id BIGINT NOT NULL, locale translation_locale NOT NULL, fields JSONB NOT NULL DEFAULT '{}'::jsonb, source_hash VARCHAR(64) NOT NULL, status translation_status NOT NULL DEFAULT 'pending', generated_by VARCHAR(16) NOT NULL DEFAULT 'ai', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT entity_translations_business_id_fkey FOREIGN KEY (business_id) REFERENCES businesses (id) ON DELETE CASCADE, CONSTRAINT entity_translations_entity_locale_unique UNIQUE (entity_type, entity_id, locale) ); CREATE INDEX IF NOT EXISTS idx_entity_translations_business_id ON entity_translations (business_id); CREATE INDEX IF NOT EXISTS idx_entity_translations_entity ON entity_translations (entity_type, entity_id); DROP TRIGGER IF EXISTS entity_translations_set_updated_at ON entity_translations; CREATE TRIGGER entity_translations_set_updated_at BEFORE UPDATE ON entity_translations FOR EACH ROW EXECUTE FUNCTION set_updated_at();