Add nursing assessment packs, ward board, and nurse performance KPIs.
Deploy Ladill Care / deploy (push) Successful in 55s
Deploy Ladill Care / deploy (push) Successful in 55s
Seeds NEWS2/Braden/Morse/pain packs with visit vitals and a unit dashboard for MAR, assessments, notes, and handover activity. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"template": {
|
||||
"code": "braden",
|
||||
"name": "Braden Scale (pressure injury risk)",
|
||||
"category": "screening",
|
||||
"version": 1,
|
||||
"is_current": true,
|
||||
"is_active": true,
|
||||
"scoring_strategy": "sum_items",
|
||||
"description": "Braden Scale for predicting pressure sore risk. Lower scores = higher risk (6–23).",
|
||||
"meta": {
|
||||
"capture_roles": ["nurse", "ed_nurse", "theatre_nurse", "labour_ward_nurse", "fertility_nurse", "dialysis_nurse", "midwife", "doctor", "general_physician"],
|
||||
"specialty": "nursing",
|
||||
"pack_family": "nursing",
|
||||
"estimated_minutes": 5,
|
||||
"max_total": 23,
|
||||
"severity_bands": [
|
||||
{ "max": 9, "label": "Very high risk" },
|
||||
{ "max": 12, "label": "High risk" },
|
||||
{ "max": 14, "label": "Moderate risk" },
|
||||
{ "max": 18, "label": "Mild risk" },
|
||||
{ "max": 23, "label": "No apparent risk" }
|
||||
],
|
||||
"attribution": "Braden Scale — verify licensing for commercial redistribution of branded materials."
|
||||
}
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"code": "sensory",
|
||||
"section": "Risk factors",
|
||||
"label": "Sensory perception",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 10,
|
||||
"score_key": "braden",
|
||||
"options": {
|
||||
"max": 4,
|
||||
"choices": [
|
||||
{ "code": "1", "label": "Completely limited", "score": 1 },
|
||||
{ "code": "2", "label": "Very limited", "score": 2 },
|
||||
{ "code": "3", "label": "Slightly limited", "score": 3 },
|
||||
{ "code": "4", "label": "No impairment", "score": 4 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "moisture",
|
||||
"section": "Risk factors",
|
||||
"label": "Moisture",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 20,
|
||||
"score_key": "braden",
|
||||
"options": {
|
||||
"max": 4,
|
||||
"choices": [
|
||||
{ "code": "1", "label": "Constantly moist", "score": 1 },
|
||||
{ "code": "2", "label": "Very moist", "score": 2 },
|
||||
{ "code": "3", "label": "Occasionally moist", "score": 3 },
|
||||
{ "code": "4", "label": "Rarely moist", "score": 4 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "activity",
|
||||
"section": "Risk factors",
|
||||
"label": "Activity",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 30,
|
||||
"score_key": "braden",
|
||||
"options": {
|
||||
"max": 4,
|
||||
"choices": [
|
||||
{ "code": "1", "label": "Bedfast", "score": 1 },
|
||||
{ "code": "2", "label": "Chairfast", "score": 2 },
|
||||
{ "code": "3", "label": "Walks occasionally", "score": 3 },
|
||||
{ "code": "4", "label": "Walks frequently", "score": 4 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "mobility",
|
||||
"section": "Risk factors",
|
||||
"label": "Mobility",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 40,
|
||||
"score_key": "braden",
|
||||
"options": {
|
||||
"max": 4,
|
||||
"choices": [
|
||||
{ "code": "1", "label": "Completely immobile", "score": 1 },
|
||||
{ "code": "2", "label": "Very limited", "score": 2 },
|
||||
{ "code": "3", "label": "Slightly limited", "score": 3 },
|
||||
{ "code": "4", "label": "No limitation", "score": 4 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "nutrition",
|
||||
"section": "Risk factors",
|
||||
"label": "Nutrition",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 50,
|
||||
"score_key": "braden",
|
||||
"options": {
|
||||
"max": 4,
|
||||
"choices": [
|
||||
{ "code": "1", "label": "Very poor", "score": 1 },
|
||||
{ "code": "2", "label": "Probably inadequate", "score": 2 },
|
||||
{ "code": "3", "label": "Adequate", "score": 3 },
|
||||
{ "code": "4", "label": "Excellent", "score": 4 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "friction",
|
||||
"section": "Risk factors",
|
||||
"label": "Friction and shear",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 60,
|
||||
"score_key": "braden",
|
||||
"options": {
|
||||
"max": 3,
|
||||
"choices": [
|
||||
{ "code": "1", "label": "Problem", "score": 1 },
|
||||
{ "code": "2", "label": "Potential problem", "score": 2 },
|
||||
{ "code": "3", "label": "No apparent problem", "score": 3 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"template": {
|
||||
"code": "morse",
|
||||
"name": "Morse Fall Scale",
|
||||
"category": "screening",
|
||||
"version": 1,
|
||||
"is_current": true,
|
||||
"is_active": true,
|
||||
"scoring_strategy": "sum_items",
|
||||
"description": "Morse Fall Scale for inpatient fall risk. Higher scores = higher risk (0–125).",
|
||||
"meta": {
|
||||
"capture_roles": ["nurse", "ed_nurse", "theatre_nurse", "labour_ward_nurse", "fertility_nurse", "dialysis_nurse", "midwife", "doctor", "general_physician"],
|
||||
"specialty": "nursing",
|
||||
"pack_family": "nursing",
|
||||
"estimated_minutes": 3,
|
||||
"max_total": 125,
|
||||
"severity_bands": [
|
||||
{ "max": 24, "label": "Low risk" },
|
||||
{ "max": 44, "label": "Medium risk" },
|
||||
{ "max": 125, "label": "High risk" }
|
||||
],
|
||||
"attribution": "Morse Fall Scale — verify licensing for commercial redistribution of branded materials."
|
||||
}
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"code": "history_falling",
|
||||
"section": "Fall risk",
|
||||
"label": "History of falling",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 10,
|
||||
"score_key": "morse",
|
||||
"options": {
|
||||
"max": 25,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "No", "score": 0 },
|
||||
{ "code": "25", "label": "Yes", "score": 25 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "secondary_diagnosis",
|
||||
"section": "Fall risk",
|
||||
"label": "Secondary diagnosis",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 20,
|
||||
"score_key": "morse",
|
||||
"options": {
|
||||
"max": 15,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "No", "score": 0 },
|
||||
{ "code": "15", "label": "Yes", "score": 15 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "ambulatory_aid",
|
||||
"section": "Fall risk",
|
||||
"label": "Ambulatory aid",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 30,
|
||||
"score_key": "morse",
|
||||
"options": {
|
||||
"max": 30,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "None / bed rest / nurse assist", "score": 0 },
|
||||
{ "code": "15", "label": "Crutches / cane / walker", "score": 15 },
|
||||
{ "code": "30", "label": "Furniture", "score": 30 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "iv_therapy",
|
||||
"section": "Fall risk",
|
||||
"label": "IV / heparin lock",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 40,
|
||||
"score_key": "morse",
|
||||
"options": {
|
||||
"max": 20,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "No", "score": 0 },
|
||||
{ "code": "20", "label": "Yes", "score": 20 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "gait",
|
||||
"section": "Fall risk",
|
||||
"label": "Gait / transferring",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 50,
|
||||
"score_key": "morse",
|
||||
"options": {
|
||||
"max": 20,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "Normal / bedrest / immobile", "score": 0 },
|
||||
{ "code": "10", "label": "Weak", "score": 10 },
|
||||
{ "code": "20", "label": "Impaired", "score": 20 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "mental_status",
|
||||
"section": "Fall risk",
|
||||
"label": "Mental status",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 60,
|
||||
"score_key": "morse",
|
||||
"options": {
|
||||
"max": 15,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "Oriented to own ability", "score": 0 },
|
||||
{ "code": "15", "label": "Forgets limitations", "score": 15 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
{
|
||||
"template": {
|
||||
"code": "news2",
|
||||
"name": "NEWS2 (Nursing early warning)",
|
||||
"category": "screening",
|
||||
"version": 1,
|
||||
"is_current": true,
|
||||
"is_active": true,
|
||||
"scoring_strategy": "sum_items",
|
||||
"description": "National Early Warning Score 2 style physiological track-and-trigger for ward nursing. Scores 0–20.",
|
||||
"meta": {
|
||||
"capture_roles": ["nurse", "ed_nurse", "theatre_nurse", "labour_ward_nurse", "fertility_nurse", "dialysis_nurse", "midwife", "doctor", "general_physician", "emergency_physician", "obstetrician", "gynecologist", "obgyn"],
|
||||
"specialty": "nursing",
|
||||
"pack_family": "nursing",
|
||||
"estimated_minutes": 3,
|
||||
"max_total": 20,
|
||||
"severity_bands": [
|
||||
{ "max": 4, "label": "Low" },
|
||||
{ "max": 6, "label": "Medium" },
|
||||
{ "max": 20, "label": "High" }
|
||||
],
|
||||
"attribution": "NEWS2-inspired clinical scoring for operational use. Official NEWS2 materials remain Royal College of Physicians IP — verify licensing for branded redistribution."
|
||||
}
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"code": "respiration",
|
||||
"section": "Physiology",
|
||||
"label": "Respiration rate (breaths/min)",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 10,
|
||||
"score_key": "news2",
|
||||
"options": {
|
||||
"max": 3,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "12–20", "score": 0 },
|
||||
{ "code": "1", "label": "9–11", "score": 1 },
|
||||
{ "code": "2", "label": "21–24", "score": 2 },
|
||||
{ "code": "3a", "label": "≤8", "score": 3 },
|
||||
{ "code": "3b", "label": "≥25", "score": 3 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "spo2",
|
||||
"section": "Physiology",
|
||||
"label": "SpO₂ scale 1 (%)",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 20,
|
||||
"score_key": "news2",
|
||||
"options": {
|
||||
"max": 3,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "≥96", "score": 0 },
|
||||
{ "code": "1", "label": "94–95", "score": 1 },
|
||||
{ "code": "2", "label": "92–93", "score": 2 },
|
||||
{ "code": "3", "label": "≤91", "score": 3 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "air_oxygen",
|
||||
"section": "Physiology",
|
||||
"label": "Air or oxygen",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 30,
|
||||
"score_key": "news2",
|
||||
"options": {
|
||||
"max": 2,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "Air", "score": 0 },
|
||||
{ "code": "2", "label": "Oxygen", "score": 2 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "systolic_bp",
|
||||
"section": "Physiology",
|
||||
"label": "Systolic BP (mmHg)",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 40,
|
||||
"score_key": "news2",
|
||||
"options": {
|
||||
"max": 3,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "111–219", "score": 0 },
|
||||
{ "code": "1", "label": "101–110", "score": 1 },
|
||||
{ "code": "2", "label": "91–100", "score": 2 },
|
||||
{ "code": "3a", "label": "≤90", "score": 3 },
|
||||
{ "code": "3b", "label": "≥220", "score": 3 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "pulse",
|
||||
"section": "Physiology",
|
||||
"label": "Pulse (bpm)",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 50,
|
||||
"score_key": "news2",
|
||||
"options": {
|
||||
"max": 3,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "51–90", "score": 0 },
|
||||
{ "code": "1", "label": "41–50 or 91–110", "score": 1 },
|
||||
{ "code": "2", "label": "111–130", "score": 2 },
|
||||
{ "code": "3a", "label": "≤40", "score": 3 },
|
||||
{ "code": "3b", "label": "≥131", "score": 3 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "consciousness",
|
||||
"section": "Physiology",
|
||||
"label": "Consciousness",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 60,
|
||||
"score_key": "news2",
|
||||
"options": {
|
||||
"max": 3,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "Alert", "score": 0 },
|
||||
{ "code": "3", "label": "CVPU", "score": 3 }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "temperature",
|
||||
"section": "Physiology",
|
||||
"label": "Temperature (°C)",
|
||||
"answer_type": "score_item",
|
||||
"is_required": true,
|
||||
"sort_order": 70,
|
||||
"score_key": "news2",
|
||||
"options": {
|
||||
"max": 3,
|
||||
"choices": [
|
||||
{ "code": "0", "label": "36.1–38.0", "score": 0 },
|
||||
{ "code": "1a", "label": "35.1–36.0 or 38.1–39.0", "score": 1 },
|
||||
{ "code": "2", "label": "≥39.1", "score": 2 },
|
||||
{ "code": "3", "label": "≤35.0", "score": 3 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"template": {
|
||||
"code": "pain_nrs",
|
||||
"name": "Pain NRS (0–10)",
|
||||
"category": "screening",
|
||||
"version": 1,
|
||||
"is_current": true,
|
||||
"is_active": true,
|
||||
"scoring_strategy": "single_value",
|
||||
"description": "Numeric rating scale for pain intensity at rest / with activity.",
|
||||
"meta": {
|
||||
"capture_roles": ["nurse", "ed_nurse", "theatre_nurse", "labour_ward_nurse", "fertility_nurse", "dialysis_nurse", "midwife", "doctor", "general_physician", "emergency_physician"],
|
||||
"specialty": "nursing",
|
||||
"pack_family": "nursing",
|
||||
"estimated_minutes": 1,
|
||||
"max_total": 10,
|
||||
"severity_bands": [
|
||||
{ "max": 3, "label": "Mild" },
|
||||
{ "max": 6, "label": "Moderate" },
|
||||
{ "max": 10, "label": "Severe" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"questions": [
|
||||
{
|
||||
"code": "pain_score",
|
||||
"section": "Pain",
|
||||
"label": "Pain intensity (0 = none, 10 = worst imaginable)",
|
||||
"answer_type": "scale",
|
||||
"is_required": true,
|
||||
"sort_order": 10,
|
||||
"score_key": "pain",
|
||||
"options": {
|
||||
"min": 0,
|
||||
"max": 10,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"code": "pain_location",
|
||||
"section": "Pain",
|
||||
"label": "Location / notes",
|
||||
"answer_type": "text",
|
||||
"is_required": false,
|
||||
"sort_order": 20,
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Visit-scoped vitals for ward nursing (no consultation required).
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('care_visit_vitals', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('owner_ref')->index();
|
||||
$table->foreignId('organization_id')->constrained('care_organizations')->cascadeOnDelete();
|
||||
$table->foreignId('visit_id')->constrained('care_visits')->cascadeOnDelete();
|
||||
$table->foreignId('patient_id')->constrained('care_patients')->cascadeOnDelete();
|
||||
$table->foreignId('care_unit_id')->nullable()->constrained('care_care_units')->nullOnDelete();
|
||||
$table->unsignedSmallInteger('bp_systolic')->nullable();
|
||||
$table->unsignedSmallInteger('bp_diastolic')->nullable();
|
||||
$table->unsignedSmallInteger('pulse')->nullable();
|
||||
$table->decimal('temperature', 4, 1)->nullable();
|
||||
$table->unsignedSmallInteger('spo2')->nullable();
|
||||
$table->unsignedSmallInteger('respiratory_rate')->nullable();
|
||||
$table->string('recorded_by')->nullable();
|
||||
$table->timestamp('recorded_at');
|
||||
$table->text('notes')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['visit_id', 'recorded_at']);
|
||||
$table->index(['care_unit_id', 'recorded_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('care_visit_vitals');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user