Skip to content
ERPNext Data Model
Esc
navigateopen⌘Jpreview
On this page

Quality Procedure, Review & Corrective Action Loop

A design reference for a records-and-workflow module that documents a quality management system rather than enforcing one

1. Requirements

1.1 Functional requirements

  • Define a Procedure and organize procedures into a hierarchy, so a broad procedure can list narrower sub-procedures as its steps.
  • Declare a Goal: a named objective, optionally tied to a procedure, carrying measurable targets and an optional monitoring frequency (daily, weekly, monthly, quarterly).
  • Produce a Review against a goal — on schedule or on demand — pre-populated with that goal’s targets, so a reviewer records an actual value and a pass/fail judgment per target.
  • Record a Non-Conformance: a free-text description of something that failed to meet a procedure, with narrative fields for corrective and preventive action taken.
  • Record a Corrective/Preventive Action: a container of resolution steps, each assignable to a person with a completion date and its own open/completed status.
  • Record Meetings: an agenda list and a minutes list, where each minute entry can be tagged as documenting a specific Review, Action, or Feedback record.
  • Capture Feedback against a reusable template of rating parameters.

1.2 Non-functional requirements

  • Traceability, not automation: every record type exists to be read back later, not to drive a downstream process.
  • Low ceremony: most fields are optional and statuses default to an open state.

1.3 Constraints

  • Only the Procedure is a tree; every other record is flat, at most cross-linked to a Procedure and/or a Goal.
  • Statuses that look like workflow summaries (Review, Action) are computed from child-row statuses a person enters directly; the module never independently judges whether a target was met.

2. High-Level Design

2.1 Component diagram

The dotted edges are the point: nearly every cross-record connection here is an optional link a user may or may not fill in, not a relationship the code enforces. The one solidly code-maintained structure is Procedure’s own parent/child tree and the scheduler-to-Review path below.

2.2 Data flow — the one automated path

A daily scheduled check is the module’s only background process. It loops over every Goal, compares its monitoring frequency to the current date (day-of-month, weekday name, or start-of-quarter month, plus every run for daily), and creates a new Review on a match. A Review created with no target rows yet — exactly what this path produces — copies each target row from the Goal on save. Everything after that is manual: a person enters a measured value and marks each row Open, Passed, or Failed by hand, and only then does the header status recompute from those rows.


3. Deep Dive

3.1 Data model

Procedure — the module’s only tree-structured entity: a name, an optional owner, and a child table of process steps that may each reference another Procedure as a sub-procedure.

Goal and Review (each with a matching child table of targets) — a Goal names an objective, an optional Procedure, a monitoring frequency, and target rows; a Review is one goal-check occurrence whose child rows mirror those targets but add an actual value and a per-row Open/Passed/Failed status only a person sets.

Non-Conformance — a subject, a required Procedure link, an Open/Resolved/Cancelled status, and two rich-text fields literally named for corrective and preventive action. No child table, no structured resolution tracking — the “action taken” is prose.

Corrective/Preventive Action (+ Resolution child) — marked Corrective or Preventive, with optional links to a Review, Goal, Procedure, and Feedback record, plus resolution rows (problem, resolution, responsible person, completion-by date, Open/Completed status). Unlike Non-Conformance, its header status recomputes on every save to Open if any resolution row is still Open, else Completed.

Meeting (+ Agenda, Minutes children) — agenda text blocks and minute entries; each minute entry names one of exactly three record types (Review, Action, Feedback) plus a reference to that specific record. Its own Open/Closed status defaults to Open and is otherwise a plain field.

Feedback Template and Feedback (each with a matching parameter child table) — a template names a reusable rating-parameter list; a Feedback record targets a user or customer and, saved against a template with no parameters yet, copies the template’s list in with a default rating.

3.2 The tree algorithm — the one real piece of logic here

The Procedure hierarchy is maintained two ways at once, and most of the module’s controller code exists to keep them consistent: a conventional nested-set left/right index pair for fast ancestor queries and tree-view rendering, plus an independent explicit child table on each parent listing its sub-procedures by reference. On every save, the controller reconciles both directions — stamping a parent field onto any newly-listed child, clearing it from any removed one, and re-splicing a procedure into its new parent’s child list (and out of its old one) when the parent link is edited directly rather than through the table. A guard rejects a child row naming a procedure that already has a different parent elsewhere, so one sub-procedure cannot silently attach under two parents. Deletion clears leftover child-table references first — and, unusually for a nested-set implementation, the root node itself may be deleted.

3.3 Error handling

There is little to report, and that is itself the finding. Non-Conformance and Action have no validation beyond the Action’s status roll-up: nothing stops a Non-Conformance being marked Resolved with its corrective-action field blank, and nothing flags an overdue Resolution date. The Meeting’s Open/Closed field has no code path that ever sets it to Closed — it is a plain toggle. The Review header status follows a simple priority rule (any row Open wins, then any row Failed, else Passed), but every row status feeding that rule is human judgment, not a computed comparison against the target value beside it.


4. Scale and Reliability

This module carries negligible load. Its only background job — the daily goal-frequency scan — is a linear pass over the Goal list, cheap at any count an organization would realistically configure, since goals are hand-authored objectives, not transactional records. The Procedure tree’s dual bookkeeping runs synchronously inside each save and touches only the parent and the changed child, so cost scales with edits, not tree size. Nothing here is concurrency-sensitive: these are low-frequency, human-paced records.


5. Trade-off Analysis

Decision Trade-off
Cross-record links (Procedure, Goal, Review, Feedback) are optional, not enforced Cheap partial adoption, but nothing guarantees related records actually reference each other.
Non-Conformance and Action are separate record types with no link between them Each stays simple, but a reviewer must manually notice when they describe the same problem; nothing connects them.
Review and Action header statuses are computed roll-ups of child rows Saves a manual step, but trusts whatever a person already typed on the rows — no independent check against the target exists.
Procedure hierarchy stored twice (nested-set indices + explicit child table) Fast tree queries and an editable child list on one form, at the cost of synchronization code keeping both in agreement.
Review creation is a full daily scan of all Goals, not a per-goal trigger Simple and cheap at expected volume, but a due goal is only discovered on the next daily run.
Meeting Minutes reference a Review/Action/Feedback record via a type-plus-name pair One child shape covers three target types, but nothing validates the named record still exists or matches its declared type.

6. What to Revisit as the System Grows

  • No handoff between Non-Conformance and Action. They read as two halves of one incident-response idea but are unrelated record types that only sit together in the same UI grouping. A real corrective-and-preventive-action workflow needs an explicit link between them.
  • No overdue or SLA enforcement anywhere — an unresolved Non-Conformance, an open Meeting (its status field has no code path that ever closes it), or a missed Resolution completion date are all silently tolerated.
  • Review scoring is entirely manual even though each row already carries both target and actual value; computing Passed/Failed from the two would close the loop’s weakest link.
  • Dynamic references on Minutes rows are unvalidated; a mistyped one would fail silently rather than surface as a broken link.

Was this page helpful?