90 lines
4.8 KiB
SQL
90 lines
4.8 KiB
SQL
SET search_path TO atlas, public;
|
|
|
|
CREATE TYPE platform_listing_source AS ENUM ('atlas_published', 'external_sync');
|
|
CREATE TYPE platform_sync_status AS ENUM ('queued', 'running', 'succeeded', 'failed', 'cancelled');
|
|
|
|
CREATE TABLE platform_product_sync_runs (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE RESTRICT,
|
|
store_id UUID NOT NULL,
|
|
platform_id UUID NOT NULL,
|
|
status platform_sync_status NOT NULL DEFAULT 'queued',
|
|
trigger_source TEXT NOT NULL CHECK (trigger_source IN ('manual', 'scheduled', 'recovery')),
|
|
cursor_started TEXT,
|
|
cursor_finished TEXT,
|
|
listed_count INTEGER NOT NULL DEFAULT 0 CHECK (listed_count >= 0),
|
|
upserted_count INTEGER NOT NULL DEFAULT 0 CHECK (upserted_count >= 0),
|
|
failed_count INTEGER NOT NULL DEFAULT 0 CHECK (failed_count >= 0),
|
|
error_payload JSONB,
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
FOREIGN KEY (workspace_id, store_id, platform_id) REFERENCES stores(workspace_id, id, platform_id) ON DELETE RESTRICT,
|
|
UNIQUE (workspace_id, id)
|
|
);
|
|
CREATE INDEX ix_platform_product_sync_runs_store ON platform_product_sync_runs (workspace_id, store_id, created_at DESC, id DESC);
|
|
CREATE UNIQUE INDEX ux_platform_product_sync_runs_active ON platform_product_sync_runs (workspace_id, store_id) WHERE status IN ('queued', 'running');
|
|
|
|
CREATE TABLE platform_listings (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE RESTRICT,
|
|
store_id UUID NOT NULL,
|
|
platform_id UUID NOT NULL,
|
|
remote_product_id TEXT NOT NULL,
|
|
offer_id TEXT NOT NULL,
|
|
remote_sku TEXT,
|
|
name TEXT,
|
|
currency_code CHAR(3) REFERENCES currencies(code),
|
|
selling_price NUMERIC(18,4) CHECK (selling_price IS NULL OR selling_price >= 0),
|
|
list_price NUMERIC(18,4) CHECK (list_price IS NULL OR list_price >= 0),
|
|
visible BOOLEAN,
|
|
remote_state TEXT,
|
|
moderation_status TEXT,
|
|
validation_status TEXT,
|
|
stock_summary JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
image_summary JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
error_payload JSONB NOT NULL DEFAULT '[]'::jsonb,
|
|
visibility_details JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
source platform_listing_source NOT NULL DEFAULT 'external_sync',
|
|
atlas_variant_listing_id UUID,
|
|
last_sync_run_id UUID,
|
|
last_synced_at TIMESTAMPTZ NOT NULL,
|
|
missing_since TIMESTAMPTZ,
|
|
archived_at TIMESTAMPTZ,
|
|
raw_payload JSONB NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
FOREIGN KEY (workspace_id, store_id, platform_id) REFERENCES stores(workspace_id, id, platform_id) ON DELETE RESTRICT,
|
|
FOREIGN KEY (workspace_id, atlas_variant_listing_id) REFERENCES product_variant_platform_listings(workspace_id, id) ON DELETE SET NULL,
|
|
FOREIGN KEY (workspace_id, last_sync_run_id) REFERENCES platform_product_sync_runs(workspace_id, id) ON DELETE SET NULL,
|
|
UNIQUE (workspace_id, id),
|
|
UNIQUE (workspace_id, store_id, platform_id, remote_product_id),
|
|
UNIQUE (workspace_id, store_id, platform_id, offer_id)
|
|
);
|
|
CREATE INDEX ix_platform_listings_store_list ON platform_listings (workspace_id, store_id, updated_at DESC, id DESC);
|
|
CREATE INDEX ix_platform_listings_store_visibility ON platform_listings (workspace_id, store_id, visible, updated_at DESC);
|
|
CREATE INDEX ix_platform_listings_atlas_mapping ON platform_listings (workspace_id, atlas_variant_listing_id) WHERE atlas_variant_listing_id IS NOT NULL;
|
|
|
|
CREATE TABLE platform_listing_sync_snapshots (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE RESTRICT,
|
|
platform_listing_id UUID NOT NULL,
|
|
sync_run_id UUID NOT NULL,
|
|
payload JSONB NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
FOREIGN KEY (workspace_id, platform_listing_id) REFERENCES platform_listings(workspace_id, id) ON DELETE CASCADE,
|
|
FOREIGN KEY (workspace_id, sync_run_id) REFERENCES platform_product_sync_runs(workspace_id, id) ON DELETE CASCADE,
|
|
UNIQUE (workspace_id, platform_listing_id, sync_run_id)
|
|
);
|
|
|
|
-- 商品镜像、同步运行和响应快照均强制租户隔离,Worker 也必须在租户事务中访问。
|
|
DO $$
|
|
DECLARE table_name TEXT;
|
|
BEGIN
|
|
FOREACH table_name IN ARRAY ARRAY['platform_product_sync_runs', 'platform_listings', 'platform_listing_sync_snapshots'] LOOP
|
|
EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', table_name);
|
|
EXECUTE format('ALTER TABLE %I FORCE ROW LEVEL SECURITY', table_name);
|
|
EXECUTE format('CREATE POLICY workspace_isolation ON %I USING (workspace_id = app_current_workspace_id()) WITH CHECK (workspace_id = app_current_workspace_id())', table_name);
|
|
END LOOP;
|
|
END $$;
|