← back to Wallco Ai
migrations/20260601_prompt_match_columns.sql
108 lines
-- 20260601_prompt_match_columns.sql
--
-- Promote the prompt-vs-image A/B rating signal from the append-only JSONL
-- ledger (data/prompt-match-ratings.jsonl) to first-class PG columns, so the
-- rating becomes the source of truth and the generator learning loop
-- (scripts/learn_from_votes.js) can read it.
--
-- NOTE on topology: `spoon_all_designs` is a VIEW over base table `all_designs`.
-- The existing user_* rating columns physically live on all_designs and are
-- exposed via the view's explicit column list. So we must (1) ALTER the BASE
-- table additively, then (2) CREATE OR REPLACE the view appending the 3 new
-- columns at the END of its select list (the only thing CREATE OR REPLACE VIEW
-- permits without a drop). The view is updatable, so the API's
-- `UPDATE spoon_all_designs SET user_prompt_*` writes through to all_designs.
--
-- ADDITIVE ONLY. No drops, no renames of existing columns. ALTER ... IF NOT
-- EXISTS makes the table change idempotent/re-runnable. CREATE OR REPLACE VIEW
-- only appends columns (existing column order/names unchanged), so it is safe
-- on local dw_unified and prod dw_unified. Mirrors existing user_stars (smallint),
-- user_color_good (boolean), user_rated_at (timestamptz).
--
-- Columns added (on all_designs, surfaced via spoon_all_designs):
-- user_prompt_match smallint -- 1..5 "does the image match the prompt"
-- user_prompt_verdict text -- 'approve' | 'reject' | NULL
-- user_prompt_rated_at timestamptz -- when the rating was last set
--
-- Does NOT touch is_published, the settlement gate, or designs.json sync.
BEGIN;
ALTER TABLE all_designs ADD COLUMN IF NOT EXISTS user_prompt_match smallint;
ALTER TABLE all_designs ADD COLUMN IF NOT EXISTS user_prompt_verdict text;
ALTER TABLE all_designs ADD COLUMN IF NOT EXISTS user_prompt_rated_at timestamptz;
-- Re-expose through the view (append-only; existing columns unchanged).
CREATE OR REPLACE VIEW spoon_all_designs AS
SELECT all_designs.id,
all_designs.brand,
all_designs.kind,
all_designs.width_in,
all_designs.height_in,
all_designs.panels,
all_designs.generator,
all_designs.prompt,
all_designs.negative_prompt,
all_designs.seed,
all_designs.steps,
all_designs.cfg_scale,
all_designs.pd_source_ids,
all_designs.image_url,
all_designs.local_path,
all_designs.dominant_hex,
all_designs.palette,
all_designs.motifs,
all_designs.tags,
all_designs.category,
all_designs.is_published,
all_designs.notes,
all_designs.created_at,
all_designs.product_line,
all_designs.parent_design_id,
all_designs.chat_session_id,
all_designs.request_text,
all_designs.verticals,
all_designs.source_shopify_id,
all_designs.source_dw_sku,
all_designs.source_url,
all_designs.gd_score,
all_designs.gd_critique,
all_designs.id_score,
all_designs.id_critique,
all_designs.combined_score,
all_designs.rating_summary,
all_designs.rated_at,
all_designs.user_score_avg,
all_designs.user_vote_count,
all_designs.poll_wins,
all_designs.poll_losses,
all_designs.elo,
all_designs.room_mockups,
all_designs.user_removed,
all_designs.user_color_good,
all_designs.user_style_good,
all_designs.user_scale_good,
all_designs.user_stars,
all_designs.user_rated_at,
all_designs.ai_title,
all_designs.ai_pattern,
all_designs.ai_color_name,
all_designs.dig_number,
all_designs.ai_reviewed_at,
all_designs.ai_review_raw,
all_designs.spoonflower_design_id,
all_designs.spoonflower_url,
all_designs.spoonflower_uploaded_at,
all_designs.shopify_product_id,
all_designs.shopify_product_url,
all_designs.shopify_uploaded_at,
all_designs.settlement_verdict,
all_designs.inspired_by_sku,
all_designs.inspired_by_vendor,
all_designs.user_prompt_match,
all_designs.user_prompt_verdict,
all_designs.user_prompt_rated_at
FROM all_designs;
COMMIT;