Files
gongxue-base/supabase/migrations/202606290002_tenant_classes.sql
2026-06-29 00:50:22 +08:00

87 lines
3.9 KiB
SQL

create table if not exists public.tenant_classes (
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,
code text,
name text not null,
description text,
status text not null default 'active' check (status in ('active', 'disabled', 'archived')),
sort_order integer not null default 0,
metadata jsonb not null default '{}'::jsonb,
created_by uuid references public.platform_users(id) on delete set null,
updated_by uuid references public.platform_users(id) on delete set null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (tenant_id, id),
unique (tenant_id, legacy_id)
);
comment on table public.tenant_classes is
'Tenant-scoped class/cohort records used for teacher, head-teacher, assistant and student data scopes.';
create unique index if not exists idx_tenant_classes_code_unique
on public.tenant_classes(tenant_id, lower(code))
where code is not null and code <> '';
create index if not exists idx_tenant_classes_tenant_status
on public.tenant_classes(tenant_id, status, sort_order, created_at desc);
create index if not exists idx_tenant_classes_region
on public.tenant_classes(tenant_id, region_id)
where region_id is not null;
create table if not exists public.tenant_class_members (
id uuid primary key default gen_random_uuid(),
tenant_id uuid not null references public.tenants(id) on delete cascade,
class_id uuid not null,
user_id uuid not null references public.platform_users(id) on delete cascade,
member_type text not null check (member_type in ('student', 'teacher', 'assistant', 'head_teacher')),
status text not null default 'active' check (status in ('active', 'disabled', 'removed')),
joined_at timestamptz not null default now(),
left_at timestamptz,
metadata jsonb not null default '{}'::jsonb,
created_by uuid references public.platform_users(id) on delete set null,
updated_by uuid references public.platform_users(id) on delete set null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique (tenant_id, class_id, user_id, member_type),
foreign key (tenant_id, class_id) references public.tenant_classes(tenant_id, id) on delete cascade
);
comment on table public.tenant_class_members is
'Class membership assignments. Students can belong to multiple classes; teachers gain scoped visibility through active class memberships.';
create index if not exists idx_class_members_tenant_class
on public.tenant_class_members(tenant_id, class_id, status, member_type);
create index if not exists idx_class_members_tenant_user
on public.tenant_class_members(tenant_id, user_id, status, member_type);
alter table public.tenant_classes enable row level security;
alter table public.tenant_class_members enable row level security;
drop policy if exists tenant_isolation on public.tenant_classes;
create policy tenant_isolation on public.tenant_classes
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.tenant_class_members;
create policy tenant_isolation on public.tenant_class_members
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.tenant_classes;
create trigger set_updated_at
before update on public.tenant_classes
for each row
execute function app.touch_updated_at();
drop trigger if exists set_updated_at on public.tenant_class_members;
create trigger set_updated_at
before update on public.tenant_class_members
for each row
execute function app.touch_updated_at();