forked from wangziqi/gongxue-base
258 lines
9.7 KiB
SQL
258 lines
9.7 KiB
SQL
create table if not exists public.products (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
region_id uuid references public.regions(id) on delete set null,
|
|
legacy_id text,
|
|
title text not null,
|
|
price_label text,
|
|
link text,
|
|
type text,
|
|
tags jsonb not null default '[]'::jsonb,
|
|
cover text,
|
|
preview_iframe text,
|
|
detail_images jsonb not null default '[]'::jsonb,
|
|
sort_order integer not null default 0,
|
|
status text not null default 'active' check (status in ('active', 'inactive', 'archived')),
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.timelines (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
region_id uuid references public.regions(id) on delete set null,
|
|
school_id uuid references public.schools(id) on delete set null,
|
|
legacy_id text,
|
|
type text,
|
|
title text not null,
|
|
description text,
|
|
event_date date,
|
|
link text,
|
|
sort_order integer not null default 0,
|
|
is_active boolean not null default true,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.video_explanations (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
legacy_id text,
|
|
title text not null,
|
|
description text,
|
|
video_url text,
|
|
thumbnail_url text,
|
|
duration_seconds integer,
|
|
knowledge_tags jsonb not null default '[]'::jsonb,
|
|
is_general boolean not null default false,
|
|
subject_id uuid references public.subjects(id) on delete set null,
|
|
legacy_subject_id text,
|
|
difficulty integer,
|
|
sort_order integer not null default 0,
|
|
is_active boolean not null default true,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.question_videos (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
question_id uuid references public.questions(id) on delete cascade,
|
|
video_id uuid references public.video_explanations(id) on delete cascade,
|
|
legacy_id text,
|
|
legacy_question_id text,
|
|
legacy_video_id text,
|
|
video_type text not null default 'specific',
|
|
sort_order integer not null default 0,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.scoreline_schools (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
region_id uuid references public.regions(id) on delete set null,
|
|
legacy_id text,
|
|
name text not null,
|
|
short_name text,
|
|
type text,
|
|
is_hot boolean not null default false,
|
|
sort_order integer not null default 0,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.scoreline_majors (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
region_id uuid references public.regions(id) on delete set null,
|
|
school_id uuid references public.scoreline_schools(id) on delete cascade,
|
|
legacy_id text,
|
|
name text not null,
|
|
sort_order integer not null default 0,
|
|
has_restriction boolean not null default false,
|
|
restriction_desc text,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.scoreline_fields (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
region_id uuid references public.regions(id) on delete set null,
|
|
legacy_id text,
|
|
field_key text not null,
|
|
field_name text not null,
|
|
field_type text,
|
|
unit text,
|
|
is_filter boolean not null default false,
|
|
is_required boolean not null default false,
|
|
is_visible boolean not null default true,
|
|
is_trend boolean not null default false,
|
|
options jsonb not null default '[]'::jsonb,
|
|
placeholder text,
|
|
description text,
|
|
sort_order integer not null default 0,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id),
|
|
unique (tenant_id, region_id, field_key)
|
|
);
|
|
|
|
create table if not exists public.scoreline_records (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
region_id uuid references public.regions(id) on delete set null,
|
|
school_id uuid references public.scoreline_schools(id) on delete set null,
|
|
major_id uuid references public.scoreline_majors(id) on delete set null,
|
|
legacy_id text,
|
|
year integer not null,
|
|
school_name text,
|
|
major_name text,
|
|
field_values jsonb not null default '{}'::jsonb,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.referral_tracks (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
legacy_id text,
|
|
event_type text not null,
|
|
ref_code text,
|
|
ref_user_id uuid references public.platform_users(id) on delete set null,
|
|
target_user_id uuid references public.platform_users(id) on delete set null,
|
|
source text,
|
|
ip_address text,
|
|
user_agent text,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.badges (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
legacy_id text,
|
|
name text not null,
|
|
description text,
|
|
category text,
|
|
icon_url text,
|
|
level integer,
|
|
unlock_type text,
|
|
condition_field text,
|
|
condition_operator text,
|
|
condition_value numeric,
|
|
condition_extra jsonb not null default '{}'::jsonb,
|
|
sort_order integer not null default 0,
|
|
is_active boolean not null default true,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.user_badges (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
user_id uuid references public.platform_users(id) on delete cascade,
|
|
badge_id uuid references public.badges(id) on delete cascade,
|
|
granted_by uuid references public.platform_users(id) on delete set null,
|
|
legacy_id text,
|
|
note text,
|
|
granted_at timestamptz,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.crm_webhook_queue (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
legacy_id text,
|
|
record_id text,
|
|
status text not null default 'pending',
|
|
scheduled_at timestamptz,
|
|
attempts integer not null default 0,
|
|
next_attempt_at timestamptz,
|
|
last_error text,
|
|
last_http_code integer,
|
|
lead_id text,
|
|
sent_at timestamptz,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create table if not exists public.crm_webhook_log (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
legacy_id text,
|
|
record_id text,
|
|
http_code integer,
|
|
outcome text,
|
|
error_message text,
|
|
lead_id text,
|
|
request_body text,
|
|
response_summary text,
|
|
signed_at timestamptz,
|
|
attempt integer,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, legacy_id)
|
|
);
|
|
|
|
create index if not exists idx_products_tenant_region on public.products(tenant_id, region_id, sort_order);
|
|
create index if not exists idx_timelines_tenant_region on public.timelines(tenant_id, region_id, event_date);
|
|
create index if not exists idx_video_explanations_tenant_subject on public.video_explanations(tenant_id, subject_id);
|
|
create index if not exists idx_scoreline_records_tenant_year on public.scoreline_records(tenant_id, region_id, year desc);
|
|
create index if not exists idx_referral_tracks_tenant_event on public.referral_tracks(tenant_id, event_type, created_at desc);
|
|
create index if not exists idx_crm_queue_tenant_status on public.crm_webhook_queue(tenant_id, status, next_attempt_at);
|
|
|
|
do $$
|
|
declare
|
|
table_name text;
|
|
begin
|
|
foreach table_name in array array[
|
|
'products', 'timelines', 'video_explanations', 'question_videos',
|
|
'scoreline_schools', 'scoreline_majors', 'scoreline_fields', 'scoreline_records',
|
|
'referral_tracks', 'badges', 'user_badges', 'crm_webhook_queue', 'crm_webhook_log'
|
|
]
|
|
loop
|
|
execute format('alter table public.%I enable row level security', table_name);
|
|
execute format('drop policy if exists tenant_isolation on public.%I', table_name);
|
|
execute format(
|
|
'create policy tenant_isolation on public.%I for all using (tenant_id = app.current_tenant_id() or app.is_platform_admin()) with check (tenant_id = app.current_tenant_id() or app.is_platform_admin())',
|
|
table_name
|
|
);
|
|
execute format('drop trigger if exists set_updated_at on public.%I', table_name);
|
|
execute format('create trigger set_updated_at before update on public.%I for each row execute function app.touch_updated_at()', table_name);
|
|
end loop;
|
|
end $$;
|