diff --git a/README.md b/README.md index 28754ee..fdb6118 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# Neon Health Tracker +# Neon Medical Tracker -A dependency-free PHP, HTML5, JavaScript, and SQLite tracker for workouts, nutrition, supplements, and body metrics. +A dependency-free PHP, HTML5, JavaScript, and SQLite web app for multi-user medical tracking, terminology lookup, medication reference links, and admin-managed profiles. + +This app is a personal tracking and reference tool. It is not medical advice, diagnosis, treatment guidance, or a substitute for a clinician or pharmacist. ## Run @@ -16,12 +18,13 @@ http://127.0.0.1:8080 ## Public Routes -- `/` - public homepage for the service. -- `/workouts.php` - workout planning feature page. -- `/nutrition.php` - nutrition tracking feature page. -- `/recovery.php` - recovery, supplements, and health monitoring feature page. +- `/` - public homepage for the medical tracker service. +- `/workouts.php` - condition-tracking feature page. +- `/nutrition.php` - medicine catalog feature page. +- `/recovery.php` - NIH/NLM research links page. +- `/medical.php` - medical terminology, conditions, medicines, and study-link database. - `/signup.php` - public profile signup. -- `/tracker.php` - the workout, nutrition, supplement, and health dashboard. +- `/tracker.php` - the medical tracker dashboard. - `/admin.php` - admin user-management dashboard. ## Storage @@ -32,20 +35,34 @@ SQLite is created automatically at: data/health_tracker.sqlite ``` -The app seeds two sample profiles, built-in exercise movements, common gym supplements, starter routines, planner entries, nutrition logs, supplement logs, and body metrics. +The app seeds sample profiles, medical terminology, condition summaries, a medication catalog, NIH/NLM study-link categories, medication logs, vitals, labs, symptoms, allergies, appointments, immunizations, and the older optional wellness/fitness data. ## Included -- Multi-user profiles with separate routines, logs, goals, and theme preferences. +- Multi-user profiles with separate records and theme preferences. - Admin dashboard for creating, editing, activating/deactivating, and deleting user profiles. - First user created in a database is automatically promoted to `admin`; later users default to `member`. -- Daily, weekly, and monthly workout planner views. -- Routine planning for weight lifting, cycling, running, swimming, conditioning, mobility, core, outdoor, and hybrid programs. -- Configurable exercise and supplement libraries. -- Nutrition goals scoped by day, week, or month, compared against actual logs. -- Supplement tracking for pre-workout, intra-workout, post-workout, daily, and evening use. -- Health metrics for weight, body fat, sleep, resting heart rate, mood, and notes. +- Daily, weekly, and monthly views for medical logs. +- Medication logging by date, dose, route, frequency, status, prescriber, and notes. +- Vital logs for blood pressure, pulse, temperature, oxygen saturation, glucose, pain score, symptoms, and notes. +- Lab result records with units, reference ranges, clinician/source notes, and collection dates. +- Symptom journal, allergy list, appointments, and immunization records. +- Medical terminology and condition database with source links. +- Medicine catalog with RxNorm, MedlinePlus, PubMed, and ClinicalTrials.gov links. +- NIH/NLM research-link categories related to the listed medicines. - Neon dark theme by default, light mode option, and green, blue, red, pink, and orange accents. +- Optional legacy fitness, nutrition, and supplement tracking remains available as wellness context. + +## Reference Sources + +- RxNorm and RxNav from the U.S. National Library of Medicine: `https://www.nlm.nih.gov/research/umls/rxnorm/index.html` +- MedlinePlus condition and medication pages: `https://medlineplus.gov/` +- PubMed search links for medicine and condition research: `https://pubmed.ncbi.nlm.nih.gov/` +- ClinicalTrials.gov search links for study discovery: `https://clinicaltrials.gov/` +- NIH/NIDDK Diabetes Prevention Program: `https://www.niddk.nih.gov/about-niddk/research-areas/diabetes/diabetes-prevention-program-dpp` +- NIH/NHLBI SPRINT study page: `https://www.nhlbi.nih.gov/science/systolic-blood-pressure-intervention-trial-sprint-study` +- NIH/NHLBI asthma page: `https://www.nhlbi.nih.gov/health/asthma` +- NIH/NIMH depression page: `https://www.nimh.nih.gov/health/topics/depression` ## Photo Credits diff --git a/app/bootstrap.php b/app/bootstrap.php index 97e051e..7fa0cb8 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -160,15 +160,182 @@ CREATE TABLE IF NOT EXISTS body_metrics ( created_at TEXT NOT NULL ); +CREATE TABLE IF NOT EXISTS medical_terms ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + term TEXT NOT NULL, + category TEXT NOT NULL, + plain_language_definition TEXT NOT NULL, + clinical_context TEXT DEFAULT '', + source_name TEXT NOT NULL, + source_url TEXT NOT NULL, + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS medical_conditions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + category TEXT NOT NULL, + overview TEXT NOT NULL, + common_tracking TEXT DEFAULT '', + source_name TEXT NOT NULL, + source_url TEXT NOT NULL, + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS medication_catalog ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + generic_name TEXT NOT NULL, + active_ingredient TEXT DEFAULT '', + chemical_name TEXT DEFAULT '', + brand_names TEXT DEFAULT '', + generic_brands TEXT DEFAULT '', + class_name TEXT NOT NULL, + drug_family TEXT DEFAULT '', + common_use TEXT NOT NULL, + tracking_note TEXT DEFAULT '', + rxnorm_url TEXT NOT NULL, + medlineplus_url TEXT DEFAULT '', + pubchem_url TEXT DEFAULT '', + dailymed_url TEXT DEFAULT '', + pubmed_url TEXT DEFAULT '', + clinicaltrials_url TEXT DEFAULT '', + source_name TEXT NOT NULL, + search_terms TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS medication_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + medication_id INTEGER REFERENCES medication_catalog(id) ON DELETE SET NULL, + taken_on TEXT NOT NULL, + medication_name TEXT NOT NULL, + dose TEXT DEFAULT '', + route TEXT DEFAULT '', + frequency TEXT DEFAULT '', + status TEXT NOT NULL DEFAULT 'planned' CHECK (status IN ('planned', 'taken', 'skipped', 'stopped')), + prescriber TEXT DEFAULT '', + notes TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS vital_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + measured_on TEXT NOT NULL, + systolic INTEGER DEFAULT 0, + diastolic INTEGER DEFAULT 0, + pulse INTEGER DEFAULT 0, + temperature_f REAL DEFAULT 0, + oxygen_pct REAL DEFAULT 0, + glucose_mg_dl REAL DEFAULT 0, + pain_score INTEGER DEFAULT 0, + symptoms TEXT DEFAULT '', + notes TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS lab_results ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + collected_on TEXT NOT NULL, + test_name TEXT NOT NULL, + result_value TEXT NOT NULL, + unit TEXT DEFAULT '', + reference_range TEXT DEFAULT '', + ordering_clinician TEXT DEFAULT '', + notes TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS symptom_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + observed_on TEXT NOT NULL, + symptom TEXT NOT NULL, + body_area TEXT DEFAULT '', + severity INTEGER DEFAULT 0, + duration TEXT DEFAULT '', + triggers TEXT DEFAULT '', + action_taken TEXT DEFAULT '', + notes TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS allergy_records ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + allergen TEXT NOT NULL, + reaction TEXT DEFAULT '', + severity TEXT NOT NULL DEFAULT 'unknown', + first_noted_on TEXT DEFAULT '', + status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'resolved')), + notes TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS appointments ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + appointment_on TEXT NOT NULL, + clinician TEXT DEFAULT '', + specialty TEXT DEFAULT '', + location TEXT DEFAULT '', + reason TEXT NOT NULL, + status TEXT NOT NULL DEFAULT 'scheduled' CHECK (status IN ('scheduled', 'completed', 'canceled')), + follow_up_notes TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS immunization_records ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + vaccine_name TEXT NOT NULL, + administered_on TEXT NOT NULL, + dose TEXT DEFAULT '', + lot_number TEXT DEFAULT '', + clinician_or_site TEXT DEFAULT '', + next_due_on TEXT DEFAULT '', + notes TEXT DEFAULT '', + created_at TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS research_studies ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + category TEXT NOT NULL, + related_medicine TEXT DEFAULT '', + related_condition TEXT DEFAULT '', + title TEXT NOT NULL, + study_type TEXT DEFAULT '', + summary TEXT NOT NULL, + nih_source TEXT NOT NULL, + source_url TEXT NOT NULL, + pubmed_url TEXT DEFAULT '', + clinicaltrials_url TEXT DEFAULT '', + created_at TEXT NOT NULL +); + CREATE INDEX IF NOT EXISTS idx_workouts_user_date ON workouts(user_id, scheduled_on); CREATE INDEX IF NOT EXISTS idx_nutrition_logs_user_date ON nutrition_logs(user_id, logged_on); CREATE INDEX IF NOT EXISTS idx_supplement_logs_user_date ON supplement_logs(user_id, taken_on); CREATE INDEX IF NOT EXISTS idx_body_metrics_user_date ON body_metrics(user_id, measured_on); +CREATE INDEX IF NOT EXISTS idx_medication_logs_user_date ON medication_logs(user_id, taken_on); +CREATE INDEX IF NOT EXISTS idx_vital_logs_user_date ON vital_logs(user_id, measured_on); +CREATE INDEX IF NOT EXISTS idx_lab_results_user_date ON lab_results(user_id, collected_on); +CREATE INDEX IF NOT EXISTS idx_symptom_logs_user_date ON symptom_logs(user_id, observed_on); +CREATE INDEX IF NOT EXISTS idx_allergy_records_user ON allergy_records(user_id, allergen); +CREATE INDEX IF NOT EXISTS idx_appointments_user_date ON appointments(user_id, appointment_on); +CREATE INDEX IF NOT EXISTS idx_immunization_records_user_date ON immunization_records(user_id, administered_on); +CREATE INDEX IF NOT EXISTS idx_medical_terms_term ON medical_terms(term); +CREATE INDEX IF NOT EXISTS idx_medication_catalog_generic ON medication_catalog(generic_name); SQL); migrate_users_table($pdo); + migrate_medication_catalog_table($pdo); seed_libraries($pdo); + seed_medical_library($pdo); seed_demo_data($pdo); + seed_medical_demo_data($pdo); ensure_first_user_is_admin($pdo); } @@ -197,6 +364,27 @@ function migrate_users_table(PDO $pdo): void $pdo->exec("UPDATE users SET updated_at = created_at WHERE updated_at IS NULL OR updated_at = ''"); } +function migrate_medication_catalog_table(PDO $pdo): void +{ + $columns = db_table_columns($pdo, 'medication_catalog'); + $definitions = [ + 'active_ingredient' => "TEXT DEFAULT ''", + 'chemical_name' => "TEXT DEFAULT ''", + 'brand_names' => "TEXT DEFAULT ''", + 'generic_brands' => "TEXT DEFAULT ''", + 'drug_family' => "TEXT DEFAULT ''", + 'pubchem_url' => "TEXT DEFAULT ''", + 'dailymed_url' => "TEXT DEFAULT ''", + 'search_terms' => "TEXT DEFAULT ''", + ]; + + foreach ($definitions as $column => $definition) { + if (!in_array($column, $columns, true)) { + $pdo->exec("ALTER TABLE medication_catalog ADD COLUMN {$column} {$definition}"); + } + } +} + function db_table_columns(PDO $pdo, string $table): array { $rows = db_all($pdo, "PRAGMA table_info({$table})"); @@ -291,6 +479,355 @@ function seed_libraries(PDO $pdo): void } } +function seed_medical_library(PDO $pdo): void +{ + $created = app_now(); + + $termCount = (int) $pdo->query('SELECT COUNT(*) FROM medical_terms')->fetchColumn(); + if ($termCount === 0) { + $terms = [ + ['Blood pressure', 'Vitals', 'Pressure of circulating blood against artery walls, commonly recorded as systolic over diastolic.', 'Often tracked for cardiovascular risk and medication follow-up.', 'MedlinePlus', 'https://medlineplus.gov/highbloodpressure.html'], + ['Hypertension', 'Condition', 'A clinical term for high blood pressure.', 'Can be tracked with home readings, clinician visits, and medication adherence.', 'MedlinePlus', 'https://medlineplus.gov/highbloodpressure.html'], + ['A1C', 'Laboratory', 'A blood test that reflects average blood glucose over roughly the previous few months.', 'Commonly followed in diabetes care.', 'MedlinePlus', 'https://medlineplus.gov/a1c.html'], + ['Hyperglycemia', 'Symptom/Lab', 'Higher-than-desired blood glucose.', 'May be logged with glucose readings, symptoms, meals, and medications.', 'MedlinePlus', 'https://medlineplus.gov/highbloodsugar.html'], + ['LDL cholesterol', 'Laboratory', 'A cholesterol fraction often discussed as a cardiovascular risk marker.', 'Frequently reviewed with lipid panels and statin therapy.', 'MedlinePlus', 'https://medlineplus.gov/cholesterollevelswhatyouneedtoknow.html'], + ['HDL cholesterol', 'Laboratory', 'A cholesterol fraction commonly included in lipid panels.', 'Used with LDL, triglycerides, and total cholesterol to understand lipid status.', 'MedlinePlus', 'https://medlineplus.gov/cholesterollevelswhatyouneedtoknow.html'], + ['Oxygen saturation', 'Vitals', 'An estimate of how much oxygen hemoglobin is carrying.', 'Often recorded as SpO2 from a pulse oximeter.', 'MedlinePlus', 'https://medlineplus.gov/ency/article/003855.htm'], + ['eGFR', 'Laboratory', 'Estimated glomerular filtration rate, a calculated kidney-function marker.', 'Often reviewed with kidney disease, diabetes, hypertension, and medication dosing.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/glomerular-filtration-rate-gfr-test/'], + ['Adverse drug reaction', 'Medication Safety', 'An unwanted or harmful response associated with taking a medicine.', 'Useful to log with medicine, dose, timing, and symptoms.', 'MedlinePlus', 'https://medlineplus.gov/drugsafety.html'], + ['Contraindication', 'Medication Safety', 'A reason a treatment may be unsuitable for a person or situation.', 'Important to discuss with a clinician or pharmacist before medication changes.', 'RxNorm/NLM', 'https://www.nlm.nih.gov/research/umls/rxnorm/index.html'], + ['Randomized controlled trial', 'Research', 'A study design that assigns participants to interventions by chance.', 'Common study type in PubMed and ClinicalTrials.gov research records.', 'ClinicalTrials.gov', 'https://clinicaltrials.gov/'], + ['Placebo', 'Research', 'An inactive comparison used in some clinical studies.', 'Helps separate treatment effects from expectation or background changes.', 'ClinicalTrials.gov', 'https://clinicaltrials.gov/'], + ]; + $stmt = $pdo->prepare( + "INSERT INTO medical_terms + (term, category, plain_language_definition, clinical_context, source_name, source_url, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?)" + ); + foreach ($terms as $term) { + $stmt->execute([...$term, $created]); + } + } + + $additionalTerms = [ + ['Complete blood count (CBC)', 'Laboratory', 'A group of blood tests that count and describe red blood cells, white blood cells, platelets, hemoglobin, hematocrit, and related measures.', 'Commonly logged when tracking anemia, infection, bleeding concerns, or medication effects.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/complete-blood-count-cbc/'], + ['Hemoglobin', 'Laboratory', 'An iron-rich protein in red blood cells that carries oxygen.', 'Often reviewed as part of a CBC and anemia evaluation.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/complete-blood-count-cbc/'], + ['Hematocrit', 'Laboratory', 'The share of whole blood made up of red blood cells.', 'Often tracked with hemoglobin and red blood cell count in CBC results.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/complete-blood-count-cbc/'], + ['White blood cell count', 'Laboratory', 'A measure of white blood cells, which are involved in infection and immune response.', 'May be followed during infections, immune conditions, and medication monitoring.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/complete-blood-count-cbc/'], + ['Platelet count', 'Laboratory', 'A measure of platelets, blood components involved in clotting.', 'Useful context for bleeding risk, clotting concerns, and some medication follow-up.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/complete-blood-count-cbc/'], + ['Creatinine', 'Laboratory', 'A waste product measured in blood or urine and commonly used to evaluate kidney function.', 'Often reviewed with eGFR, diabetes, hypertension, and medication dosing.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/creatinine-test/'], + ['Triglycerides', 'Laboratory', 'A type of fat measured in the blood as part of cardiovascular and metabolic risk review.', 'Frequently tracked with cholesterol labs and lipid-management medicines.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/triglycerides-test/'], + ['Body mass index (BMI)', 'Body Measurements', 'A calculated measure based on height and weight.', 'Can be tracked as one rough context marker, though it does not replace clinical assessment.', 'MedlinePlus', 'https://medlineplus.gov/ency/article/007196.htm'], + ['INR', 'Laboratory', 'International normalized ratio, a standardized blood-clotting measure often reported with prothrombin time.', 'Important for certain anticoagulant monitoring when ordered by a clinician.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/prothrombin-time-test-and-inr-ptinr/'], + ['C-reactive protein (CRP)', 'Laboratory', 'A blood marker that may rise with inflammation.', 'Can be logged with symptoms, diagnosis workups, and clinician instructions.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/c-reactive-protein-crp-test/'], + ['Urinalysis', 'Laboratory', 'A urine test that can screen for substances, cells, or signs of several health conditions.', 'Commonly tracked with kidney, urinary, diabetes, or pregnancy-related care.', 'MedlinePlus', 'https://medlineplus.gov/lab-tests/urinalysis/'], + ]; + $termInsert = $pdo->prepare( + "INSERT INTO medical_terms + (term, category, plain_language_definition, clinical_context, source_name, source_url, created_at) + SELECT ?, ?, ?, ?, ?, ?, ? + WHERE NOT EXISTS (SELECT 1 FROM medical_terms WHERE term = ?)" + ); + foreach ($additionalTerms as $term) { + $termInsert->execute([...$term, $created, $term[0]]); + } + + $conditionCount = (int) $pdo->query('SELECT COUNT(*) FROM medical_conditions')->fetchColumn(); + if ($conditionCount === 0) { + $conditions = [ + ['Hypertension', 'Cardiovascular', 'High blood pressure is a common condition tracked through repeated readings and risk-factor review.', 'Blood pressure, pulse, medications, symptoms, lifestyle notes', 'MedlinePlus', 'https://medlineplus.gov/highbloodpressure.html'], + ['Type 2 Diabetes', 'Endocrine/Metabolic', 'Type 2 diabetes is commonly tracked with glucose, A1C, medications, nutrition, and activity patterns.', 'Glucose, A1C, medication adherence, symptoms, nutrition notes', 'MedlinePlus', 'https://medlineplus.gov/diabetestype2.html'], + ['Asthma', 'Respiratory', 'Asthma tracking often focuses on symptoms, rescue inhaler use, triggers, and breathing measures.', 'Symptoms, medication use, peak flow if prescribed, oxygen saturation', 'MedlinePlus', 'https://medlineplus.gov/asthma.html'], + ['Depression', 'Mental Health', 'Depression tracking may include mood, sleep, medication use, symptoms, and care-team notes.', 'Mood, sleep, symptoms, medication adherence, side effects', 'MedlinePlus', 'https://medlineplus.gov/depression.html'], + ['High Cholesterol', 'Cardiovascular/Metabolic', 'Cholesterol management is commonly followed through lipid labs and medication response.', 'LDL, HDL, triglycerides, statin adherence, side effects', 'MedlinePlus', 'https://medlineplus.gov/cholesterol.html'], + ['Pain and Inflammation', 'General Medicine', 'Pain tracking can connect severity, location, medication use, and functional impact.', 'Pain score, medication timing, symptoms, notes', 'MedlinePlus', 'https://medlineplus.gov/pain.html'], + ]; + $stmt = $pdo->prepare( + "INSERT INTO medical_conditions + (name, category, overview, common_tracking, source_name, source_url, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?)" + ); + foreach ($conditions as $condition) { + $stmt->execute([...$condition, $created]); + } + } + + $medicineCount = (int) $pdo->query('SELECT COUNT(*) FROM medication_catalog')->fetchColumn(); + if ($medicineCount === 0) { + $medicines = [ + ['metformin', 'Biguanide antidiabetic', 'Often used in type 2 diabetes care.', 'Track dose, meals if relevant, glucose readings, and GI symptoms.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=metformin', 'https://medlineplus.gov/druginfo/meds/a696005.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=metformin+diabetes+prevention+program', 'https://clinicaltrials.gov/search?term=metformin', 'RxNorm / MedlinePlus / PubMed'], + ['lisinopril', 'ACE inhibitor', 'Often used in blood pressure and cardiovascular care.', 'Track blood pressure, pulse, cough, dizziness, and lab follow-up if ordered.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=lisinopril', 'https://medlineplus.gov/druginfo/meds/a692051.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=lisinopril+hypertension+trial', 'https://clinicaltrials.gov/search?term=lisinopril', 'RxNorm / MedlinePlus / PubMed'], + ['atorvastatin', 'HMG-CoA reductase inhibitor statin', 'Often used for cholesterol management and cardiovascular risk reduction.', 'Track lipid labs, muscle symptoms, dose changes, and care-team notes.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=atorvastatin', 'https://medlineplus.gov/druginfo/meds/a600045.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=atorvastatin+cardiovascular+trial', 'https://clinicaltrials.gov/search?term=atorvastatin', 'RxNorm / MedlinePlus / PubMed'], + ['albuterol', 'Short-acting beta agonist bronchodilator', 'Often used as a rescue medicine for asthma or bronchospasm.', 'Track inhaler use, symptoms, triggers, pulse, and breathing status.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=albuterol', 'https://medlineplus.gov/druginfo/meds/a682145.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=albuterol+asthma+clinical+trial', 'https://clinicaltrials.gov/search?term=albuterol', 'RxNorm / MedlinePlus / PubMed'], + ['sertraline', 'Selective serotonin reuptake inhibitor', 'Often used in depression, anxiety, and related mental health care.', 'Track mood, sleep, side effects, dose changes, and follow-up notes.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=sertraline', 'https://medlineplus.gov/druginfo/meds/a697048.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=sertraline+depression+trial', 'https://clinicaltrials.gov/search?term=sertraline', 'RxNorm / MedlinePlus / PubMed'], + ['ibuprofen', 'Nonsteroidal anti-inflammatory drug', 'Often used for pain, fever, or inflammation.', 'Track dose, pain score, stomach symptoms, and frequency of use.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=ibuprofen', 'https://medlineplus.gov/druginfo/meds/a682159.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=ibuprofen+pain+clinical+trial', 'https://clinicaltrials.gov/search?term=ibuprofen', 'RxNorm / MedlinePlus / PubMed'], + ['acetaminophen', 'Analgesic and antipyretic', 'Often used for pain or fever.', 'Track total daily dose, pain score, fever, and other combination products.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=acetaminophen', 'https://medlineplus.gov/druginfo/meds/a681004.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=acetaminophen+pain+clinical+trial', 'https://clinicaltrials.gov/search?term=acetaminophen', 'RxNorm / MedlinePlus / PubMed'], + ['amoxicillin', 'Penicillin antibiotic', 'Often used for susceptible bacterial infections.', 'Track start/stop dates, dose schedule, allergy symptoms, and care-team instructions.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=amoxicillin', 'https://medlineplus.gov/druginfo/meds/a685001.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=amoxicillin+clinical+trial', 'https://clinicaltrials.gov/search?term=amoxicillin', 'RxNorm / MedlinePlus / PubMed'], + ['omeprazole', 'Proton pump inhibitor', 'Often used for acid-related gastrointestinal conditions.', 'Track symptom response, dose timing, duration, and clinician instructions.', 'https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=omeprazole', 'https://medlineplus.gov/druginfo/meds/a693050.html', 'https://pubmed.ncbi.nlm.nih.gov/?term=omeprazole+clinical+trial', 'https://clinicaltrials.gov/search?term=omeprazole', 'RxNorm / MedlinePlus / PubMed'], + ]; + $stmt = $pdo->prepare( + "INSERT INTO medication_catalog + (generic_name, class_name, common_use, tracking_note, rxnorm_url, medlineplus_url, pubmed_url, + clinicaltrials_url, source_name, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + foreach ($medicines as $medicine) { + $stmt->execute([...$medicine, $created]); + } + } + seed_expanded_medication_catalog($pdo); + + $studyCount = (int) $pdo->query('SELECT COUNT(*) FROM research_studies')->fetchColumn(); + if ($studyCount === 0) { + $studies = [ + ['Diabetes', 'metformin', 'Type 2 Diabetes', 'Diabetes Prevention Program and metformin research', 'NIH clinical research program', 'NIH diabetes prevention research is a major category for metformin-related prevention and metabolic-risk evidence.', 'NIDDK / PubMed / ClinicalTrials.gov', 'https://www.niddk.nih.gov/about-niddk/research-areas/diabetes/diabetes-prevention-program-dpp', 'https://pubmed.ncbi.nlm.nih.gov/?term=Diabetes+Prevention+Program+metformin', 'https://clinicaltrials.gov/search?term=metformin%20diabetes%20prevention'], + ['Cardiovascular', 'lisinopril', 'Hypertension', 'Blood pressure intervention and antihypertensive treatment studies', 'NIH clinical trial category', 'NIH cardiovascular studies include blood-pressure targets, antihypertensive treatment, and outcomes research relevant to hypertension medicines.', 'NHLBI / PubMed / ClinicalTrials.gov', 'https://www.nhlbi.nih.gov/science/systolic-blood-pressure-intervention-trial-sprint-study', 'https://pubmed.ncbi.nlm.nih.gov/?term=lisinopril+hypertension+clinical+trial', 'https://clinicaltrials.gov/search?term=lisinopril%20hypertension'], + ['Cardiovascular', 'atorvastatin', 'High Cholesterol', 'Statin and lipid-management outcomes research', 'Medication outcomes research', 'Statin studies evaluate lipid changes and cardiovascular outcomes; this app links the medication catalog to PubMed and ClinicalTrials.gov searches.', 'PubMed / ClinicalTrials.gov', 'https://pubmed.ncbi.nlm.nih.gov/?term=atorvastatin+cardiovascular+outcomes+trial', 'https://pubmed.ncbi.nlm.nih.gov/?term=atorvastatin+cardiovascular+outcomes+trial', 'https://clinicaltrials.gov/search?term=atorvastatin'], + ['Respiratory', 'albuterol', 'Asthma', 'Asthma medication and rescue inhaler studies', 'Clinical research category', 'Asthma studies often evaluate symptom control, rescue medication use, and exacerbation outcomes.', 'NHLBI / PubMed / ClinicalTrials.gov', 'https://www.nhlbi.nih.gov/health/asthma', 'https://pubmed.ncbi.nlm.nih.gov/?term=albuterol+asthma+clinical+trial', 'https://clinicaltrials.gov/search?term=albuterol%20asthma'], + ['Mental Health', 'sertraline', 'Depression', 'Depression treatment studies and medication-response research', 'NIH mental health research category', 'Depression studies evaluate symptom scores, remission, side effects, and care pathways for medicines including SSRIs.', 'NIMH / PubMed / ClinicalTrials.gov', 'https://www.nimh.nih.gov/health/topics/depression', 'https://pubmed.ncbi.nlm.nih.gov/?term=sertraline+depression+randomized+trial', 'https://clinicaltrials.gov/search?term=sertraline%20depression'], + ['Pain', 'ibuprofen', 'Pain and Inflammation', 'NSAID pain and inflammation studies', 'Medication safety and outcomes category', 'Pain studies can compare pain scores, function, adverse effects, and dose schedules for NSAIDs.', 'PubMed / ClinicalTrials.gov', 'https://pubmed.ncbi.nlm.nih.gov/?term=ibuprofen+pain+randomized+trial', 'https://pubmed.ncbi.nlm.nih.gov/?term=ibuprofen+pain+randomized+trial', 'https://clinicaltrials.gov/search?term=ibuprofen%20pain'], + ['Pain', 'acetaminophen', 'Pain and Fever', 'Acetaminophen pain and fever studies', 'Medication safety and outcomes category', 'Acetaminophen studies often evaluate pain relief, fever reduction, dosing, and safety monitoring.', 'PubMed / ClinicalTrials.gov', 'https://pubmed.ncbi.nlm.nih.gov/?term=acetaminophen+pain+randomized+trial', 'https://pubmed.ncbi.nlm.nih.gov/?term=acetaminophen+pain+randomized+trial', 'https://clinicaltrials.gov/search?term=acetaminophen'], + ['Infectious Disease', 'amoxicillin', 'Bacterial Infection', 'Antibiotic effectiveness and safety studies', 'Medication outcomes category', 'Antibiotic studies evaluate infection outcomes, adverse reactions, resistance patterns, and dosing strategies.', 'PubMed / ClinicalTrials.gov', 'https://pubmed.ncbi.nlm.nih.gov/?term=amoxicillin+clinical+trial', 'https://pubmed.ncbi.nlm.nih.gov/?term=amoxicillin+clinical+trial', 'https://clinicaltrials.gov/search?term=amoxicillin'], + ['Gastroenterology', 'omeprazole', 'Acid-related GI Conditions', 'Proton pump inhibitor studies', 'Medication outcomes category', 'PPI studies evaluate symptom control, healing outcomes, duration, and safety topics.', 'PubMed / ClinicalTrials.gov', 'https://pubmed.ncbi.nlm.nih.gov/?term=omeprazole+clinical+trial', 'https://pubmed.ncbi.nlm.nih.gov/?term=omeprazole+clinical+trial', 'https://clinicaltrials.gov/search?term=omeprazole'], + ]; + $stmt = $pdo->prepare( + "INSERT INTO research_studies + (category, related_medicine, related_condition, title, study_type, summary, nih_source, + source_url, pubmed_url, clinicaltrials_url, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + foreach ($studies as $study) { + $stmt->execute([...$study, $created]); + } + } +} + +function medication_source_url(string $base, string $query): string +{ + return $base . rawurlencode($query); +} + +function seed_expanded_medication_catalog(PDO $pdo): void +{ + $created = app_now(); + $rows = expanded_medication_catalog_rows(); + + $select = $pdo->prepare('SELECT id FROM medication_catalog WHERE lower(generic_name) = lower(?) LIMIT 1'); + $insert = $pdo->prepare( + "INSERT INTO medication_catalog + (generic_name, active_ingredient, chemical_name, brand_names, generic_brands, class_name, drug_family, + common_use, tracking_note, rxnorm_url, medlineplus_url, pubchem_url, dailymed_url, pubmed_url, + clinicaltrials_url, source_name, search_terms, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $update = $pdo->prepare( + "UPDATE medication_catalog + SET active_ingredient = ?, chemical_name = ?, brand_names = ?, generic_brands = ?, + class_name = ?, drug_family = ?, common_use = ?, tracking_note = ?, rxnorm_url = ?, + medlineplus_url = ?, pubchem_url = ?, dailymed_url = ?, pubmed_url = ?, + clinicaltrials_url = ?, source_name = ?, search_terms = ? + WHERE id = ?" + ); + + foreach ($rows as $row) { + [$genericName, $activeIngredient, $chemicalName, $brandNames, $genericBrands, $className, $drugFamily, $commonUse, $trackingNote, $medlinePlusUrl] = $row; + $rxnormUrl = medication_source_url('https://mor.nlm.nih.gov/RxNav/search?searchBy=String&searchTerm=', $genericName); + $pubchemUrl = medication_source_url('https://pubchem.ncbi.nlm.nih.gov/#query=', $activeIngredient ?: $genericName); + $dailymedUrl = medication_source_url('https://dailymed.nlm.nih.gov/dailymed/search.cfm?query=', $genericName); + $pubmedUrl = medication_source_url('https://pubmed.ncbi.nlm.nih.gov/?term=', $genericName . ' medication'); + $clinicalTrialsUrl = medication_source_url('https://clinicaltrials.gov/search?term=', $genericName); + $sourceName = 'RxNorm / DailyMed / PubChem / MedlinePlus'; + $searchTerms = implode(' ', [ + $genericName, + $activeIngredient, + $chemicalName, + $brandNames, + $genericBrands, + $className, + $drugFamily, + $commonUse, + ]); + + $select->execute([$genericName]); + $existingId = (int) $select->fetchColumn(); + if ($existingId > 0) { + $update->execute([ + $activeIngredient, + $chemicalName, + $brandNames, + $genericBrands, + $className, + $drugFamily, + $commonUse, + $trackingNote, + $rxnormUrl, + $medlinePlusUrl, + $pubchemUrl, + $dailymedUrl, + $pubmedUrl, + $clinicalTrialsUrl, + $sourceName, + $searchTerms, + $existingId, + ]); + continue; + } + + $insert->execute([ + $genericName, + $activeIngredient, + $chemicalName, + $brandNames, + $genericBrands, + $className, + $drugFamily, + $commonUse, + $trackingNote, + $rxnormUrl, + $medlinePlusUrl, + $pubchemUrl, + $dailymedUrl, + $pubmedUrl, + $clinicalTrialsUrl, + $sourceName, + $searchTerms, + $created, + ]); + } +} + +function expanded_medication_catalog_rows(): array +{ + $defaultMedline = 'https://medlineplus.gov/druginformation.html'; + return [ + ['acetaminophen', 'acetaminophen', 'N-(4-hydroxyphenyl)acetamide', 'Tylenol, Mapap, Panadol', 'paracetamol, APAP', 'Analgesic and antipyretic', 'Pain and fever', 'Often used for pain or fever.', 'Track total daily dose and other combination products that may also contain acetaminophen.', 'https://medlineplus.gov/druginfo/meds/a681004.html'], + ['ibuprofen', 'ibuprofen', '2-(4-isobutylphenyl)propanoic acid', 'Advil, Motrin, Midol', 'ibuprofen tablets, ibuprofen suspension', 'Nonsteroidal anti-inflammatory drug', 'Pain and inflammation', 'Often used for pain, fever, or inflammation.', 'Track dose, pain score, stomach symptoms, and frequency of use.', 'https://medlineplus.gov/druginfo/meds/a682159.html'], + ['naproxen', 'naproxen', '(S)-2-(6-methoxynaphthalen-2-yl)propanoic acid', 'Aleve, Naprosyn, Anaprox', 'naproxen sodium, naproxen tablets', 'Nonsteroidal anti-inflammatory drug', 'Pain and inflammation', 'Often used for pain, fever, or inflammation.', 'Track dose timing, stomach symptoms, kidney-risk context, and pain response.', $defaultMedline], + ['aspirin', 'acetylsalicylic acid', '2-acetyloxybenzoic acid', 'Bayer, Bufferin, Ecotrin', 'acetylsalicylic acid, ASA', 'Salicylate antiplatelet and analgesic', 'Pain, fever, antiplatelet therapy', 'Used for pain, fever, inflammation, or antiplatelet therapy when directed.', 'Track indication, dose, bleeding symptoms, and clinician instructions.', $defaultMedline], + ['diclofenac', 'diclofenac', '2-[2-(2,6-dichloroanilino)phenyl]acetic acid', 'Voltaren, Cataflam, Zipsor', 'diclofenac sodium, diclofenac potassium', 'Nonsteroidal anti-inflammatory drug', 'Pain and inflammation', 'Often used for arthritis or musculoskeletal pain.', 'Track pain score, application site for topical use, stomach symptoms, and dose schedule.', $defaultMedline], + ['celecoxib', 'celecoxib', '4-[5-(4-methylphenyl)-3-(trifluoromethyl)pyrazol-1-yl]benzenesulfonamide', 'Celebrex, Elyxyb', 'celecoxib capsules', 'COX-2 selective nonsteroidal anti-inflammatory drug', 'Pain and inflammation', 'Often used for arthritis pain or inflammatory conditions.', 'Track pain relief, stomach symptoms, swelling, blood pressure, and clinician instructions.', $defaultMedline], + ['meloxicam', 'meloxicam', 'meloxicam', 'Mobic, Vivlodex, Anjeso', 'meloxicam tablets, meloxicam capsules', 'Nonsteroidal anti-inflammatory drug', 'Pain and inflammation', 'Often used for arthritis and inflammatory pain.', 'Track pain response, stomach symptoms, and blood pressure or kidney follow-up if ordered.', $defaultMedline], + ['tramadol', 'tramadol', 'tramadol hydrochloride', 'Ultram, ConZip, Qdolo', 'tramadol tablets, tramadol ER', 'Opioid analgesic', 'Pain', 'Used for selected pain conditions when prescribed.', 'Track dose, sedation, constipation, dizziness, pain score, and stop/start dates.', $defaultMedline], + ['hydrocodone acetaminophen', 'hydrocodone bitartrate and acetaminophen', 'hydrocodone plus acetaminophen', 'Norco, Vicodin, Lortab', 'hydrocodone/APAP', 'Opioid analgesic combination', 'Pain', 'Combination pain medicine containing an opioid and acetaminophen.', 'Track total acetaminophen exposure, sedation, constipation, and prescriber instructions.', $defaultMedline], + ['oxycodone', 'oxycodone', 'oxycodone hydrochloride', 'OxyContin, Roxicodone, Oxaydo', 'oxycodone IR, oxycodone ER', 'Opioid analgesic', 'Pain', 'Used for selected pain conditions when prescribed.', 'Track dose, sedation, constipation, pain score, and safety instructions.', $defaultMedline], + ['morphine', 'morphine', 'morphine sulfate', 'MS Contin, Kadian, Roxanol', 'morphine IR, morphine ER', 'Opioid analgesic', 'Pain', 'Used for selected pain conditions when prescribed.', 'Track dose, sedation, constipation, respiratory symptoms, and pain score.', $defaultMedline], + ['gabapentin', 'gabapentin', '1-(aminomethyl)cyclohexaneacetic acid', 'Neurontin, Gralise, Horizant', 'gabapentin capsules, gabapentin tablets', 'Anticonvulsant nerve-pain medicine', 'Neurology and pain', 'Often used for seizures or nerve-related pain.', 'Track sleepiness, dizziness, dose changes, and symptom response.', $defaultMedline], + ['pregabalin', 'pregabalin', '(S)-3-(aminomethyl)-5-methylhexanoic acid', 'Lyrica', 'pregabalin capsules', 'Anticonvulsant nerve-pain medicine', 'Neurology and pain', 'Often used for nerve pain, fibromyalgia, or seizures.', 'Track dizziness, swelling, sleepiness, and symptom response.', $defaultMedline], + ['cyclobenzaprine', 'cyclobenzaprine', 'cyclobenzaprine hydrochloride', 'Flexeril, Amrix, Fexmid', 'cyclobenzaprine tablets', 'Skeletal muscle relaxant', 'Musculoskeletal', 'Often used short term for muscle spasm.', 'Track sedation, dry mouth, dose timing, and symptom response.', $defaultMedline], + ['amoxicillin', 'amoxicillin', '(2S,5R,6R)-6-[[(2R)-2-amino-2-(4-hydroxyphenyl)acetyl]amino]-3,3-dimethyl-7-oxo-4-thia-1-azabicyclo[3.2.0]heptane-2-carboxylic acid', 'Amoxil, Moxatag, Trimox', 'amoxicillin capsules, amoxicillin suspension', 'Penicillin antibiotic', 'Infectious disease', 'Often used for susceptible bacterial infections.', 'Track start/stop dates, dose schedule, allergy symptoms, and care-team instructions.', 'https://medlineplus.gov/druginfo/meds/a685001.html'], + ['amoxicillin clavulanate', 'amoxicillin and clavulanate potassium', 'amoxicillin plus clavulanic acid', 'Augmentin', 'amoxicillin/clavulanate, co-amoxiclav', 'Penicillin antibiotic with beta-lactamase inhibitor', 'Infectious disease', 'Used for selected bacterial infections when prescribed.', 'Track dose schedule, GI symptoms, allergy symptoms, and completion date.', $defaultMedline], + ['azithromycin', 'azithromycin', 'azithromycin', 'Zithromax, Z-Pak, Zmax', 'azithromycin tablets, azithromycin suspension', 'Macrolide antibiotic', 'Infectious disease', 'Used for selected bacterial infections when prescribed.', 'Track start/stop dates, dose schedule, diarrhea, rash, and symptom response.', $defaultMedline], + ['doxycycline', 'doxycycline', 'doxycycline hyclate or monohydrate', 'Vibramycin, Doryx, Oracea', 'doxycycline tablets, doxycycline capsules', 'Tetracycline antibiotic', 'Infectious disease', 'Used for selected bacterial infections and some inflammatory skin conditions.', 'Track sun sensitivity, stomach symptoms, dose timing, and completion date.', $defaultMedline], + ['cephalexin', 'cephalexin', 'cefalexin', 'Keflex', 'cephalexin capsules, cephalexin suspension', 'Cephalosporin antibiotic', 'Infectious disease', 'Used for selected bacterial infections when prescribed.', 'Track start/stop dates, allergy symptoms, GI symptoms, and symptom response.', $defaultMedline], + ['ciprofloxacin', 'ciprofloxacin', 'ciprofloxacin hydrochloride', 'Cipro, Cipro XR', 'ciprofloxacin tablets, ciprofloxacin drops', 'Fluoroquinolone antibiotic', 'Infectious disease', 'Used for selected bacterial infections when prescribed.', 'Track tendon pain, nerve symptoms, GI symptoms, and clinician instructions.', $defaultMedline], + ['levofloxacin', 'levofloxacin', 'levofloxacin', 'Levaquin', 'levofloxacin tablets', 'Fluoroquinolone antibiotic', 'Infectious disease', 'Used for selected bacterial infections when prescribed.', 'Track tendon pain, nerve symptoms, mood changes, and completion date.', $defaultMedline], + ['clindamycin', 'clindamycin', 'clindamycin hydrochloride', 'Cleocin, Clindesse', 'clindamycin capsules, clindamycin topical', 'Lincosamide antibiotic', 'Infectious disease', 'Used for selected bacterial infections or topical acne treatment.', 'Track diarrhea, rash, dose timing, and symptom response.', $defaultMedline], + ['metronidazole', 'metronidazole', '2-(2-methyl-5-nitroimidazol-1-yl)ethanol', 'Flagyl, Metrogel, Vandazole', 'metronidazole tablets, metronidazole gel', 'Nitroimidazole antimicrobial', 'Infectious disease', 'Used for selected bacterial or protozoal infections when prescribed.', 'Track dose schedule, GI symptoms, metallic taste, and alcohol-related instructions.', $defaultMedline], + ['trimethoprim sulfamethoxazole', 'sulfamethoxazole and trimethoprim', 'trimethoprim plus sulfamethoxazole', 'Bactrim, Septra', 'TMP-SMX, co-trimoxazole', 'Sulfonamide antibiotic combination', 'Infectious disease', 'Used for selected bacterial infections when prescribed.', 'Track rash, sun sensitivity, GI symptoms, dose schedule, and completion date.', $defaultMedline], + ['nitrofurantoin', 'nitrofurantoin', 'nitrofurantoin', 'Macrobid, Macrodantin, Furadantin', 'nitrofurantoin capsules, nitrofurantoin suspension', 'Nitrofuran antibiotic', 'Infectious disease', 'Often used for selected urinary tract infections.', 'Track urinary symptoms, dose schedule, GI symptoms, and completion date.', $defaultMedline], + ['fluconazole', 'fluconazole', 'fluconazole', 'Diflucan', 'fluconazole tablets', 'Azole antifungal', 'Infectious disease', 'Used for selected fungal infections when prescribed.', 'Track symptom response, rash, stomach symptoms, and liver-lab follow-up if ordered.', $defaultMedline], + ['acyclovir', 'acyclovir', 'acyclovir', 'Zovirax', 'acyclovir tablets, acyclovir cream', 'Antiviral nucleoside analog', 'Infectious disease', 'Used for herpes-virus infections when prescribed.', 'Track outbreak timing, dose schedule, kidney-risk context, and symptom response.', $defaultMedline], + ['valacyclovir', 'valacyclovir', 'valacyclovir hydrochloride', 'Valtrex', 'valacyclovir tablets', 'Antiviral prodrug', 'Infectious disease', 'Used for herpes-virus infections when prescribed.', 'Track outbreak timing, dose schedule, symptom response, and kidney-risk context.', $defaultMedline], + ['lisinopril', 'lisinopril', '(2S)-1-[(2S)-6-amino-2-[[(1S)-1-carboxy-3-phenylpropyl]amino]hexanoyl]pyrrolidine-2-carboxylic acid', 'Prinivil, Zestril, Qbrelis', 'lisinopril tablets, lisinopril solution', 'ACE inhibitor', 'Cardiovascular', 'Often used in blood pressure and cardiovascular care.', 'Track blood pressure, pulse, cough, dizziness, and lab follow-up if ordered.', 'https://medlineplus.gov/druginfo/meds/a692051.html'], + ['losartan', 'losartan', 'losartan potassium', 'Cozaar', 'losartan tablets', 'Angiotensin II receptor blocker', 'Cardiovascular', 'Often used for blood pressure, kidney protection, or cardiovascular care.', 'Track blood pressure, dizziness, potassium/kidney labs if ordered, and dose changes.', $defaultMedline], + ['valsartan', 'valsartan', 'valsartan', 'Diovan', 'valsartan tablets', 'Angiotensin II receptor blocker', 'Cardiovascular', 'Often used for blood pressure or heart failure care.', 'Track blood pressure, dizziness, kidney/potassium labs if ordered, and dose changes.', $defaultMedline], + ['amlodipine', 'amlodipine', 'amlodipine besylate', 'Norvasc, Katerzia', 'amlodipine tablets, amlodipine solution', 'Calcium channel blocker', 'Cardiovascular', 'Often used for blood pressure or angina care.', 'Track blood pressure, swelling, dizziness, and dose changes.', $defaultMedline], + ['metoprolol', 'metoprolol', 'metoprolol tartrate or succinate', 'Lopressor, Toprol XL, Kapspargo Sprinkle', 'metoprolol tartrate, metoprolol succinate ER', 'Beta blocker', 'Cardiovascular', 'Often used for blood pressure, heart rate, angina, or heart failure care.', 'Track pulse, blood pressure, dizziness, fatigue, and formulation.', $defaultMedline], + ['carvedilol', 'carvedilol', 'carvedilol', 'Coreg, Coreg CR', 'carvedilol tablets, carvedilol ER', 'Alpha/beta blocker', 'Cardiovascular', 'Often used for heart failure or blood pressure care.', 'Track pulse, blood pressure, dizziness, weight changes, and dose titration.', $defaultMedline], + ['atenolol', 'atenolol', 'atenolol', 'Tenormin', 'atenolol tablets', 'Beta blocker', 'Cardiovascular', 'Often used for blood pressure, heart rate, or angina care.', 'Track pulse, blood pressure, dizziness, fatigue, and dose changes.', $defaultMedline], + ['hydrochlorothiazide', 'hydrochlorothiazide', '6-chloro-3,4-dihydro-2H-1,2,4-benzothiadiazine-7-sulfonamide 1,1-dioxide', 'Microzide, HydroDIURIL', 'HCTZ, hydrochlorothiazide tablets', 'Thiazide diuretic', 'Cardiovascular and renal', 'Often used for blood pressure or fluid management.', 'Track blood pressure, urination, dizziness, electrolytes if ordered, and weight trends.', $defaultMedline], + ['chlorthalidone', 'chlorthalidone', 'chlorthalidone', 'Thalitone, Hygroton', 'chlorthalidone tablets', 'Thiazide-like diuretic', 'Cardiovascular and renal', 'Often used for blood pressure or fluid management.', 'Track blood pressure, dizziness, electrolytes if ordered, and urination changes.', $defaultMedline], + ['furosemide', 'furosemide', '4-chloro-N-furfuryl-5-sulfamoylanthranilic acid', 'Lasix', 'furosemide tablets, furosemide solution', 'Loop diuretic', 'Cardiovascular and renal', 'Often used for fluid management when prescribed.', 'Track weight, swelling, urine output, dizziness, and electrolytes if ordered.', $defaultMedline], + ['spironolactone', 'spironolactone', 'spironolactone', 'Aldactone, CaroSpir', 'spironolactone tablets, spironolactone suspension', 'Potassium-sparing diuretic and aldosterone antagonist', 'Cardiovascular and endocrine', 'Often used for heart failure, blood pressure, fluid, or hormonal indications.', 'Track blood pressure, potassium labs if ordered, dizziness, and dose changes.', $defaultMedline], + ['clopidogrel', 'clopidogrel', 'clopidogrel bisulfate', 'Plavix', 'clopidogrel tablets', 'P2Y12 antiplatelet', 'Cardiovascular', 'Used to reduce clotting risk when prescribed.', 'Track bruising, bleeding symptoms, procedures, and prescriber instructions.', $defaultMedline], + ['warfarin', 'warfarin', 'warfarin sodium', 'Coumadin, Jantoven', 'warfarin tablets', 'Vitamin K antagonist anticoagulant', 'Cardiovascular and hematology', 'Used for anticoagulation when prescribed.', 'Track INR, dose schedule, bleeding symptoms, diet changes, and interactions.', $defaultMedline], + ['apixaban', 'apixaban', 'apixaban', 'Eliquis', 'apixaban tablets', 'Direct factor Xa inhibitor anticoagulant', 'Cardiovascular and hematology', 'Used for anticoagulation when prescribed.', 'Track dose adherence, bleeding symptoms, procedures, kidney follow-up, and refills.', $defaultMedline], + ['rivaroxaban', 'rivaroxaban', 'rivaroxaban', 'Xarelto', 'rivaroxaban tablets', 'Direct factor Xa inhibitor anticoagulant', 'Cardiovascular and hematology', 'Used for anticoagulation when prescribed.', 'Track dose timing with food if directed, bleeding symptoms, procedures, and refills.', $defaultMedline], + ['nitroglycerin', 'nitroglycerin', 'glyceryl trinitrate', 'Nitrostat, Nitro-Dur, NitroMist', 'nitroglycerin sublingual, nitroglycerin patch', 'Nitrate vasodilator', 'Cardiovascular', 'Used for angina or cardiovascular indications when prescribed.', 'Track symptom timing, dose use, blood pressure symptoms, and emergency instructions.', $defaultMedline], + ['atorvastatin', 'atorvastatin', 'atorvastatin calcium', 'Lipitor', 'atorvastatin tablets', 'HMG-CoA reductase inhibitor statin', 'Cardiovascular and metabolic', 'Often used for cholesterol management and cardiovascular risk reduction.', 'Track lipid labs, muscle symptoms, dose changes, and care-team notes.', 'https://medlineplus.gov/druginfo/meds/a600045.html'], + ['rosuvastatin', 'rosuvastatin', 'rosuvastatin calcium', 'Crestor, Ezallor Sprinkle', 'rosuvastatin tablets', 'HMG-CoA reductase inhibitor statin', 'Cardiovascular and metabolic', 'Often used for cholesterol management and cardiovascular risk reduction.', 'Track lipid labs, muscle symptoms, dose changes, and care-team notes.', $defaultMedline], + ['simvastatin', 'simvastatin', 'simvastatin', 'Zocor, FloLipid', 'simvastatin tablets', 'HMG-CoA reductase inhibitor statin', 'Cardiovascular and metabolic', 'Often used for cholesterol management.', 'Track lipid labs, muscle symptoms, dose changes, and medication interactions.', $defaultMedline], + ['ezetimibe', 'ezetimibe', 'ezetimibe', 'Zetia', 'ezetimibe tablets', 'Cholesterol absorption inhibitor', 'Cardiovascular and metabolic', 'Often used for cholesterol management.', 'Track lipid labs, GI symptoms, muscle symptoms, and combination therapy.', $defaultMedline], + ['metformin', 'metformin', 'N,N-dimethylbiguanide', 'Glucophage, Glumetza, Fortamet, Riomet', 'metformin tablets, metformin ER', 'Biguanide antidiabetic', 'Endocrine and metabolic', 'Often used in type 2 diabetes care.', 'Track dose, meals if relevant, glucose readings, and GI symptoms.', 'https://medlineplus.gov/druginfo/meds/a696005.html'], + ['insulin glargine', 'insulin glargine', 'recombinant human insulin analog insulin glargine', 'Lantus, Basaglar, Toujeo, Semglee', 'insulin glargine-yfgn, insulin glargine pens', 'Long-acting insulin', 'Endocrine and metabolic', 'Used for diabetes care when prescribed.', 'Track dose, glucose readings, hypoglycemia symptoms, injection site, and timing.', $defaultMedline], + ['insulin lispro', 'insulin lispro', 'recombinant human insulin analog insulin lispro', 'Humalog, Admelog, Lyumjev', 'insulin lispro-aabc, insulin lispro pens', 'Rapid-acting insulin', 'Endocrine and metabolic', 'Used for diabetes meal or correction dosing when prescribed.', 'Track glucose readings, meals, dose timing, hypoglycemia symptoms, and injection site.', $defaultMedline], + ['semaglutide', 'semaglutide', 'glucagon-like peptide-1 receptor agonist peptide analog semaglutide', 'Ozempic, Wegovy, Rybelsus', 'semaglutide injection, semaglutide tablets', 'GLP-1 receptor agonist', 'Endocrine and metabolic', 'Used for diabetes or weight-management indications when prescribed.', 'Track dose titration, GI symptoms, weight, glucose, and prescriber instructions.', $defaultMedline], + ['dulaglutide', 'dulaglutide', 'glucagon-like peptide-1 receptor agonist dulaglutide', 'Trulicity', 'dulaglutide injection', 'GLP-1 receptor agonist', 'Endocrine and metabolic', 'Used for type 2 diabetes care when prescribed.', 'Track weekly dose, GI symptoms, glucose readings, and injection site.', $defaultMedline], + ['liraglutide', 'liraglutide', 'glucagon-like peptide-1 receptor agonist liraglutide', 'Victoza, Saxenda', 'liraglutide injection', 'GLP-1 receptor agonist', 'Endocrine and metabolic', 'Used for diabetes or weight-management indications when prescribed.', 'Track dose titration, GI symptoms, weight, glucose, and injection site.', $defaultMedline], + ['empagliflozin', 'empagliflozin', 'empagliflozin', 'Jardiance', 'empagliflozin tablets', 'SGLT2 inhibitor', 'Endocrine and metabolic', 'Used for diabetes and selected heart/kidney indications when prescribed.', 'Track glucose, urinary symptoms, hydration, weight, and kidney labs if ordered.', $defaultMedline], + ['dapagliflozin', 'dapagliflozin', 'dapagliflozin propanediol', 'Farxiga', 'dapagliflozin tablets', 'SGLT2 inhibitor', 'Endocrine and metabolic', 'Used for diabetes and selected heart/kidney indications when prescribed.', 'Track glucose, urinary symptoms, hydration, weight, and kidney labs if ordered.', $defaultMedline], + ['sitagliptin', 'sitagliptin', 'sitagliptin phosphate', 'Januvia', 'sitagliptin tablets', 'DPP-4 inhibitor', 'Endocrine and metabolic', 'Used for type 2 diabetes care when prescribed.', 'Track glucose readings, GI symptoms, dose changes, and kidney follow-up if ordered.', $defaultMedline], + ['glipizide', 'glipizide', 'glipizide', 'Glucotrol, Glucotrol XL', 'glipizide tablets, glipizide ER', 'Sulfonylurea antidiabetic', 'Endocrine and metabolic', 'Used for type 2 diabetes care when prescribed.', 'Track glucose readings, hypoglycemia symptoms, meals, and dose timing.', $defaultMedline], + ['glyburide', 'glyburide', 'glyburide', 'Diabeta, Glynase', 'glyburide tablets', 'Sulfonylurea antidiabetic', 'Endocrine and metabolic', 'Used for type 2 diabetes care when prescribed.', 'Track glucose readings, hypoglycemia symptoms, meals, and dose timing.', $defaultMedline], + ['pioglitazone', 'pioglitazone', 'pioglitazone hydrochloride', 'Actos', 'pioglitazone tablets', 'Thiazolidinedione antidiabetic', 'Endocrine and metabolic', 'Used for type 2 diabetes care when prescribed.', 'Track glucose, swelling, weight, shortness of breath, and liver follow-up if ordered.', $defaultMedline], + ['albuterol', 'albuterol', '4-[2-(tert-butylamino)-1-hydroxyethyl]-2-(hydroxymethyl)phenol', 'Ventolin, ProAir, Proventil', 'salbutamol, albuterol inhaler', 'Short-acting beta agonist bronchodilator', 'Respiratory', 'Often used as a rescue medicine for asthma or bronchospasm.', 'Track inhaler use, symptoms, triggers, pulse, and breathing status.', 'https://medlineplus.gov/druginfo/meds/a682145.html'], + ['fluticasone', 'fluticasone', 'fluticasone propionate or furoate', 'Flonase, Flovent, Arnuity, Flonase Sensimist', 'fluticasone nasal spray, fluticasone inhaler', 'Corticosteroid', 'Respiratory and allergy', 'Used for allergic rhinitis, asthma, or inflammation depending on formulation.', 'Track formulation, symptoms, throat irritation, nosebleeds, and controller adherence.', $defaultMedline], + ['budesonide formoterol', 'budesonide and formoterol fumarate', 'budesonide plus formoterol', 'Symbicort, Breyna', 'budesonide/formoterol inhaler', 'Inhaled corticosteroid and long-acting beta agonist', 'Respiratory', 'Used for asthma or COPD controller therapy when prescribed.', 'Track doses, rescue inhaler use, symptoms, oral rinsing, and exacerbations.', $defaultMedline], + ['fluticasone salmeterol', 'fluticasone propionate and salmeterol', 'fluticasone plus salmeterol', 'Advair, Wixela Inhub, AirDuo', 'fluticasone/salmeterol inhaler', 'Inhaled corticosteroid and long-acting beta agonist', 'Respiratory', 'Used for asthma or COPD controller therapy when prescribed.', 'Track doses, rescue inhaler use, symptoms, oral rinsing, and exacerbations.', $defaultMedline], + ['montelukast', 'montelukast', 'montelukast sodium', 'Singulair', 'montelukast tablets, montelukast chewables', 'Leukotriene receptor antagonist', 'Respiratory and allergy', 'Used for asthma or allergy indications when prescribed.', 'Track symptoms, sleep/mood changes, rescue inhaler use, and triggers.', $defaultMedline], + ['cetirizine', 'cetirizine', 'cetirizine hydrochloride', 'Zyrtec, Aller-Tec', 'cetirizine tablets, cetirizine solution', 'Second-generation antihistamine', 'Allergy', 'Used for allergy symptoms or hives.', 'Track symptom response, drowsiness, and dose timing.', $defaultMedline], + ['loratadine', 'loratadine', 'loratadine', 'Claritin, Alavert', 'loratadine tablets, loratadine syrup', 'Second-generation antihistamine', 'Allergy', 'Used for allergy symptoms.', 'Track symptom response and dose timing.', $defaultMedline], + ['fexofenadine', 'fexofenadine', 'fexofenadine hydrochloride', 'Allegra', 'fexofenadine tablets, fexofenadine suspension', 'Second-generation antihistamine', 'Allergy', 'Used for allergy symptoms or hives.', 'Track symptom response and dose timing.', $defaultMedline], + ['diphenhydramine', 'diphenhydramine', 'diphenhydramine hydrochloride', 'Benadryl, ZzzQuil', 'diphenhydramine tablets, diphenhydramine liquid', 'First-generation antihistamine', 'Allergy and sleep', 'Used for allergy symptoms, itching, or sleep aid products.', 'Track drowsiness, confusion, dry mouth, dose timing, and reason for use.', $defaultMedline], + ['pseudoephedrine', 'pseudoephedrine', 'pseudoephedrine hydrochloride', 'Sudafed', 'pseudoephedrine tablets', 'Nasal decongestant', 'Respiratory and allergy', 'Used for nasal congestion.', 'Track blood pressure, heart rate symptoms, sleep effects, and dose timing.', $defaultMedline], + ['epinephrine', 'epinephrine', 'adrenaline', 'EpiPen, Auvi-Q, Adrenaclick', 'epinephrine auto-injector', 'Adrenergic agonist', 'Emergency allergy and cardiovascular', 'Used for severe allergic reactions or emergency indications when prescribed.', 'Track expiration dates, use events, emergency follow-up, and refill status.', $defaultMedline], + ['omeprazole', 'omeprazole', '5-methoxy-2-[(4-methoxy-3,5-dimethylpyridin-2-yl)methylsulfinyl]-1H-benzimidazole', 'Prilosec, Zegerid', 'omeprazole capsules, omeprazole tablets', 'Proton pump inhibitor', 'Gastroenterology', 'Often used for acid-related gastrointestinal conditions.', 'Track symptom response, dose timing, duration, and clinician instructions.', 'https://medlineplus.gov/druginfo/meds/a693050.html'], + ['pantoprazole', 'pantoprazole', 'pantoprazole sodium', 'Protonix', 'pantoprazole tablets', 'Proton pump inhibitor', 'Gastroenterology', 'Often used for acid-related gastrointestinal conditions.', 'Track symptom response, dose timing, duration, and clinician instructions.', $defaultMedline], + ['famotidine', 'famotidine', 'famotidine', 'Pepcid', 'famotidine tablets, famotidine suspension', 'Histamine H2 receptor antagonist', 'Gastroenterology', 'Often used for acid-related symptoms.', 'Track symptom response, dose timing, kidney-dose context if relevant, and duration.', $defaultMedline], + ['ondansetron', 'ondansetron', 'ondansetron hydrochloride', 'Zofran, Zuplenz', 'ondansetron tablets, ondansetron ODT', '5-HT3 receptor antagonist antiemetic', 'Gastroenterology', 'Used for nausea or vomiting when prescribed.', 'Track nausea score, constipation, headache, dose timing, and hydration.', $defaultMedline], + ['metoclopramide', 'metoclopramide', 'metoclopramide hydrochloride', 'Reglan, Gimoti', 'metoclopramide tablets, metoclopramide nasal spray', 'Dopamine antagonist prokinetic antiemetic', 'Gastroenterology', 'Used for selected nausea or motility conditions when prescribed.', 'Track movement symptoms, drowsiness, mood changes, and duration.', $defaultMedline], + ['polyethylene glycol 3350', 'polyethylene glycol 3350', 'polyethylene glycol 3350', 'MiraLAX, GlycoLax', 'PEG 3350 powder', 'Osmotic laxative', 'Gastroenterology', 'Used for constipation.', 'Track bowel movements, hydration, bloating, and dose frequency.', $defaultMedline], + ['loperamide', 'loperamide', 'loperamide hydrochloride', 'Imodium, Diamode', 'loperamide capsules, loperamide liquid', 'Antidiarrheal opioid receptor agonist', 'Gastroenterology', 'Used for diarrhea symptoms when appropriate.', 'Track stool frequency, fever/blood symptoms, dose count, and hydration.', $defaultMedline], + ['dicyclomine', 'dicyclomine', 'dicyclomine hydrochloride', 'Bentyl', 'dicyclomine tablets, dicyclomine capsules', 'Anticholinergic antispasmodic', 'Gastroenterology', 'Used for intestinal spasm symptoms when prescribed.', 'Track abdominal pain, dry mouth, dizziness, constipation, and dose timing.', $defaultMedline], + ['sertraline', 'sertraline', '(1S,4S)-4-(3,4-dichlorophenyl)-N-methyl-1,2,3,4-tetrahydronaphthalen-1-amine', 'Zoloft', 'sertraline tablets, sertraline solution', 'Selective serotonin reuptake inhibitor', 'Mental health', 'Often used in depression, anxiety, and related mental health care.', 'Track mood, sleep, side effects, dose changes, and follow-up notes.', 'https://medlineplus.gov/druginfo/meds/a697048.html'], + ['fluoxetine', 'fluoxetine', 'fluoxetine hydrochloride', 'Prozac, Sarafem, Rapiflux', 'fluoxetine capsules, fluoxetine solution', 'Selective serotonin reuptake inhibitor', 'Mental health', 'Often used in depression, anxiety, or related mental health care.', 'Track mood, sleep, GI symptoms, activation, and dose changes.', $defaultMedline], + ['escitalopram', 'escitalopram', 'escitalopram oxalate', 'Lexapro', 'escitalopram tablets, escitalopram solution', 'Selective serotonin reuptake inhibitor', 'Mental health', 'Often used in depression or anxiety care.', 'Track mood, sleep, side effects, dose changes, and follow-up notes.', $defaultMedline], + ['citalopram', 'citalopram', 'citalopram hydrobromide', 'Celexa', 'citalopram tablets, citalopram solution', 'Selective serotonin reuptake inhibitor', 'Mental health', 'Often used in depression care.', 'Track mood, sleep, side effects, dose changes, and follow-up notes.', $defaultMedline], + ['paroxetine', 'paroxetine', 'paroxetine hydrochloride', 'Paxil, Pexeva, Brisdelle', 'paroxetine tablets, paroxetine suspension', 'Selective serotonin reuptake inhibitor', 'Mental health', 'Used for depression, anxiety, or related indications when prescribed.', 'Track mood, sleep, side effects, dose changes, and discontinuation instructions.', $defaultMedline], + ['venlafaxine', 'venlafaxine', 'venlafaxine hydrochloride', 'Effexor XR', 'venlafaxine tablets, venlafaxine ER', 'Serotonin-norepinephrine reuptake inhibitor', 'Mental health', 'Used for depression, anxiety, or related indications when prescribed.', 'Track mood, blood pressure, sleep, side effects, and dose changes.', $defaultMedline], + ['duloxetine', 'duloxetine', 'duloxetine hydrochloride', 'Cymbalta, Drizalma Sprinkle', 'duloxetine capsules', 'Serotonin-norepinephrine reuptake inhibitor', 'Mental health and pain', 'Used for depression, anxiety, nerve pain, or related indications when prescribed.', 'Track mood, pain, sleep, blood pressure, and side effects.', $defaultMedline], + ['bupropion', 'bupropion', 'bupropion hydrochloride', 'Wellbutrin, Wellbutrin XL, Zyban, Aplenzin', 'bupropion SR, bupropion XL', 'Norepinephrine-dopamine reuptake inhibitor', 'Mental health and smoking cessation', 'Used for depression or smoking cessation indications when prescribed.', 'Track mood, sleep, appetite, anxiety, dose formulation, and seizure-risk context.', $defaultMedline], + ['mirtazapine', 'mirtazapine', 'mirtazapine', 'Remeron, Remeron SolTab', 'mirtazapine tablets, mirtazapine ODT', 'Noradrenergic and specific serotonergic antidepressant', 'Mental health', 'Used for depression care when prescribed.', 'Track mood, sleep, appetite, weight, sedation, and dose changes.', $defaultMedline], + ['trazodone', 'trazodone', 'trazodone hydrochloride', 'Desyrel, Oleptro', 'trazodone tablets', 'Serotonin antagonist and reuptake inhibitor', 'Mental health and sleep', 'Used for depression or sleep-related indications when prescribed.', 'Track sleep, dizziness, next-day sedation, mood, and dose timing.', $defaultMedline], + ['buspirone', 'buspirone', 'buspirone hydrochloride', 'Buspar', 'buspirone tablets', 'Anxiolytic', 'Mental health', 'Used for anxiety care when prescribed.', 'Track anxiety symptoms, dizziness, dose schedule, and time-to-effect.', $defaultMedline], + ['hydroxyzine', 'hydroxyzine', 'hydroxyzine hydrochloride or pamoate', 'Atarax, Vistaril', 'hydroxyzine tablets, hydroxyzine capsules', 'First-generation antihistamine anxiolytic', 'Mental health and allergy', 'Used for anxiety, itching, or allergy indications when prescribed.', 'Track drowsiness, dry mouth, anxiety symptoms, itching, and dose timing.', $defaultMedline], + ['alprazolam', 'alprazolam', 'alprazolam', 'Xanax, Xanax XR, Niravam', 'alprazolam tablets, alprazolam ER', 'Benzodiazepine', 'Mental health', 'Used for anxiety or panic indications when prescribed.', 'Track sedation, dose timing, driving cautions, refills, and taper instructions.', $defaultMedline], + ['lorazepam', 'lorazepam', 'lorazepam', 'Ativan', 'lorazepam tablets, lorazepam solution', 'Benzodiazepine', 'Mental health and neurology', 'Used for anxiety, sedation, or seizure-related indications when prescribed.', 'Track sedation, dose timing, falls risk, and taper instructions.', $defaultMedline], + ['clonazepam', 'clonazepam', 'clonazepam', 'Klonopin', 'clonazepam tablets, clonazepam ODT', 'Benzodiazepine', 'Mental health and neurology', 'Used for seizure, panic, or related indications when prescribed.', 'Track sedation, symptom response, dose timing, and taper instructions.', $defaultMedline], + ['zolpidem', 'zolpidem', 'zolpidem tartrate', 'Ambien, Ambien CR, Edluar, Intermezzo', 'zolpidem tablets, zolpidem ER', 'Sedative-hypnotic', 'Sleep', 'Used for insomnia when prescribed.', 'Track sleep duration, next-day sedation, unusual sleep behaviors, and dose timing.', $defaultMedline], + ['methylphenidate', 'methylphenidate', 'methylphenidate hydrochloride', 'Ritalin, Concerta, Metadate, Jornay PM, Quillivant XR', 'methylphenidate IR, methylphenidate ER', 'Central nervous system stimulant', 'Mental health and neurology', 'Used for ADHD or related indications when prescribed.', 'Track focus, appetite, sleep, pulse, blood pressure, and formulation.', $defaultMedline], + ['amphetamine dextroamphetamine', 'mixed amphetamine salts', 'amphetamine and dextroamphetamine salts', 'Adderall, Adderall XR, Mydayis', 'mixed amphetamine salts IR, mixed amphetamine salts ER', 'Central nervous system stimulant', 'Mental health and neurology', 'Used for ADHD or narcolepsy indications when prescribed.', 'Track focus, appetite, sleep, pulse, blood pressure, and formulation.', $defaultMedline], + ['atomoxetine', 'atomoxetine', 'atomoxetine hydrochloride', 'Strattera', 'atomoxetine capsules', 'Selective norepinephrine reuptake inhibitor', 'Mental health and neurology', 'Used for ADHD care when prescribed.', 'Track focus, appetite, sleep, mood, pulse, blood pressure, and dose changes.', $defaultMedline], + ['lamotrigine', 'lamotrigine', 'lamotrigine', 'Lamictal, Lamictal XR', 'lamotrigine tablets, lamotrigine ODT', 'Anticonvulsant mood stabilizer', 'Neurology and mental health', 'Used for seizures or bipolar disorder indications when prescribed.', 'Track rash, mood, seizure activity, dose titration, and missed doses.', $defaultMedline], + ['levetiracetam', 'levetiracetam', 'levetiracetam', 'Keppra, Keppra XR, Spritam', 'levetiracetam tablets, levetiracetam solution', 'Anticonvulsant', 'Neurology', 'Used for seizure care when prescribed.', 'Track seizure activity, mood changes, sleepiness, and dose schedule.', $defaultMedline], + ['topiramate', 'topiramate', 'topiramate', 'Topamax, Trokendi XR, Qudexy XR', 'topiramate tablets, topiramate ER', 'Anticonvulsant', 'Neurology', 'Used for seizures or migraine prevention indications when prescribed.', 'Track headache frequency, seizure activity, cognitive symptoms, tingling, and hydration.', $defaultMedline], + ['levothyroxine', 'levothyroxine', 'levothyroxine sodium', 'Synthroid, Levoxyl, Unithroid, Tirosint, Euthyrox', 'levothyroxine tablets, levothyroxine capsules', 'Synthetic thyroid hormone', 'Endocrine', 'Used for hypothyroidism or thyroid hormone replacement when prescribed.', 'Track dose timing, TSH/T4 labs if ordered, symptoms, and brand/formulation changes.', $defaultMedline], + ['methimazole', 'methimazole', 'methimazole', 'Tapazole', 'methimazole tablets', 'Antithyroid medicine', 'Endocrine', 'Used for hyperthyroidism care when prescribed.', 'Track thyroid labs if ordered, rash, fever/sore throat, and dose changes.', $defaultMedline], + ['prednisone', 'prednisone', '17,21-dihydroxypregna-1,4-diene-3,11,20-trione', 'Deltasone, Rayos', 'prednisone tablets, prednisone solution', 'Systemic corticosteroid', 'Inflammation and immune conditions', 'Used for inflammatory, allergic, or immune-related conditions when prescribed.', 'Track dose taper, mood, glucose, sleep, swelling, and infection symptoms.', $defaultMedline], + ['methylprednisolone', 'methylprednisolone', 'methylprednisolone', 'Medrol, Solu-Medrol, Depo-Medrol', 'methylprednisolone dose pack, methylprednisolone injection', 'Systemic corticosteroid', 'Inflammation and immune conditions', 'Used for inflammatory, allergic, or immune-related conditions when prescribed.', 'Track dose taper, mood, glucose, sleep, swelling, and infection symptoms.', $defaultMedline], + ['hydrocortisone', 'hydrocortisone', 'cortisol', 'Cortef, Solu-Cortef, Anusol-HC', 'hydrocortisone tablets, hydrocortisone cream', 'Corticosteroid', 'Endocrine, inflammation, and dermatology', 'Used for steroid replacement or inflammation depending on formulation.', 'Track formulation, dose timing, skin response for topical use, and sick-day instructions if applicable.', $defaultMedline], + ['ethinyl estradiol levonorgestrel', 'ethinyl estradiol and levonorgestrel', 'ethinyl estradiol plus levonorgestrel', 'Alesse, Aviane, Lessina, Seasonale', 'levonorgestrel/ethinyl estradiol tablets', 'Combined hormonal contraceptive', 'Reproductive health', 'Used for contraception or hormonal indications when prescribed.', 'Track cycle changes, missed doses, side effects, blood pressure, and clot-warning symptoms.', $defaultMedline], + ['norethindrone', 'norethindrone', 'norethisterone', 'Aygestin, Camila, Errin, Heather', 'norethindrone tablets', 'Progestin', 'Reproductive health', 'Used for contraception or hormonal indications when prescribed.', 'Track cycle changes, missed doses, headaches, mood, and bleeding pattern.', $defaultMedline], + ['medroxyprogesterone', 'medroxyprogesterone', 'medroxyprogesterone acetate', 'Provera, Depo-Provera', 'medroxyprogesterone tablets, medroxyprogesterone injection', 'Progestin', 'Reproductive health', 'Used for contraception or hormonal indications when prescribed.', 'Track injection dates, bleeding pattern, mood, weight, and follow-up schedule.', $defaultMedline], + ['estradiol', 'estradiol', '17 beta-estradiol', 'Estrace, Vivelle-Dot, Climara, Divigel', 'estradiol tablets, estradiol patch, estradiol cream', 'Estrogen hormone', 'Reproductive health and endocrine', 'Used for hormone therapy or related indications when prescribed.', 'Track formulation, dose changes, symptoms, bleeding, and clinician follow-up.', $defaultMedline], + ['clotrimazole', 'clotrimazole', 'clotrimazole', 'Lotrimin, Mycelex, Gyne-Lotrimin', 'clotrimazole cream, clotrimazole lozenges', 'Azole antifungal', 'Dermatology and infectious disease', 'Used for selected fungal infections.', 'Track symptom response, application site, irritation, and completion date.', $defaultMedline], + ['terbinafine', 'terbinafine', 'terbinafine hydrochloride', 'Lamisil', 'terbinafine tablets, terbinafine cream', 'Allylamine antifungal', 'Dermatology and infectious disease', 'Used for selected fungal infections.', 'Track skin/nail response, rash, GI symptoms, and liver-lab follow-up if ordered.', $defaultMedline], + ['mupirocin', 'mupirocin', 'mupirocin', 'Bactroban, Centany', 'mupirocin ointment, mupirocin cream', 'Topical antibiotic', 'Dermatology and infectious disease', 'Used for selected skin infections when prescribed.', 'Track application schedule, skin response, irritation, and completion date.', $defaultMedline], + ['triamcinolone', 'triamcinolone', 'triamcinolone acetonide', 'Kenalog, Nasacort, Triderm', 'triamcinolone cream, triamcinolone nasal spray', 'Corticosteroid', 'Dermatology, allergy, and inflammation', 'Used for inflammation depending on formulation.', 'Track formulation, application site, skin thinning/irritation, and symptom response.', $defaultMedline], + ['isotretinoin', 'isotretinoin', '13-cis-retinoic acid', 'Accutane, Absorica, Claravis, Myorisan, Zenatane', 'isotretinoin capsules', 'Retinoid', 'Dermatology', 'Used for severe acne when prescribed under strict monitoring.', 'Track pregnancy-prevention program requirements, mood, dryness, labs, and dose schedule.', $defaultMedline], + ['tamsulosin', 'tamsulosin', 'tamsulosin hydrochloride', 'Flomax', 'tamsulosin capsules', 'Alpha-1 blocker', 'Urology', 'Often used for urinary symptoms related to enlarged prostate.', 'Track urinary symptoms, dizziness, falls, and dose timing.', $defaultMedline], + ['finasteride', 'finasteride', 'finasteride', 'Proscar, Propecia', 'finasteride tablets', '5-alpha-reductase inhibitor', 'Urology and dermatology', 'Used for enlarged prostate or hair-loss indications when prescribed.', 'Track urinary symptoms or hair goals, sexual side effects, and dose indication.', $defaultMedline], + ['sildenafil', 'sildenafil', 'sildenafil citrate', 'Viagra, Revatio', 'sildenafil tablets', 'PDE-5 inhibitor', 'Urology and pulmonary vascular', 'Used for erectile dysfunction or pulmonary hypertension indications when prescribed.', 'Track dose timing, blood pressure symptoms, headache, vision symptoms, and nitrate warnings.', $defaultMedline], + ['tadalafil', 'tadalafil', 'tadalafil', 'Cialis, Adcirca', 'tadalafil tablets', 'PDE-5 inhibitor', 'Urology and pulmonary vascular', 'Used for erectile dysfunction, urinary symptoms, or pulmonary hypertension indications when prescribed.', 'Track dose timing, blood pressure symptoms, headache, back pain, and nitrate warnings.', $defaultMedline], + ['oxybutynin', 'oxybutynin', 'oxybutynin chloride', 'Ditropan XL, Gelnique, Oxytrol', 'oxybutynin tablets, oxybutynin patch', 'Anticholinergic bladder antispasmodic', 'Urology', 'Used for overactive bladder symptoms when prescribed.', 'Track dry mouth, constipation, confusion, urinary symptoms, and formulation.', $defaultMedline], + ['allopurinol', 'allopurinol', 'allopurinol', 'Zyloprim, Aloprim', 'allopurinol tablets', 'Xanthine oxidase inhibitor', 'Rheumatology and metabolic', 'Often used for gout prevention or uric-acid management.', 'Track uric acid labs if ordered, rash, flares, kidney follow-up, and dose changes.', $defaultMedline], + ['colchicine', 'colchicine', 'colchicine', 'Colcrys, Mitigare, Gloperba', 'colchicine tablets, colchicine capsules', 'Antigout anti-inflammatory', 'Rheumatology', 'Used for gout flares or prevention when prescribed.', 'Track GI symptoms, flare timing, dose schedule, and interaction cautions.', $defaultMedline], + ['methotrexate', 'methotrexate', 'amethopterin', 'Trexall, Rasuvo, Otrexup, RediTrex', 'methotrexate tablets, methotrexate injection', 'Antimetabolite immunomodulator', 'Rheumatology, oncology, and immune conditions', 'Used for autoimmune or cancer indications under clinician monitoring.', 'Track weekly schedule, folic acid plan if prescribed, labs, mouth sores, infection symptoms, and pregnancy precautions.', $defaultMedline], + ['adalimumab', 'adalimumab', 'recombinant human monoclonal antibody adalimumab', 'Humira, Amjevita, Hadlima, Hyrimoz, Yuflyma', 'adalimumab biosimilars', 'TNF blocker biologic', 'Immune-mediated conditions', 'Used for selected autoimmune inflammatory conditions when prescribed.', 'Track injection dates, infection symptoms, flares, site reactions, and biologic brand.', $defaultMedline], + ['etanercept', 'etanercept', 'recombinant TNF receptor fusion protein etanercept', 'Enbrel, Erelzi, Eticovo', 'etanercept biosimilars', 'TNF blocker biologic', 'Immune-mediated conditions', 'Used for selected autoimmune inflammatory conditions when prescribed.', 'Track injection dates, infection symptoms, flares, site reactions, and biologic brand.', $defaultMedline], + ]; +} + function seed_demo_data(PDO $pdo): void { $userCount = (int) $pdo->query('SELECT COUNT(*) FROM users')->fetchColumn(); @@ -437,6 +974,172 @@ function seed_demo_data(PDO $pdo): void foreach ($metrics as $metric) { $metricStmt->execute([...$metric, $created]); } + + $medicineIds = db_key_values($pdo, "SELECT generic_name AS name, id FROM medication_catalog"); + $medicationStmt = $pdo->prepare( + "INSERT INTO medication_logs + (user_id, medication_id, taken_on, medication_name, dose, route, frequency, status, prescriber, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $medicationLogs = [ + [$alexId, $medicineIds['metformin'] ?? null, app_date($today), 'metformin', '500 mg', 'oral', 'twice daily', 'taken', 'Primary care', 'Demo log for glucose tracking.'], + [$alexId, $medicineIds['atorvastatin'] ?? null, app_date($today), 'atorvastatin', '20 mg', 'oral', 'nightly', 'planned', 'Cardiology', 'Review lipid panel at follow-up.'], + [$mayaId, $medicineIds['albuterol'] ?? null, app_date($today), 'albuterol', '2 puffs', 'inhaled', 'as needed', 'planned', 'Pulmonology', 'Track use with symptoms and triggers.'], + ]; + foreach ($medicationLogs as $log) { + $medicationStmt->execute([...$log, $created]); + } + + $vitalStmt = $pdo->prepare( + "INSERT INTO vital_logs + (user_id, measured_on, systolic, diastolic, pulse, temperature_f, oxygen_pct, glucose_mg_dl, pain_score, symptoms, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $vitals = [ + [$alexId, app_date($today), 126, 78, 62, 98.4, 98, 112, 1, 'Mild soreness', 'Morning reading before breakfast.'], + [$mayaId, app_date($today), 112, 70, 56, 98.2, 99, 0, 0, 'None', 'Rest day baseline.'], + ]; + foreach ($vitals as $vital) { + $vitalStmt->execute([...$vital, $created]); + } + + $labStmt = $pdo->prepare( + "INSERT INTO lab_results + (user_id, collected_on, test_name, result_value, unit, reference_range, ordering_clinician, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $labs = [ + [$alexId, app_date($today->modify('-14 days')), 'A1C', '6.2', '%', 'Clinician supplied', 'Primary care', 'Demo metabolic marker.'], + [$alexId, app_date($today->modify('-14 days')), 'LDL cholesterol', '96', 'mg/dL', 'Clinician supplied', 'Cardiology', 'Review with statin plan.'], + [$mayaId, app_date($today->modify('-10 days')), 'Ferritin', '42', 'ng/mL', 'Clinician supplied', 'Primary care', 'Endurance training context.'], + ]; + foreach ($labs as $lab) { + $labStmt->execute([...$lab, $created]); + } +} + +function seed_medical_demo_data(PDO $pdo): void +{ + $users = db_all($pdo, 'SELECT id, name FROM users ORDER BY id LIMIT 2'); + if (!$users) { + return; + } + + $created = app_now(); + $today = new DateTimeImmutable('today'); + $alexId = (int) $users[0]['id']; + $mayaId = isset($users[1]) ? (int) $users[1]['id'] : $alexId; + $medicineIds = db_key_values($pdo, "SELECT generic_name AS name, id FROM medication_catalog"); + + if ((int) $pdo->query('SELECT COUNT(*) FROM medication_logs')->fetchColumn() === 0) { + $medicationStmt = $pdo->prepare( + "INSERT INTO medication_logs + (user_id, medication_id, taken_on, medication_name, dose, route, frequency, status, prescriber, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $medicationLogs = [ + [$alexId, $medicineIds['metformin'] ?? null, app_date($today), 'metformin', '500 mg', 'oral', 'twice daily', 'taken', 'Primary care', 'Demo log for glucose tracking.'], + [$alexId, $medicineIds['atorvastatin'] ?? null, app_date($today), 'atorvastatin', '20 mg', 'oral', 'nightly', 'planned', 'Cardiology', 'Review lipid panel at follow-up.'], + [$mayaId, $medicineIds['albuterol'] ?? null, app_date($today), 'albuterol', '2 puffs', 'inhaled', 'as needed', 'planned', 'Pulmonology', 'Track use with symptoms and triggers.'], + ]; + foreach ($medicationLogs as $log) { + $medicationStmt->execute([...$log, $created]); + } + } + + if ((int) $pdo->query('SELECT COUNT(*) FROM vital_logs')->fetchColumn() === 0) { + $vitalStmt = $pdo->prepare( + "INSERT INTO vital_logs + (user_id, measured_on, systolic, diastolic, pulse, temperature_f, oxygen_pct, glucose_mg_dl, pain_score, symptoms, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $vitals = [ + [$alexId, app_date($today), 126, 78, 62, 98.4, 98, 112, 1, 'Mild soreness', 'Morning reading before breakfast.'], + [$mayaId, app_date($today), 112, 70, 56, 98.2, 99, 0, 0, 'None', 'Rest day baseline.'], + ]; + foreach ($vitals as $vital) { + $vitalStmt->execute([...$vital, $created]); + } + } + + if ((int) $pdo->query('SELECT COUNT(*) FROM lab_results')->fetchColumn() === 0) { + $labStmt = $pdo->prepare( + "INSERT INTO lab_results + (user_id, collected_on, test_name, result_value, unit, reference_range, ordering_clinician, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $labs = [ + [$alexId, app_date($today->modify('-14 days')), 'A1C', '6.2', '%', 'Clinician supplied', 'Primary care', 'Demo metabolic marker.'], + [$alexId, app_date($today->modify('-14 days')), 'LDL cholesterol', '96', 'mg/dL', 'Clinician supplied', 'Cardiology', 'Review with statin plan.'], + [$mayaId, app_date($today->modify('-10 days')), 'Ferritin', '42', 'ng/mL', 'Clinician supplied', 'Primary care', 'Endurance training context.'], + ]; + foreach ($labs as $lab) { + $labStmt->execute([...$lab, $created]); + } + } + + if ((int) $pdo->query('SELECT COUNT(*) FROM symptom_logs')->fetchColumn() === 0) { + $symptomStmt = $pdo->prepare( + "INSERT INTO symptom_logs + (user_id, observed_on, symptom, body_area, severity, duration, triggers, action_taken, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $symptoms = [ + [$alexId, app_date($today), 'Headache', 'Head', 3, '2 hours', 'Long screen session', 'Hydration and rest', 'Monitor if it returns.'], + [$alexId, app_date($today->modify('-1 day')), 'Dizziness', 'General', 2, '15 minutes', 'Standing quickly', 'Sat down and checked BP', 'No recurrence after breakfast.'], + [$mayaId, app_date($today), 'Wheezing', 'Chest', 4, '20 minutes', 'Cold air run', 'Used rescue inhaler as directed', 'Track with activity and weather.'], + ]; + foreach ($symptoms as $symptom) { + $symptomStmt->execute([...$symptom, $created]); + } + } + + if ((int) $pdo->query('SELECT COUNT(*) FROM allergy_records')->fetchColumn() === 0) { + $allergyStmt = $pdo->prepare( + "INSERT INTO allergy_records + (user_id, allergen, reaction, severity, first_noted_on, status, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)" + ); + $allergies = [ + [$alexId, 'Penicillin', 'Rash', 'moderate', app_date($today->modify('-5 years')), 'active', 'Demo allergy record. Confirm with clinician.'], + [$mayaId, 'Peanuts', 'Hives and throat tightness', 'severe', app_date($today->modify('-12 years')), 'active', 'Carries emergency plan per clinician.'], + ]; + foreach ($allergies as $allergy) { + $allergyStmt->execute([...$allergy, $created]); + } + } + + if ((int) $pdo->query('SELECT COUNT(*) FROM appointments')->fetchColumn() === 0) { + $appointmentStmt = $pdo->prepare( + "INSERT INTO appointments + (user_id, appointment_on, clinician, specialty, location, reason, status, follow_up_notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $appointments = [ + [$alexId, app_date($today->modify('+3 days')), 'Dr. Morgan', 'Primary care', 'Downtown Clinic', 'Medication and blood pressure follow-up', 'scheduled', 'Bring home BP readings.'], + [$alexId, app_date($today->modify('+21 days')), 'Cardiology team', 'Cardiology', 'Heart Center', 'Lipid panel review', 'scheduled', 'Ask about statin tolerance.'], + [$mayaId, app_date($today->modify('+8 days')), 'Pulmonary clinic', 'Pulmonology', 'Respiratory Care', 'Asthma action plan review', 'scheduled', 'Discuss cold-weather symptoms.'], + ]; + foreach ($appointments as $appointment) { + $appointmentStmt->execute([...$appointment, $created]); + } + } + + if ((int) $pdo->query('SELECT COUNT(*) FROM immunization_records')->fetchColumn() === 0) { + $immunizationStmt = $pdo->prepare( + "INSERT INTO immunization_records + (user_id, vaccine_name, administered_on, dose, lot_number, clinician_or_site, next_due_on, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $immunizations = [ + [$alexId, 'Influenza', app_date($today->modify('-4 months')), '0.5 mL', '', 'Local pharmacy', app_date($today->modify('+8 months')), 'Annual reminder demo.'], + [$alexId, 'COVID-19 booster', app_date($today->modify('-7 months')), 'Booster', '', 'Community clinic', '', 'Record source: demo profile.'], + [$mayaId, 'Tdap', app_date($today->modify('-2 years')), 'Adult dose', '', 'Primary care', app_date($today->modify('+8 years')), 'Next due date depends on clinician guidance.'], + ]; + foreach ($immunizations as $immunization) { + $immunizationStmt->execute([...$immunization, $created]); + } + } } function app_now(): string @@ -674,6 +1377,13 @@ function admin_user_rows(PDO $pdo): array (SELECT COUNT(*) FROM nutrition_logs WHERE nutrition_logs.user_id = users.id) AS nutrition_log_count, (SELECT COUNT(*) FROM supplement_logs WHERE supplement_logs.user_id = users.id) AS supplement_log_count, (SELECT COUNT(*) FROM body_metrics WHERE body_metrics.user_id = users.id) AS metric_count, + (SELECT COUNT(*) FROM medication_logs WHERE medication_logs.user_id = users.id) AS medication_log_count, + (SELECT COUNT(*) FROM vital_logs WHERE vital_logs.user_id = users.id) AS vital_log_count, + (SELECT COUNT(*) FROM lab_results WHERE lab_results.user_id = users.id) AS lab_result_count, + (SELECT COUNT(*) FROM symptom_logs WHERE symptom_logs.user_id = users.id) AS symptom_log_count, + (SELECT COUNT(*) FROM allergy_records WHERE allergy_records.user_id = users.id) AS allergy_count, + (SELECT COUNT(*) FROM appointments WHERE appointments.user_id = users.id) AS appointment_count, + (SELECT COUNT(*) FROM immunization_records WHERE immunization_records.user_id = users.id) AS immunization_count, (SELECT MAX(measured_on) FROM body_metrics WHERE body_metrics.user_id = users.id) AS last_metric_on FROM users ORDER BY @@ -691,6 +1401,10 @@ function admin_summary(PDO $pdo): array 'inactive_users' => (int) db_value($pdo, "SELECT COUNT(*) FROM users WHERE status <> 'active'"), 'admins' => (int) db_value($pdo, "SELECT COUNT(*) FROM users WHERE role = 'admin'"), 'members' => (int) db_value($pdo, "SELECT COUNT(*) FROM users WHERE role = 'member'"), + 'medication_logs' => (int) db_value($pdo, 'SELECT COUNT(*) FROM medication_logs'), + 'vital_logs' => (int) db_value($pdo, 'SELECT COUNT(*) FROM vital_logs'), + 'lab_results' => (int) db_value($pdo, 'SELECT COUNT(*) FROM lab_results'), + 'appointments' => (int) db_value($pdo, 'SELECT COUNT(*) FROM appointments'), ]; } @@ -821,6 +1535,69 @@ function state_payload(array $query): array LIMIT 1", [$userId] ); + $medicalTerms = db_all($pdo, 'SELECT * FROM medical_terms ORDER BY category, term'); + $medicalConditions = db_all($pdo, 'SELECT * FROM medical_conditions ORDER BY category, name'); + $medicationCatalog = db_all($pdo, 'SELECT * FROM medication_catalog ORDER BY generic_name'); + $researchStudies = db_all($pdo, 'SELECT * FROM research_studies ORDER BY category, related_medicine, title'); + $medicationLogs = db_all( + $pdo, + "SELECT medication_logs.*, medication_catalog.class_name, medication_catalog.rxnorm_url, medication_catalog.pubmed_url + FROM medication_logs + LEFT JOIN medication_catalog ON medication_catalog.id = medication_logs.medication_id + WHERE medication_logs.user_id = ? AND medication_logs.taken_on BETWEEN ? AND ? + ORDER BY medication_logs.taken_on DESC, medication_logs.id DESC", + [$userId, app_date($start), app_date($end)] + ); + $vitalLogs = db_all( + $pdo, + "SELECT * FROM vital_logs + WHERE user_id = ? AND measured_on BETWEEN ? AND ? + ORDER BY measured_on DESC, id DESC", + [$userId, app_date($start), app_date($end)] + ); + $labResults = db_all( + $pdo, + "SELECT * FROM lab_results + WHERE user_id = ? AND collected_on BETWEEN ? AND ? + ORDER BY collected_on DESC, id DESC", + [$userId, app_date($start), app_date($end)] + ); + $symptomLogs = db_all( + $pdo, + "SELECT * FROM symptom_logs + WHERE user_id = ? AND observed_on BETWEEN ? AND ? + ORDER BY observed_on DESC, severity DESC, id DESC", + [$userId, app_date($start), app_date($end)] + ); + $allergyRecords = db_all( + $pdo, + "SELECT * FROM allergy_records + WHERE user_id = ? + ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END, allergen", + [$userId] + ); + $appointments = db_all( + $pdo, + "SELECT * FROM appointments + WHERE user_id = ? AND appointment_on BETWEEN ? AND ? + ORDER BY appointment_on, id", + [$userId, app_date($start), app_date($end)] + ); + $immunizationRecords = db_all( + $pdo, + "SELECT * FROM immunization_records + WHERE user_id = ? + ORDER BY administered_on DESC, id DESC", + [$userId] + ); + $latestVitals = db_one( + $pdo, + "SELECT * FROM vital_logs + WHERE user_id = ? + ORDER BY measured_on DESC, id DESC + LIMIT 1", + [$userId] + ); return [ 'users' => $users, @@ -844,6 +1621,18 @@ function state_payload(array $query): array 'supplementLogs' => $supplementLogs, 'bodyMetrics' => $bodyMetrics, 'latestMetric' => $latestMetric, + 'medicalTerms' => $medicalTerms, + 'medicalConditions' => $medicalConditions, + 'medicationCatalog' => $medicationCatalog, + 'researchStudies' => $researchStudies, + 'medicationLogs' => $medicationLogs, + 'vitalLogs' => $vitalLogs, + 'labResults' => $labResults, + 'symptomLogs' => $symptomLogs, + 'allergyRecords' => $allergyRecords, + 'appointments' => $appointments, + 'immunizationRecords' => $immunizationRecords, + 'latestVitals' => $latestVitals, 'nutritionSummary' => [ 'target' => nutrition_goal_for($pdo, $userId, $view, $start, $end), 'actual' => nutrition_totals($pdo, $userId, $start, $end), @@ -852,6 +1641,70 @@ function state_payload(array $query): array ]; } +function library_search_payload(array $query): array +{ + $pdo = app_db(); + $search = trim((string) ($query['q'] ?? '')); + $limit = max(10, min(500, (int) ($query['limit'] ?? 250))); + + if ($search === '') { + return [ + 'query' => '', + 'medicalTerms' => db_all($pdo, 'SELECT * FROM medical_terms ORDER BY category, term LIMIT ?', [$limit]), + 'medicalConditions' => db_all($pdo, 'SELECT * FROM medical_conditions ORDER BY category, name LIMIT ?', [$limit]), + 'medicationCatalog' => db_all($pdo, 'SELECT * FROM medication_catalog ORDER BY generic_name LIMIT ?', [$limit]), + 'researchStudies' => db_all($pdo, 'SELECT * FROM research_studies ORDER BY category, related_medicine, title LIMIT ?', [$limit]), + ]; + } + + $like = '%' . $search . '%'; + $termParams = array_fill(0, 5, $like); + $conditionParams = array_fill(0, 4, $like); + $medicineParams = array_fill(0, 10, $like); + $studyParams = array_fill(0, 6, $like); + + return [ + 'query' => $search, + 'medicalTerms' => db_all( + $pdo, + "SELECT * FROM medical_terms + WHERE term LIKE ? OR category LIKE ? OR plain_language_definition LIKE ? + OR clinical_context LIKE ? OR source_name LIKE ? + ORDER BY category, term + LIMIT {$limit}", + $termParams + ), + 'medicalConditions' => db_all( + $pdo, + "SELECT * FROM medical_conditions + WHERE name LIKE ? OR category LIKE ? OR overview LIKE ? OR common_tracking LIKE ? + ORDER BY category, name + LIMIT {$limit}", + $conditionParams + ), + 'medicationCatalog' => db_all( + $pdo, + "SELECT * FROM medication_catalog + WHERE generic_name LIKE ? OR active_ingredient LIKE ? OR chemical_name LIKE ? + OR brand_names LIKE ? OR generic_brands LIKE ? OR class_name LIKE ? + OR drug_family LIKE ? OR common_use LIKE ? OR tracking_note LIKE ? + OR search_terms LIKE ? + ORDER BY generic_name + LIMIT {$limit}", + $medicineParams + ), + 'researchStudies' => db_all( + $pdo, + "SELECT * FROM research_studies + WHERE category LIKE ? OR related_medicine LIKE ? OR related_condition LIKE ? + OR title LIKE ? OR study_type LIKE ? OR summary LIKE ? + ORDER BY category, related_medicine, title + LIMIT {$limit}", + $studyParams + ), + ]; +} + function create_user(array $data): array { $pdo = app_db(); @@ -1338,6 +2191,222 @@ function create_body_metric(array $data): array return ['bodyMetric' => db_one($pdo, 'SELECT * FROM body_metrics WHERE id = ?', [(int) $pdo->lastInsertId()])]; } +function create_medication_log(array $data): array +{ + $pdo = app_db(); + $userId = user_id_value($data); + $medicationId = int_value($data, 'medication_id') ?: null; + $catalog = $medicationId ? db_one($pdo, 'SELECT * FROM medication_catalog WHERE id = ?', [$medicationId]) : null; + $medicationName = text_value($data, 'medication_name', $catalog['generic_name'] ?? ''); + if ($medicationName === '') { + throw new InvalidArgumentException('Medication name is required.'); + } + $status = clamp_choice(text_value($data, 'status', 'planned'), ['planned', 'taken', 'skipped', 'stopped'], 'planned'); + + $stmt = $pdo->prepare( + "INSERT INTO medication_logs + (user_id, medication_id, taken_on, medication_name, dose, route, frequency, status, prescriber, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([ + $userId, + $medicationId, + app_date(parse_app_date(text_value($data, 'taken_on'))), + $medicationName, + text_value($data, 'dose'), + text_value($data, 'route'), + text_value($data, 'frequency'), + $status, + text_value($data, 'prescriber'), + text_value($data, 'notes'), + app_now(), + ]); + + return ['medicationLog' => db_one($pdo, 'SELECT * FROM medication_logs WHERE id = ?', [(int) $pdo->lastInsertId()])]; +} + +function create_vital_log(array $data): array +{ + $pdo = app_db(); + $userId = user_id_value($data); + $painScore = max(0, min(10, int_value($data, 'pain_score'))); + + $stmt = $pdo->prepare( + "INSERT INTO vital_logs + (user_id, measured_on, systolic, diastolic, pulse, temperature_f, oxygen_pct, + glucose_mg_dl, pain_score, symptoms, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([ + $userId, + app_date(parse_app_date(text_value($data, 'measured_on'))), + int_value($data, 'systolic'), + int_value($data, 'diastolic'), + int_value($data, 'pulse'), + number_value($data, 'temperature_f'), + number_value($data, 'oxygen_pct'), + number_value($data, 'glucose_mg_dl'), + $painScore, + text_value($data, 'symptoms'), + text_value($data, 'notes'), + app_now(), + ]); + + return ['vitalLog' => db_one($pdo, 'SELECT * FROM vital_logs WHERE id = ?', [(int) $pdo->lastInsertId()])]; +} + +function create_lab_result(array $data): array +{ + $pdo = app_db(); + $userId = user_id_value($data); + $testName = text_value($data, 'test_name'); + $resultValue = text_value($data, 'result_value'); + if ($testName === '' || $resultValue === '') { + throw new InvalidArgumentException('Lab test name and result are required.'); + } + + $stmt = $pdo->prepare( + "INSERT INTO lab_results + (user_id, collected_on, test_name, result_value, unit, reference_range, ordering_clinician, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([ + $userId, + app_date(parse_app_date(text_value($data, 'collected_on'))), + $testName, + $resultValue, + text_value($data, 'unit'), + text_value($data, 'reference_range'), + text_value($data, 'ordering_clinician'), + text_value($data, 'notes'), + app_now(), + ]); + + return ['labResult' => db_one($pdo, 'SELECT * FROM lab_results WHERE id = ?', [(int) $pdo->lastInsertId()])]; +} + +function create_symptom_log(array $data): array +{ + $pdo = app_db(); + $userId = user_id_value($data); + $symptom = text_value($data, 'symptom'); + if ($symptom === '') { + throw new InvalidArgumentException('Symptom is required.'); + } + $severity = max(0, min(10, int_value($data, 'severity'))); + + $stmt = $pdo->prepare( + "INSERT INTO symptom_logs + (user_id, observed_on, symptom, body_area, severity, duration, triggers, action_taken, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([ + $userId, + app_date(parse_app_date(text_value($data, 'observed_on'))), + $symptom, + text_value($data, 'body_area'), + $severity, + text_value($data, 'duration'), + text_value($data, 'triggers'), + text_value($data, 'action_taken'), + text_value($data, 'notes'), + app_now(), + ]); + + return ['symptomLog' => db_one($pdo, 'SELECT * FROM symptom_logs WHERE id = ?', [(int) $pdo->lastInsertId()])]; +} + +function create_allergy_record(array $data): array +{ + $pdo = app_db(); + $userId = user_id_value($data); + $allergen = text_value($data, 'allergen'); + if ($allergen === '') { + throw new InvalidArgumentException('Allergen is required.'); + } + $severity = clamp_choice(text_value($data, 'severity', 'unknown'), ['unknown', 'mild', 'moderate', 'severe', 'life-threatening'], 'unknown'); + $status = clamp_choice(text_value($data, 'status', 'active'), ['active', 'resolved'], 'active'); + $firstNoted = text_value($data, 'first_noted_on'); + + $stmt = $pdo->prepare( + "INSERT INTO allergy_records + (user_id, allergen, reaction, severity, first_noted_on, status, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([ + $userId, + $allergen, + text_value($data, 'reaction'), + $severity, + $firstNoted === '' ? '' : app_date(parse_app_date($firstNoted)), + $status, + text_value($data, 'notes'), + app_now(), + ]); + + return ['allergyRecord' => db_one($pdo, 'SELECT * FROM allergy_records WHERE id = ?', [(int) $pdo->lastInsertId()])]; +} + +function create_appointment(array $data): array +{ + $pdo = app_db(); + $userId = user_id_value($data); + $reason = text_value($data, 'reason'); + if ($reason === '') { + throw new InvalidArgumentException('Appointment reason is required.'); + } + $status = clamp_choice(text_value($data, 'status', 'scheduled'), ['scheduled', 'completed', 'canceled'], 'scheduled'); + + $stmt = $pdo->prepare( + "INSERT INTO appointments + (user_id, appointment_on, clinician, specialty, location, reason, status, follow_up_notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([ + $userId, + app_date(parse_app_date(text_value($data, 'appointment_on'))), + text_value($data, 'clinician'), + text_value($data, 'specialty'), + text_value($data, 'location'), + $reason, + $status, + text_value($data, 'follow_up_notes'), + app_now(), + ]); + + return ['appointment' => db_one($pdo, 'SELECT * FROM appointments WHERE id = ?', [(int) $pdo->lastInsertId()])]; +} + +function create_immunization_record(array $data): array +{ + $pdo = app_db(); + $userId = user_id_value($data); + $vaccineName = text_value($data, 'vaccine_name'); + if ($vaccineName === '') { + throw new InvalidArgumentException('Vaccine name is required.'); + } + $nextDue = text_value($data, 'next_due_on'); + + $stmt = $pdo->prepare( + "INSERT INTO immunization_records + (user_id, vaccine_name, administered_on, dose, lot_number, clinician_or_site, next_due_on, notes, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([ + $userId, + $vaccineName, + app_date(parse_app_date(text_value($data, 'administered_on'))), + text_value($data, 'dose'), + text_value($data, 'lot_number'), + text_value($data, 'clinician_or_site'), + $nextDue === '' ? '' : app_date(parse_app_date($nextDue)), + text_value($data, 'notes'), + app_now(), + ]); + + return ['immunizationRecord' => db_one($pdo, 'SELECT * FROM immunization_records WHERE id = ?', [(int) $pdo->lastInsertId()])]; +} + function json_input(): array { $raw = file_get_contents('php://input'); diff --git a/data/health_tracker.sqlite b/data/health_tracker.sqlite index eaa4c70..2fe6a18 100644 Binary files a/data/health_tracker.sqlite and b/data/health_tracker.sqlite differ diff --git a/public/admin.php b/public/admin.php index 41fc374..128a08a 100644 --- a/public/admin.php +++ b/public/admin.php @@ -4,7 +4,7 @@ declare(strict_types=1); require __DIR__ . '/../app/bootstrap.php'; app_db(); -$pageTitle = 'Admin Dashboard | Neon Health Tracker'; +$pageTitle = 'Admin Dashboard | Neon Medical Tracker'; $activePage = 'admin'; require __DIR__ . '/partials/site-header.php'; ?> @@ -13,7 +13,7 @@ require __DIR__ . '/partials/site-header.php';

Admin dashboard

Manage users and their profiles.

-

Use an active admin profile to create users, update profile details, assign roles, activate or deactivate accounts, and remove users.

+

Use an active admin profile to create users, update profile details, assign roles, activate or deactivate accounts, and remove users with their medical tracker records.

@@ -50,10 +50,10 @@ require __DIR__ . '/partials/site-header.php'; - + - +
diff --git a/public/api.php b/public/api.php index 4f3fad6..10d9675 100644 --- a/public/api.php +++ b/public/api.php @@ -12,6 +12,11 @@ try { exit; } + if ($method === 'GET' && $action === 'library_search') { + json_response(library_search_payload($_GET)); + exit; + } + if ($method !== 'POST') { json_response(['error' => 'Unsupported method.'], 405); exit; @@ -33,6 +38,13 @@ try { 'create_nutrition_log' => 'create_nutrition_log', 'create_supplement_log' => 'create_supplement_log', 'create_body_metric' => 'create_body_metric', + 'create_medication_log' => 'create_medication_log', + 'create_vital_log' => 'create_vital_log', + 'create_lab_result' => 'create_lab_result', + 'create_symptom_log' => 'create_symptom_log', + 'create_allergy_record' => 'create_allergy_record', + 'create_appointment' => 'create_appointment', + 'create_immunization_record' => 'create_immunization_record', ]; if (!isset($routes[$action])) { diff --git a/public/assets/admin.js b/public/assets/admin.js index 0b36519..0ecbe5b 100644 --- a/public/assets/admin.js +++ b/public/assets/admin.js @@ -92,6 +92,10 @@ function renderAdminStats() { ["Inactive", summary.inactive_users || 0], ["Admins", summary.admins || 0], ["Members", summary.members || 0], + ["Med logs", summary.medication_logs || 0], + ["Vitals", summary.vital_logs || 0], + ["Labs", summary.lab_results || 0], + ["Visits", summary.appointments || 0], ]; admin$("#adminStats").innerHTML = stats.map(([label, value]) => ` @@ -116,7 +120,7 @@ function renderAdminUsers() {

${adminEscape(user.name)}${isCurrent ? " (current)" : ""}

${adminEscape(user.email || "No email")}

-

${adminEscape(user.fitness_focus || "No focus set")}

+

${adminEscape(user.fitness_focus || "No care focus set")}

${adminEscape(user.phone || "No phone")}${adminEscape(training)}${adminEscape(height)}

@@ -130,6 +134,10 @@ function renderAdminUsers() { ${adminNumber(user.nutrition_log_count)} nutrition logs ${adminNumber(user.supplement_log_count)} supplement logs ${adminNumber(user.metric_count)} metrics + ${adminNumber(user.medication_log_count)} meds + ${adminNumber(user.vital_log_count)} vitals + ${adminNumber(user.lab_result_count)} labs + ${adminNumber(user.appointment_count)} appointments
diff --git a/public/assets/app.js b/public/assets/app.js index e8d6221..1a37b2d 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -114,6 +114,7 @@ function render() { applyTheme(); renderControls(); renderSummaries(); + renderMedical(); renderTimeline(); renderNutrition(); renderRoutines(); @@ -141,7 +142,7 @@ function applyTheme() { function renderControls() { const data = appState.data; const user = data.currentUser; - $("#profileFocus").textContent = user.fitness_focus || "Multi-profile training dashboard"; + $("#profileFocus").textContent = user.fitness_focus || "Multi-profile medical dashboard"; if (data.currentUserIsAdmin) { $("#profileFocus").textContent += " / admin"; } @@ -158,18 +159,21 @@ function renderControls() { } function renderSummaries() { - const { workoutSummary, nutritionSummary, latestMetric, supplementLogs } = appState.data; - const actual = nutritionSummary.actual; - const target = nutritionSummary.target; - const supplementTaken = supplementLogs.filter((item) => item.status === "taken").length; + const { latestVitals, medicationLogs, labResults, symptomLogs, allergyRecords, appointments } = appState.data; + const medicationTaken = medicationLogs.filter((item) => item.status === "taken").length; + const bp = latestVitals && Number(latestVitals.systolic) > 0 ? `${latestVitals.systolic}/${latestVitals.diastolic}` : "No BP"; + const highestSeverity = symptomLogs.reduce((max, item) => Math.max(max, Number(item.severity || 0)), 0); + const activeAllergies = allergyRecords.filter((item) => item.status === "active").length; + const scheduledAppointments = appointments.filter((item) => item.status === "scheduled").length; const cards = [ - ["Completion", `${number(workoutSummary.completion_rate, 1)}%`, `${workoutSummary.completed}/${workoutSummary.planned} workouts`], - ["Volume", number(workoutSummary.weight_volume_lbs), "lb lifted"], - ["Cardio", `${number(workoutSummary.minutes, 0)} min`, `${number(workoutSummary.distance_mi, 2)} mi`], - ["Calories", number(actual.calories), `${number(target.calories)} target`], - ["Protein", `${number(actual.protein_g)} g`, `${number(target.protein_g)} g target`], - ["Weight", latestMetric ? `${number(latestMetric.weight_lbs, 1)} lb` : "No log", latestMetric ? `${number(latestMetric.sleep_hours, 1)} hr sleep` : `${supplementTaken} doses taken`], + ["Medications", `${number(medicationLogs.length)}`, `${number(medicationTaken)} taken in range`], + ["Blood Pressure", bp, latestVitals ? `${number(latestVitals.pulse)} pulse` : "No vitals log"], + ["Glucose", latestVitals && Number(latestVitals.glucose_mg_dl) > 0 ? `${number(latestVitals.glucose_mg_dl)} mg/dL` : "No glucose", latestVitals ? `${number(latestVitals.oxygen_pct, 1)}% oxygen` : "No oxygen log"], + ["Labs", `${number(labResults.length)}`, "results in range"], + ["Symptoms", `${number(symptomLogs.length)}`, `highest severity ${number(highestSeverity)}`], + ["Allergies", `${number(activeAllergies)}`, `${number(allergyRecords.length)} total records`], + ["Appointments", `${number(scheduledAppointments)}`, "scheduled in range"], ]; $("#summaryGrid").innerHTML = cards @@ -244,6 +248,143 @@ function renderWorkoutItem(workout) { `; } +function renderMedical() { + renderMedicationLogs(); + renderVitalLogs(); + renderLabResults(); + renderSymptomLogs(); + renderAllergyRecords(); + renderAppointments(); + renderImmunizationRecords(); + renderStudies(); +} + +function renderMedicationLogs() { + const logs = appState.data.medicationLogs || []; + $("#medicationLogList").innerHTML = logs.length ? logs.map((log) => ` +
+
+
+

${escapeHtml(log.medication_name)}

+

${shortDate(log.taken_on)} | ${escapeHtml(log.dose || "open dose")} | ${escapeHtml(log.route || "route not set")} | ${escapeHtml(log.frequency || "frequency not set")}

+ ${log.class_name ? `

${escapeHtml(log.class_name)}

` : ""} +
+ ${escapeHtml(log.status)} +
+

${escapeHtml([log.prescriber, log.notes].filter(Boolean).join(" | ") || "No notes")}

+ ${log.rxnorm_url ? `RxNorm` : ""} +
+ `).join("") : `
No medication logs in this range
`; +} + +function renderVitalLogs() { + const logs = appState.data.vitalLogs || []; + $("#vitalLogList").innerHTML = logs.length ? logs.map((log) => { + const bp = Number(log.systolic) > 0 ? `${log.systolic}/${log.diastolic}` : "No BP"; + return ` +
+
+ ${shortDate(log.measured_on)} + ${bp} +
+

${number(log.pulse)} pulse / ${number(log.temperature_f, 1)} F / ${number(log.oxygen_pct, 1)}% O2 / ${number(log.glucose_mg_dl)} glucose / pain ${number(log.pain_score)}

+

${escapeHtml([log.symptoms, log.notes].filter(Boolean).join(" | ") || "No symptoms noted")}

+
+ `; + }).join("") : `
No vitals in this range
`; +} + +function renderLabResults() { + const labs = appState.data.labResults || []; + $("#labResultList").innerHTML = labs.length ? labs.map((lab) => ` +
+
+ ${escapeHtml(lab.test_name)} + ${escapeHtml(lab.result_value)} ${escapeHtml(lab.unit || "")} +
+

${shortDate(lab.collected_on)} / ${escapeHtml(lab.reference_range || "No reference range")}

+

${escapeHtml([lab.ordering_clinician, lab.notes].filter(Boolean).join(" | ") || "No notes")}

+
+ `).join("") : `
No lab results in this range
`; +} + +function renderSymptomLogs() { + const logs = appState.data.symptomLogs || []; + $("#symptomLogList").innerHTML = logs.length ? logs.map((log) => ` +
+
+ ${escapeHtml(log.symptom)} + severity ${number(log.severity)} +
+

${shortDate(log.observed_on)} / ${escapeHtml(log.body_area || "body area not set")} / ${escapeHtml(log.duration || "duration not set")}

+

${escapeHtml([log.triggers, log.action_taken, log.notes].filter(Boolean).join(" | ") || "No notes")}

+
+ `).join("") : `
No symptom logs in this range
`; +} + +function renderAllergyRecords() { + const records = appState.data.allergyRecords || []; + $("#allergyRecordList").innerHTML = records.length ? records.map((record) => ` +
+
+ ${escapeHtml(record.allergen)} + ${escapeHtml(record.severity)} +
+

${escapeHtml(record.reaction || "Reaction not set")} / ${escapeHtml(record.status)}

+

${escapeHtml([record.first_noted_on ? `first noted ${shortDate(record.first_noted_on)}` : "", record.notes].filter(Boolean).join(" | ") || "No notes")}

+
+ `).join("") : `
No allergy records yet
`; +} + +function renderAppointments() { + const appointments = appState.data.appointments || []; + $("#appointmentList").innerHTML = appointments.length ? appointments.map((appointment) => ` +
+
+ ${escapeHtml(appointment.reason)} + ${escapeHtml(appointment.status)} +
+

${shortDate(appointment.appointment_on)} / ${escapeHtml(appointment.clinician || "clinician not set")} / ${escapeHtml(appointment.specialty || "specialty not set")}

+

${escapeHtml([appointment.location, appointment.follow_up_notes].filter(Boolean).join(" | ") || "No follow-up notes")}

+
+ `).join("") : `
No appointments in this range
`; +} + +function renderImmunizationRecords() { + const records = appState.data.immunizationRecords || []; + $("#immunizationRecordList").innerHTML = records.length ? records.slice(0, 8).map((record) => ` +
+
+ ${escapeHtml(record.vaccine_name)} + ${shortDate(record.administered_on)} +
+

${escapeHtml(record.dose || "dose not set")} / ${escapeHtml(record.clinician_or_site || "site not set")}

+

${escapeHtml([record.next_due_on ? `next due ${shortDate(record.next_due_on)}` : "", record.lot_number ? `lot ${record.lot_number}` : "", record.notes].filter(Boolean).join(" | ") || "No notes")}

+
+ `).join("") : `
No immunization records yet
`; +} + +function renderStudies() { + const studies = (appState.data.researchStudies || []).slice(0, 6); + $("#studyList").innerHTML = studies.length ? studies.map((study) => ` +
+
+
+

${escapeHtml(study.title)}

+

${escapeHtml(study.category)} | ${escapeHtml(study.related_medicine || "general")}

+
+ ${escapeHtml(study.study_type || "research")} +
+

${escapeHtml(study.summary)}

+ +
+ `).join("") : `
No study links seeded
`; +} + function renderNutrition() { const { nutritionSummary, nutritionLogs } = appState.data; const target = nutritionSummary.target; @@ -374,7 +515,7 @@ function renderAdmin() {

${escapeHtml(user.name)}${isCurrent ? " (current)" : ""}

${escapeHtml(user.email || "No email")}

-

${escapeHtml(user.fitness_focus || "No focus set")}

+

${escapeHtml(user.fitness_focus || "No care focus set")}

${escapeHtml(user.phone || "No phone")}${escapeHtml(training)}${escapeHtml(height)}

@@ -388,6 +529,10 @@ function renderAdmin() { ${number(user.nutrition_log_count)} nutrition logs ${number(user.supplement_log_count)} supplement logs ${number(user.metric_count)} metrics + ${number(user.medication_log_count)} meds + ${number(user.vital_log_count)} vitals + ${number(user.lab_result_count)} labs + ${number(user.appointment_count)} appointments
@@ -455,18 +600,26 @@ function option(value, label, selected = false) { } function populateForms() { - const { routines, exercises, supplements, nutritionGoals, range } = appState.data; + const { routines, exercises, supplements, nutritionGoals, medicationCatalog, range } = appState.data; const routineOptions = option("", "No routine") + routines.map((routine) => option(routine.id, `${routine.name} (${routine.planner_scope})`)).join(""); const goalOptions = option("", "Separate target") + nutritionGoals.map((goal) => option(goal.id, `${goal.label} (${goal.scope})`)).join(""); const exerciseOptions = option("", "Choose exercise") + exercises.map((exercise) => option(exercise.id, `${exercise.name} (${exercise.category})`)).join(""); const supplementOptions = option("", "Choose supplement") + supplements.map((supplement) => option(supplement.id, `${supplement.name} (${supplement.timing})`)).join(""); + const medicationOptions = option("", "Choose medication") + medicationCatalog.map((medicine) => option(medicine.id, `${medicine.generic_name} (${medicine.class_name})`)).join(""); $$("#workoutForm [name='routine_id']").forEach((select) => select.innerHTML = routineOptions); $$("#routineForm [name='nutrition_goal_id']").forEach((select) => select.innerHTML = goalOptions); $$("#workoutForm [name='exercise_id']").forEach((select) => select.innerHTML = exerciseOptions); $$("#supplementLogForm [name='supplement_id']").forEach((select) => select.innerHTML = supplementOptions); + $$("#medicationLogForm [name='medication_id']").forEach((select) => select.innerHTML = medicationOptions); const dateFields = [ + "#medicationLogForm [name='taken_on']", + "#vitalLogForm [name='measured_on']", + "#labResultForm [name='collected_on']", + "#symptomLogForm [name='observed_on']", + "#appointmentForm [name='appointment_on']", + "#immunizationRecordForm [name='administered_on']", "#workoutForm [name='scheduled_on']", "#routineForm [name='start_date']", "#nutritionGoalForm [name='start_date']", @@ -575,6 +728,15 @@ function wireControls() { $("#supplementLogForm [name='dose']").value = supplement.default_dose; }); + $("#medicationLogForm [name='medication_id']").addEventListener("change", (event) => { + const medicine = appState.data.medicationCatalog.find((item) => String(item.id) === event.target.value); + if (!medicine) return; + $("#medicationLogForm [name='medication_name']").value = medicine.generic_name; + if (!$("#medicationLogForm [name='notes']").value) { + $("#medicationLogForm [name='notes']").value = medicine.tracking_note; + } + }); + $("#newAdminUserButton").addEventListener("click", () => { resetAdminUserForm(); $("#adminUserForm").scrollIntoView({ behavior: "smooth", block: "start" }); @@ -642,6 +804,13 @@ async function saveTheme(mode = null, accent = null) { } function wireForms() { + wireForm("#medicationLogForm", "create_medication_log", "Medication logged"); + wireForm("#vitalLogForm", "create_vital_log", "Vitals logged"); + wireForm("#labResultForm", "create_lab_result", "Lab result logged"); + wireForm("#symptomLogForm", "create_symptom_log", "Symptom logged"); + wireForm("#allergyRecordForm", "create_allergy_record", "Allergy saved"); + wireForm("#appointmentForm", "create_appointment", "Appointment saved"); + wireForm("#immunizationRecordForm", "create_immunization_record", "Immunization saved"); wireForm("#workoutForm", "create_workout", "Workout saved"); wireForm("#routineForm", "create_routine", "Routine saved"); wireForm("#nutritionGoalForm", "create_nutrition_goal", "Nutrition target saved"); diff --git a/public/assets/site.css b/public/assets/site.css index b49ce25..d30bbc7 100644 --- a/public/assets/site.css +++ b/public/assets/site.css @@ -323,6 +323,7 @@ figcaption a { .detail-grid article, .site-metric-stack article, .signup-steps article, +.term-table article, .admin-denied, .admin-stat, .admin-user-card, @@ -346,6 +347,7 @@ figcaption a { .feature-grid p, .detail-grid p, +.term-table p, .site-metric-stack span, .signup-steps span, .details-line, @@ -355,6 +357,43 @@ figcaption a { line-height: 1.5; } +.term-table { + display: grid; + gap: 10px; +} + +.term-table article { + display: grid; + grid-template-columns: minmax(180px, 0.34fr) minmax(0, 0.4fr) minmax(0, 0.4fr) auto; + gap: 12px; + align-items: start; +} + +.term-table span { + color: var(--accent); + font-size: 0.78rem; +} + +.term-table a, +.source-links a { + color: var(--accent); + text-decoration: none; +} + +.source-links { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 8px; +} + +.source-links a { + border: 1px solid var(--line); + border-radius: 999px; + padding: 4px 8px; + font-size: 0.78rem; +} + .site-split, .detail-hero, .signup-layout { @@ -730,6 +769,10 @@ textarea:focus { justify-content: flex-start; } + .term-table article { + grid-template-columns: 1fr; + } + .detail-hero img { height: 320px; } diff --git a/public/assets/styles.css b/public/assets/styles.css index 5d6a1ff..1428f3b 100644 --- a/public/assets/styles.css +++ b/public/assets/styles.css @@ -630,6 +630,7 @@ textarea:focus { } .badge.skipped, +.badge.stopped, .badge.inactive { color: var(--danger); border-color: color-mix(in srgb, var(--danger), transparent 50%); diff --git a/public/index.php b/public/index.php index 6c228e5..a9f28b4 100644 --- a/public/index.php +++ b/public/index.php @@ -4,7 +4,7 @@ declare(strict_types=1); require __DIR__ . '/../app/bootstrap.php'; app_db(); -$pageTitle = 'Neon Health Tracker'; +$pageTitle = 'Neon Medical Tracker'; $activePage = 'home'; $heroImage = 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Jogging_Woman_in_Grass.jpg/1280px-Jogging_Woman_in_Grass.jpg'; @@ -14,12 +14,12 @@ require __DIR__ . '/partials/site-header.php';
Runner training outdoors in bright green grass
-

Workout planning, nutrition balance, supplement tracking

-

Neon Health Tracker

-

A multi-user fitness planner for people who want routines, meals, recovery, and body metrics in one fast web dashboard.

+

Medication logs, vitals, labs, terminology, NIH/NLM research links

+

Neon Medical Tracker

+

A multi-user medical tracking workspace for people who want medicines, readings, labs, symptoms, source links, and profile administration in one web dashboard.

@@ -31,50 +31,50 @@ require __DIR__ . '/partials/site-header.php';

Built for daily use

-

One workspace for training, food, recovery, and progress.

+

One workspace for personal health records and sourced reference links.

01 -

Routine planning

-

Schedule weight lifting, cycling, running, swimming, conditioning, mobility, and custom workouts by day, week, or month.

+

Medication tracking

+

Log prescription and over-the-counter medicines by date, dose, route, frequency, status, prescriber, and notes.

02 -

Nutrition targets

-

Compare actual logs against daily, weekly, or monthly calories, protein, carbs, fat, and hydration goals.

+

Vitals and symptoms

+

Track blood pressure, pulse, temperature, oxygen saturation, glucose, pain scores, symptoms, and context.

03 -

Supplement timing

-

Track pre-workout, intra-workout, post-workout, daily, and evening supplements without mixing them into meal logs.

+

Labs and terminology

+

Store lab values and browse plain-language medical terms connected to MedlinePlus, RxNorm, PubMed, and ClinicalTrials.gov.

04 -

Health monitoring

-

Keep weight, body fat, sleep, resting heart rate, mood, and notes connected to the training plan.

+

NIH/NLM studies

+

Browse NIH/NLM research categories and study-search links related to the medicines included in the catalog.

-

For individuals and small teams

+

For households, caregivers, and small teams

Profiles stay separate, admins stay in control.

-

Each user gets a profile, theme preference, routines, logs, goals, and metric history. Admins can create users, edit details, activate or deactivate accounts, and remove profiles from a dedicated dashboard.

+

Each user gets a profile, theme preference, medication logs, vitals, lab results, medical notes, and research references. Admins can create users, edit details, activate or deactivate accounts, and remove profiles from a dedicated dashboard.

Open admin dashboard
-
DailyPlan today’s workout, meals, supplements, and body check-in.
-
WeeklySee volume, cardio minutes, macro targets, and completion rate.
-
MonthlyCompare long-range goals against real nutrition and training behavior.
+
DailyLog today’s medicines, readings, symptoms, and notes.
+
WeeklyReview medication adherence, vital trends, labs, and follow-up context.
+
MonthlyKeep longer-term records ready for visits with clinicians or caregivers.

Ready when you are

-

Create your profile and open the tracker.

+

Create your profile and open the medical tracker.

Sign up
diff --git a/public/medical.php b/public/medical.php new file mode 100644 index 0000000..ab4672c --- /dev/null +++ b/public/medical.php @@ -0,0 +1,103 @@ + +
+
+
+

Medical terminology database

+

Terms, conditions, medicines, and NIH/NLM study links.

+

Entries are concise app-authored summaries with links to NIH/NLM systems such as MedlinePlus, RxNorm, PubMed, and ClinicalTrials.gov. This is a tracking/reference aid, not medical advice.

+
+ +
+ + + +
+
+ +
+
+

Terminology

+

Plain-language medical terms

+
+
+ +
+
+

+ +
+

+

+ +
+ +
+
+ +
+
+

Medication catalog

+

Medicines with RxNorm, PubMed, and ClinicalTrials.gov links

+
+
+ + + +
+
+ +
+
+

NIH/NLM study links

+

Research categories connected to the listed medicines

+
+
+ + + +
+
+
+ diff --git a/public/nutrition.php b/public/nutrition.php index cfedfa2..8715a93 100644 --- a/public/nutrition.php +++ b/public/nutrition.php @@ -2,47 +2,46 @@ declare(strict_types=1); require __DIR__ . '/../app/bootstrap.php'; -app_db(); +$pdo = app_db(); -$pageTitle = 'Nutrition Tracking | Neon Health Tracker'; -$activePage = 'nutrition'; +$pageTitle = 'Medicine Catalog | Neon Medical Tracker'; +$activePage = 'medicines'; +$medicines = db_all($pdo, 'SELECT * FROM medication_catalog ORDER BY generic_name'); $photo = 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/A_large_mixed_salad.jpg/1024px-A_large_mixed_salad.jpg'; require __DIR__ . '/partials/site-header.php'; ?>
- Large mixed salad with vegetables and protein + Large mixed salad
Photo: A large mixed salad by Jmabel, CC BY-SA 4.0.
-

Targets vs actuals

-

Keep nutrition flexible without losing the plan.

-

Set daily, weekly, or monthly goals for calories, protein, carbs, fat, and hydration. Log actual intake separately so deviations stay visible instead of buried.

- Start a nutrition plan +

Medicine catalog

+

Track medicines with source links beside every catalog entry.

+

The starter catalog includes common medicines and links each one to RxNorm, MedlinePlus, PubMed, and ClinicalTrials.gov searches.

+ Open medical tracker
-
-

Separate goals

-

Nutrition goals can be attached to routines or kept independent for users who want to experiment.

-
-
-

Macro balance

-

Progress bars show how far actual logs are from the chosen target for the current planner range.

-
-
-

Hydration

-

Water targets stay beside macros so recovery and performance habits remain part of the daily flow.

-
-
-

Range scaling

-

Use daily, weekly, or monthly target scopes, with daily goals scaling when a broader target is not set.

-
+ + +
diff --git a/public/partials/site-footer.php b/public/partials/site-footer.php index e793ead..1bd47b7 100644 --- a/public/partials/site-footer.php +++ b/public/partials/site-footer.php @@ -1,11 +1,11 @@
- Neon Health Tracker -

Workout planning, nutrition tracking, supplement timing, health metrics, and admin-managed profiles.

+ Neon Medical Tracker +

Medication logs, vitals, lab results, terminology, NIH/NLM study links, and admin-managed profiles.

diff --git a/public/partials/site-header.php b/public/partials/site-header.php index 5b0e957..745c61c 100644 --- a/public/partials/site-header.php +++ b/public/partials/site-header.php @@ -1,5 +1,5 @@
@@ -64,6 +64,96 @@ app_db();
+
+
+
+
+

Medication Plan

+

Medication Log

+
+ +
+
+
+ +
+
+
+

Vitals

+

Latest Readings

+
+ +
+
+
+ +
+
+
+

Labs

+

Lab Results

+
+ +
+
+
+ +
+
+
+

Symptoms

+

Symptom Journal

+
+ +
+
+
+ +
+
+
+

Safety

+

Allergies

+
+ +
+
+
+ +
+
+
+

Care Plan

+

Appointments

+
+ +
+
+
+ +
+
+
+

Prevention

+

Immunizations

+
+ +
+
+
+ +
+
+
+

Reference

+

NIH/NLM Studies

+
+ Open database +
+
+
+
+
+
+
+
+

Medication

+

Log Medication

+
+
+
+ + + + + + + + + +
+ +
+ +
+
+
+

Vitals

+

Log Vitals

+
+
+
+ + + + + + + + + + +
+ +
+ +
+
+
+

Labs

+

Log Lab Result

+
+
+
+ + + + + + + +
+ +
+ +
+
+
+

Symptoms

+

Log Symptom

+
+
+
+ + + + + + + + +
+ +
+ +
+
+
+

Safety

+

Add Allergy

+
+
+
+ + + + + + +
+ +
+ +
+
+
+

Care Plan

+

Add Appointment

+
+
+
+ + + + + + + +
+ +
+ +
+
+
+

Prevention

+

Add Immunization

+
+
+
+ + + + + + + +
+ +
+
diff --git a/public/workouts.php b/public/workouts.php index efda3cd..9e4ce4e 100644 --- a/public/workouts.php +++ b/public/workouts.php @@ -2,23 +2,24 @@ declare(strict_types=1); require __DIR__ . '/../app/bootstrap.php'; -app_db(); +$pdo = app_db(); -$pageTitle = 'Workout Planning | Neon Health Tracker'; -$activePage = 'workouts'; +$pageTitle = 'Condition Tracking | Neon Medical Tracker'; +$activePage = 'conditions'; +$conditions = db_all($pdo, 'SELECT * FROM medical_conditions ORDER BY category, name'); $photo = 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/33/Cycling_in_Amsterdam_%28893%29.jpg/1280px-Cycling_in_Amsterdam_%28893%29.jpg'; require __DIR__ . '/partials/site-header.php'; ?>
-

Daily, weekly, monthly

-

Plan training without losing the details that matter.

-

Build routines around weight lifting, cycling, running, swimming, mobility, conditioning, or anything custom. Track volume, duration, distance, intensity, status, and notes from one dashboard.

+

Condition tracking

+

Track readings, symptoms, labs, and medications by condition.

+

Use structured logs for blood pressure, glucose, pain, oxygen, temperature, lab results, medications, and notes. The condition library links back to NIH/NLM patient-information sources.

Create a profile
- Cyclists riding through Amsterdam + People cycling outdoors
Photo: Cycling in Amsterdam (893) by FaceMePLS, CC BY-SA 2.0. @@ -27,22 +28,15 @@ require __DIR__ . '/partials/site-header.php';
-
-

Routine templates

-

Create recurring programs for strength blocks, endurance weeks, hybrid plans, or recovery cycles.

-
-
-

Workout library

-

Start with known movements like squats, deadlifts, bench press, pull-ups, runs, rides, swims, rows, HIIT, and mobility work.

-
-
-

Completion tracking

-

Mark workouts as planned, complete, or skipped and watch completion rate update across the selected range.

-
-
-

Volume and cardio totals

-

Lift volume, training minutes, and distance are summarized automatically for the current day, week, or month.

-
+ + +