HH/docs/workflows.md
ismail 45b75eb9ef
All checks were successful
Build and Push Docker Image / build (push) Successful in 2m27s
fix: align workflow behavior (Phase 1) + lucide icon-race mitigation
Behavioral consistency across complaint/inquiry/observation (re-run: 0 FAIL):
- activation gate on complaints: complaint_send_to + send_to_department_form now
  reject status=open ("Activate this complaint before sending it to a department")
- observation resolve dead-end fixed: observation_change_status now allows
  hospital_admin (was triage_perm/px_admin only) + added a Resolve action on the
  observation detail page -> accepted dept responses can be resolved from the flow
- status validation: Observation.clean() rejects invalid statuses + a DB
  CheckConstraint (migration 0016 normalizes legacy "new"->"open" first)
- inquiry sent_to_department consistency: inquiry_transfer_to_department now also
  sets sent_to_department=True/At (matches observation/complaint for cross-module queries)

Lucide icon-race mitigation: added a defensive `window.lucide || {createIcons:noop}`
shim to the three base layouts + standalone CDN pages (login, select_hospital,
password reset) so the "lucide is not defined" ReferenceError can't throw during
navigation races. Audit listener classifies any residual occurrence as WARN (cosmetic).

Docs: docs/workflows.md records the intentional complaint vs inquiry/observation
differences (multi-dept join + manager review vs single-dept flat) + the field-name map.

Specs: champion spec now activates before send (matches the new gate).
2026-06-14 23:27:03 +03:00

3.7 KiB

Patient-feedback workflow architecture

This document records the intentional differences between the three department-response workflows so they don't get "fixed" into inconsistencies.

Shared rules (apply to all three)

  • Activation gate: an item cannot be worked on or sent to a department until it has been activated (open → in_progress). Every send-to-department endpoint rejects status == open.
  • Status vocabulary: open → in_progress → resolved → closed (complaints additionally have partially_resolved, cancelled, pending_external, ovr_pending). Invalid statuses are rejected at the model (clean()) and DB (CheckConstraint) level.
  • "Sent" signal: sent_to_department (bool) + sent_to_department_at is set by every module's send flow so cross-module reporting works uniformly.
  • Reject loops: when PX marks a department response not_acceptable, the response is cleared and the item returns to the champion.

Per-module differences (intentional)

Complaint — multi-department + manager review + investigation

  • Uses a join model ComplaintInvolvedDepartment so multiple departments can be involved in one complaint simultaneously.
  • Two-level review: champion submits a response → department manager approves/rejects → PX accepts/rejects → resolve.
  • Investigation sub-flow: the champion can create questions that are emailed (token links) to involved staff, who answer; the champion reviews the answers before writing the department response.
  • Resolve is direct from any active status.

Inquiry — single department, no manager review

  • Flat fields on Inquiry (transferred_to_department / outgoing_department
    • department_response_en + dept_response_acceptance_status). One department at a time.
  • One-level review: champion responds → PX accepts/rejects → resolve.
  • Resolve requires a PX response (inquiry.response, set via inquiry_respond) — the PX-team must write their reply to the inquirer before the inquiry can be marked resolved.
  • Token-response path: emailed link to /inquiries/<id>/respond/<token>/.

Observation — single department, no manager review

  • Flat fields on Observation (assigned_department + department_response_en
    • dept_response_acceptance_status). One department at a time.
  • One-level review: champion responds → PX accepts/rejects → resolve.
  • Status change (observation_change_status) requires the triage_observation permission OR px_admin OR hospital_admin.
  • Token-response path: emailed link to /observations/<id>/respond/<token>/.

Field-name reference (the "same concept, different name" map)

Concept Complaint (join) Inquiry Observation
target dept ComplaintInvolvedDepartment.department transferred_to_department / outgoing_department assigned_department
sent flag ComplaintInvolvedDepartment.sent sent_to_department sent_to_department
response text response_notes_en/ar department_response_en/ar department_response_en/ar
response at/by response_submitted_at (+ ComplaintExplanation) department_responded_at/_by department_responded_at/_by
acceptance acceptance_status dept_response_acceptance_status dept_response_acceptance_status
manager review manager_review_status — (none) — (none)
token ComplaintExplanation / InvestigationResponse response_token response_token

The naming drift between complaint and the other two is a direct consequence of the architecture difference (join vs flat) and is intentional.