-- MedSchedule — семейное медицинское расписание CREATE TABLE IF NOT EXISTS med_family_groups ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, name TEXT NOT NULL, invite_code TEXT NOT NULL UNIQUE, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_family_groups_org_idx ON med_family_groups(organization_id); CREATE UNIQUE INDEX IF NOT EXISTS med_family_groups_invite_idx ON med_family_groups(invite_code); CREATE TABLE IF NOT EXISTS med_family_members ( id SERIAL PRIMARY KEY, family_id INTEGER NOT NULL REFERENCES med_family_groups(id) ON DELETE CASCADE, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, profile_name TEXT NOT NULL, profile_type TEXT NOT NULL DEFAULT 'person', date_of_birth DATE, gender TEXT, notes TEXT, telegram_chat_id TEXT, max_chat_id TEXT, role TEXT NOT NULL DEFAULT 'member', created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_family_members_family_idx ON med_family_members(family_id); CREATE INDEX IF NOT EXISTS med_family_members_user_idx ON med_family_members(user_id); CREATE TABLE IF NOT EXISTS med_medications ( id SERIAL PRIMARY KEY, family_id INTEGER NOT NULL REFERENCES med_family_groups(id) ON DELETE CASCADE, member_id INTEGER NOT NULL REFERENCES med_family_members(id) ON DELETE CASCADE, name TEXT NOT NULL, dosage TEXT, form TEXT, schedule JSONB NOT NULL, instructions TEXT, color TEXT DEFAULT '#4CAF50', is_active BOOLEAN DEFAULT TRUE, created_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_medications_family_idx ON med_medications(family_id); CREATE INDEX IF NOT EXISTS med_medications_member_idx ON med_medications(member_id); CREATE TABLE IF NOT EXISTS med_intake_logs ( id SERIAL PRIMARY KEY, medication_id INTEGER NOT NULL REFERENCES med_medications(id) ON DELETE CASCADE, member_id INTEGER NOT NULL REFERENCES med_family_members(id) ON DELETE CASCADE, scheduled_at TIMESTAMP NOT NULL, taken_at TIMESTAMP, status TEXT NOT NULL DEFAULT 'pending', note TEXT, reminded_via TEXT[] DEFAULT '{}', created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_intake_logs_medication_idx ON med_intake_logs(medication_id); CREATE INDEX IF NOT EXISTS med_intake_logs_member_idx ON med_intake_logs(member_id); CREATE INDEX IF NOT EXISTS med_intake_logs_scheduled_idx ON med_intake_logs(scheduled_at); CREATE INDEX IF NOT EXISTS med_intake_logs_status_idx ON med_intake_logs(status); CREATE TABLE IF NOT EXISTS med_cabinet_items ( id SERIAL PRIMARY KEY, family_id INTEGER NOT NULL REFERENCES med_family_groups(id) ON DELETE CASCADE, name TEXT NOT NULL, form TEXT, dosage TEXT, quantity REAL DEFAULT 0, unit TEXT DEFAULT 'шт', expiry_date DATE, indication TEXT, location TEXT, photo_url TEXT, added_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_cabinet_items_family_idx ON med_cabinet_items(family_id); CREATE INDEX IF NOT EXISTS med_cabinet_items_expiry_idx ON med_cabinet_items(expiry_date); CREATE TABLE IF NOT EXISTS med_cabinet_stock ( id SERIAL PRIMARY KEY, cabinet_item_id INTEGER NOT NULL REFERENCES med_cabinet_items(id) ON DELETE CASCADE, change REAL NOT NULL, reason TEXT, note TEXT, changed_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_cabinet_stock_item_idx ON med_cabinet_stock(cabinet_item_id); CREATE TABLE IF NOT EXISTS med_medical_records ( id SERIAL PRIMARY KEY, family_id INTEGER NOT NULL REFERENCES med_family_groups(id) ON DELETE CASCADE, member_id INTEGER NOT NULL REFERENCES med_family_members(id) ON DELETE CASCADE, title TEXT NOT NULL, record_type TEXT NOT NULL, record_date DATE, doctor_name TEXT, clinic_name TEXT, raw_text TEXT, ai_summary TEXT, ai_findings JSONB, file_urls TEXT[] DEFAULT '{}', added_by INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_medical_records_family_idx ON med_medical_records(family_id); CREATE INDEX IF NOT EXISTS med_medical_records_member_idx ON med_medical_records(member_id); CREATE INDEX IF NOT EXISTS med_medical_records_date_idx ON med_medical_records(record_date); CREATE TABLE IF NOT EXISTS med_daily_checkins ( id SERIAL PRIMARY KEY, family_id INTEGER NOT NULL REFERENCES med_family_groups(id) ON DELETE CASCADE, member_id INTEGER REFERENCES med_family_members(id) ON DELETE CASCADE, check_in_date DATE NOT NULL, status TEXT NOT NULL DEFAULT 'pending', question TEXT NOT NULL, answer_text TEXT, ai_summary TEXT, ai_alert TEXT, created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE INDEX IF NOT EXISTS med_daily_checkins_family_idx ON med_daily_checkins(family_id); CREATE INDEX IF NOT EXISTS med_daily_checkins_member_idx ON med_daily_checkins(member_id); CREATE INDEX IF NOT EXISTS med_daily_checkins_date_idx ON med_daily_checkins(check_in_date); CREATE TABLE IF NOT EXISTS med_bot_bindings ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, telegram_chat_id TEXT, max_chat_id TEXT, telegram_username TEXT, max_username TEXT, created_at TIMESTAMP DEFAULT NOW() NOT NULL, updated_at TIMESTAMP DEFAULT NOW() NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS med_bot_bindings_user_org_idx ON med_bot_bindings(user_id, organization_id); CREATE UNIQUE INDEX IF NOT EXISTS med_bot_bindings_telegram_idx ON med_bot_bindings(organization_id, telegram_chat_id) WHERE telegram_chat_id IS NOT NULL; CREATE UNIQUE INDEX IF NOT EXISTS med_bot_bindings_max_idx ON med_bot_bindings(organization_id, max_chat_id) WHERE max_chat_id IS NOT NULL;