By Isaac Muthui, CEO, Tamalaki Business Network Ltd. Originally published at factoraerp.com.
If you build production or MES/ERP software for food manufacturers, here is a failure mode worth designing out: the next product's production order can start on a line while the previous product is still, in practice, on it.
In small and mid-sized food and agro factories in Kenya, where I work, changeovers between SKUs on the same line (flavoured yoghurt to plain, peanut snack to plain snack, spice blend A to blend B) are where residue, leftover labels, work in progress and stale machine settings carry over. The operational fix is a line clearance checklist. The software fix is to make clearance an explicit event in the model, so the system cannot start the next order until it has happened.
This post covers how to model that, plus the eight-point checklist that acts as the spec.
The anti-pattern: production orders without a line state
A common design looks like this:
-
production_orderhasstatus(planned,in_progress,completed) and aline_id. - Starting an order just flips its status to
in_progress. - Nothing stops two orders being
in_progresson the same line, or a new order starting while the previous one has unreturned WIP and packaging. - Cleaning, if recorded at all, lives in a separate log with no link to either order.
The result: the batch record says product B started at 12:00, but nothing in the data says whether product A was ever cleared off the line.
Model the line, not just the order
Give each line its own state machine, and make orders depend on it:
RUNNING(order A)
│ close_order(A): final qty, lot, WIP/packaging returned
▼
CLOSED_OUT(A)
│ record_cleaning(programme, by, finished_at)
▼
CLEANED
│ verify_clearance(checker ≠ cleaner, checks[], result)
▼
CLEARED ──(fail)──► CLEANED (re-clean, re-verify)
│ setup(order B): recipe/BOM version, settings, packaging, coder
▼
SETUP(B)
│ first_off_qc(B, result)
▼
RUNNING(order B) ──(fail)──► SETUP(B)
Rules worth enforcing in code, not in the UI:
-
One active order per line.
start_order(B)is only valid when the line is inSETUP(B)and first-off QC has passed. -
No skipping states. There is no transition from
RUNNING(A)toRUNNING(B). Not even for admins without a recorded override. -
Changeover type drives the required checks. Derive the type from the from/to products: same product, different pack (
light); different recipe (full); allergen profile changes from contains to free-from (allergen). Each type maps to a cleaning programme and a set of required verification checks. -
Segregation of duties.
verify_clearance.checked_bymust differ fromrecord_cleaning.cleaned_by, and the releaser must hold a QA/supervisor role. -
Close-out is a precondition.
close_order(A)should fail if issued packaging or WIP has not been returned, consumed or explicitly scrapped.
A minimal schema sketch:
create table line_changeover (
id uuid primary key,
line_id uuid not null references line(id),
from_order_id uuid not null references production_order(id),
to_order_id uuid references production_order(id),
changeover_type text not null check (changeover_type in ('light','full','allergen')),
state text not null check (state in
('closed_out','cleaned','cleared','setup','released')),
cleaning_programme text,
cleaned_by uuid references app_user(id),
cleaned_at timestamptz,
checked_by uuid references app_user(id),
checked_at timestamptz,
released_by uuid references app_user(id),
released_at timestamptz,
constraint checker_not_cleaner check (checked_by is null or checked_by <> cleaned_by)
);
create table changeover_check (
changeover_id uuid references line_changeover(id),
check_code text not null, -- e.g. 'wip_removed','no_residue','old_labels_removed'
result text not null check (result in ('pass','fail','n_a')),
note text,
recorded_by uuid references app_user(id),
recorded_at timestamptz not null default now()
);
And the guard on starting an order:
function startOrder(line: Line, order: ProductionOrder, user: User) {
const co = line.currentChangeover;
if (!co || co.toOrderId !== order.id) throw new Error("No changeover for this order");
if (co.state !== "setup") throw new Error(`Line not ready: ${co.state}`);
if (!requiredChecksPassed(co)) throw new Error("Clearance checks incomplete");
if (!order.firstOffQc?.passed) throw new Error("First-off QC not passed");
if (!user.roles.includes("line_release")) throw new Error("Not authorised to release line");
co.state = "released";
co.releasedBy = user.id;
co.releasedAt = now();
order.status = "in_progress";
}
The point is not the exact code. It is that "the line is cleared" becomes a row with names and timestamps, and starting the next order depends on it.
The eight checks (your spec)
These become the check_code values in changeover_check. Your customer's SOP and HACCP plan decide which apply to each changeover type.
- Previous product and batch closed out. Final quantity and lot recorded; WIP, part-filled containers and samples removed or segregated; unused materials and packaging returned under lot identity.
- Food-contact equipment cleaned or sanitised per SOP (or the CIP programme run) for this changeover type. Tetra Pak Kenya describes CIP as preparing equipment after a run or when switching a line from one recipe to another.
- Visual check, plus any required verification, confirms no previous residue, done by someone other than the cleaner.
- Only the new product's packaging, labels and coding on the line. Old labels and lids removed; coder changed and a printed sample checked.
- Allergen switch handled. Stricter clean, dedicated tools, colour-coding, allergen ingredients removed from the area.
- Correct recipe/BOM version and process settings loaded, and the staged material lots match those issued to the new order.
- Line documents updated. From-product/batch, to-product/batch, times, who cleared and who released.
- First-off / start-up QC passed before full-speed running; start-up packs held until they pass.
Why this matters for compliance-shaped data
Kenyan food factories work against guidance like the Ministry of Health Checklist for Food Hygiene Licensing (April 2023), which expects cleanable food-contact surfaces, hazard monitoring during processing, cleaning and disinfection SOPs and a HACCP plan, and the East African code of practice EAS 39:2001, which calls for documented cleaning programmes with records showing they were followed. KEBS factory inspections for the Standardization Mark look at process controls and records. Software doesn't make a plant compliant. But if your data model stores clearance as a first-class event, the records an inspector or customer asks for already exist, linked to the batches they cover.
It also pays off for traceability: when a complaint arrives, you can answer which run preceded the affected batch, what changeover type it was, and who released the line.
Practical tips for builders
-
Default to blocked. A new line changeover starts in
closed_out, neverreleased. - Make overrides loud. If an override exists, require a reason and a second approver, and surface it on the batch record.
- Expose changeover time. Store state timestamps so planners can see real clearance durations and put them in the schedule.
-
Offline matters. Many plant floors have patchy connectivity. Let checks be recorded on a tablet offline and synced, but don't allow
releaseduntil the sync confirms the required checks.
Where we apply this
At FactoraERP we link production orders to recipes, BOM versions, issued lots and batch records for food and agro manufacturers in East Africa. Modelling the changeover explicitly is what lets the batch record show which lots went into which run and who released the line.
The operations version of this checklist, with an FAQ for factory teams, is on our blog: Line Clearance Checklist: 8 Checks Before You Start the Next Product on a Kenyan Food Line.
Operations guidance, not legal advice.
Top comments (0)