CREATE TABLE IF NOT EXISTS media_supply_favorite_owners ( tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, revision BIGINT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (tenant_id, user_id), CONSTRAINT chk_media_supply_favorite_owner_revision CHECK (revision >= 0) ); CREATE TABLE IF NOT EXISTS media_supply_favorite_groups ( tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, group_key VARCHAR(64) NOT NULL, name VARCHAR(64) NOT NULL, sort_order INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (tenant_id, user_id, group_key), CONSTRAINT fk_media_supply_favorite_group_owner FOREIGN KEY (tenant_id, user_id) REFERENCES media_supply_favorite_owners (tenant_id, user_id) ON DELETE CASCADE, CONSTRAINT chk_media_supply_favorite_group_key_not_blank CHECK (BTRIM(group_key) <> ''), CONSTRAINT chk_media_supply_favorite_group_name_not_blank CHECK (BTRIM(name) <> '') ); CREATE UNIQUE INDEX IF NOT EXISTS uk_media_supply_favorite_group_name ON media_supply_favorite_groups (tenant_id, user_id, LOWER(name)); CREATE INDEX IF NOT EXISTS idx_media_supply_favorite_group_owner_order ON media_supply_favorite_groups (tenant_id, user_id, sort_order, created_at); CREATE TABLE IF NOT EXISTS media_supply_favorite_resources ( tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, group_key VARCHAR(64) NOT NULL, resource_id BIGINT NOT NULL REFERENCES supplier_media_resources(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (tenant_id, user_id, group_key, resource_id), CONSTRAINT fk_media_supply_favorite_resource_group FOREIGN KEY (tenant_id, user_id, group_key) REFERENCES media_supply_favorite_groups (tenant_id, user_id, group_key) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_media_supply_favorite_group_page ON media_supply_favorite_resources ( tenant_id, user_id, group_key, created_at DESC, resource_id DESC ); CREATE INDEX IF NOT EXISTS idx_media_supply_favorite_resource_lookup ON media_supply_favorite_resources (resource_id, tenant_id, user_id);