feat: add feedback checkins exam dates

This commit is contained in:
Codex
2026-06-29 01:48:38 +08:00
parent 726d090a8e
commit 8f92d0427e
16 changed files with 1232 additions and 33 deletions

View File

@@ -0,0 +1,95 @@
alter table public.exam_dates
add column if not exists description text,
add column if not exists metadata jsonb not null default '{}'::jsonb;
alter table public.reports
add column if not exists title text,
add column if not exists category text,
add column if not exists priority text not null default 'normal'
check (priority in ('low', 'normal', 'high', 'urgent')),
add column if not exists handled_by uuid references public.platform_users(id) on delete set null,
add column if not exists handled_at timestamptz,
add column if not exists resolution text,
add column if not exists contact text,
add column if not exists attachments jsonb not null default '[]'::jsonb,
add column if not exists metadata jsonb not null default '{}'::jsonb;
do $$
begin
if not exists (select 1 from pg_constraint where conname = 'reports_status_check') then
alter table public.reports
add constraint reports_status_check
check (status in ('pending', 'accepted', 'rejected', 'resolved', 'closed'));
end if;
if not exists (select 1 from pg_constraint where conname = 'reports_type_check') then
alter table public.reports
add constraint reports_type_check
check (type is null or type in ('question_error', 'content_error', 'video_error', 'asset_error', 'system_bug', 'suggestion', 'other'));
end if;
end $$;
create table if not exists public.report_status_events (
id uuid primary key default gen_random_uuid(),
tenant_id uuid not null references public.tenants(id) on delete cascade,
report_id uuid not null references public.reports(id) on delete cascade,
from_status text,
to_status text not null,
note text,
actor_user_id uuid references public.platform_users(id) on delete set null,
metadata jsonb not null default '{}'::jsonb,
created_at timestamptz not null default now()
);
comment on table public.report_status_events is
'Audit timeline for student feedback/question correction status changes.';
create table if not exists public.user_score_events (
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,
event_type text not null
check (event_type in ('check_in', 'manual_adjust', 'feedback_reward', 'activity_reward', 'redeem_cost')),
points integer not null,
balance_after integer not null,
source_type text,
source_id uuid,
idempotency_key text,
metadata jsonb not null default '{}'::jsonb,
created_at timestamptz not null default now(),
unique (tenant_id, idempotency_key)
);
comment on table public.user_score_events is
'Tenant-scoped student score ledger. Positive points add score, negative points consume score.';
create index if not exists idx_reports_tenant_status
on public.reports(tenant_id, status, created_at desc);
create index if not exists idx_reports_tenant_question
on public.reports(tenant_id, question_id, created_at desc)
where question_id is not null;
create index if not exists idx_report_status_events_report
on public.report_status_events(tenant_id, report_id, created_at desc);
create index if not exists idx_score_events_user
on public.user_score_events(tenant_id, user_id, created_at desc);
create index if not exists idx_exam_dates_tenant_school
on public.exam_dates(tenant_id, school_id, exam_date);
alter table public.report_status_events enable row level security;
alter table public.user_score_events enable row level security;
drop policy if exists tenant_isolation on public.report_status_events;
create policy tenant_isolation on public.report_status_events
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.user_score_events;
create policy tenant_isolation on public.user_score_events
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());