forked from wangziqi/gongxue-base
151 lines
6.7 KiB
SQL
151 lines
6.7 KiB
SQL
create table if not exists public.referral_codes (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
user_id uuid not null references public.platform_users(id) on delete cascade,
|
|
code citext not null,
|
|
status text not null default 'active' check (status in ('active', 'disabled')),
|
|
channel text,
|
|
landing_path text,
|
|
metadata jsonb not null default '{}'::jsonb,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, user_id),
|
|
unique (tenant_id, code)
|
|
);
|
|
|
|
comment on table public.referral_codes is
|
|
'Tenant-scoped referral codes for sales, agents, teachers, operators, and other permitted referrers.';
|
|
|
|
create table if not exists public.referral_leads (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
student_user_id uuid not null references public.platform_users(id) on delete cascade,
|
|
referrer_user_id uuid references public.platform_users(id) on delete set null,
|
|
ref_code citext,
|
|
source text,
|
|
first_track_id uuid references public.referral_tracks(id) on delete set null,
|
|
bind_type text not null default 'first_touch' check (bind_type in ('first_touch', 'manual', 'imported')),
|
|
status text not null default 'protected' check (status in ('protected', 'invalid', 'released')),
|
|
protected_until timestamptz,
|
|
metadata jsonb not null default '{}'::jsonb,
|
|
bound_at timestamptz not null default now(),
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, student_user_id)
|
|
);
|
|
|
|
comment on table public.referral_leads is
|
|
'First-binding lead ownership. Once a student is bound to a referrer, normal scan/share events cannot rebind the lead.';
|
|
|
|
create table if not exists public.referral_team_edges (
|
|
id uuid primary key default gen_random_uuid(),
|
|
tenant_id uuid not null references public.tenants(id) on delete cascade,
|
|
member_user_id uuid not null references public.platform_users(id) on delete cascade,
|
|
leader_user_id uuid references public.platform_users(id) on delete set null,
|
|
relation_type text not null default 'sales_team' check (relation_type in ('sales_team', 'agent_network', 'teacher_class')),
|
|
status text not null default 'active' check (status in ('active', 'disabled')),
|
|
metadata jsonb not null default '{}'::jsonb,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, member_user_id, relation_type)
|
|
);
|
|
|
|
create table if not exists public.referral_qrcodes (
|
|
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 set null,
|
|
ref_code citext not null,
|
|
scene text not null,
|
|
page text not null default 'pages/index/index',
|
|
provider text not null default 'wechat-miniapp',
|
|
qrcode_url text,
|
|
status text not null default 'pending' check (status in ('pending', 'ready', 'failed', 'disabled')),
|
|
error_message text,
|
|
metadata jsonb not null default '{}'::jsonb,
|
|
created_at timestamptz not null default now(),
|
|
updated_at timestamptz not null default now(),
|
|
unique (tenant_id, provider, scene, page)
|
|
);
|
|
|
|
alter table public.referral_tracks
|
|
add column if not exists metadata jsonb not null default '{}'::jsonb,
|
|
add column if not exists lead_id uuid references public.referral_leads(id) on delete set null;
|
|
|
|
alter table public.crm_webhook_queue
|
|
add column if not exists source text,
|
|
add column if not exists payload jsonb not null default '{}'::jsonb,
|
|
add column if not exists idempotency_key text,
|
|
add column if not exists target_url text;
|
|
|
|
alter table public.crm_webhook_log
|
|
add column if not exists request_payload jsonb not null default '{}'::jsonb;
|
|
|
|
create unique index if not exists idx_crm_queue_tenant_record_id
|
|
on public.crm_webhook_queue(tenant_id, record_id)
|
|
where record_id is not null;
|
|
|
|
create unique index if not exists idx_crm_queue_tenant_idempotency
|
|
on public.crm_webhook_queue(tenant_id, idempotency_key)
|
|
where idempotency_key is not null;
|
|
|
|
create index if not exists idx_referral_codes_tenant_code
|
|
on public.referral_codes(tenant_id, code, status);
|
|
|
|
create index if not exists idx_referral_leads_referrer
|
|
on public.referral_leads(tenant_id, referrer_user_id, bound_at desc);
|
|
|
|
create index if not exists idx_referral_team_leader
|
|
on public.referral_team_edges(tenant_id, leader_user_id, status);
|
|
|
|
create index if not exists idx_referral_tracks_lead
|
|
on public.referral_tracks(tenant_id, lead_id, created_at desc);
|
|
|
|
alter table public.referral_codes enable row level security;
|
|
alter table public.referral_leads enable row level security;
|
|
alter table public.referral_team_edges enable row level security;
|
|
alter table public.referral_qrcodes enable row level security;
|
|
|
|
drop policy if exists tenant_isolation on public.referral_codes;
|
|
create policy tenant_isolation on public.referral_codes
|
|
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());
|
|
|
|
drop policy if exists tenant_isolation on public.referral_leads;
|
|
create policy tenant_isolation on public.referral_leads
|
|
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());
|
|
|
|
drop policy if exists tenant_isolation on public.referral_team_edges;
|
|
create policy tenant_isolation on public.referral_team_edges
|
|
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());
|
|
|
|
drop policy if exists tenant_isolation on public.referral_qrcodes;
|
|
create policy tenant_isolation on public.referral_qrcodes
|
|
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());
|
|
|
|
drop trigger if exists set_updated_at on public.referral_codes;
|
|
create trigger set_updated_at
|
|
before update on public.referral_codes
|
|
for each row execute function app.touch_updated_at();
|
|
|
|
drop trigger if exists set_updated_at on public.referral_leads;
|
|
create trigger set_updated_at
|
|
before update on public.referral_leads
|
|
for each row execute function app.touch_updated_at();
|
|
|
|
drop trigger if exists set_updated_at on public.referral_team_edges;
|
|
create trigger set_updated_at
|
|
before update on public.referral_team_edges
|
|
for each row execute function app.touch_updated_at();
|
|
|
|
drop trigger if exists set_updated_at on public.referral_qrcodes;
|
|
create trigger set_updated_at
|
|
before update on public.referral_qrcodes
|
|
for each row execute function app.touch_updated_at();
|