feat(edit): 商品编辑页开发
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
SET search_path TO atlas, public;
|
||||
|
||||
-- M3.3 keeps the user-curated AI source material beside the product aggregate.
|
||||
-- The original collection normalized_payload/raw_evidence remains immutable
|
||||
-- evidence; this nullable document is initialized from that evidence on read
|
||||
-- and becomes durable only after the user saves the editor draft.
|
||||
ALTER TABLE products
|
||||
ADD COLUMN ai_source_material JSONB,
|
||||
ADD CONSTRAINT ck_products_ai_source_material_object
|
||||
CHECK (ai_source_material IS NULL OR jsonb_typeof(ai_source_material) = 'object');
|
||||
@@ -0,0 +1,40 @@
|
||||
SET search_path TO atlas, public;
|
||||
|
||||
-- M3.3.1 evolves the full AI source snapshot into field-level overrides.
|
||||
-- Preserve any document saved between migrations 019 and 020 by treating all
|
||||
-- of its material fields as explicit overrides based on its recorded source
|
||||
-- snapshot revision.
|
||||
ALTER TABLE products
|
||||
ADD COLUMN ai_source_material_base_revision BIGINT
|
||||
CHECK (ai_source_material_base_revision IS NULL OR ai_source_material_base_revision > 0);
|
||||
|
||||
-- The migrator owns the table, but products uses FORCE RLS. Temporarily turn
|
||||
-- it off inside this atomic migration so existing rows from every workspace
|
||||
-- can be transformed; the table lock prevents application writes in between.
|
||||
ALTER TABLE products NO FORCE ROW LEVEL SECURITY;
|
||||
ALTER TABLE products DISABLE ROW LEVEL SECURITY;
|
||||
|
||||
UPDATE products
|
||||
SET ai_source_material_base_revision =
|
||||
CASE
|
||||
WHEN ai_source_material ? 'source_snapshot_revision'
|
||||
AND (ai_source_material->>'source_snapshot_revision') ~ '^[1-9][0-9]*$'
|
||||
THEN (ai_source_material->>'source_snapshot_revision')::BIGINT
|
||||
ELSE NULL
|
||||
END,
|
||||
ai_source_material = ai_source_material - 'source_snapshot_revision'
|
||||
WHERE ai_source_material IS NOT NULL;
|
||||
|
||||
ALTER TABLE products RENAME COLUMN ai_source_material TO ai_source_material_overrides;
|
||||
ALTER TABLE products
|
||||
ALTER COLUMN ai_source_material_overrides SET DEFAULT '{}'::jsonb;
|
||||
|
||||
UPDATE products
|
||||
SET ai_source_material_overrides = '{}'::jsonb
|
||||
WHERE ai_source_material_overrides IS NULL;
|
||||
|
||||
ALTER TABLE products
|
||||
ALTER COLUMN ai_source_material_overrides SET NOT NULL;
|
||||
|
||||
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE products FORCE ROW LEVEL SECURITY;
|
||||
@@ -0,0 +1,46 @@
|
||||
SET search_path TO atlas, public;
|
||||
|
||||
-- M3.4 stores the platform's cached category attribute contract separately
|
||||
-- from workspace drafts. Product attributes always reference IDs from this
|
||||
-- schema; dictionary values are a cache, never free-form client metadata.
|
||||
CREATE TABLE platform_product_category_attributes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
platform_id UUID NOT NULL REFERENCES platforms(id) ON DELETE CASCADE,
|
||||
platform_product_category_id UUID NOT NULL,
|
||||
platform_attribute_id TEXT NOT NULL,
|
||||
complex_id TEXT NOT NULL DEFAULT '0',
|
||||
name TEXT NOT NULL,
|
||||
value_type TEXT NOT NULL CHECK (value_type IN ('text', 'integer', 'decimal', 'boolean', 'dictionary')),
|
||||
is_required BOOLEAN NOT NULL DEFAULT false,
|
||||
is_collection BOOLEAN NOT NULL DEFAULT false,
|
||||
max_value_count INTEGER NOT NULL DEFAULT 1 CHECK (max_value_count BETWEEN 1 AND 100),
|
||||
dictionary_id TEXT,
|
||||
is_aspect BOOLEAN NOT NULL DEFAULT false,
|
||||
source_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
FOREIGN KEY (platform_id, platform_product_category_id)
|
||||
REFERENCES platform_product_categories(platform_id, id) ON DELETE CASCADE,
|
||||
UNIQUE (platform_id, platform_product_category_id, platform_attribute_id, complex_id),
|
||||
CHECK ((value_type = 'dictionary') = (dictionary_id IS NOT NULL)),
|
||||
CHECK (is_collection OR max_value_count = 1)
|
||||
);
|
||||
CREATE INDEX ix_platform_product_category_attributes_lookup
|
||||
ON platform_product_category_attributes (platform_id, platform_product_category_id, is_required DESC, name, id);
|
||||
|
||||
CREATE TABLE platform_attribute_dictionary_values (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
platform_id UUID NOT NULL REFERENCES platforms(id) ON DELETE CASCADE,
|
||||
dictionary_id TEXT NOT NULL,
|
||||
external_value_id TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
source_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (platform_id, dictionary_id, external_value_id)
|
||||
);
|
||||
CREATE INDEX ix_platform_attribute_dictionary_values_search
|
||||
ON platform_attribute_dictionary_values (platform_id, dictionary_id, is_active, value, external_value_id);
|
||||
Reference in New Issue
Block a user