007_listing_ai.sql 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. CREATE TABLE IF NOT EXISTS voc.listing_source_snapshot (
  2. id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  3. public_id text NOT NULL UNIQUE,
  4. workspace_id bigint NOT NULL REFERENCES voc.workspace(id) ON DELETE CASCADE,
  5. platform text NOT NULL CHECK (platform IN ('jd')),
  6. shop_id text NOT NULL,
  7. product_id text NOT NULL,
  8. source_hash text NOT NULL,
  9. payload jsonb NOT NULL,
  10. detail_status text NOT NULL CHECK (detail_status IN ('available', 'empty', 'failed')),
  11. source_modified_at timestamptz,
  12. observed_at timestamptz NOT NULL,
  13. created_at timestamptz NOT NULL DEFAULT now(),
  14. UNIQUE (workspace_id, platform, shop_id, product_id, source_hash)
  15. );
  16. CREATE INDEX IF NOT EXISTS listing_source_current_idx
  17. ON voc.listing_source_snapshot (workspace_id, platform, product_id, observed_at DESC, id DESC);
  18. CREATE TABLE IF NOT EXISTS voc.listing_score_result (
  19. id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  20. public_id text NOT NULL UNIQUE,
  21. workspace_id bigint NOT NULL REFERENCES voc.workspace(id) ON DELETE CASCADE,
  22. product_id text NOT NULL,
  23. source_hash text NOT NULL,
  24. rubric_version text NOT NULL,
  25. overall_score numeric(6,2),
  26. coverage jsonb NOT NULL,
  27. result jsonb NOT NULL,
  28. model_info jsonb NOT NULL DEFAULT '{}'::jsonb,
  29. created_at timestamptz NOT NULL,
  30. UNIQUE (workspace_id, product_id, source_hash, rubric_version)
  31. );
  32. CREATE INDEX IF NOT EXISTS listing_score_product_created_idx
  33. ON voc.listing_score_result (workspace_id, product_id, created_at DESC, id DESC);
  34. CREATE TABLE IF NOT EXISTS voc.listing_score_job (
  35. id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  36. public_id text NOT NULL UNIQUE,
  37. workspace_id bigint NOT NULL REFERENCES voc.workspace(id) ON DELETE CASCADE,
  38. platform text NOT NULL CHECK (platform IN ('jd')),
  39. idempotency_key text NOT NULL,
  40. request_hash text NOT NULL,
  41. rubric_version text NOT NULL,
  42. include_ai_suggestions boolean NOT NULL DEFAULT true,
  43. scope jsonb NOT NULL,
  44. status text NOT NULL CHECK (status IN ('queued', 'running', 'completed', 'partial', 'failed', 'cancelled')),
  45. total integer NOT NULL DEFAULT 0,
  46. processed integer NOT NULL DEFAULT 0,
  47. succeeded integer NOT NULL DEFAULT 0,
  48. partial integer NOT NULL DEFAULT 0,
  49. blocked integer NOT NULL DEFAULT 0,
  50. failed integer NOT NULL DEFAULT 0,
  51. requested_by_external_id text NOT NULL,
  52. requested_at timestamptz NOT NULL,
  53. started_at timestamptz,
  54. completed_at timestamptz,
  55. updated_at timestamptz NOT NULL,
  56. UNIQUE (workspace_id, idempotency_key)
  57. );
  58. CREATE INDEX IF NOT EXISTS listing_score_job_status_idx
  59. ON voc.listing_score_job (workspace_id, status, requested_at DESC, id DESC);
  60. CREATE TABLE IF NOT EXISTS voc.listing_score_item (
  61. id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  62. public_id text NOT NULL UNIQUE,
  63. job_id bigint NOT NULL REFERENCES voc.listing_score_job(id) ON DELETE CASCADE,
  64. workspace_id bigint NOT NULL REFERENCES voc.workspace(id) ON DELETE CASCADE,
  65. product_id text NOT NULL,
  66. source_hash text NOT NULL,
  67. status text NOT NULL CHECK (status IN ('queued', 'rules_scored', 'ai_pending', 'scored', 'partial', 'blocked', 'failed')),
  68. attempts integer NOT NULL DEFAULT 0,
  69. score_result_public_id text,
  70. error_code text,
  71. error_detail_redacted text,
  72. updated_at timestamptz NOT NULL,
  73. UNIQUE (job_id, product_id, source_hash)
  74. );
  75. CREATE INDEX IF NOT EXISTS listing_score_item_status_idx
  76. ON voc.listing_score_item (job_id, status, product_id, id);
  77. CREATE TABLE IF NOT EXISTS voc.listing_version (
  78. id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  79. public_id text NOT NULL UNIQUE,
  80. workspace_id bigint NOT NULL REFERENCES voc.workspace(id) ON DELETE CASCADE,
  81. product_id text NOT NULL,
  82. version_no integer NOT NULL,
  83. base_source_hash text NOT NULL,
  84. base_score_result_public_id text,
  85. content jsonb NOT NULL,
  86. status text NOT NULL CHECK (status IN ('draft', 'adopted', 'stale', 'archived')),
  87. created_by_external_id text NOT NULL,
  88. created_at timestamptz NOT NULL,
  89. adopted_at timestamptz,
  90. UNIQUE (workspace_id, product_id, version_no)
  91. );
  92. CREATE INDEX IF NOT EXISTS listing_version_product_idx
  93. ON voc.listing_version (workspace_id, product_id, created_at DESC, id DESC);