Bin-Level Lot Genealogy
Bin-Level Lot Genealogy is the discipline of tracking material at the smallest physical container unit — bin / IBC / drum / pail / tote / sub-container — not just at the lot level. A lot can contain 12 IBCs; if one IBC is contaminated, lot-level recall pulls all 12 unnecessarily — bin-level genealogy pulls the affected one + traces forward only to the batches that consumed it. The discipline is built from four primitives: container_id (unique to a single physical vessel), parent_lot_id (the lot the container belongs to), state (intact / opened / consumed / split / merged / scrapped / returned / quarantined), and event_chain (receipt → put-away → moves → opens → sub-charges → returns → close-out). Every move + every open + every sub-charge writes a CTE per FSMA-204 KDE/CTE rules, and the chain reconstructs forward + backward via Postgres recursive CTE at sub-second response for recall + investigation queries. 21 CFR 211.184 + 211.188(b)(11) + 211.196 + 820.65 + 820.184(c) + 111.260(g) + 111.610 + FSMA 204 + EU FMD + DSCSA + UDI all converge on the same point — the regulatory genealogy must support 'identify every batch that consumed material from this specific container' in minutes, not days. A lot-level system that requires manual reconstruction to answer a sub-container query is the §211.196 + 820.198 + FSMA-204 finding the first time a high-stakes recall arrives.
01The four primitives that make bin-level genealogy queryable
Bin-level genealogy is built from four primitives. Get any of them wrong and the graph becomes inconsistent — the rebuild cost during a recall is days of paper-trail reconciliation when the FDA expects an answer in hours.
| Primitive | What it is | Why it matters | Failure mode if missing |
|---|---|---|---|
| container_id | Globally unique identifier per physical vessel (bin / IBC / drum / pail / tote / sub-container). Typically GS1 SSCC or facility-prefixed serial. Stamped + barcoded + 2D-coded onto the container itself. | The graph node — every event references container_id; lot-only references collapse 12 containers into 1 row and lose the resolution. | Recall scope inflates from 1 affected bin to 12 unaffected bins; investigations lose the chain at the first split. |
| parent_lot_id | Reference to the manufacturing lot the container belongs to. Many-to-one: a lot can have N containers; a container belongs to exactly one lot at a time. | The aggregation key for lot-level reports + supplier-quality + regulatory submissions while preserving sub-container resolution. | Reports look right at lot level but cannot answer 'which IBC of lot X went to batch Y'. |
| state | Lifecycle enum: intact / opened / consumed / split / merged / scrapped / returned / quarantined / re-packed / under-investigation. State transitions are immutable audit-trail events with operator + UTC + reason. | Tells the engine what queries to allow + what reservations to honour. An 'opened' container cannot be moved without close-down; a 'quarantined' container cannot be picked. | Pick lists serve quarantined containers; opened containers move with residue inside; investigations can't reconstruct what state a container was in at a past timestamp. |
| event_chain | Chronological sequence of CTEs per container: receipt → put-away → moves → opens → sub-charges → returns → close-out → ship → scrap. Each event row contains container_id + event_type + UTC + operator + supervisor (where required) + reason + reference to BMR / WO / pick / shipment. | The raw data the recursive-CTE genealogy graph walks; the §211.192 + 820.198 + FSMA-204 audit-trail evidence; the ALCOA+ contemporaneity gate. | Genealogy queries return incomplete chains; recall queries miss downstream batches; investigations rely on operator memory. |
02The eleven events that change the genealogy graph
Every change to the physical world that affects material identity or location must write a genealogy event. Skipping events is the silent killer — the graph drifts from reality + the gap surfaces during the recall when it matters most.
| Event | What triggers it | What the row captures | Who signs |
|---|---|---|---|
| receipt | Container arrives at receiving dock; scan against PO + ASN | container_id, parent_lot_id, supplier, PO ref, ASN ref, gross + tare + net mass, CoA reference, initial state=intact | Receiver + warehouse supervisor |
| put-away | Container moves from receiving to designated storage location | from_location, to_location, operator, UTC; state unchanged | Operator scan (no supervisor required for routine put-away) |
| move | Container relocates within the warehouse (e.g. zone change, FEFO repositioning, line-side staging) | from_location, to_location, operator, UTC, reason; state unchanged | Operator scan |
| open | Container is broken (lid removed, seal cut) for the first time | container_id, operator, UTC, WO ref, post-open container mass, state→opened | Operator + supervisor (two-person for potent / cytotoxic / hormone) |
| sub-charge | Material drawn from container for a specific weighment / batch charge | container_id, WO ref, charge sequence, pre-charge mass, post-charge mass, mass_drawn, dispense_result_id reference; state remains opened | Operator e-sig + supervisor witness per §211.101(c) |
| close-down | Container re-sealed at end of session (shift / WO completion / planned close) | container_id, operator, UTC, remaining mass, re-seal verification, state remains opened-closed-down (re-openable) | Operator + supervisor |
| consume | Container fully exhausted (remaining mass ≤ residue envelope) | container_id, final residual mass, final WO ref, state→consumed; container removed from pickable inventory | Operator + supervisor |
| return | Residual material returned to inventory (back to source lot) with chain-of-custody | container_id, destination_container_id (or original), mass returned, WO ref, paired inventory_transaction_id, state may revert to opened-closed-down or original container's state | Operator + supervisor (mandatory two-person) |
| split | One container divided into two or more sub-containers (e.g. large IBC repacked into smaller totes) | parent_container_id, child_container_ids[], mass per child, operator, UTC, reason, parent state→split (terminal) | Operator + supervisor + QA (especially for sub-lot regulated material) |
| merge | Two or more containers combined into one (e.g. two near-empty drums consolidated). Typically prohibited for regulated material; allowed only with QA approval + risk assessment. | child_container_ids[] → parent_container_id, mass per child, combined mass, operator, UTC, QRM ref, QA approval ref, child states→merged (terminal) | Operator + supervisor + QA + QRM (mandatory) |
| scrap / quarantine | Container removed from usable inventory for quality reasons (OOS, OOT, damage, expiry, deviation) | container_id, reason, deviation ref, destination (scrap bin / quarantine cage), operator, UTC, state→scrapped or quarantined | Operator + supervisor + QA |
| re-pack | Container repackaged due to damage or container failure (material identity preserved; container ID changes) | old_container_id → new_container_id, reason, operator, UTC, mass before + after, old state→re-packed (terminal), new container state=intact (with re-pack lineage) | Operator + supervisor + QA |
03Building the genealogy graph — recursive CTE in Postgres
Bin-level genealogy is a directed acyclic graph (DAG) where nodes are containers + batches + work orders + shipments, and edges are sub-charge / split / merge / consume / ship events. Postgres recursive common table expressions (CTEs) traverse the graph backward (input lots that fed a batch) + forward (batches that consumed material from a container) with millisecond response times when the indexes are right.
Forward query (recall scenario): 'Container 940123456789012345 has been recalled — give me every batch + every shipment + every customer that received material derived from it.' The recursive CTE walks sub-charge events from the container forward to WOs, then from WOs to finished-product lots, then from finished-product lots to distribution shipments, then from shipments to customer accounts. Returned as a tree with hop count per node; total query time under 500 ms on a 10-million-row event table with correct (container_id, event_type, utc) compound indexes.
Backward query (investigation scenario): 'Finished-product lot FP-2025-0341 failed dissolution at QC — give me every input container that contributed material, with masses + dates + suppliers.' The recursive CTE walks sub-charge events backward from the WO to consumed containers, then from consumed containers to their receipt CTEs, then to supplier + PO + ASN. Returned as a per-component tree with quantities + percentage contribution per source container.
- Indexes — (container_id, utc, event_type) compound + (wo_id, utc) compound + (parent_lot_id, utc) compound; partial indexes on state IN ('intact', 'opened') for live inventory queries.
- Materialised view — daily-refreshed forward + backward graph snapshots per container for hot-path recall queries; live query for current-state + investigation depth.
- Recursion limits — CTE depth-capped at 20 hops to prevent runaway queries on circular re-pack chains; circular detection raises an audit-trail anomaly flag.
- Snapshot semantics — every query records the as-of timestamp; queries replay history by filtering events to event.utc <= as_of, so a 2024-09-15 recall investigation sees the graph as it was on that date even if events written later edited container states.
- Performance budget — recall queries on a 50-million-row event table must complete in <2 s for forward + <2 s for backward; investigation queries with sub-charge mass aggregation under <5 s.
- Recursive CTE template — WITH RECURSIVE walk AS (SELECT … FROM events WHERE container_id = $1 UNION ALL SELECT … FROM events e JOIN walk w ON e.parent_event_id = w.event_id) SELECT * FROM walk; — Postgres optimiser handles cycle detection if we set the right ordering + LIMIT clauses.
04Regulatory overlay across regimes
| Clause | Regime | What it requires that touches bin-level genealogy |
|---|---|---|
| 21 CFR 211.184 | US human drugs | Component records — receipt + identity + quantity + container + lot + supplier; container-level capture is the GMP baseline |
| 21 CFR 211.188(b)(11) | US human drugs | Batch record — actual yield + reconciliation; container-level sub-charge is the input |
| 21 CFR 211.196 | US human drugs | Distribution records — recall must trace shipments forward from lot; bin-level enables sub-lot recall scope reduction |
| 21 CFR 211.165(f) | US human drugs | OOS products recalled to prevent distribution; sub-lot resolution reduces recall scope + cost |
| 21 CFR 820.65 | US devices | Traceability — control number for each unit / lot / batch of finished devices + components for high-risk devices |
| 21 CFR 820.184(c) | US devices | DHR — actual material identity + quantity used per device |
| 21 CFR 820.198 | US devices | Complaint files + recall — sub-lot resolution narrows recall scope |
| 21 CFR 111.260(g) | US supplements | Component reconciliation — container-level resolution required for accurate reconciliation |
| 21 CFR 111.610 | US supplements | Distribution records — recall + traceability for finished-product lots |
| FSMA 204 KDE / CTE | US food (FTL) | Critical tracking events at container level for high-risk foods — receipt, transformation, ship; 24-month retention; 24-hour-response to FDA request |
| EU FMD 2011/62/EU + 2016/161 | EU human drugs | Serialisation at the smallest pack level + verification at dispense — package-level genealogy |
| DSCSA 2013 | US prescription drugs | Package + homogeneous-case-level serialisation + transaction history + transaction statement + transaction information |
| UDI 21 CFR 830 / 801 | US devices | Device identifier at production unit level + Production Identifier (lot / serial / expiry) |
| ICH Q7 §6.5 | API global | Reconciliation at each significant stage; sub-container resolution preserves chain-of-custody |
| ICH Q10 §3.2.5 | Global pharma | PQR aggregates per-container per-supplier trends for supplier-quality management |
| MHRA DI 2018 | UK pharma | Audit trail + traceability is ALCOA+ — contemporaneous + complete + original + attributable + legible + enduring + accurate |
| PIC/S PI 041-1 | Global PIC/S | Data management + integrity — genealogy events are GMP records subject to Part 11 / Annex 11 controls |
| FDA PV Guidance 2024 | US pharma | Stage-3 CPV trending per-component per-supplier per-container surfaces drift before it becomes OOS |
| GS1 General Specifications | Global industry | SSCC / GTIN / GLN serialisation standards — the technology layer the regulations sit on |
05Eight failure modes auditors hunt for first
- Lot-only genealogy — 12 IBCs of one lot all roll up to lot_id; recall pulls all 12 instead of the one affected; cost of unnecessary recall scope is the §211.196 finding-magnet.
- Container ID is a manual hand-written sticker — not scannable, not unique, not GS1-compliant; first time the container moves between sites the chain breaks.
- Open events not captured — container opened on the floor but no 'open' event written; subsequent sub-charges have no container state context; clean-validation of the container before next use cannot be reconstructed.
- Sub-charge events aggregated to lot level — 14 individual draws from one drum captured as a single 'drum 90% consumed' summary; per-batch traceability lost; investigations can't isolate which draw produced the deviation.
- Split / merge events ad-hoc + paper-only — operator splits an IBC into 5 totes on the warehouse floor; child container IDs created in Excel; events never written to the system; graph diverges from reality permanently.
- Return-to-inventory without destination container ID — residual mass returned but the destination is logged as 'back to source lot'; if the source lot is now in 8 containers, the system doesn't know which one received the return; next pick from any of the 8 has unknown provenance.
- Re-pack lineage not preserved — damaged container is repacked into new container; new container_id created but lineage to old container_id not captured; if the old container's lot has an issue, the recall query misses the re-packed child.
- Quarantine state not RLS-enforced — quarantined container_id appears in pick lists because the application-layer filter has a bug; operator picks + dispenses quarantined material; §211.42 + 211.100 + 211.184 + 211.192 finding cluster with potential market recall.
06The KPI suite that proves bin-level genealogy holds
- Container-ID coverage — fraction of inbound containers with GS1-SSCC or facility-unique scannable ID at receipt (target 100%); manual sticker coverage = data-integrity gap.
- Event capture rate — fraction of physical events (receipt + put-away + move + open + sub-charge + close-down + consume + return + split + merge + scrap + re-pack) captured to the genealogy event table within 5 min of physical execution (target ≥99%).
- Recall query response time — median time to return forward + backward genealogy result for a single container_id (target ≤2 s on production-size event table); slower = §211.196 + FSMA-204 + 820.198 risk.
- Recall scope reduction ratio — average ratio of (bin-level recall scope) ÷ (lot-level recall scope) across past 12 months of mock + real recalls (target ≤0.3; lower is better — proves the bin-level data prevents over-recall).
- Mock-recall pass rate — fraction of quarterly mock recalls completed within FDA / EMA expected response time (24 h for FDA, 48 h for EMA) with full forward + backward chain (target 100%).
- Split / merge QA-approval coverage — fraction of split + merge events with documented QRM + QA approval reference (target 100% for regulated material; 0% merges for penicillin / cytotoxic / hormone / live-biologic).
- Return-to-inventory destination_container_id capture — fraction of returns with explicit destination container ID (target 100%); 'back to source lot' returns are graph breakage.
- Quarantine RLS enforcement test — quarterly automated test confirms quarantined containers cannot appear in pick lists or be sub-charged (target 100% block); service-role-key bypass test must also fail (RLS works at DB layer).
07How V5 implements bin-level genealogy end-to-end
- Container master schema — container_id (GS1 SSCC or facility-prefixed serial, unique), parent_lot_id, supplier_id, initial_mass, current_mass, current_state (intact / opened / consumed / split / merged / scrapped / returned / quarantined / re-packed / under-investigation), current_location_id, cofa_doc_ref, expiry_date, retest_date, restricted_access_flag, container_class (drum / IBC / pail / tote / sub-container).
- Event schema — genealogy_event (event_id, container_id, event_type, utc, operator_id, supervisor_id, qa_id, wo_ref, dispense_result_id, mass_before, mass_after, mass_delta, from_location, to_location, parent_event_id, parent_container_id, child_container_ids[], reason_code, deviation_id, qrm_doc_ref, qa_approval_id, audit_trail_id) — append-only, RLS-protected, indexed for graph traversal.
- Receipt workflow — receiver scans PO + ASN + container GS1 barcode at dock; system creates container_id row + writes receipt event with supplier + PO + ASN + CoA ref + mass; container state = intact; auto-routes to put-away location per FEFO + zone rules.
- Move + put-away — every scan-move writes a move event with from + to + operator; no supervisor required for routine moves; movements within an open WO line stage are tracked as line-side movements with WO ref.
- Open + sub-charge — when operator selects container for first weighment, kiosk writes open event (container state → opened); every dispense_result references the source container_id + writes a sub-charge event; container current_mass auto-decrements.
- Close-down + consume — at end of WO or shift, operator triggers close-down (container re-sealed + verified); if current_mass ≤ residue envelope, auto-prompts consume event (state → consumed); otherwise container remains opened-closed-down (re-openable).
- Return-to-inventory — operator initiates return; UI mandates destination_container_id selection (default: original source if still available); creates return event + paired inventory_transaction row; orphan returns RLS-blocked.
- Split workflow — operator triggers split from kiosk; UI walks through parent → child container creation (new GS1 SSCC per child or facility-issued); supervisor + QA e-sig required for regulated material; creates split event with parent_container_id → child_container_ids[].
- Merge workflow — operator triggers merge; UI mandates QRM doc reference + QA approval ID; RLS blocks merge for penicillin / cytotoxic / hormone / live-biologic regardless of approval; creates merge event with child_container_ids[] → parent_container_id.
- Quarantine workflow — QA triggers quarantine on container_id; state → quarantined; RLS blocks any subsequent pick / sub-charge / move (except QA-authorised quarantine-cage move); paired deviation_id required.
- Recall + investigation API — server function takes container_id (or wo_id or finished_lot_id) + direction (forward / backward) + optional as_of_timestamp; executes recursive CTE; returns graph with hop count + masses + dates; PDF report renders the graph + chain-of-custody for regulatory submission.
- Mock-recall quarterly drill — automated job picks a random container_id from past 6 months of events; executes full forward + backward query; logs response time + completeness; surfaces on Quality dashboard; chronic miss triggers index + materialised-view tuning.
- §211.192 + 820.198 + FSMA-204 review integration — every batch record render auto-includes the bin-level genealogy graph for every consumed container; reviewer can drill into any container's full event chain; closing the batch records the genealogy snapshot to immutable storage.
08Frequent inspector questions
- Q: Is lot-level genealogy enough if we're not on the FSMA-204 Food Traceability List? A: Lot-level meets the literal §211.184 + 820.65 minimum. But §211.196 + 820.198 recall expectations + the foreseeable-risk doctrine increasingly drive inspectors to ask 'why didn't you use bin-level when it was achievable?' — especially after one expensive over-recall. The cost differential is small relative to one avoided unnecessary recall.
- Q: How small is 'too small' for a container_id? A: The smallest physical unit that is independently moved, opened, or sub-charged. For a 25 kg drum that's drum-level. For a 1000 L IBC that's IBC-level. For a 5 g vial of reference standard that's vial-level. The rule is: if it can move independently, it gets an ID.
- Q: Can we use facility-private serials instead of GS1 SSCC? A: For internal-only material that never crosses a site or supply-chain boundary, yes. The moment material moves to another site, a contract manufacturer, or a customer, GS1 SSCC is the only interoperable standard that scans reliably + carries through the chain. We recommend GS1 SSCC from day one to avoid the future migration.
- Q: How do we handle continuous-flow material (no discrete containers)? A: Time-bin the flow into 'virtual containers' — every N minutes or N kg of throughput is a virtual container with a synthetic container_id + start + end timestamps. Sub-charges reference the virtual container by timestamp. This pattern works for continuous granulation, continuous fluid-bed, continuous tabletting, and many fermentation / bioreactor processes.
- Q: What's the audit-trail retention for genealogy events? A: §211.180(c) = 1 year past expiry or 3 years past distribution, whichever later. FSMA-204 = 24 months from event date. EU GMP = retention per the marketing-authorisation regime, typically 5 years past last distribution. We default to the longest applicable + recommend 7 years for regulated facilities.
- Q: How do we genealogy-track returns from customers? A: A customer return is a receipt event with source = customer + reverse-trace to the original shipment + finished-lot. The returned material is quarantined by default + cannot re-enter manufacturing without QA disposition + risk assessment + likely re-test. The genealogy chain stays connected so subsequent investigations can trace 'which customer batch returned this material'.
- Q: Does bin-level genealogy work for active raw materials AND for packaging components? A: Yes — packaging components (vials, stoppers, caps, labels, cartons, inserts) follow identical genealogy patterns. The DSCSA + EU FMD + UDI regimes all require package-level traceability for finished products; the upstream component genealogy is the input to the finished-product serial number.
Frequently asked questions
Q.Is lot-level genealogy enough if we're not on the FSMA-204 Food Traceability List?+
Lot-level meets the literal §211.184 + 820.65 minimum. But §211.196 + 820.198 recall expectations + the foreseeable-risk doctrine increasingly drive inspectors to ask 'why didn't you use bin-level when it was achievable?' — especially after one expensive over-recall. The cost differential is small relative to one avoided unnecessary recall.
Q.How small is 'too small' for a container_id?+
The smallest physical unit that is independently moved, opened, or sub-charged. For a 25 kg drum that's drum-level. For a 1000 L IBC that's IBC-level. For a 5 g vial of reference standard that's vial-level. The rule is: if it can move independently, it gets an ID.
Q.Can we use facility-private serials instead of GS1 SSCC?+
For internal-only material that never crosses a site or supply-chain boundary, yes. The moment material moves to another site, a contract manufacturer, or a customer, GS1 SSCC is the only interoperable standard that scans reliably + carries through the chain. We recommend GS1 SSCC from day one to avoid the future migration.
Q.How do we handle continuous-flow material with no discrete containers?+
Time-bin the flow into 'virtual containers' — every N minutes or N kg of throughput is a virtual container with a synthetic container_id + start + end timestamps. Sub-charges reference the virtual container by timestamp. Works for continuous granulation, fluid-bed, tabletting, fermentation, bioreactor.
Q.What's the audit-trail retention for genealogy events?+
§211.180(c) = 1 year past expiry or 3 years past distribution whichever later. FSMA-204 = 24 months from event date. EU GMP = retention per the marketing-authorisation regime, typically 5 years past last distribution. We default to the longest applicable + recommend 7 years for regulated facilities.
Q.How do we genealogy-track returns from customers?+
A customer return is a receipt event with source = customer + reverse-trace to the original shipment + finished-lot. The returned material is quarantined by default + cannot re-enter manufacturing without QA disposition + risk assessment + likely re-test. The genealogy chain stays connected so subsequent investigations can trace 'which customer batch returned this material'.
Q.Does bin-level genealogy work for active raw materials AND for packaging components?+
Yes — packaging components (vials, stoppers, caps, labels, cartons, inserts) follow identical genealogy patterns. The DSCSA + EU FMD + UDI regimes all require package-level traceability for finished products; the upstream component genealogy is the input to the finished-product serial number.
Primary sources
- 21 CFR 211.184 — Component, drug product container, closure, and labeling records
- 21 CFR 211.188 — Batch production and control records
- 21 CFR 211.196 — Distribution records
- 21 CFR 211.165(f) — Drug products failing to meet specifications (recall)
- 21 CFR 820.65 — Traceability (devices)
- 21 CFR 820.184(c) — DHR — material identity + quantity used
- 21 CFR 820.198 — Complaint files + recall
- 21 CFR 111.260(g) — Component reconciliation (supplements)
- 21 CFR 111.610 — Distribution records (supplements)
- FSMA 204 Final Rule — Traceability KDE / CTE
- EU Falsified Medicines Directive (FMD) 2011/62/EU
- EU Delegated Regulation 2016/161 — Safety features serialisation
- Drug Supply Chain Security Act (DSCSA) 2013
- 21 CFR 830 + 801 — Unique Device Identification (UDI)
- GS1 General Specifications — GTIN + SSCC + GLN
- ICH Q7 §6.5 — Reconciliation (API)
- ICH Q10 §3.2.5 — Quarterly product review
- MHRA DI 2018 — Audit trail + traceability ALCOA+
- PIC/S PI 041-1 — Data management + integrity
- FDA Process Validation Guidance 2024 — Stage-3 CPV genealogy trending
Further reading
- GenealogyLot-level genealogy is the parent abstraction; bin-level extends to the smallest physical container with full bidirectional graph traversal.
- Net-vs-Gross ReconciliationReturned-to-inventory residuals require paired inventory_transaction rows with destination_container_id — bin-level genealogy is the destination spec.
- Key Data Element (KDE)FSMA-204 KDEs are bin-level events — receipt, move, open, sub-charge, transformation, ship — captured at container granularity.
- Critical Tracking Event (CTE)Every bin event is a CTE — the genealogy graph is built from the chronological CTE sequence per container.
- FSMA 204Sub-lot traceability for high-risk foods on the FTL is bin-level-or-finer by regulatory definition.
- UDIDevice UDI applies at the production lot + serial level — bin-level genealogy maps the production-lot UDI to the component-bin chain.
- DSCSADSCSA package-level + homogeneous-case serialisation is the prescription-drug analogue of bin-level genealogy applied downstream.
- Tare-Verified WeighingThe container-binding chain at every weighment writes the source bin_id to dispense_result — the upstream input to the genealogy graph.
V5 Ultimate ships with the Bin-Level Lot Genealogy controls already wired in — audit trail, e-signatures, validation evidence. Free trial, no credit card, onboard in days, not months.
