Files
ctms/database/init.sql
T
2026-01-13 19:42:28 +08:00

742 lines
48 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Idempotent schema for CTMS (derived from current SQLAlchemy models)
DO $$
BEGIN
CREATE TYPE public.user_role AS ENUM ('ADMIN', 'PM', 'CRA', 'PV', 'IMP');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$
BEGIN
CREATE TYPE public.user_status AS ENUM ('PENDING', 'ACTIVE', 'REJECTED', 'DISABLED');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
CREATE TABLE IF NOT EXISTS public.users (
id uuid PRIMARY KEY,
email character varying(255) NOT NULL,
password_hash character varying(255) NOT NULL,
full_name character varying(255) NOT NULL,
role public.user_role NOT NULL,
department character varying(255) NOT NULL,
status public.user_status NOT NULL DEFAULT 'PENDING',
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
approved_by uuid,
approved_at timestamp with time zone,
avatar_url character varying(500),
CONSTRAINT uq_users_email UNIQUE (email)
);
CREATE TABLE IF NOT EXISTS public.studies (
id uuid PRIMARY KEY,
code character varying(50) NOT NULL,
name character varying(200) NOT NULL,
sponsor character varying(200),
protocol_no character varying(100),
phase character varying(50),
status character varying(20) NOT NULL DEFAULT 'DRAFT',
visit_interval_days integer,
visit_total integer,
visit_window_start_offset integer,
visit_window_end_offset integer,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT uq_studies_code UNIQUE (code),
CONSTRAINT fk_studies_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.sites (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
name character varying(200) NOT NULL,
city character varying(100),
pi_name character varying(100),
contact character varying(100),
is_active boolean NOT NULL DEFAULT true,
created_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_sites_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.study_members (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
user_id uuid NOT NULL,
role_in_study character varying(20) NOT NULL,
is_active boolean NOT NULL DEFAULT true,
added_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT uq_study_member UNIQUE (study_id, user_id),
CONSTRAINT fk_study_members_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_study_members_user_id FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.milestones (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
type character varying(50) NOT NULL,
name character varying(200) NOT NULL,
planned_date date,
actual_date date,
status character varying(20) NOT NULL DEFAULT 'NOT_STARTED',
site_id uuid,
owner_id uuid,
notes text,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_milestones_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_milestones_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
CONSTRAINT fk_milestones_owner_id FOREIGN KEY (owner_id) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.subjects (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
site_id uuid NOT NULL,
subject_no character varying(50) NOT NULL,
status character varying(20) NOT NULL DEFAULT 'SCREENING',
screening_date date,
consent_date date,
enrollment_date date,
completion_date date,
drop_reason text,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT uq_subject_study_no UNIQUE (study_id, subject_no),
CONSTRAINT fk_subjects_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_subjects_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.subject_histories (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
subject_id uuid NOT NULL,
record_date date,
content text NOT NULL,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_subject_histories_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_subject_histories_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT,
CONSTRAINT fk_subject_histories_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.visits (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
subject_id uuid NOT NULL,
visit_code character varying(50) NOT NULL,
planned_date date,
actual_date date,
status character varying(20) NOT NULL DEFAULT 'PLANNED',
window_start date,
window_end date,
notes text,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_visits_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_visits_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.adverse_events (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
site_id uuid,
subject_id uuid,
visit_id uuid,
term character varying(255) NOT NULL,
onset_date date,
resolution_date date,
seriousness character varying(50) NOT NULL,
severity character varying(50) NOT NULL,
causality character varying(50),
action_taken text,
outcome character varying(50),
reported_to_sponsor boolean NOT NULL DEFAULT false,
report_due_date date,
status character varying(20) NOT NULL DEFAULT 'NEW',
description text,
created_by uuid NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_adverse_events_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_adverse_events_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
CONSTRAINT fk_adverse_events_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT,
CONSTRAINT fk_adverse_events_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.finance_contracts (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
site_name character varying(255) NOT NULL,
contract_no character varying(100) NOT NULL,
signed_date date,
amount numeric(12, 2) NOT NULL,
currency character varying(10) NOT NULL DEFAULT 'CNY',
remark text,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_finance_contracts_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_finance_contracts_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.finance_specials (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
site_name character varying(255) NOT NULL,
fee_type character varying(50) NOT NULL,
amount numeric(12, 2) NOT NULL,
occur_date date,
staff_name character varying(100),
remark text,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_finance_specials_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_finance_specials_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.contract_fees (
id uuid PRIMARY KEY,
project_id uuid NOT NULL,
center_id uuid NOT NULL,
contract_amount numeric(12, 2) NOT NULL,
contract_cases integer NOT NULL,
actual_cases integer,
settlement_amount numeric(12, 2),
final_payment_amount numeric(12, 2),
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT uq_contract_fees_project_center UNIQUE (project_id, center_id),
CONSTRAINT fk_contract_fees_project_id FOREIGN KEY (project_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_contract_fees_center_id FOREIGN KEY (center_id) REFERENCES public.sites(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.contract_fee_payments (
id uuid PRIMARY KEY,
contract_fee_id uuid NOT NULL,
seq integer NOT NULL,
amount numeric(12, 2) NOT NULL,
paid_date date,
verified_date date,
is_paid boolean NOT NULL DEFAULT false,
is_verified boolean NOT NULL DEFAULT false,
remark text,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_contract_fee_payments_contract_fee_id FOREIGN KEY (contract_fee_id) REFERENCES public.contract_fees(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS public.special_expenses (
id uuid PRIMARY KEY,
project_id uuid NOT NULL,
center_id uuid,
category character varying(50) NOT NULL,
amount numeric(12, 2) NOT NULL,
happen_date date,
description text,
is_paid boolean NOT NULL DEFAULT false,
paid_date date,
is_verified boolean NOT NULL DEFAULT false,
verified_date date,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_special_expenses_project_id FOREIGN KEY (project_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_special_expenses_center_id FOREIGN KEY (center_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
CONSTRAINT fk_special_expenses_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.fee_attachments (
id uuid PRIMARY KEY,
entity_type character varying(50) NOT NULL,
entity_id uuid NOT NULL,
file_type character varying(30) NOT NULL,
filename character varying(255) NOT NULL,
mime_type character varying(100),
size integer NOT NULL,
storage_key character varying(500),
url text,
uploaded_by uuid NOT NULL,
uploaded_at timestamp with time zone NOT NULL DEFAULT now(),
is_deleted boolean NOT NULL DEFAULT false,
CONSTRAINT fk_fee_attachments_uploaded_by FOREIGN KEY (uploaded_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.finance_items (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
site_id uuid,
subject_id uuid,
visit_id uuid,
category character varying(50) NOT NULL,
title character varying(255) NOT NULL,
description text,
currency character varying(10) NOT NULL DEFAULT 'CNY',
amount numeric(12, 2) NOT NULL,
occur_date date NOT NULL,
status character varying(20) NOT NULL DEFAULT 'DRAFT',
submitted_at timestamp with time zone,
approved_at timestamp with time zone,
rejected_at timestamp with time zone,
paid_at timestamp with time zone,
approver_id uuid,
payer_id uuid,
reject_reason text,
created_by uuid NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_finance_items_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_finance_items_site_id FOREIGN KEY (site_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
CONSTRAINT fk_finance_items_subject_id FOREIGN KEY (subject_id) REFERENCES public.subjects(id) ON DELETE RESTRICT,
CONSTRAINT fk_finance_items_approver_id FOREIGN KEY (approver_id) REFERENCES public.users(id) ON DELETE RESTRICT,
CONSTRAINT fk_finance_items_payer_id FOREIGN KEY (payer_id) REFERENCES public.users(id) ON DELETE RESTRICT,
CONSTRAINT fk_finance_items_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.drug_shipments (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
direction character varying(20) NOT NULL,
center_id uuid,
site_name character varying(255) NOT NULL,
ship_date date,
receive_date date,
quantity integer,
batch_no character varying(100),
carrier character varying(100),
tracking_no character varying(100),
status character varying(30) NOT NULL,
remark text,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_drug_shipments_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_drug_shipments_center_id FOREIGN KEY (center_id) REFERENCES public.sites(id) ON DELETE RESTRICT,
CONSTRAINT fk_drug_shipments_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.startup_feasibility (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
submit_date date,
accept_date date,
approved_date date,
project_no character varying(100),
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_startup_feasibility_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_startup_feasibility_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.startup_ethics (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
submit_date date,
accept_date date,
meeting_date date,
approved_date date,
approval_no character varying(100),
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_startup_ethics_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_startup_ethics_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.kickoff_meetings (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
kickoff_date date,
attendees json,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_kickoff_meetings_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_kickoff_meetings_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.training_authorizations (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
name character varying(100) NOT NULL,
role character varying(100),
site_name character varying(255),
trained boolean NOT NULL DEFAULT false,
authorized boolean NOT NULL DEFAULT false,
trained_date date,
authorized_date date,
remark text,
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_training_authorizations_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_training_authorizations_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.knowledge_notes (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
site_name character varying(255) NOT NULL,
title character varying(255) NOT NULL,
content text NOT NULL,
level character varying(50),
created_by uuid,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_knowledge_notes_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_knowledge_notes_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.faq_categories (
id uuid PRIMARY KEY,
study_id uuid,
name character varying(100) NOT NULL,
description text,
sort_order integer NOT NULL DEFAULT 0,
is_active boolean NOT NULL DEFAULT true,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT uq_faq_category_name UNIQUE (study_id, name),
CONSTRAINT fk_faq_categories_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.faq_items (
id uuid PRIMARY KEY,
study_id uuid,
category_id uuid NOT NULL,
best_reply_id uuid,
status character varying(20) NOT NULL DEFAULT 'PENDING',
resolved_by_confirm boolean NOT NULL DEFAULT false,
question text NOT NULL,
answer text NOT NULL,
keywords character varying(255),
version integer NOT NULL DEFAULT 1,
is_active boolean NOT NULL DEFAULT true,
created_by uuid NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_faq_items_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_faq_items_category_id FOREIGN KEY (category_id) REFERENCES public.faq_categories(id) ON DELETE RESTRICT,
CONSTRAINT fk_faq_items_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.faq_replies (
id uuid PRIMARY KEY,
faq_id uuid NOT NULL,
study_id uuid,
content text NOT NULL,
created_by uuid NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
quote_reply_id uuid,
is_deleted boolean NOT NULL DEFAULT false,
CONSTRAINT fk_faq_replies_faq_id FOREIGN KEY (faq_id) REFERENCES public.faq_items(id) ON DELETE RESTRICT,
CONSTRAINT fk_faq_replies_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_faq_replies_created_by FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE RESTRICT,
CONSTRAINT fk_faq_replies_quote_reply_id FOREIGN KEY (quote_reply_id) REFERENCES public.faq_replies(id) ON DELETE RESTRICT
);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'fk_faq_items_best_reply_id'
) THEN
ALTER TABLE public.faq_items
ADD CONSTRAINT fk_faq_items_best_reply_id
FOREIGN KEY (best_reply_id) REFERENCES public.faq_replies(id) ON DELETE SET NULL;
END IF;
END $$;
CREATE TABLE IF NOT EXISTS public.attachments (
id uuid PRIMARY KEY,
study_id uuid NOT NULL,
entity_type character varying(50) NOT NULL,
entity_id uuid NOT NULL,
filename character varying(255) NOT NULL,
file_path character varying(500) NOT NULL,
file_size integer NOT NULL,
content_type character varying(100),
uploaded_by uuid NOT NULL,
uploaded_at timestamp with time zone NOT NULL DEFAULT now(),
is_deleted boolean NOT NULL DEFAULT false,
CONSTRAINT fk_attachments_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_attachments_uploaded_by FOREIGN KEY (uploaded_by) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE TABLE IF NOT EXISTS public.audit_logs (
id uuid PRIMARY KEY,
study_id uuid,
entity_type character varying(50) NOT NULL,
entity_id uuid,
action character varying(50) NOT NULL,
detail text,
operator_id uuid NOT NULL,
operator_role character varying(50) NOT NULL,
created_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT fk_audit_logs_study_id FOREIGN KEY (study_id) REFERENCES public.studies(id) ON DELETE RESTRICT,
CONSTRAINT fk_audit_logs_operator_id FOREIGN KEY (operator_id) REFERENCES public.users(id) ON DELETE RESTRICT
);
CREATE INDEX IF NOT EXISTS ix_sites_study_id ON public.sites (study_id);
CREATE INDEX IF NOT EXISTS ix_study_members_study_id ON public.study_members (study_id);
CREATE INDEX IF NOT EXISTS ix_milestones_study_id ON public.milestones (study_id);
CREATE INDEX IF NOT EXISTS ix_subjects_study_id ON public.subjects (study_id);
CREATE INDEX IF NOT EXISTS ix_subjects_site_id ON public.subjects (site_id);
CREATE INDEX IF NOT EXISTS ix_subject_histories_study_id ON public.subject_histories (study_id);
CREATE INDEX IF NOT EXISTS ix_subject_histories_subject_id ON public.subject_histories (subject_id);
CREATE INDEX IF NOT EXISTS ix_visits_subject_id ON public.visits (subject_id);
CREATE INDEX IF NOT EXISTS ix_adverse_events_study_id ON public.adverse_events (study_id);
CREATE INDEX IF NOT EXISTS ix_adverse_events_site_id ON public.adverse_events (site_id);
CREATE INDEX IF NOT EXISTS ix_adverse_events_subject_id ON public.adverse_events (subject_id);
CREATE INDEX IF NOT EXISTS ix_finance_contracts_study_id ON public.finance_contracts (study_id);
CREATE INDEX IF NOT EXISTS ix_finance_specials_study_id ON public.finance_specials (study_id);
CREATE INDEX IF NOT EXISTS ix_finance_items_study_id ON public.finance_items (study_id);
CREATE INDEX IF NOT EXISTS ix_finance_items_site_id ON public.finance_items (site_id);
CREATE INDEX IF NOT EXISTS ix_finance_items_subject_id ON public.finance_items (subject_id);
CREATE INDEX IF NOT EXISTS ix_drug_shipments_study_id ON public.drug_shipments (study_id);
CREATE INDEX IF NOT EXISTS ix_drug_shipments_center_id ON public.drug_shipments (center_id);
CREATE INDEX IF NOT EXISTS ix_startup_feasibility_study_id ON public.startup_feasibility (study_id);
CREATE INDEX IF NOT EXISTS ix_startup_ethics_study_id ON public.startup_ethics (study_id);
CREATE INDEX IF NOT EXISTS ix_kickoff_meetings_study_id ON public.kickoff_meetings (study_id);
CREATE INDEX IF NOT EXISTS ix_training_authorizations_study_id ON public.training_authorizations (study_id);
CREATE INDEX IF NOT EXISTS ix_knowledge_notes_study_id ON public.knowledge_notes (study_id);
CREATE INDEX IF NOT EXISTS ix_faq_categories_study_id ON public.faq_categories (study_id);
CREATE INDEX IF NOT EXISTS ix_faq_items_study_id ON public.faq_items (study_id);
CREATE INDEX IF NOT EXISTS ix_faq_items_category_id ON public.faq_items (category_id);
CREATE INDEX IF NOT EXISTS ix_faq_replies_faq_id ON public.faq_replies (faq_id);
CREATE INDEX IF NOT EXISTS ix_faq_replies_study_id ON public.faq_replies (study_id);
-- =========================================
-- DEMO SEED DATA (idempotent)
-- =========================================
INSERT INTO public.users (
id, email, password_hash, full_name, role, department, status, created_at, updated_at
) VALUES
('11111111-1111-1111-1111-111111111111', 'admin@example.com', '$2y$12$FMfyBt7YfZWeh/x8WMEIA.S6VUTIMryk2NxWHyOOuJvd6YrDwHAdu', 'System Admin', 'ADMIN', 'SYSTEM', 'ACTIVE', '2025-01-05 08:00:00+00', '2025-01-05 08:00:00+00'),
('22222222-2222-2222-2222-222222222222', 'pm@example.com', '$2y$12$P9UDKu48ru84uVrlquqhXufmw/CfMEzQosC0X8eT2EmY/PgM/03j2', '项目经理', 'PM', 'PMO', 'ACTIVE', '2025-01-05 08:10:00+00', '2025-01-05 08:10:00+00'),
('33333333-3333-3333-3333-333333333333', 'cra@example.com', '$2y$12$D/.ZeDrUByPZFPnAl9MnKuzKn2G4ctKQ9IAS/CqS2sfMdE/5NaKAK', 'CRA 用户', 'CRA', 'CRA', 'ACTIVE', '2025-01-05 08:20:00+00', '2025-01-05 08:20:00+00')
ON CONFLICT (email) DO UPDATE SET
password_hash = EXCLUDED.password_hash,
full_name = EXCLUDED.full_name,
role = EXCLUDED.role,
department = EXCLUDED.department,
status = EXCLUDED.status,
updated_at = EXCLUDED.updated_at;
INSERT INTO public.studies (
id, code, name, sponsor, protocol_no, phase, status, visit_interval_days, visit_total, visit_window_start_offset, visit_window_end_offset, created_by, created_at
) VALUES (
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
'DEMO-CTMS',
'示例项目:糖尿病新药',
'Demo Pharma',
'DP-001',
'Phase II',
'ACTIVE',
7,
3,
-2,
2,
(SELECT id FROM public.users WHERE email = 'admin@example.com'),
'2025-01-06 08:00:00+00'
) ON CONFLICT (code) DO UPDATE SET
name = EXCLUDED.name,
sponsor = EXCLUDED.sponsor,
protocol_no = EXCLUDED.protocol_no,
phase = EXCLUDED.phase,
status = EXCLUDED.status,
visit_interval_days = EXCLUDED.visit_interval_days,
visit_total = EXCLUDED.visit_total,
visit_window_start_offset = EXCLUDED.visit_window_start_offset,
visit_window_end_offset = EXCLUDED.visit_window_end_offset,
created_by = EXCLUDED.created_by;
INSERT INTO public.sites (
id, study_id, name, city, pi_name, contact, is_active, created_at
) VALUES
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '北京', '李主任', '010-12345678', true, '2025-01-06 09:00:00+00'),
('cccccccc-cccc-cccc-cccc-cccccccccccc', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', '上海', '王主任', '021-12345678', true, '2025-01-06 09:10:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.study_members (
id, study_id, user_id, role_in_study, is_active, added_at
) VALUES
('dddddddd-dddd-dddd-dddd-dddddddddddd', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'admin@example.com'), 'ADMIN', true, '2025-01-06 10:00:00+00'),
('eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'pm@example.com'), 'PM', true, '2025-01-06 10:05:00+00'),
('ffffffff-ffff-ffff-ffff-ffffffffffff', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), (SELECT id FROM public.users WHERE email = 'cra@example.com'), 'CRA', true, '2025-01-06 10:10:00+00')
ON CONFLICT (study_id, user_id) DO UPDATE SET
role_in_study = EXCLUDED.role_in_study,
is_active = EXCLUDED.is_active;
INSERT INTO public.milestones (
id, study_id, type, name, planned_date, actual_date, status, site_id, owner_id, notes, created_at, updated_at
) VALUES
('10101010-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'SIV', '启动会', '2025-01-10', '2025-01-12', 'DONE', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '现场启动完成', '2025-01-06 12:00:00+00', '2025-01-12 10:00:00+00'),
('20202020-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'LPI', '首例入组', '2025-02-01', NULL, 'NOT_STARTED', 'cccccccc-cccc-cccc-cccc-cccccccccccc', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '待完成', '2025-01-06 12:10:00+00', '2025-01-06 12:10:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.finance_contracts (
id, study_id, site_name, contract_no, signed_date, amount, currency, remark, created_by, created_at, updated_at
) VALUES
('77777777-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', 'CON-001', '2025-01-08', 1200000.00, 'CNY', '首批合同签署', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-08 09:00:00+00', '2025-01-08 09:00:00+00'),
('77777777-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', 'CON-002', '2025-01-10', 980000.00, 'CNY', '分中心合同签署', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 09:00:00+00', '2025-01-10 09:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.finance_specials (
id, study_id, site_name, fee_type, amount, occur_date, staff_name, remark, created_by, created_at, updated_at
) VALUES
('88888888-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '差旅', 5200.00, '2025-01-15', '赵敏', 'SIV 差旅费', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-15 10:00:00+00', '2025-01-15 10:00:00+00'),
('88888888-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', '住宿', 3200.00, '2025-01-18', '李雷', '监查住宿费', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-18 10:00:00+00', '2025-01-18 10:00:00+00'),
('88888888-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '交通', 860.00, '2025-01-20', '韩梅梅', '市内交通费', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 10:00:00+00', '2025-01-20 10:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.finance_items (
id, study_id, site_id, subject_id, visit_id, category, title, description, currency, amount, occur_date, status, submitted_at, approved_at, rejected_at, paid_at, approver_id, payer_id, reject_reason, created_by, created_at, updated_at
) VALUES
('99999999-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', NULL, NULL, 'SITE_FEE', '启动费', '中心启动费用', 'CNY', 30000.00, '2025-01-12', 'PAID', '2025-01-13 08:00:00+00', '2025-01-13 10:00:00+00', NULL, '2025-01-15 09:00:00+00', (SELECT id FROM public.users WHERE email = 'pm@example.com'), (SELECT id FROM public.users WHERE email = 'admin@example.com'), NULL, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 09:00:00+00', '2025-01-15 09:00:00+00'),
('99999999-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', NULL, NULL, 'TRAVEL', '监查差旅', 'CRA 监查差旅报销', 'CNY', 4800.00, '2025-01-20', 'APPROVED', '2025-01-21 08:00:00+00', '2025-01-21 10:00:00+00', NULL, NULL, (SELECT id FROM public.users WHERE email = 'pm@example.com'), NULL, NULL, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 10:00:00+00', '2025-01-21 10:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.drug_shipments (
id, study_id, direction, site_name, drug_desc, ship_date, carrier, tracking_no, from_party, to_party, status, remark, created_by, created_at, updated_at
) VALUES
('aaaa1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '寄送', '北京协和医院', 'DP-001 片剂 50mg × 200 盒', '2025-01-12', '顺丰', 'SF100001', '中央库房', '北京协和医院药房', '运输中', '首批寄送', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-12 11:00:00+00', '2025-01-12 11:00:00+00'),
('bbbb1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '寄送', '上海瑞金医院', 'DP-001 片剂 50mg × 150 盒', '2025-01-13', '京东物流', 'JD200002', '中央库房', '上海瑞金医院药房', '已签收', '分中心补货', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-13 11:00:00+00', '2025-01-14 09:00:00+00'),
('cccc1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '回收', '北京协和医院', '空药盒及剩余药品回收', '2025-02-05', '顺丰', 'SF100003', '北京协和医院药房', '中央库房', '已回收', '首批回收', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-02-05 14:00:00+00', '2025-02-06 09:00:00+00'),
('dddd1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '回收', '上海瑞金医院', '冷链箱回收', '2025-02-08', '德邦', 'DB300004', '上海瑞金医院药房', '中央库房', '运输中', '回收途中', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-02-08 16:00:00+00', '2025-02-08 16:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.startup_feasibility (
id, study_id, submit_date, accept_date, approved_date, project_no, created_by, created_at, updated_at
) VALUES
('eeee1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '2025-01-02', '2025-01-05', '2025-01-10', 'FEA-BJ-001', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 10:00:00+00', '2025-01-10 10:00:00+00'),
('ffff1111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '2025-01-03', '2025-01-06', '2025-01-12', 'FEA-SH-002', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 10:00:00+00', '2025-01-12 10:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.startup_ethics (
id, study_id, submit_date, accept_date, meeting_date, approved_date, approval_no, created_by, created_at, updated_at
) VALUES
('1111aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '2025-01-04', '2025-01-07', '2025-01-15', '2025-01-20', 'ETH-BJ-001', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 11:00:00+00', '2025-01-20 11:00:00+00'),
('2222aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '2025-01-05', '2025-01-08', '2025-01-16', '2025-01-22', 'ETH-SH-002', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-22 11:00:00+00', '2025-01-22 11:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.kickoff_meetings (
id, study_id, kickoff_date, attendees, created_by, created_at, updated_at
) VALUES (
'3333aaaa-2222-3333-4444-555555555555',
(SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'),
'2025-01-12',
'["张三","李四","王五"]'::json,
(SELECT id FROM public.users WHERE email = 'pm@example.com'),
'2025-01-12 13:00:00+00',
'2025-01-12 13:00:00+00'
) ON CONFLICT (id) DO NOTHING;
INSERT INTO public.training_authorizations (
id, study_id, name, role, site_name, trained, authorized, trained_date, authorized_date, remark, created_by, created_at, updated_at
) VALUES
('4444bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '赵敏', '研究医生', '北京协和医院', true, false, '2025-01-12', NULL, '待授权', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 15:00:00+00', '2025-01-12 15:00:00+00'),
('5555bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '李雷', 'CRC', '上海瑞金医院', false, true, NULL, '2025-01-18', '先授权后补训', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-18 15:00:00+00', '2025-01-18 15:00:00+00'),
('6666bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '韩梅梅', '药房管理员', '北京协和医院', true, true, '2025-01-10', '2025-01-12', '已完成', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 16:00:00+00', '2025-01-12 16:00:00+00'),
('7777bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '王强', 'CRA', '上海瑞金医院', false, false, NULL, NULL, '待安排', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 16:00:00+00', '2025-01-20 16:00:00+00'),
('8888bbbb-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '刘晨', '研究护士', '北京协和医院', true, false, '2025-01-14', NULL, '仅完成培训', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-14 16:00:00+00', '2025-01-14 16:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.subjects (
id, study_id, site_id, subject_no, status, screening_date, consent_date, enrollment_date, completion_date, drop_reason, created_at, updated_at
) VALUES
('11111111-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'SUBJ-001', 'ENROLLED', '2025-01-05', '2025-01-06', '2025-01-10', NULL, NULL, '2025-01-10 10:00:00+00', '2025-01-10 10:00:00+00'),
('22222222-3333-4444-5555-666666666666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', 'SUBJ-002', 'SCREENING', '2025-01-12', '2025-01-13', NULL, NULL, NULL, '2025-01-12 10:00:00+00', '2025-01-12 10:00:00+00'),
('33333333-4444-5555-6666-777777777777', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'SUBJ-003', 'COMPLETED', '2024-12-20', '2024-12-21', '2024-12-28', '2025-02-05', NULL, '2025-02-05 10:00:00+00', '2025-02-05 10:00:00+00')
ON CONFLICT (study_id, subject_no) DO UPDATE SET
site_id = EXCLUDED.site_id,
status = EXCLUDED.status,
screening_date = EXCLUDED.screening_date,
consent_date = EXCLUDED.consent_date,
enrollment_date = EXCLUDED.enrollment_date,
completion_date = EXCLUDED.completion_date,
drop_reason = EXCLUDED.drop_reason,
updated_at = EXCLUDED.updated_at;
INSERT INTO public.subject_histories (
id, study_id, subject_id, record_date, content, created_by, created_at, updated_at
) VALUES
('55555555-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', '2025-01-08', '既往有高血压病史,长期服药控制。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-08 11:00:00+00', '2025-01-08 11:00:00+00'),
('55555555-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '22222222-3333-4444-5555-666666666666', '2025-01-13', '糖耐量异常,需进一步评估。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-13 11:00:00+00', '2025-01-13 11:00:00+00'),
('55555555-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '33333333-4444-5555-6666-777777777777', '2025-01-02', '既往病史稳定,未见严重合并症。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-02 11:00:00+00', '2025-01-02 11:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.visits (
id, study_id, subject_id, visit_code, planned_date, actual_date, status, window_start, window_end, notes, created_at, updated_at
) VALUES
('44444444-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', 'V1', '2025-01-09', '2025-01-10', 'DONE', '2025-01-07', '2025-01-12', '按期完成', '2025-01-10 12:00:00+00', '2025-01-10 12:00:00+00'),
('44444444-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', 'FU1', '2025-02-09', NULL, 'PLANNED', '2025-02-07', '2025-02-12', NULL, '2025-01-20 12:00:00+00', '2025-01-20 12:00:00+00'),
('44444444-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '11111111-2222-3333-4444-555555555555', 'FU2', '2025-03-11', NULL, 'PLANNED', '2025-03-09', '2025-03-14', NULL, '2025-02-01 12:00:00+00', '2025-02-01 12:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.adverse_events (
id, study_id, site_id, subject_id, visit_id, term, onset_date, resolution_date, seriousness, severity, causality, action_taken, outcome, reported_to_sponsor, report_due_date, status, description, created_by, created_at, updated_at
) VALUES
('66666666-aaaa-bbbb-cccc-111111111111', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '11111111-2222-3333-4444-555555555555', '44444444-aaaa-bbbb-cccc-111111111111', '轻微头痛', '2025-01-10', '2025-01-11', 'NON_SERIOUS', 'MILD', '可能相关', '休息观察', '恢复', true, '2025-01-20', 'CLOSED', '参与者轻微头痛,次日缓解。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-10 13:00:00+00', '2025-01-11 09:00:00+00'),
('66666666-aaaa-bbbb-cccc-222222222222', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'cccccccc-cccc-cccc-cccc-cccccccccccc', '22222222-3333-4444-5555-666666666666', NULL, '血糖升高', '2025-01-18', NULL, 'SERIOUS', 'SEVERE', '相关', '调整用药', '未恢复', false, '2025-01-28', 'NEW', '筛选期血糖异常。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-18 13:00:00+00', '2025-01-18 13:00:00+00'),
('66666666-aaaa-bbbb-cccc-333333333333', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', '11111111-2222-3333-4444-555555555555', NULL, '轻度皮疹', '2025-02-10', NULL, 'NON_SERIOUS', 'MODERATE', '待评估', NULL, '未恢复', false, '2025-02-20', 'FOLLOW_UP', '出现皮疹,持续观察。', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-02-10 13:00:00+00', '2025-02-10 13:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.knowledge_notes (
id, study_id, site_name, title, content, level, created_by, created_at, updated_at
) VALUES
('4444aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '样本采集注意', '采血需在早晨空腹完成,样本 2 小时内送达。', '高', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 18:00:00+00', '2025-01-12 18:00:00+00'),
('5555aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '上海瑞金医院', '访视资料上传', '访视完成后 24 小时内完成资料上传与核对。', '中', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-15 18:00:00+00', '2025-01-15 18:00:00+00'),
('6666aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '北京协和医院', '冷链运输提醒', '冷链记录必须随药品一起封存。', '低', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-18 18:00:00+00', '2025-01-18 18:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.faq_categories (
id, study_id, name, description, sort_order, is_active, created_at, updated_at
) VALUES
('7777aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '访视相关', '访视常见问题', 1, true, '2025-01-10 08:00:00+00', '2025-01-10 08:00:00+00'),
('8888aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '用药相关', '用药与回收问题', 2, true, '2025-01-10 08:10:00+00', '2025-01-10 08:10:00+00')
ON CONFLICT (study_id, name) DO UPDATE SET
description = EXCLUDED.description,
sort_order = EXCLUDED.sort_order,
is_active = EXCLUDED.is_active,
updated_at = EXCLUDED.updated_at;
INSERT INTO public.faq_items (
id, study_id, category_id, best_reply_id, status, resolved_by_confirm, question, answer, keywords, version, is_active, created_by, created_at, updated_at
) VALUES
('9999aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '7777aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, 'V1 访视需要携带什么?', '携带知情同意书、病历及用药记录本。', '访视,携带物品', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 09:00:00+00', '2025-01-10 09:00:00+00'),
('aaaa9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '7777aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '访视延迟是否需要重新排期?', '若延迟超过窗口期需重新安排并备注原因。', '访视,窗口期', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-11 09:00:00+00', '2025-01-11 09:00:00+00'),
('bbbb9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '8888aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '药品回收需要哪些材料?', '需提供回收清单、交接单及冷链记录。', '回收,交接单', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 09:00:00+00', '2025-01-12 09:00:00+00'),
('cccc9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '8888aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '药品签收后如何登记?', '签收后在药品流向中登记并上传快递单。', '药品,签收', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-13 09:00:00+00', '2025-01-13 09:00:00+00'),
('dddd9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '7777aaaa-2222-3333-4444-555555555555', NULL, 'PENDING', false, '随访资料上传时间要求?', '访视结束 24 小时内上传。', '随访,资料上传', 1, true, (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-14 09:00:00+00', '2025-01-14 09:00:00+00')
ON CONFLICT (id) DO NOTHING;
INSERT INTO public.faq_replies (
id, faq_id, study_id, content, created_by, created_at, quote_reply_id, is_deleted
) VALUES
('eeee9999-2222-3333-4444-555555555555', '9999aaaa-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '如有特殊情况请提前沟通 PM。', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-10 10:00:00+00', NULL, false),
('ffff9999-2222-3333-4444-555555555555', 'bbbb9999-2222-3333-4444-555555555555', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), '回收材料可在下载中心获取模板。', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 10:00:00+00', NULL, false)
ON CONFLICT (id) DO NOTHING;
UPDATE public.faq_items
SET best_reply_id = 'eeee9999-2222-3333-4444-555555555555'
WHERE id = '9999aaaa-2222-3333-4444-555555555555'
AND best_reply_id IS NULL;
UPDATE public.faq_items
SET best_reply_id = 'ffff9999-2222-3333-4444-555555555555'
WHERE id = 'bbbb9999-2222-3333-4444-555555555555'
AND best_reply_id IS NULL;
INSERT INTO public.attachments (
id, study_id, entity_type, entity_id, filename, file_path, file_size, content_type, uploaded_by, uploaded_at, is_deleted
) VALUES
('aaaa0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'finance_contract', '77777777-aaaa-bbbb-cccc-111111111111', 'contract_beijing.pdf', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/finance_contract_77777777-aaaa-bbbb-cccc-111111111111/contract_beijing.pdf', 1024, 'application/pdf', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-08 10:00:00+00', false),
('bbbb0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'drug_shipment', 'aaaa1111-2222-3333-4444-555555555555', 'shipment_beijing.pdf', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/drug_shipment_aaaa1111-2222-3333-4444-555555555555/shipment_beijing.pdf', 2048, 'application/pdf', (SELECT id FROM public.users WHERE email = 'cra@example.com'), '2025-01-12 12:00:00+00', false),
('cccc0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'startup_ethics', '1111aaaa-2222-3333-4444-555555555555', 'ethics_beijing.pdf', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/startup_ethics_1111aaaa-2222-3333-4444-555555555555/ethics_beijing.pdf', 1536, 'application/pdf', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-20 12:00:00+00', false),
('dddd0000-1111-2222-3333-444455556666', (SELECT id FROM public.studies WHERE code = 'DEMO-CTMS'), 'knowledge_note', '4444aaaa-2222-3333-4444-555555555555', 'note_sample.txt', '/code/app/uploads/study_aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/knowledge_note_4444aaaa-2222-3333-4444-555555555555/note_sample.txt', 512, 'text/plain', (SELECT id FROM public.users WHERE email = 'pm@example.com'), '2025-01-12 19:00:00+00', false)
ON CONFLICT (id) DO NOTHING;