Skip to main content

Parivar — Clinical Reporting Module

Companion to the Technical Architecture blueprint. Full specification of the nurse reporting workflow for the NestJS backend, Next.js admin/web, and the Flutter/React Native nurse app.

This is the most behaviour-heavy part of the platform. The old API reference modelled "assessments" as a single flat table; the live system is a multi-form reporting workspace with drafts, versioning, a 24-hour edit window, and an approval loop. This document is the source of truth for that workflow and supersedes the simplified ClinicalModule section in the architecture doc.


1. Eligibility — when a report can be created

A report can be created only while its visit is in_progress. The nurse must first Start Visit, which:

  • sets visits.status = 'in_progress', and
  • sets nurses.status = 'on_visit'.

The Reports screen lists only visits.status === 'in_progress' as selectable. In NestJS this is a guard on POST /visits/:id/assessment*: reject with 422 BUSINESS_RULE (VISIT_NOT_IN_PROGRESS) otherwise.


2. The four form types (+ one read-only)

The reporting screen is not one form — it is a tabbed workspace over five surfaces:

TabAvailabilityTableRequired?
Visit Report (Regular)Alwaysassessments✅ Mandatory for every visit
First Visit AssessmentOnly if no first_visit_assessments row exists for the parentfirst_visit_assessmentsOnly on the first-ever visit
Wound CareAlways (optional)wound_care_forms❌ Optional, multiple per visit
Clinical ModulesAlways (optional)clinical_modules❌ Optional
View Admission FormOnly if admission_forms existsadmission_forms (read-only)N/A

⚠️ "First visit" is determined by absence of a first_visit_assessments row for the parent, not by visits.visit_type (which is only routine / follow_up). Do not gate this on visit_type.

Suggested NestJS routes

ActionRoute
Save/submit regular reportPUT /visits/:visitId/assessment (draft) · POST /visits/:visitId/assessment/submit
First visit assessmentPOST /visits/:visitId/first-visit-assessment
Add wound recordPOST /visits/:visitId/wound-care
Clinical modulePOST /visits/:visitId/clinical-module
Read admission formGET /parents/:parentId/admission-form

3. Regular Visit Report — field specification (assessments)

Section A — Vital Signs

FieldColumnTypeRequiredRangeNotes
BP 1 Systolicbp_systolic_1int50–250Paired with diastolic via "/"
BP 1 Diastolicbp_diastolic_1int30–150
BP 2 Systolicbp_systolic_2int50–250Optional second reading
BP 2 Diastolicbp_diastolic_2int30–150
Respiratory Raterespiratory_rateint4–60breaths/min
Pulse Ratepulse_rateint20–300bpm
Temperaturetemperaturedecimal30–45°C
SpO2spo2decimal50–100%
Blood Sugarblood_sugar_valuedecimalConditional20–600Required if the parent's admission_forms.is_diabetic = true
Blood Sugar Typeblood_sugar_typeblood_sugar_typewith sugarfasting / random

Diabetic detection: read admission_forms.is_diabetic for the parent; if true, surface blood sugar as a required, highlighted field.

Section B — Observations

FieldColumnTypeRequiredOptions
General Conditiongeneral_conditiongeneral_condition enumnormal, weak, dizzy, stable, improving, deteriorating, critical, other
Concerns / IssuesconcernstextFree text
Progress Notesprogress_notestextFree text

Section C — Follow-Up

FieldColumnTypeRequiredNotes
Doctor Review Required?doctor_review_requiredboolRoutes to doctor queue if true
Emergency Escalation?emergency_escalationboolIf true → immediate high-severity admin alert + likely escalations row

Section D — Additional Notes

nurse_notes (text, optional).

Section E — Photo Documentation

FieldColumnTypeConstraints
Photo consent(client state)boolMust be ON to enable upload
Photosphoto_pathstext[]≤ 5 photos, 10 MB each, JPG/PNG/HEIC

Storage path: {parentId}/{visitId}/{timestamp}-{filename} in the reports bucket. Upload is non-blocking — a failed photo upload must not block report submission.

Section F — Nurse Confirmation (mandatory)

nurse_confirmed (bool, ✅): "I confirm this report reflects the patient's condition during the visit." Submit is disabled until checked.

Server-managed columns

nurse_id (from nurses, not the user id), client_user_id (copied from visits.client_user_id), is_draft, submitted_at, approval_status, admin_viewed, version_count.


4. Draft vs. Submit

ButtonValidationSets
Save DraftNoneis_draft = true, submitted_at = null — visit stays in_progress
Submit ReportFull (Section §6 required fields)is_draft = false, submitted_at = now(), approval_status = 'pending', admin_viewed = false, version_count = 1 — visit → report_submitted

Drafts live in a separate "Drafts" tab with a count badge and "Last saved X ago", resumable via Continue. A draft never changes visit status.

🔁 Rebuild note. Keep draft autosave on the client; persist drafts via PUT /visits/:visitId/assessment with is_draft=true. The submit endpoint runs the full validator (class-validator DTO) and the state transition in one transaction.


5. Edit / resubmit — the 24-hour window

After submission a nurse may edit within 24 hours and only while not yet approved.

Rules:

  • isWithinEditWindow = (now - submitted_at) < 24h.
  • Blocked once approval_status === 'approved'.
  • Each edit writes a snapshot to assessment_versions and increments version_count.
  • Resubmission resets approval_status = 'pending' and admin_viewed = false.
  • After 24h the report locks (🔒) — "contact admin to change".

Version snapshot

assessment_versions.insert({
assessment_id, version_number, nurse_id, nurse_name,
action: "submitted" | "edited",
snapshot: { ...full assessment at this version }
})

Implement the window check server-side (never trust the client clock): compare submitted_at against server now() in the edit guard, returning 422 EDIT_WINDOW_EXPIRED.


6. Validation summary

Required to submit (not for drafts): visit selected, bp_systolic_1, bp_diastolic_1, respiratory_rate, pulse_rate, temperature, spo2, general_condition, progress_notes (non-empty), nurse_confirmed = true, plus blood_sugar_value when the parent is diabetic.

Vital ranges: Systolic 50–250 · Diastolic 30–150 · Pulse 20–300 · Temp 30–45 · SpO2 50–100 · Respiratory 4–60 · Blood Sugar 20–600.

Inputs are type="text" on the client to avoid mobile spinner widgets; parse to number on submit. Enforce ranges again on the server.


7. First Visit Assessment (first_visit_assessments)

A one-time comprehensive intake, lock-once (is_locked = true, locked_at set on save; no draft concept; single "Save Assessment" button). Six sections:

Vital Signs (single BP reading): bp_systolic, bp_diastolic, pulse_rate, respiratory_rate, temperature, spo2, blood_sugar_value, blood_sugar_type.

Mobility: mobility_level (independent/with_aid/wheelchair/bedbound), mobility_aid (text), fall_risk (bool), fall_history (text, shown if fall_risk).

Nutrition: nutrition_status (adequate/poor/at_risk), weight, height, bmi (auto, read-only), swallowing_difficulty (bool), dietary_requirements (text).

Cognition: cognition_level (alert/confused/disoriented/unresponsive), orientation (text), memory_issues (bool), communication_ability (text).

Skin: skin_condition (intact/dry/fragile/broken), pressure_areas (bool), pressure_area_details (text, if checked), existing_wounds (bool), wound_details (text, if checked).

Continence: continence_status (text), continence_aids (text), catheter (bool), catheter_type (text, if checked).

After locking, the tab becomes "View First Visit" (read-only). In NestJS, reject edits to a locked record with 409 CONFLICT (FIRST_VISIT_LOCKED).


8. Wound Care (wound_care_forms)

Multiple wound records per visit (additive — each save creates a new record; existing records render as read-only cards above the form).

FieldColumnTypeRequiredOptions
Wound Typewound_typeenumsurgical, pressure_ulcer, diabetic_ulcer, venous_ulcer, arterial_ulcer, laceration, burn, skin_tear, other
Locationwound_locationtext
Length/Width/Depth (cm)length_cm/width_cm/depth_cmdecimal
Colourwound_colourenumred (granulating), yellow (sloughy), black (necrotic), pink (epithelialising), green (infected)
Dischargedischarge_typeenumnone, serous, sanguineous, purulent, serosanguineous
Photophoto_pathfileSingle photo → wound-photos bucket
Dressing Plandressing_plantext
Review Requiredreview_requiredbool
Review Datereview_datedateShown if review_required

Photo path: {parentId}/{visitId}/{timestamp}-{filename} in wound-photos. Camera capture uses capture="environment".


9. Clinical Modules (clinical_modules)

Optional structured add-ons attached to a visit (FKs visit_id, nurse_id, parent_id). Treat as a flexible module container; specific module fields weren't enumerated in the source — confirm the catalogue with the clinical team and model each module as a typed payload (jsonb or a child table per module).


10. Submission side effects & state machine

On submit (not draft), inside one transaction + post-commit events:

  1. visits.statusreport_submitted.
  2. Emit assessment.submitted → create an admin_alerts row and queue the report email (send-notification-email equivalent → MailService, { type: 'assessment_submitted', assessment_id }).
  3. If emergency_escalation = true → high-severity alert (and create an escalations row of type urgent_health).

Approval loop (admin):

in_progress
├─ Save Draft ──────────► assessments.is_draft = true (visit stays in_progress)
└─ Submit Report ───────► assessments.is_draft = false
visits.status = report_submitted
├─ Admin Approve ─► visits.status = approved
│ assessments.approval_status = approved
│ → insert nurse_earnings (pending), send purchase email + PDF
└─ Admin Reject ──► visits.status = in_progress
assessments.approval_status = rejected
└─ Nurse edits & resubmits (≤24h) ─► report_submitted
(24h elapses) ────► report locked; admin contact required

NestJS endpoints: POST /admin/assessments/:id/approve, POST /admin/assessments/:id/reject. Approval inserts earnings and fires the customer email with the report PDF link.


11. Cache invalidation (client) / event fan-out (server)

The web/mobile clients invalidate these query keys after create/update; the server should emit the matching realtime events so other clients refresh without polling:

Client query keyServer event → realtime room
nurse-assessments, nurse-visitsvisits:nurse:<nurse_id>
client-assessments, client-pending-reports, client-visitsassessments:parent:<parent_id>, visits:client:<user_id>
admin-assessments, admin-visits, unviewed-reports-countvisits:admin, admin_alerts
assessment-versions (on edit)

12. Rebuild checklist for this module

  • DTOs with class-validator enforcing every range and conditional (diabetic → blood sugar).
  • Visit-state guard (in_progress required) on all create routes.
  • Draft autosave endpoint separate from submit; submit runs validation + transition in a transaction.
  • Server-side 24h edit-window check; version snapshot written on every edit.
  • First-visit lock enforced server-side; wound records additive.
  • Non-blocking photo upload via pre-signed URLs (reports, wound-photos buckets).
  • Approval/reject endpoints emit earnings + email + realtime events.
  • Idempotency on submit (avoid duplicate reports on retry) using a request key in Redis.

End of Clinical Reporting Module.