Files
order_site/apps/backend/src/db/migrations/001_init.sql
T

203 lines
7.7 KiB
SQL

CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE IF NOT EXISTS admin_users (
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
role TEXT NOT NULL,
status TEXT NOT NULL,
session_version INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
CREATE TABLE IF NOT EXISTS admin_audit_logs (
id BIGSERIAL PRIMARY KEY,
actor_user_id BIGINT,
actor_username TEXT NOT NULL DEFAULT '',
actor_role TEXT NOT NULL DEFAULT '',
action TEXT NOT NULL,
target_type TEXT NOT NULL,
target_id TEXT NOT NULL,
payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_created_at ON admin_audit_logs(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_target ON admin_audit_logs(target_type, target_id);
CREATE TABLE IF NOT EXISTS fulfillment_profiles (
id BIGSERIAL PRIMARY KEY,
profile_key TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
executor_key TEXT NOT NULL,
requires_claim BOOLEAN NOT NULL DEFAULT FALSE,
auto_dispatch BOOLEAN NOT NULL DEFAULT FALSE,
inventory_strategy TEXT NOT NULL DEFAULT 'static_pool',
config_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
CREATE TABLE IF NOT EXISTS fulfillment_profile_requirements (
id BIGSERIAL PRIMARY KEY,
profile_id BIGINT NOT NULL REFERENCES fulfillment_profiles(id) ON DELETE CASCADE,
role_key TEXT NOT NULL,
credential_type TEXT NOT NULL,
quantity_per_unit INTEGER NOT NULL DEFAULT 1,
is_required BOOLEAN NOT NULL DEFAULT TRUE,
config_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
UNIQUE(profile_id, role_key)
);
CREATE TABLE IF NOT EXISTS orders (
id BIGSERIAL PRIMARY KEY,
provider TEXT NOT NULL,
platform TEXT NOT NULL,
shop_id TEXT NOT NULL DEFAULT '',
shop_name TEXT NOT NULL DEFAULT '',
platform_order_id TEXT NOT NULL,
order_status TEXT NOT NULL DEFAULT 'created',
pay_status TEXT NOT NULL DEFAULT 'unpaid',
buyer_id TEXT NOT NULL DEFAULT '',
buyer_name TEXT NOT NULL DEFAULT '',
receiver_contact TEXT NOT NULL DEFAULT '',
total_amount INTEGER NOT NULL DEFAULT 0,
currency TEXT NOT NULL DEFAULT 'CNY',
raw_payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
paid_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
UNIQUE(provider, platform, shop_id, platform_order_id)
);
CREATE INDEX IF NOT EXISTS idx_orders_platform_order_lookup
ON orders(provider, platform, platform_order_id, id DESC);
CREATE INDEX IF NOT EXISTS idx_orders_created_at_desc
ON orders(created_at DESC);
CREATE TABLE IF NOT EXISTS order_items (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
sku_code TEXT NOT NULL,
sku_name TEXT NOT NULL DEFAULT '',
quantity INTEGER NOT NULL DEFAULT 1,
spec_json JSONB NOT NULL DEFAULT '{}'::jsonb,
item_snapshot_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_order_items_order_id ON order_items(order_id);
CREATE INDEX IF NOT EXISTS idx_order_items_sku_code ON order_items(sku_code);
CREATE TABLE IF NOT EXISTS fulfillment_tasks (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
order_item_id BIGINT NOT NULL REFERENCES order_items(id) ON DELETE CASCADE,
unit_index INTEGER NOT NULL DEFAULT 1,
task_no TEXT NOT NULL UNIQUE,
provider TEXT NOT NULL,
platform TEXT NOT NULL,
shop_id TEXT NOT NULL DEFAULT '',
shop_name TEXT NOT NULL DEFAULT '',
platform_order_id TEXT NOT NULL,
profile_id BIGINT NOT NULL REFERENCES fulfillment_profiles(id) ON DELETE RESTRICT,
executor_key TEXT NOT NULL,
task_status TEXT NOT NULL DEFAULT 'pending_payment',
delivery_status TEXT NOT NULL DEFAULT 'pending',
result_code TEXT NOT NULL DEFAULT '',
result_message TEXT NOT NULL DEFAULT '',
claim_token TEXT NOT NULL DEFAULT '',
claim_expires_at TIMESTAMPTZ,
automation_mode TEXT NOT NULL DEFAULT 'manual',
requires_claim BOOLEAN NOT NULL DEFAULT FALSE,
user_action_status TEXT NOT NULL DEFAULT 'not_required',
attempt_count INTEGER NOT NULL DEFAULT 0,
last_error TEXT NOT NULL DEFAULT '',
context_json JSONB NOT NULL DEFAULT '{}'::jsonb,
claimed_at TIMESTAMPTZ,
role_confirmed_at TIMESTAMPTZ,
redeemed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
UNIQUE(order_item_id, unit_index)
);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_status ON fulfillment_tasks(task_status, delivery_status);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_order ON fulfillment_tasks(order_id, order_item_id);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_claim_token ON fulfillment_tasks(claim_token);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_platform_order_lookup
ON fulfillment_tasks(provider, platform, platform_order_id, id DESC);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_created_at_desc
ON fulfillment_tasks(created_at DESC);
CREATE TABLE IF NOT EXISTS claim_tokens (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT NOT NULL UNIQUE REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
token TEXT NOT NULL UNIQUE,
status TEXT NOT NULL DEFAULT 'active',
expired_at TIMESTAMPTZ NOT NULL,
used_at TIMESTAMPTZ,
max_use_count INTEGER NOT NULL DEFAULT 1,
used_count INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_claim_tokens_status ON claim_tokens(status, expired_at);
CREATE TABLE IF NOT EXISTS task_events (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT NOT NULL REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
event_type TEXT NOT NULL,
payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_task_events_task_created_at ON task_events(task_id, created_at DESC);
CREATE TABLE IF NOT EXISTS task_runtime_contexts (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT NOT NULL UNIQUE REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
runtime_session_id TEXT NOT NULL DEFAULT '',
login_type TEXT NOT NULL DEFAULT '',
nickname TEXT NOT NULL DEFAULT '',
role_id TEXT NOT NULL DEFAULT '',
role_name TEXT NOT NULL DEFAULT '',
area TEXT NOT NULL DEFAULT '',
partition_name TEXT NOT NULL DEFAULT '',
screenshot_path TEXT NOT NULL DEFAULT '',
artifacts_json JSONB NOT NULL DEFAULT '{}'::jsonb,
state_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL
);
CREATE TABLE IF NOT EXISTS kuaishou_cloud_task_states (
task_id BIGINT PRIMARY KEY REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
ticket_status TEXT NOT NULL DEFAULT 'pending',
ticket_code_masked TEXT NOT NULL DEFAULT '',
bind_url TEXT NOT NULL DEFAULT '',
vn_phone TEXT NOT NULL DEFAULT '',
role_name TEXT NOT NULL DEFAULT '',
role_id TEXT NOT NULL DEFAULT '',
dispatch_status TEXT NOT NULL DEFAULT 'pending',
consume_status TEXT NOT NULL DEFAULT 'pending',
source_key TEXT NOT NULL DEFAULT '',
updated_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_role_id
ON kuaishou_cloud_task_states(role_id);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_source_key
ON kuaishou_cloud_task_states(source_key);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_dispatch_status
ON kuaishou_cloud_task_states(dispatch_status);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_consume_status
ON kuaishou_cloud_task_states(consume_status);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_updated_at_desc
ON kuaishou_cloud_task_states(updated_at DESC);