""" DoctorKavach (Nidan-Trust) — National Healthcare Verification & Consent History Platform Production-Ready Database Schema & Initialization Engine (Upgraded) Architected for: - 1. Strictly Isolated Multi-Role Healthcare Portal (Patient, Doctor, Hospital, Govt) - 2. Strict Data Scoping & Real-Time Active Consent Revocation Engine - 3. Document Upload & Legal Verification Pipeline (CEA & Fire NOC Audits) - 4. Patient Self-Registration & Direct OPD Slot / Token Booking Engine - 5. Dual-Mode Smart Diet & Nutrition Engine (disease_diets) - 6. Multi-Entity Audit Trail & Dual-Feedback Engine """ import os import sqlite3 import hashlib import secrets import logging from datetime import datetime, timedelta, date # ============================================================================= # LOGGING CONFIGURATION # ============================================================================= logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(name)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S' ) logger = logging.getLogger("DoctorKavach.DB") # Database File Path (database.db for production edge deployment) DB_PATH = os.environ.get("DOCTORKAVACH_DB", os.path.join(os.path.dirname(os.path.abspath(__file__)), "database.db")) SECRET_SALT = "DoctorKavach_National_Health_Salt_2026" def hash_secret(plain_text: str) -> str: """Computes a SHA-256 salted hash for credentials and privacy.""" return hashlib.sha256(f"{SECRET_SALT}_{plain_text.strip()}".encode('utf-8')).hexdigest() # ============================================================================= # DDL SCHEMA DEFINITIONS # ============================================================================= SCHEMA_SQL = """ -- 0. USERS (Unified Authentication Table for All 4 Roles) CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, -- ABHA ID / Phone / NMC Reg / CEA License / Admin ID / Govt ID password_hash TEXT NOT NULL, role TEXT NOT NULL CHECK (role IN ('patient', 'doctor', 'hospital', 'govt')), foreign_id INTEGER, -- Points to patients.id, doctors.id, hospitals.id, or 1 for govt created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 1. HOSPITALS (Clinical Establishment Act Registered Entities) CREATE TABLE IF NOT EXISTS hospitals ( id INTEGER PRIMARY KEY AUTOINCREMENT, hospital_name TEXT NOT NULL, cea_license TEXT UNIQUE NOT NULL, -- CEA License Number address TEXT NOT NULL, city TEXT NOT NULL, total_beds INTEGER DEFAULT 120, available_beds INTEGER DEFAULT 35, admin_id TEXT UNIQUE NOT NULL, -- Admin / Reception ID for Triage desk login password_hash TEXT NOT NULL, is_govt_verified BOOLEAN DEFAULT 0 CHECK (is_govt_verified IN (0, 1)), cea_document TEXT, -- File path/name in uploads/hospital_docs noc_document TEXT, -- File path/name in uploads/hospital_docs contact_phone TEXT, verified_at TIMESTAMP ); -- 2. DOCTORS (National Medical Commission & Clinical Establishment Act Registry) CREATE TABLE IF NOT EXISTS doctors ( id INTEGER PRIMARY KEY AUTOINCREMENT, full_name TEXT NOT NULL, govt_id_hash TEXT NOT NULL, -- SHA-256 hash of national ID (Aadhaar/PAN) nmc_reg_number TEXT UNIQUE NOT NULL, -- National Medical Commission registration state_medical_council TEXT NOT NULL, degrees TEXT NOT NULL, -- e.g., "MBBS, MD (General Medicine)" specialization TEXT DEFAULT 'General Medicine', medical_college TEXT NOT NULL, internship_hospital TEXT NOT NULL, current_hospital_clinic TEXT NOT NULL, clinic_establishment_license TEXT NOT NULL, -- CEA License Number password_hash TEXT NOT NULL, is_verified BOOLEAN DEFAULT 0 CHECK (is_verified IN (0, 1)), verified_timestamp TIMESTAMP, verification_badge TEXT DEFAULT 'Pending' CHECK (verification_badge IN ('Verified Green Shield', 'Rejected', 'Pending')) ); -- 3. DOCTOR-HOSPITAL AFFILIATIONS (Regulator Governed Deployment) CREATE TABLE IF NOT EXISTS doctor_hospital_affiliations ( id INTEGER PRIMARY KEY AUTOINCREMENT, doctor_id INTEGER NOT NULL, hospital_id INTEGER NOT NULL, department TEXT NOT NULL DEFAULT 'General Medicine', opd_room TEXT NOT NULL DEFAULT 'OPD Counter 1', -- e.g., "OPD Counter 2", "Room 104" is_active BOOLEAN DEFAULT 1 CHECK (is_active IN (0, 1)), status TEXT DEFAULT 'ACTIVE' CHECK (status IN ('PENDING_AUDIT', 'ACTIVE', 'REJECTED')), proof_document TEXT, -- Uploaded appointment / affiliation letter affiliated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, verified_at TIMESTAMP, FOREIGN KEY (doctor_id) REFERENCES doctors(id) ON DELETE CASCADE, FOREIGN KEY (hospital_id) REFERENCES hospitals(id) ON DELETE CASCADE ); -- 4. PATIENTS (ABDM / ABHA Identity Framework) CREATE TABLE IF NOT EXISTS patients ( id INTEGER PRIMARY KEY AUTOINCREMENT, health_id TEXT UNIQUE NOT NULL, -- ABHA ID (e.g., "ABHA-XXXX-XXXX") full_name TEXT NOT NULL, phone TEXT NOT NULL, age INTEGER NOT NULL CHECK (age >= 0 AND age <= 130), gender TEXT NOT NULL CHECK (gender IN ('Male', 'Female', 'Other')), village_city TEXT NOT NULL, emergency_contact TEXT, password_hash TEXT DEFAULT '' ); -- 5. DISEASE DIETS (Preset Clinical Nutrition Knowledge Base) CREATE TABLE IF NOT EXISTS disease_diets ( id INTEGER PRIMARY KEY AUTOINCREMENT, disease_key TEXT UNIQUE NOT NULL, -- e.g., "Typhoid", "Hypertension", "Jaundice" default_allowed TEXT NOT NULL, -- Preset comma-separated allowed dietary items default_restricted TEXT NOT NULL, -- Preset comma-separated restricted items clinical_notes TEXT ); -- 6. CLINICAL VISITS (Historical Consultations, Multi-Entity Audit Trail & Diet) CREATE TABLE IF NOT EXISTS clinical_visits ( id INTEGER PRIMARY KEY AUTOINCREMENT, patient_id INTEGER NOT NULL, doctor_id INTEGER NOT NULL, hospital_id INTEGER, hospital_name TEXT, doctor_name TEXT, specialization TEXT, visit_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, visit_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, symptoms TEXT NOT NULL, provisional_diagnosis TEXT NOT NULL, treatments_performed TEXT, tests_ordered TEXT, lab_tests_prescribed TEXT, -- e.g., "Widal Test, CBC" lab_test_results TEXT, -- e.g., "Widal Positive 1:160" custom_diet_prescription TEXT, -- Customized diet prescription JSON/Text recovery_status TEXT CHECK (recovery_status IN ('Improving', 'Cured', 'Critical', 'Under Observation')), recovery_percentage INTEGER DEFAULT 0 CHECK (recovery_percentage >= 0 AND recovery_percentage <= 100), efficacy_feedback TEXT, -- Patient/Doctor feedback on earlier drugs FOREIGN KEY (patient_id) REFERENCES patients(id) ON DELETE CASCADE, FOREIGN KEY (doctor_id) REFERENCES doctors(id) ON DELETE RESTRICT, FOREIGN KEY (hospital_id) REFERENCES hospitals(id) ON DELETE SET NULL ); -- 7. PRESCRIPTIONS (Active Courses & Outcomes) CREATE TABLE IF NOT EXISTS prescriptions ( id INTEGER PRIMARY KEY AUTOINCREMENT, visit_id INTEGER NOT NULL, medicine_name TEXT NOT NULL, dosage TEXT NOT NULL, -- e.g., "500mg" frequency_time TEXT NOT NULL, -- e.g., "09:00 AM, 09:00 PM (After Food)" total_days INTEGER NOT NULL CHECK (total_days > 0), start_date DATE NOT NULL, remaining_days INTEGER NOT NULL CHECK (remaining_days >= 0), FOREIGN KEY (visit_id) REFERENCES clinical_visits(id) ON DELETE CASCADE ); -- 8. CONSENT REQUESTS (Time-Bounded ABDM Gateway & Audit Log) CREATE TABLE IF NOT EXISTS consent_requests ( id INTEGER PRIMARY KEY AUTOINCREMENT, patient_id INTEGER NOT NULL, requesting_doctor_id INTEGER NOT NULL, request_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, status TEXT DEFAULT 'PENDING' CHECK (status IN ('PENDING', 'APPROVED', 'DENIED', 'EXPIRED', 'REVOKED')), access_token TEXT, -- Cryptographically secure session token token_expiry TIMESTAMP, -- 2 hours validity from approval FOREIGN KEY (patient_id) REFERENCES patients(id) ON DELETE CASCADE, FOREIGN KEY (requesting_doctor_id) REFERENCES doctors(id) ON DELETE RESTRICT ); -- 8B. ACTIVE CONSENTS (Strict Real-Time Live Consent & Immediate Revocation Guard) CREATE TABLE IF NOT EXISTS active_consents ( id INTEGER PRIMARY KEY AUTOINCREMENT, patient_id INTEGER NOT NULL, doctor_id INTEGER NOT NULL, is_active BOOLEAN DEFAULT 1 CHECK (is_active IN (0, 1)), access_token TEXT, granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP, FOREIGN KEY (patient_id) REFERENCES patients(id) ON DELETE CASCADE, FOREIGN KEY (doctor_id) REFERENCES doctors(id) ON DELETE CASCADE ); -- 9. MEDICINE REMINDERS (Smart Clock & Refill Notifications) CREATE TABLE IF NOT EXISTS medicine_reminders ( id INTEGER PRIMARY KEY AUTOINCREMENT, prescription_id INTEGER NOT NULL, reminder_time TIME NOT NULL, reminder_type TEXT NOT NULL CHECK (reminder_type IN ('DOSAGE', 'REFILL_ALERT', 'CHECKUP_ALERT')), message TEXT NOT NULL, is_dismissed BOOLEAN DEFAULT 0 CHECK (is_dismissed IN (0, 1)), FOREIGN KEY (prescription_id) REFERENCES prescriptions(id) ON DELETE CASCADE ); -- 10. PATIENT FEEDBACKS (Dual Rating for Doctor & Hospital Facility) CREATE TABLE IF NOT EXISTS patient_feedbacks ( id INTEGER PRIMARY KEY AUTOINCREMENT, patient_id INTEGER NOT NULL, visit_id INTEGER, doctor_id INTEGER NOT NULL, hospital_id INTEGER, doctor_rating INTEGER NOT NULL CHECK (doctor_rating BETWEEN 1 AND 5), doctor_review TEXT, hospital_rating INTEGER NOT NULL CHECK (hospital_rating BETWEEN 1 AND 5), hospital_hygiene_facility_review TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (patient_id) REFERENCES patients(id) ON DELETE CASCADE, FOREIGN KEY (visit_id) REFERENCES clinical_visits(id) ON DELETE SET NULL, FOREIGN KEY (doctor_id) REFERENCES doctors(id) ON DELETE CASCADE, FOREIGN KEY (hospital_id) REFERENCES hospitals(id) ON DELETE SET NULL ); -- 11. OPD QUEUE (Triage Pipeline & Token Allocation) CREATE TABLE IF NOT EXISTS opd_queue ( id INTEGER PRIMARY KEY AUTOINCREMENT, token_number INTEGER NOT NULL, token_display TEXT NOT NULL, patient_id INTEGER NOT NULL, doctor_id INTEGER NOT NULL, hospital_id INTEGER NOT NULL, opd_counter TEXT NOT NULL, status TEXT DEFAULT 'WAITING' CHECK (status IN ('WAITING', 'IN_CONSULTATION', 'COMPLETED', 'CANCELLED')), vitals_bp TEXT, vitals_pulse INTEGER, vitals_temp REAL, vitals_spo2 INTEGER, priority TEXT DEFAULT 'REGULAR' CHECK (priority IN ('REGULAR', 'URGENT', 'EMERGENCY')), queue_date DATE DEFAULT CURRENT_DATE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, called_at TIMESTAMP, completed_at TIMESTAMP, FOREIGN KEY (patient_id) REFERENCES patients(id) ON DELETE CASCADE, FOREIGN KEY (doctor_id) REFERENCES doctors(id) ON DELETE CASCADE, FOREIGN KEY (hospital_id) REFERENCES hospitals(id) ON DELETE CASCADE ); -- 12. OPD BOOKINGS (Patient Self-Registration & Direct Slot Booking Engine) CREATE TABLE IF NOT EXISTS opd_bookings ( id INTEGER PRIMARY KEY AUTOINCREMENT, booking_reference TEXT UNIQUE NOT NULL, -- e.g., "BK-2026-0891" patient_id INTEGER NOT NULL, hospital_id INTEGER NOT NULL, doctor_id INTEGER NOT NULL, booking_date DATE NOT NULL, token_number INTEGER NOT NULL, token_display TEXT NOT NULL, status TEXT DEFAULT 'WAITING' CHECK (status IN ('BOOKED', 'WAITING', 'IN_CONSULTATION', 'COMPLETED', 'CANCELLED')), booking_mode TEXT DEFAULT 'ONLINE_PATIENT_SELF' CHECK (booking_mode IN ('ONLINE_PATIENT_SELF', 'HOSPITAL_DESK_WALKIN')), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (patient_id) REFERENCES patients(id) ON DELETE CASCADE, FOREIGN KEY (hospital_id) REFERENCES hospitals(id) ON DELETE CASCADE, FOREIGN KEY (doctor_id) REFERENCES doctors(id) ON DELETE CASCADE ); -- ============================================================================= -- PERFORMANCE INDEXES (Optimized for Fast Lookups & Foreign Key Joins) -- ============================================================================= CREATE INDEX IF NOT EXISTS idx_users_username ON users(username); CREATE INDEX IF NOT EXISTS idx_hospitals_cea ON hospitals(cea_license); CREATE INDEX IF NOT EXISTS idx_hospitals_verified ON hospitals(is_govt_verified); CREATE INDEX IF NOT EXISTS idx_doctors_nmc ON doctors(nmc_reg_number); CREATE INDEX IF NOT EXISTS idx_doctors_verified ON doctors(is_verified, verification_badge); CREATE INDEX IF NOT EXISTS idx_patients_health_id ON patients(health_id); CREATE INDEX IF NOT EXISTS idx_patients_phone ON patients(phone); CREATE INDEX IF NOT EXISTS idx_clinical_visits_patient ON clinical_visits(patient_id, visit_date); CREATE INDEX IF NOT EXISTS idx_clinical_visits_doctor ON clinical_visits(doctor_id); CREATE INDEX IF NOT EXISTS idx_clinical_visits_hospital ON clinical_visits(hospital_id); CREATE INDEX IF NOT EXISTS idx_prescriptions_visit ON prescriptions(visit_id); CREATE INDEX IF NOT EXISTS idx_consent_patient_doctor ON consent_requests(patient_id, requesting_doctor_id); CREATE INDEX IF NOT EXISTS idx_active_consents_lookup ON active_consents(patient_id, doctor_id, is_active); CREATE INDEX IF NOT EXISTS idx_reminders_prescription ON medicine_reminders(prescription_id); CREATE INDEX IF NOT EXISTS idx_reminders_active ON medicine_reminders(reminder_type, is_dismissed); CREATE INDEX IF NOT EXISTS idx_feedbacks_doctor ON patient_feedbacks(doctor_id); CREATE INDEX IF NOT EXISTS idx_feedbacks_hospital ON patient_feedbacks(hospital_id); CREATE INDEX IF NOT EXISTS idx_opd_queue_status ON opd_queue(doctor_id, status, queue_date); CREATE INDEX IF NOT EXISTS idx_opd_bookings_lookup ON opd_bookings(doctor_id, booking_date, token_number); """ def hash_govt_id(plain_id: str) -> str: """Computes a SHA-256 hash of national ID for zero-knowledge privacy.""" return hash_secret(plain_id) def get_db_connection(db_path: str = DB_PATH) -> sqlite3.Connection: """ Creates and configures an edge-grade SQLite connection. Enforces Foreign Key Constraints, Write-Ahead Logging (WAL), and dict row factory. """ conn = sqlite3.connect(db_path) conn.execute("PRAGMA foreign_keys = ON;") conn.execute("PRAGMA journal_mode = WAL;") conn.execute("PRAGMA synchronous = NORMAL;") conn.row_factory = sqlite3.Row return conn def ensure_table_columns(conn: sqlite3.Connection) -> None: """Ensures existing tables have new columns before applying index script.""" cur = conn.cursor() # Hospitals table columns try: cur.execute("PRAGMA table_info(hospitals);") h_cols = [r[1] for r in cur.fetchall()] if h_cols: if "is_govt_verified" not in h_cols: conn.execute("ALTER TABLE hospitals ADD COLUMN is_govt_verified BOOLEAN DEFAULT 0;") if "cea_document" not in h_cols: conn.execute("ALTER TABLE hospitals ADD COLUMN cea_document TEXT;") if "noc_document" not in h_cols: conn.execute("ALTER TABLE hospitals ADD COLUMN noc_document TEXT;") if "contact_phone" not in h_cols: conn.execute("ALTER TABLE hospitals ADD COLUMN contact_phone TEXT;") if "verified_at" not in h_cols: conn.execute("ALTER TABLE hospitals ADD COLUMN verified_at TIMESTAMP;") except Exception as e: logger.debug("Hospitals migration check: %s", e) # Doctors table columns try: cur.execute("PRAGMA table_info(doctors);") d_cols = [r[1] for r in cur.fetchall()] if d_cols: if "specialization" not in d_cols: conn.execute("ALTER TABLE doctors ADD COLUMN specialization TEXT DEFAULT 'General Medicine';") if "password_hash" not in d_cols: conn.execute("ALTER TABLE doctors ADD COLUMN password_hash TEXT DEFAULT '';") except Exception as e: logger.debug("Doctor migration check: %s", e) # Doctor-hospital affiliations table columns try: cur.execute("PRAGMA table_info(doctor_hospital_affiliations);") a_cols = [r[1] for r in cur.fetchall()] if a_cols: if "status" not in a_cols: conn.execute("ALTER TABLE doctor_hospital_affiliations ADD COLUMN status TEXT DEFAULT 'ACTIVE';") if "department" not in a_cols: conn.execute("ALTER TABLE doctor_hospital_affiliations ADD COLUMN department TEXT DEFAULT 'General Medicine';") if "opd_room" not in a_cols: conn.execute("ALTER TABLE doctor_hospital_affiliations ADD COLUMN opd_room TEXT DEFAULT 'OPD Counter 1';") if "proof_document" not in a_cols: conn.execute("ALTER TABLE doctor_hospital_affiliations ADD COLUMN proof_document TEXT;") if "verified_at" not in a_cols: conn.execute("ALTER TABLE doctor_hospital_affiliations ADD COLUMN verified_at TIMESTAMP;") except Exception as e: logger.debug("Affiliations migration check: %s", e) # Patients table columns try: cur.execute("PRAGMA table_info(patients);") p_cols = [r[1] for r in cur.fetchall()] if p_cols: if "password_hash" not in p_cols: conn.execute("ALTER TABLE patients ADD COLUMN password_hash TEXT DEFAULT '';") except Exception as e: logger.debug("Patients migration check: %s", e) # Clinical visits table columns try: cur.execute("PRAGMA table_info(clinical_visits);") cv_cols = [r[1] for r in cur.fetchall()] if cv_cols: for col_name, col_type in [ ("hospital_id", "INTEGER"), ("hospital_name", "TEXT"), ("doctor_name", "TEXT"), ("specialization", "TEXT"), ("visit_timestamp", "TIMESTAMP"), ("treatments_performed", "TEXT"), ("tests_ordered", "TEXT"), ("custom_diet_prescription", "TEXT"), ]: if col_name not in cv_cols: conn.execute(f"ALTER TABLE clinical_visits ADD COLUMN {col_name} {col_type};") except Exception as e: logger.debug("Clinical visits migration check: %s", e) def init_db(db_path: str = DB_PATH) -> None: """Executes the DDL schema to initialize all tables and indexes.""" logger.info("Initializing DoctorKavach upgraded database at: %s", db_path) conn = get_db_connection(db_path) try: with conn: ensure_table_columns(conn) conn.executescript(SCHEMA_SQL) logger.info("Schema creation and index build successfully completed.") except Exception as e: logger.error("Database schema initialization failed: %s", e) raise finally: conn.close() def seed_database(db_path: str = DB_PATH) -> None: """ Populates database with production-grade seed fixtures across all modules: - Users (Pre-seeded accounts for Patient, Doctor, Hospital, Govt) - Hospitals (3 Verified + 1 Unverified Apex Hospital with sample uploaded documents) - Doctors (3 Verified + 1 Pending Affiliation + 1 Unlicensed/Quack) - Doctor-Hospital Affiliations (Active + 1 PENDING_AUDIT) - Active Consents (Time-bound live consent with revocation capability) - Preset Disease Diets (6 clinical condition templates) - Patients (with ABHA IDs and phone credentials) - Clinical Visits with Multi-Entity Audit Trail & Prescriptions - Live OPD Queue tokens and OPD Bookings """ logger.info("Seeding upgraded database with clinical fixtures...") conn = get_db_connection(db_path) cur = conn.cursor() try: with conn: # Clean existing records in reverse dependency order tables_to_clear = [ "users", "opd_bookings", "active_consents", "patient_feedbacks", "opd_queue", "doctor_hospital_affiliations", "disease_diets", "medicine_reminders", "consent_requests", "prescriptions", "clinical_visits", "patients", "doctors", "hospitals" ] for t in tables_to_clear: cur.execute(f"DELETE FROM {t};") try: cur.execute(f"DELETE FROM sqlite_sequence WHERE name IN ({','.join(['?']*len(tables_to_clear))});", tables_to_clear) except Exception: pass # ----------------------------------------------------------------- # 1. SEED HOSPITALS (3 Verified + 1 Unverified Pending Audit) # ----------------------------------------------------------------- hospitals_data = [ ( "Sharma Health Clinic & Diagnostics", "CEA-DL-2021-9921", "Suite 402, Metro Pillar 118, Janakpuri, New Delhi - 110058", "New Delhi", 40, 12, "ADMIN-SHARMA-01", hash_secret("admin123"), 1, # Verified "cea_license_sharma.pdf", "fire_noc_sharma.pdf", "+91 11 2548 9921", "2023-01-15 10:00:00" ), ( "Lok Nayak Jai Prakash Hospital (LNJP)", "CEA-DL-2018-0012", "Jawaharlal Nehru Marg, Delhi Gate, New Delhi - 110002", "New Delhi", 500, 85, "ADMIN-LNJP-01", hash_secret("admin123"), 1, # Verified "cea_license_lnjp.pdf", "fire_noc_lnjp.pdf", "+91 11 2323 3000", "2022-04-10 11:30:00" ), ( "HeartShield Advanced Cardio Care (AIIMS Affiliated)", "CEA-DL-2018-4412", "B-14, Green Park Main, New Delhi - 110016", "New Delhi", 150, 28, "ADMIN-AIIMS-01", hash_secret("admin123"), 1, # Verified "cea_license_heartshield.pdf", "fire_noc_heartshield.pdf", "+91 11 2658 8500", "2023-06-01 09:15:00" ), ( "Apex Multi-Specialty Hospital", "CEA-DL-2023-8841", "Sector 14, Rohini Outer Ring Road, New Delhi - 110085", "New Delhi", 250, 90, "ADMIN-APEX-01", hash_secret("admin123"), 0, # UNVERIFIED / PENDING AUDIT for Govt Review Demo! "apex_cea_license.pdf", "apex_fire_biowaste_noc.pdf", "+91 11 2785 8841", None ) ] cur.executemany(""" INSERT INTO hospitals ( hospital_name, cea_license, address, city, total_beds, available_beds, admin_id, password_hash, is_govt_verified, cea_document, noc_document, contact_phone, verified_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); """, hospitals_data) logger.info("Inserted %d hospitals (including 1 pending audit).", len(hospitals_data)) hosp_sharma_id = 1 hosp_lnjp_id = 2 hosp_heart_id = 3 hosp_apex_id = 4 # ----------------------------------------------------------------- # 2. SEED DOCTORS (3 Verified + 1 Pending Affiliation + 1 Quack) # ----------------------------------------------------------------- doctors_data = [ ( "Dr. Arun Kumar Sharma", hash_govt_id("AADHAAR-8472-9102-3841"), "NMC-2018-847291", "Delhi Medical Council", "MBBS, MD (General Medicine)", "General Medicine", "Maulana Azad Medical College, New Delhi", "Lok Nayak Hospital, Delhi", "Sharma Health Clinic & Diagnostics", "CEA-DL-2021-9921", hash_secret("doctor123"), 1, "2024-01-10 10:30:00", "Verified Green Shield" ), ( "Dr. Priya Nair", hash_govt_id("AADHAAR-1928-3746-5520"), "NMC-2016-192837", "Delhi Medical Council", "MBBS, MD, DM (Cardiology)", "Cardiology", "AIIMS New Delhi", "AIIMS Hospital, New Delhi", "HeartShield Advanced Cardio Care (AIIMS Affiliated)", "CEA-DL-2018-4412", hash_secret("doctor123"), 1, "2023-08-14 09:00:00", "Verified Green Shield" ), ( "Dr. Rajesh Mehta", hash_govt_id("AADHAAR-7738-2190-4412"), "NMC-2015-773821", "Delhi Medical Council", "MBBS, MS (General Surgery)", "General Surgery", "Lady Hardinge Medical College, Delhi", "Safdarjung Hospital, New Delhi", "Apex Multi-Specialty Hospital", "CEA-DL-2023-8841", hash_secret("doctor123"), 1, "2023-11-20 14:00:00", "Verified Green Shield" ), ( "Suresh Prasad (Unregistered / Quack)", hash_govt_id("AADHAAR-0000-0000-0000"), "NMC-FAKE-000000", "Unregistered", "B.A. (Pass) - Forged Degrees", "Quackery / Fraudulent Clinic", "Non-Existent Medical Institute", "None", "Prasad Wellness Clinic", "UNLICENSED-0000", hash_secret("quack123"), 0, None, "Rejected" ) ] cur.executemany(""" INSERT INTO doctors ( full_name, govt_id_hash, nmc_reg_number, state_medical_council, degrees, specialization, medical_college, internship_hospital, current_hospital_clinic, clinic_establishment_license, password_hash, is_verified, verified_timestamp, verification_badge ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); """, doctors_data) logger.info("Inserted %d doctors.", len(doctors_data)) doc_sharma_id = 1 doc_nair_id = 2 doc_mehta_id = 3 doc_quack_id = 4 # ----------------------------------------------------------------- # 3. SEED DOCTOR-HOSPITAL AFFILIATIONS # ----------------------------------------------------------------- affiliations_data = [ (doc_sharma_id, hosp_sharma_id, "Outpatient Department (OPD)", "OPD Counter 2", 1, "ACTIVE", "affiliation_sharma.pdf", "2023-01-20 10:00:00"), (doc_sharma_id, hosp_lnjp_id, "General Medicine (Visiting)", "Ward 4B / Desk 3", 1, "ACTIVE", "affiliation_lnjp.pdf", "2023-02-15 11:00:00"), (doc_nair_id, hosp_heart_id, "Cardiology & Intensive Care", "Cath Lab Consultation Suite", 1, "ACTIVE", "affiliation_nair.pdf", "2023-03-01 09:30:00"), (doc_mehta_id, hosp_apex_id, "General Surgery & Daycare", "OPD Counter 104", 0, "PENDING_AUDIT", "affiliation_letter_dr_mehta.pdf", None) ] cur.executemany(""" INSERT INTO doctor_hospital_affiliations ( doctor_id, hospital_id, department, opd_room, is_active, status, proof_document, verified_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?); """, affiliations_data) logger.info("Inserted %d doctor-hospital affiliations (including 1 pending audit).", len(affiliations_data)) # ----------------------------------------------------------------- # 4. SEED PRESET DISEASE DIETS # ----------------------------------------------------------------- diets_data = [ ( "Typhoid", "Boiled water, coconut water, thin khichdi, strained vegetable soup, steamed apples, barley water", "Deep-fried items, raw salads, unpasteurized milk, spicy curries, whole beans, cabbage", "Convalescent soft diet; enteric rest is imperative. Strict boiled water intake for 3 weeks." ), ( "Hypertension", "DASH protocol, oatmeal, fresh seasonal fruits, low-fat yogurt, garlic, steamed spinach", "Pickles, papad, processed meats, bakery items with baking soda, sodium > 2g/day", "Reduce dietary sodium (<1500mg/day). Emphasize potassium-rich foods (bananas, coconut water)." ), ( "Jaundice", "Sugarcane juice (hygienic), radish leaf extract, glucose water, boiled rice, papayas, chhena", "Ghee, butter, fried snacks, oil > 1 tsp/day, heavy meats, alcohol, egg yolks", "Ultra-low fat hepatic regimen. Avoid liver over-taxation during acute hyperbilirubinemia." ), ( "Type 2 Diabetes", "Low GI millets, methi leaves, bitter gourd (karela), roasted chana, cucumbers, skimmed milk", "Refined sugar, jaggery, honey, white bread, sweetened fruit juices, potatoes, pastries", "Complex carbohydrates with high soluble fiber to flatten glycemic spikes; monitor HbA1c." ), ( "Chronic Kidney Disease (CKD)", "Controlled low-protein (0.6g/kg), white rice, bottle gourd (lauki), apples, leached vegetables", "High potassium foods (tomatoes, oranges), high phosphorus (nuts, colas, dairy), rock salt", "Renal protocol: strict fluid restriction as per 24h urine output + 500mL; leach vegetables." ), ( "Acute Gastroenteritis", "Oral Rehydration Salts (ORS), BRAT regimen (Banana, Rice, Applesauce, Toast), curd with cumin", "Dairy milk, spicy foods, carbonated sodas, raw fruits with skin, caffeine, oily gravies", "Hydration priority. Measure stool frequency; resume bland solids as frequency settles." ) ] cur.executemany(""" INSERT INTO disease_diets ( disease_key, default_allowed, default_restricted, clinical_notes ) VALUES (?, ?, ?, ?); """, diets_data) logger.info("Inserted %d clinical disease diet templates.", len(diets_data)) # ----------------------------------------------------------------- # 5. SEED PATIENTS (ABDM / ABHA Identity) # ----------------------------------------------------------------- patients_data = [ ( "ABHA-9148-2910-4821", "Riya Verma", "+91 98112 34567", 28, "Female", "Janakpuri, New Delhi", "Suresh Verma (Father): +91 98112 34567", hash_secret("patient123") ), ( "ABHA-4412-8820-1920", "Sidharth Malhotra", "+91 99581 23456", 45, "Male", "Rohini Sector 7, New Delhi", "Pooja Malhotra (Wife): +91 99581 23457", hash_secret("patient123") ), ( "ABHA-3310-9921-5544", "Amitabh Sen", "+91 97110 88221", 62, "Male", "CR Park, New Delhi", "Debashis Sen (Son): +91 97110 88222", hash_secret("patient123") ), ( "ABHA-5582-1102-7733", "Kavita Deshmukh", "+91 98200 44119", 34, "Female", "Green Park, New Delhi", "Rajesh Deshmukh (Husband): +91 98200 44120", hash_secret("patient123") ) ] cur.executemany(""" INSERT INTO patients ( health_id, full_name, phone, age, gender, village_city, emergency_contact, password_hash ) VALUES (?, ?, ?, ?, ?, ?, ?, ?); """, patients_data) logger.info("Inserted %d ABDM registered patients.", len(patients_data)) patient_riya_id = 1 patient_sid_id = 2 patient_amit_id = 3 patient_kavita_id = 4 # ----------------------------------------------------------------- # 6. SEED UNIFIED USERS TABLE (All 4 Portals Login Registry) # ----------------------------------------------------------------- users_data = [ # Patients ("ABHA-9148-2910-4821", hash_secret("patient123"), "patient", patient_riya_id), ("+91 98112 34567", hash_secret("patient123"), "patient", patient_riya_id), ("9811234567", hash_secret("patient123"), "patient", patient_riya_id), ("ABHA-4412-8820-1920", hash_secret("patient123"), "patient", patient_sid_id), # Doctors ("NMC-2018-847291", hash_secret("doctor123"), "doctor", doc_sharma_id), ("NMC-2016-192837", hash_secret("doctor123"), "doctor", doc_nair_id), ("NMC-2015-773821", hash_secret("doctor123"), "doctor", doc_mehta_id), # Hospitals ("CEA-DL-2021-9921", hash_secret("admin123"), "hospital", hosp_sharma_id), ("ADMIN-SHARMA-01", hash_secret("admin123"), "hospital", hosp_sharma_id), ("CEA-DL-2018-0012", hash_secret("admin123"), "hospital", hosp_lnjp_id), ("ADMIN-LNJP-01", hash_secret("admin123"), "hospital", hosp_lnjp_id), ("CEA-DL-2018-4412", hash_secret("admin123"), "hospital", hosp_heart_id), ("ADMIN-AIIMS-01", hash_secret("admin123"), "hospital", hosp_heart_id), ("CEA-DL-2023-8841", hash_secret("admin123"), "hospital", hosp_apex_id), ("ADMIN-APEX-01", hash_secret("admin123"), "hospital", hosp_apex_id), # Govt Regulators ("GMO-DELHI-001", hash_secret("govt123"), "govt", 1), ("NMC-REGULATOR-99", hash_secret("govt123"), "govt", 1), ("STATE-HEALTH-AUTH", hash_secret("govt123"), "govt", 1) ] cur.executemany(""" INSERT INTO users (username, password_hash, role, foreign_id) VALUES (?, ?, ?, ?); """, users_data) logger.info("Inserted %d unified login credentials.", len(users_data)) # ----------------------------------------------------------------- # 7. SEED CLINICAL VISITS (Multi-Entity Audit Trail & Diet) # ----------------------------------------------------------------- visit_1_date = (datetime.now() - timedelta(days=12)).strftime('%Y-%m-%d %H:%M:%S') visit_2_date = (datetime.now() - timedelta(days=4)).strftime('%Y-%m-%d %H:%M:%S') visit_3_date = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S') visits_data = [ ( patient_riya_id, doc_sharma_id, hosp_sharma_id, "Sharma Health Clinic & Diagnostics", "Dr. Arun Kumar Sharma", "General Medicine", visit_1_date, visit_1_date, "High step-ladder fever (103°F), abdominal colic, headache, severe fatigue", "Enteric Fever (Typhoid)", "Widal agglutination serology, oral rehydration therapy, antipyretic administration", "Widal Slide & Tube Test, Complete Blood Count (CBC)", "Widal Test, CBC", "Widal Positive (S. Typhi O: 1:160, H: 1:320), Leukopenia", "Allowed: Boiled water, thin moong khichdi, steamed apples | Restricted: Deep-fried items, street food, spices | Note: Strict boiled water for 3 weeks.", "Under Observation", 40, "Good tolerance to Cefixime; mild nausea reported on Day 2." ), ( patient_riya_id, doc_sharma_id, hosp_lnjp_id, "Lok Nayak Jai Prakash Hospital (LNJP)", "Dr. Arun Kumar Sharma", "General Medicine", visit_2_date, visit_2_date, "Follow-up for enteric fever; fever defervescence observed, mild residual weakness", "Typhoid in Defervescence Phase", "Hydration check, nutritional recovery review, liver function monitoring", "Liver Function Test (LFT), Hemoglobin re-check", "LFT, Hemoglobin", "Bilirubin normal (0.8 mg/dL), SGPT 38 U/L (normalized)", "Allowed: Coconut water, vegetable soup, curd with roasted cumin | Restricted: Heavy restaurant curries, excess sodium", "Improving", 80, "Patient afebrile for 48 hours; appetite recovering well." ), ( patient_sid_id, doc_nair_id, hosp_heart_id, "HeartShield Advanced Cardio Care (AIIMS Affiliated)", "Dr. Priya Nair", "Cardiology", visit_3_date, visit_3_date, "Occipital morning headache, exertional dyspnea, BP recorded 164/102 mmHg", "Stage II Essential Hypertension", "12-lead ECG, fundus examination (Grade 1 hypertensive changes), salt restriction counseling", "12-Lead ECG, Lipid Profile, Serum Creatinine", "12-Lead ECG, Serum Creatinine", "ECG: Sinus rhythm, LVH by voltage criteria. Creatinine 1.0 mg/dL", "Allowed: DASH regimen, oatmeal, garlic, steamed greens | Restricted: Pickles, papad, sodium > 2g/day", "Improving", 65, "BP responsive to Telmisartan; counseled on regular brisk walking." ) ] cur.executemany(""" INSERT INTO clinical_visits ( patient_id, doctor_id, hospital_id, hospital_name, doctor_name, specialization, visit_date, visit_timestamp, symptoms, provisional_diagnosis, treatments_performed, tests_ordered, lab_tests_prescribed, lab_test_results, custom_diet_prescription, recovery_status, recovery_percentage, efficacy_feedback ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); """, visits_data) logger.info("Inserted %d clinical visits with multi-entity audit trail.", len(visits_data)) visit_riya_1 = 1 visit_riya_2 = 2 visit_sid_1 = 3 # ----------------------------------------------------------------- # 8. SEED PRESCRIPTIONS # ----------------------------------------------------------------- prescriptions_data = [ (visit_riya_1, "Cefixime 200mg", "200mg", "09:00 AM, 09:00 PM (After Food)", 14, (date.today() - timedelta(days=12)).isoformat(), 2), (visit_riya_1, "Paracetamol 650mg", "650mg", "SOS (Max TID for temp > 100°F)", 5, (date.today() - timedelta(days=12)).isoformat(), 0), (visit_riya_1, "Pantoprazole 40mg", "40mg", "08:00 AM (Empty Stomach)", 14, (date.today() - timedelta(days=12)).isoformat(), 2), (visit_riya_2, "B-Complex + Zinc Forte", "1 Capsule", "01:00 PM (After Lunch)", 15, (date.today() - timedelta(days=4)).isoformat(), 11), (visit_sid_1, "Telmisartan 40mg", "40mg", "08:30 AM (Once Daily)", 30, (date.today() - timedelta(days=1)).isoformat(), 29), (visit_sid_1, "Amlodipine 5mg", "5mg", "08:30 PM (Once Daily)", 30, (date.today() - timedelta(days=1)).isoformat(), 29) ] cur.executemany(""" INSERT INTO prescriptions ( visit_id, medicine_name, dosage, frequency_time, total_days, start_date, remaining_days ) VALUES (?, ?, ?, ?, ?, ?, ?); """, prescriptions_data) logger.info("Inserted %d prescriptions.", len(prescriptions_data)) # ----------------------------------------------------------------- # 9. SEED MEDICINE REMINDERS (Dosage + 3-Day Refill Alert) # ----------------------------------------------------------------- reminders_data = [ (1, "09:00", "DOSAGE", "Take Cefixime 200mg (1 Tablet) after breakfast.", 0), (1, "21:00", "DOSAGE", "Take Cefixime 200mg (1 Tablet) after dinner.", 0), (1, "10:00", "REFILL_ALERT", "Low Stock Warning: Only 2 days remaining for Cefixime 200mg. Re-order at Jan Aushadhi Kendra.", 0), (3, "08:00", "DOSAGE", "Take Pantoprazole 40mg on empty stomach.", 1), (5, "08:30", "DOSAGE", "Take Telmisartan 40mg for BP control.", 0) ] cur.executemany(""" INSERT INTO medicine_reminders ( prescription_id, reminder_time, reminder_type, message, is_dismissed ) VALUES (?, ?, ?, ?, ?); """, reminders_data) logger.info("Inserted %d smart medicine reminders.", len(reminders_data)) # ----------------------------------------------------------------- # 10. SEED CONSENT REQUESTS & ACTIVE CONSENTS (Live Revocation Engine) # ----------------------------------------------------------------- token_active = secrets.token_hex(24) expiry_active = (datetime.now() + timedelta(hours=2)).strftime('%Y-%m-%d %H:%M:%S') cur.execute(""" INSERT INTO consent_requests ( patient_id, requesting_doctor_id, request_timestamp, status, access_token, token_expiry ) VALUES (?, ?, ?, 'APPROVED', ?, ?); """, (patient_riya_id, doc_sharma_id, (datetime.now() - timedelta(minutes=15)).strftime('%Y-%m-%d %H:%M:%S'), token_active, expiry_active)) cur.execute(""" INSERT INTO active_consents ( patient_id, doctor_id, is_active, access_token, granted_at, expires_at ) VALUES (?, ?, 1, ?, ?, ?); """, (patient_riya_id, doc_sharma_id, token_active, datetime.now().strftime('%Y-%m-%d %H:%M:%S'), expiry_active)) logger.info("Seeded active live consent for Patient #%d and Doctor #%d.", patient_riya_id, doc_sharma_id) # ----------------------------------------------------------------- # 11. SEED PATIENT FEEDBACKS (Independent Doctor & Hospital Ratings) # ----------------------------------------------------------------- feedbacks_data = [ ( patient_riya_id, visit_riya_1, doc_sharma_id, hosp_sharma_id, 5, "Dr. Sharma correctly diagnosed enteric fever when two other clinics missed it. Very reassuring bedside manner.", 5, "Clinic was spotless. Hand sanitizers at every desk, sterile equipment, clean waiting lounge.", (datetime.now() - timedelta(days=10)).strftime('%Y-%m-%d %H:%M:%S') ), ( patient_riya_id, visit_riya_2, doc_sharma_id, hosp_lnjp_id, 5, "Dr. Sharma took extra time to review the convalescent diet chart and stopped unnecessary antibiotics.", 4, "LNJP OPD was crowded, but the consultation room was sanitized and nursing staff was helpful.", (datetime.now() - timedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S') ) ] cur.executemany(""" INSERT INTO patient_feedbacks ( patient_id, visit_id, doctor_id, hospital_id, doctor_rating, doctor_review, hospital_rating, hospital_hygiene_facility_review, created_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); """, feedbacks_data) logger.info("Inserted %d dual feedbacks.", len(feedbacks_data)) # ----------------------------------------------------------------- # 12. SEED LIVE OPD QUEUE TOKENS & OPD BOOKINGS # ----------------------------------------------------------------- today_str = date.today().isoformat() queue_data = [ ( 14, "TK-14", patient_riya_id, doc_sharma_id, hosp_sharma_id, "OPD Counter 2", "WAITING", "118/78 mmHg", 74, 98.4, 99, "REGULAR", today_str ), ( 15, "TK-15", patient_sid_id, doc_sharma_id, hosp_sharma_id, "OPD Counter 2", "WAITING", "130/85 mmHg", 82, 100.2, 97, "URGENT", today_str ), ( 12, "TK-12", patient_amit_id, doc_nair_id, hosp_heart_id, "OPD Counter 1", "COMPLETED", "126/80 mmHg", 72, 98.6, 98, "REGULAR", today_str ) ] cur.executemany(""" INSERT INTO opd_queue ( token_number, token_display, patient_id, doctor_id, hospital_id, opd_counter, status, vitals_bp, vitals_pulse, vitals_temp, vitals_spo2, priority, queue_date ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); """, queue_data) logger.info("Inserted %d OPD queue tokens.", len(queue_data)) # ----------------------------------------------------------------- # 13. SEED OPD BOOKINGS (Self-Registration & Direct Booking Engine) # ----------------------------------------------------------------- bookings_data = [ ( "BK-2026-0014", patient_riya_id, hosp_sharma_id, doc_sharma_id, today_str, 14, "TK-14", "WAITING", "ONLINE_PATIENT_SELF" ), ( "BK-2026-0015", patient_sid_id, hosp_sharma_id, doc_sharma_id, today_str, 15, "TK-15", "WAITING", "ONLINE_PATIENT_SELF" ), ( "BK-2026-0012", patient_amit_id, hosp_heart_id, doc_nair_id, today_str, 12, "TK-12", "COMPLETED", "HOSPITAL_DESK_WALKIN" ) ] cur.executemany(""" INSERT INTO opd_bookings ( booking_reference, patient_id, hospital_id, doctor_id, booking_date, token_number, token_display, status, booking_mode ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?); """, bookings_data) logger.info("Inserted %d direct OPD bookings.", len(bookings_data)) logger.info("DoctorKavach upgraded database successfully seeded.") except Exception as e: logger.error("Error during database seeding: %s", e) conn.rollback() raise finally: conn.close() def verify_database(db_path: str = DB_PATH) -> None: """Runs automated integrity checks across all 13 tables and prints summary diagnostics.""" conn = get_db_connection(db_path) cur = conn.cursor() try: logger.info("=========================================================") logger.info(" DOCTORKAVACH UPGRADED DATABASE INTEGRITY VERIFICATION") logger.info("=========================================================") tables = [ "users", "hospitals", "doctors", "doctor_hospital_affiliations", "patients", "disease_diets", "clinical_visits", "prescriptions", "consent_requests", "active_consents", "medicine_reminders", "patient_feedbacks", "opd_queue", "opd_bookings" ] for table in tables: cur.execute(f"SELECT COUNT(*) FROM {table};") count = cur.fetchone()[0] logger.info("Table '%-30s' : %2d records", table, count) logger.info("---------------------------------------------------------") logger.info("Active Consents & Real-Time Revocation Test:") cur.execute(""" SELECT ac.id, p.full_name AS patient, d.full_name AS doctor, ac.is_active, ac.expires_at FROM active_consents ac JOIN patients p ON ac.patient_id = p.id JOIN doctors d ON ac.doctor_id = d.id; """) for r in cur.fetchall(): logger.info(" Consent #%d: Patient %s -> Dr. %s (Active: %s, Expires: %s)", r['id'], r['patient'], r['doctor'], bool(r['is_active']), r['expires_at']) logger.info("---------------------------------------------------------") logger.info("Direct OPD Bookings Sample:") cur.execute(""" SELECT b.booking_reference, b.token_display, p.full_name AS patient, d.full_name AS doctor, h.hospital_name, b.booking_mode, b.status FROM opd_bookings b JOIN patients p ON b.patient_id = p.id JOIN doctors d ON b.doctor_id = d.id JOIN hospitals h ON b.hospital_id = h.id; """) for r in cur.fetchall(): logger.info(" Booking %s [%s]: Patient %s -> Dr. %s at %s (%s, %s)", r['booking_reference'], r['token_display'], r['patient'], r['doctor'], r['hospital_name'], r['booking_mode'], r['status']) logger.info("=========================================================") logger.info("Database verification completed: ALL TABLES OPERATIONAL.") finally: conn.close() if __name__ == "__main__": init_db() seed_database() verify_database()