01 β Master Data Layer
Foundation layer. Defines what a product is and how it's made. If master data is wrong, everything downstream is wrong. Inherits all rules from
00_architecture_and_principles.md.
1.1 Purpose
Master Data holds the stable definitions that all transactions reference: the product recipe (BOM), the manufacturing path (Routing), the production resources (Work Center / Tool), and item settings. It is created once and changed via controlled change orders (ECO).
1.2 Entity: BOM (Bill of Materials)
Purpose: The product's manufacturing identity β what components and quantities go into one unit. Must support multi-level nesting.
BOM_Header
- bom_id (PK)
- parent_item_id (FK β Item)
- bom_type β { Production, Engineering, Phantom }
- version (multiple versions kept for history)
- base_quantity (usually 1 β the unit the BOM is defined per)
- uom (unit of measure of the parent)
- status β { Draft, Active, Inactive, Obsolete }
- effective_from / effective_to
- created_by / approved_by
BOM_Line
- bom_id (FK β BOM_Header)
- line_no
- component_id (FK β Item)
- quantity (per one base_quantity of parent)
- uom
- scrap_percentage (expected waste; MRP multiplies qty by (1+scrap%))
- issue_type β { Manual, Backflush, AutoIssue }
- issue_level β { PerOrder, PerShift, PerOperation }
- operation_seq (which routing operation consumes it β links BOMβRouting)
- substitute_items (alternatives if primary unavailable)
Generic-design notes
- Base quantity defaults to 1 (per piece) for flexibility. Shared packaging (e.g. one carton per set) is handled at the parent assembly level, not forced onto each piece.
- Multi-level: a BOM_Line's component may itself have a BOM (sub-assembly / semi-finished). MRP explodes recursively.
- Low-value consumables (negligible cost, hard to meter per unit) should NOT be BOM lines β treat as overhead. Provide a flag or simply omit and account in overhead pool.
Melamine test case
4-level BOM proven:
Set (50 pcs) β level 0, type=Production
ββ Large dish Γ6 β level 1, procurement=Make
β ββ Melamine powder 0.15kg, scrap 3% β level 3 raw
β ββ Ready decor cutout Γ1 β level 2, semi-finished
β ββ Decor sheet, scrap 15% β level 3 raw
ββ ... other pieces
ββ Printed carton Γ1 β packaging at SET level (not piece)
Glaze: NOT a BOM line β overhead consumable (sprayed, negligible).
1.3 Entity: Routing
Purpose: The manufacturing path β the sequence of operations, who does each, and how long. Enables scheduling and time calculation.
Routing_Header
- routing_id (PK)
- item_id (FK β Item)
- routing_type β { Production, Repair, Inspection }
- version
- lot_size_from / lot_size_to (a product may have different routings per batch size)
- status β { Draft, Active, Inactive }
- effective_from / effective_to
- total_lead_time (computed)
Routing_Operation
- operation_no (sequence: 10, 20, 30 β multiples of 10 to allow inserts)
- description
- work_center_id (FK β Work_Center)
- tool_id (FK β Tool, nullable β the mold/die required)
- setup_time (fixed, independent of batch size)
- run_time_per_unit
- cavity_count (units produced per cycle β DEFAULT 1; >1 for multi-cavity)
- cycle_time (time for one cycle/press β use with cavity_count)
- queue_time (wait before start β adds to lead time, not cost)
- move_time (transfer to next op)
- inspection_required (bool)
- critical_operation (bool β cannot be skipped)
- required_skill_code
Generic-design notes
- Operation numbering in 10s is a convention so an operation can be inserted (15, 25) without renumbering.
- cavity_count is the key generalization for molding/multi-output processes. The real per-piece time is:
time_per_piece = cycle_time / cavity_countDefault cavity_count = 1 makes this collapse to normal behaviour for discrete manufacturers. - queue_time / move_time affect lead time but are usually NOT costed.
- An operation may reference a Tool in addition to a Work Center β both must be available to run (resource intersection, see Β§1.5).
Melamine test case
Plain dish routing:
Op 10 Press (WC-PRESS, MOLD-LG, cycle 70s, cavity 1) β 70s/piece
Op 15 Cooling (queue, no cost)
Op 20 Deflash (WC-DEFLASH)
Op 30 Sanding (WC-SAND)
Op 40 Grading (WC-QC) β produces grade distribution
Multi-cavity proof: cup mold cavity=4, cycle 60s β 15s/piece (4Γ throughput, same machine).
Printed dish: SAME routing (decor prepared separately as semi-finished, see 1.2).
1.4 Entity: Work Center
Purpose: Where work happens. The interface between production and accounting β all costs flow through it.
- wc_id (PK)
- description
- category β { Machine, Labor, SetupGroup }
- plant_location
- cost_center_id (FK β Cost_Center)
- capacity_unit β { Hours, Pieces, Kg }
- daily_capacity (per single unit)
- capacity_multiplier (number of identical machines/workers in this WC)
- efficiency_percent
- utilization_percent
- calendar_id (shifts & holidays)
- setup_cost_rate
- labor_cost_rate
- machine_cost_rate
- overhead_rate
- labor_calc β { Hourly, PieceRate } β see Β§1.6
- bottleneck_flag
Effective capacity
effective_capacity = daily_capacity Γ capacity_multiplier Γ efficiency% Γ utilization%
CRP uses effective (not gross) capacity.
Generic-design notes
- capacity_multiplier lets N identical machines be ONE work center (a "pool of capacity"). Use separate WCs only when operations/costs genuinely differ.
- Decision rule (what defines a separate WC): the type of operation and its cost, NOT the count of machines. Identical machines doing identical work at identical cost = one WC with a multiplier. Different work or different cost = separate WCs.
Melamine test case
WC-PRESS: 2 groups Γ 2 presses each. Modeled as multiplier=2 per group,
3 shifts, eff 85%. Bottleneck=true.
Machine_cost_rate = (depreciation + maintenance + cooling water) / press-hours.
Labor: PieceRate (operator paid per piece, NOT hourly).
Note: operator runs 2 presses alternately β worker may be the real constraint
if manual handling time exceeds cycle time (machine-coupling).
1.5 Entity: Tool / Mold (Resource generalization)
Purpose: In molding/tooling industries the tool is the capacity constraint, not the machine. Generalized as a Resource of type Tool.
- tool_id (PK)
- description
- product_id (which product it makes β or many)
- cavity_count (pieces per cycle)
- setup_time (mount/dismount β often large)
- status β { Available, Mounted, Maintenance, Retired }
- life_cycles (expected cycles before replacement β for usage depreciation)
- cycles_used (running counter)
- purchase_cost (for depreciation per cycle)
Generic-design notes
- Resource abstraction: Machine, Tool, and Labor are all
Resourcewithresource_type. An operation may require several resources simultaneously. Available start =MAX(earliest free time across all required resources). - Usage depreciation: tools wear by cycles, not calendar. Only mounted/running tools accrue wear.
depreciation_per_piece = purchase_cost / life_cycles / cavity_count - A factory with no tooling simply has no Tool resources β the abstraction collapses gracefully.
Melamine test case
50 molds total, but only ~4 mounted (running) at any time β only those 4 depreciate.
Mold cost from 40k EGP up. Setup (mounting) is heavy β drives large lot sizing.
Some molds multi-cavity (e.g. tea-set tray mold yields 4 small pieces/cycle).
1.6 Generic point: Labor calculation mode
labor_calc on the Work Center (or item) decides how direct labor cost is computed:
if labor_calc == Hourly: cost = labor_hours Γ labor_rate
if labor_calc == PieceRate: cost = quantity Γ piece_rate (piece_rate may vary by product/size)
Consequence: under PieceRate, a slow worker costs himself (earns less), not the factory β so there is no traditional Labor Efficiency Variance; the deviation shifts to machine/overhead. The system must handle both modes.
1.7 Dependencies & Integrations (this layer)
- Depends on: Item Master (host ERP), Calendar, Skills/Tools master, Approval workflow (ECO).
- Feeds: MRP (BOM explosion), Production Order (snapshot source), Costing (standard cost build-up), CRP (capacity definition).