Touch and Dwell

oee station time-tracking

Two distinct measures of “time on a job at a station”. Both are central to the stations view.

Definitions

MeasureDefinitionSource
TouchSum of operator time entries on the job at this station. Many shifts to one job.oee_time_entries rows where batch_id = job.id AND user_id IS NOT NULL
DwellWall-clock since the job arrived at this station. Ticks regardless of operator activity.NOW() - v_oee_batches.actual_start_ts

A job is the per-station instance of a batch. When a batch moves to a new station a new job is instantiated there, so Touch and Dwell are always scoped to one (job, station) pair.

Why both

  • Touch answers “how much labor have we spent on this job?” — the input to OPS Efficiency (Std Hours ÷ Touch).
  • Dwell answers “how long has this job been sitting here?” — catches batches stuck in the station with no operator attention.

A batch with high Dwell but flat Touch is stalled — operators left, the batch hasn’t moved, but no labor is being recorded. The station dashboard surfaces this as a flat segment on the Touch chart.

Standard for comparison

standard_hours is configured per (product, station) in oee_product_equipment_config. It’s the expected Touch on this product at this station.

The station view derives three warning levels from Touch vs standard:

LevelTrigger
greenTouch < 1× standard
yellowTouch ≥ 1× standard
redTouch ≥ 2× standard

If no standard is configured for the (product, station) pair, the job has no warning level — the system never defaults to yellow on absent data. KPI tiles render instead of 0.0.

Touch sum formula

SUM(CASE
    WHEN te.duration_override_minutes IS NOT NULL THEN te.duration_override_minutes
    WHEN te.end_ts IS NOT NULL THEN EXTRACT(EPOCH FROM (te.end_ts - te.start_ts)) / 60.0
    ELSE EXTRACT(EPOCH FROM (NOW() - te.start_ts)) / 60.0
END)
FROM oee_time_entries te
WHERE te.batch_id = <job.id>
  AND te.user_id IS NOT NULL

Both 'shift'-tagged (live clock-in) and 'labor'-tagged (retroactive gap-fill) entries are valid Touch contributions. The filter is on user_id IS NOT NULL, not on tag.

Schema gotcha — trg_prevent_station_equipment_time_entry

A trigger on oee_time_entries silently DROPs any insert where equipment_id IS NOT NULL AND user_id IS NULL and the equipment is a station. Touch entries must always be operator-scoped — the station context is implied via batch_id (the job belongs to one station).

Synthetic test entries that need to read as Touch must therefore be (user_id NOT NULL, equipment_id NULL, batch_id = job.id), tagged with 'shift' so the My Shifts UI and labor analytics also recognize them.

See Also