Inventory & traceability · The complete guide

Bin-Level Lot Genealogy

TL;DR

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.

Reviewed · By V5 Ultimate compliance team· 3,700 words · ~17 min read

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.

PrimitiveWhat it isWhy it mattersFailure mode if missing
container_idGlobally 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_idReference 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'.
stateLifecycle 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_chainChronological 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.

EventWhat triggers itWhat the row capturesWho signs
receiptContainer arrives at receiving dock; scan against PO + ASNcontainer_id, parent_lot_id, supplier, PO ref, ASN ref, gross + tare + net mass, CoA reference, initial state=intactReceiver + warehouse supervisor
put-awayContainer moves from receiving to designated storage locationfrom_location, to_location, operator, UTC; state unchangedOperator scan (no supervisor required for routine put-away)
moveContainer relocates within the warehouse (e.g. zone change, FEFO repositioning, line-side staging)from_location, to_location, operator, UTC, reason; state unchangedOperator scan
openContainer is broken (lid removed, seal cut) for the first timecontainer_id, operator, UTC, WO ref, post-open container mass, state→openedOperator + supervisor (two-person for potent / cytotoxic / hormone)
sub-chargeMaterial drawn from container for a specific weighment / batch chargecontainer_id, WO ref, charge sequence, pre-charge mass, post-charge mass, mass_drawn, dispense_result_id reference; state remains openedOperator e-sig + supervisor witness per §211.101(c)
close-downContainer 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
consumeContainer fully exhausted (remaining mass ≤ residue envelope)container_id, final residual mass, final WO ref, state→consumed; container removed from pickable inventoryOperator + supervisor
returnResidual material returned to inventory (back to source lot) with chain-of-custodycontainer_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 stateOperator + supervisor (mandatory two-person)
splitOne 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)
mergeTwo 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 / quarantineContainer 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 quarantinedOperator + supervisor + QA
re-packContainer 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.

  1. 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.
  2. Materialised view — daily-refreshed forward + backward graph snapshots per container for hot-path recall queries; live query for current-state + investigation depth.
  3. 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.
  4. 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.
  5. 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.
  6. 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

ClauseRegimeWhat it requires that touches bin-level genealogy
21 CFR 211.184US human drugsComponent records — receipt + identity + quantity + container + lot + supplier; container-level capture is the GMP baseline
21 CFR 211.188(b)(11)US human drugsBatch record — actual yield + reconciliation; container-level sub-charge is the input
21 CFR 211.196US human drugsDistribution records — recall must trace shipments forward from lot; bin-level enables sub-lot recall scope reduction
21 CFR 211.165(f)US human drugsOOS products recalled to prevent distribution; sub-lot resolution reduces recall scope + cost
21 CFR 820.65US devicesTraceability — control number for each unit / lot / batch of finished devices + components for high-risk devices
21 CFR 820.184(c)US devicesDHR — actual material identity + quantity used per device
21 CFR 820.198US devicesComplaint files + recall — sub-lot resolution narrows recall scope
21 CFR 111.260(g)US supplementsComponent reconciliation — container-level resolution required for accurate reconciliation
21 CFR 111.610US supplementsDistribution records — recall + traceability for finished-product lots
FSMA 204 KDE / CTEUS 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/161EU human drugsSerialisation at the smallest pack level + verification at dispense — package-level genealogy
DSCSA 2013US prescription drugsPackage + homogeneous-case-level serialisation + transaction history + transaction statement + transaction information
UDI 21 CFR 830 / 801US devicesDevice identifier at production unit level + Production Identifier (lot / serial / expiry)
ICH Q7 §6.5API globalReconciliation at each significant stage; sub-container resolution preserves chain-of-custody
ICH Q10 §3.2.5Global pharmaPQR aggregates per-container per-supplier trends for supplier-quality management
MHRA DI 2018UK pharmaAudit trail + traceability is ALCOA+ — contemporaneous + complete + original + attributable + legible + enduring + accurate
PIC/S PI 041-1Global PIC/SData management + integrity — genealogy events are GMP records subject to Part 11 / Annex 11 controls
FDA PV Guidance 2024US pharmaStage-3 CPV trending per-component per-supplier per-container surfaces drift before it becomes OOS
GS1 General SpecificationsGlobal industrySSCC / GTIN / GLN serialisation standards — the technology layer the regulations sit on

05Eight failure modes auditors hunt for first

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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

  1. 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).
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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).
  7. 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.
  8. 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[].
  9. 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.
  10. 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.
  11. 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.
  12. 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.
  13. §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

Further reading

See Bin-Level Lot Genealogy working on a real shop floor

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.