feat: harden auth and study workflows
- replace plaintext login and unlock requests with RSA-OAEP/AES-GCM encrypted payloads - add login challenge replay protection, production RSA key validation, and auth tests - wire compose to environment-driven dev/prod settings without committing local secrets - update setup-config smoke scripts and Postman docs for encrypted login - add visit schedule migrations/tests and update study/subject setup workflows
This commit is contained in:
+15
-17
@@ -46,10 +46,7 @@ CREATE TABLE IF NOT EXISTS public.studies (
|
||||
phase character varying(50),
|
||||
status character varying(20) NOT NULL DEFAULT 'DRAFT',
|
||||
is_locked boolean NOT NULL DEFAULT false,
|
||||
visit_interval_days integer,
|
||||
visit_total integer,
|
||||
visit_window_start_offset integer,
|
||||
visit_window_end_offset integer,
|
||||
visit_schedule jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
created_by uuid,
|
||||
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
||||
CONSTRAINT uq_studies_code UNIQUE (code),
|
||||
@@ -112,6 +109,7 @@ CREATE TABLE IF NOT EXISTS public.subjects (
|
||||
screening_date date,
|
||||
consent_date date,
|
||||
enrollment_date date,
|
||||
baseline_date date,
|
||||
completion_date date,
|
||||
drop_reason text,
|
||||
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
||||
@@ -591,7 +589,7 @@ ON CONFLICT (email) DO UPDATE SET
|
||||
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
|
||||
id, code, name, sponsor, protocol_no, phase, status, visit_schedule, created_by, created_at
|
||||
) VALUES (
|
||||
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
|
||||
'DEMO-CTMS',
|
||||
@@ -600,10 +598,12 @@ INSERT INTO public.studies (
|
||||
'DP-001',
|
||||
'Phase II',
|
||||
'ACTIVE',
|
||||
7,
|
||||
3,
|
||||
-2,
|
||||
2,
|
||||
'[
|
||||
{"visit_code": "基线访视", "baseline_offset_days": 0, "window_before_days": 0, "window_after_days": 0},
|
||||
{"visit_code": "V1", "baseline_offset_days": 7, "window_before_days": 2, "window_after_days": 2},
|
||||
{"visit_code": "V2", "baseline_offset_days": 15, "window_before_days": 2, "window_after_days": 2},
|
||||
{"visit_code": "V3", "baseline_offset_days": 23, "window_before_days": 3, "window_after_days": 3}
|
||||
]'::jsonb,
|
||||
(SELECT id FROM public.users WHERE email = 'admin@example.com'),
|
||||
'2025-01-06 08:00:00+00'
|
||||
) ON CONFLICT (code) DO UPDATE SET
|
||||
@@ -612,10 +612,7 @@ INSERT INTO public.studies (
|
||||
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,
|
||||
visit_schedule = EXCLUDED.visit_schedule,
|
||||
created_by = EXCLUDED.created_by;
|
||||
|
||||
INSERT INTO public.sites (
|
||||
@@ -753,17 +750,18 @@ INSERT INTO public.training_authorizations (
|
||||
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
|
||||
id, study_id, site_id, subject_no, status, screening_date, consent_date, enrollment_date, baseline_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')
|
||||
('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', '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, 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', '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,
|
||||
baseline_date = EXCLUDED.baseline_date,
|
||||
completion_date = EXCLUDED.completion_date,
|
||||
drop_reason = EXCLUDED.drop_reason,
|
||||
updated_at = EXCLUDED.updated_at;
|
||||
|
||||
Reference in New Issue
Block a user