Asset Hierarchy Data Model: Levels, Fields and Rules
Key takeaways
- A usable plant hierarchy is five or six levels: site, area, line, machine, component, with enterprise on top only for multi-plant groups.
- It is carried by one field, parent_
asset_ , plus a level field saying what kind of node this is.id - Put no meaning in the tag that can change. A number encoding the line becomes a lie the first time a machine moves.
- Worked below: a line whose true cost is 7,300 EUR reads 9,280 EUR when one 1,980 EUR job sits on both a machine and its parent.
- Line downtime is the union of the stop windows, not their sum. One shift gives 87.8% correctly and 82.2% by adding the machines up.
What an asset hierarchy is
An asset hierarchy is a parent and child tree of every physical thing in the plant that can be worked on, measured or paid for.
It answers what no flat list can answer: what line 2 cost last year, which area has the worst downtime, and what is inside this machine.
In the data it is one self-referencing field, and everything below is the rules that keep that field meaningful five years in.
For the surrounding tables (meters, plans, work orders, parts) see our CMMS data model, and for tag and code formats see the asset hierarchy and naming convention guide.
The levels a plant actually needs
Six levels cover almost every discrete plant. Each exists because something must attach there that cannot sit above or below it.
| Level | What sits there | Example |
|---|---|---|
| 0 Enterprise | The group, only with more than one plant | GROUP |
| 1 Site | One address, one legal entity | BG-PLANT-1 |
| 2 Area | A hall or department, usually a cost centre boundary | PACKAGING |
| 3 Line | The group that starts and stops together | LINE-02 |
| 4 Machine | A nameplate, a serial number, a maker | FIL-02 |
| 5 Component | The part you replace or rebuild | FIL-02-VB |
Level 3 has several names. A cell, a work centre or a system all sit in that slot, and the test is the same: does it stop as one unit.
Process plants often add a system level for utilities, clean in place and compressed air, because those cross lines. That is one extra node on a few branches, not depth everywhere.
Where "function" fits
A function level names a position rather than a machine: P-101A is "the duty transfer pump position", and the physical pump in it changes over time.
It earns its place only if you rotate repairable units through positions, because the position then keeps its process history while the serial numbered unit keeps its own repair history.
How many levels are too many
Seven physical levels below the enterprise is the practical ceiling. Past that nobody maintains the structure, and a level you cannot keep correct is worse than none.
Before adding one, run this test: is it a level or a field. If a filter on a column answers the question, it is a field, which is where a node per maker or a "critical assets" branch belongs.
The asset record: one table, every level
Do not build a table per level. One asset table holds site, area, line, machine and component rows, and a level field says which is which.
Separate tables look tidy on day one, then block every query that crosses levels.
| Field | What it holds | Example |
|---|---|---|
| asset_ | The key, unique, never reused | FIL-02 |
| parent_ | The node one level up | LINE-02 |
| level | Site, Area, Line, Machine, Component | Machine |
| name | Plain language name | Rotary filler 24 valve |
| asset_ | Type from a fixed list | FILLER |
| manufacturer | Maker on the nameplate | Nameplate value |
| model | Model designation | RF-24/6 |
| serial_ | Maker's serial number | 2019-8841 |
| location_ | Link to a place record | P1-HALL-B-BAY3 |
| cost_ | Link to the finance list | CC-4120 |
| fixed_ | The finance register number | FA-0331 |
| criticality | A, B or C, set at this node | A |
| status | Lifecycle state | Operating |
| commissioning_ | Handover to production | 2019-11-04 |
| sort_ | Position among siblings, in process order | 30 |
| superseded_ | Tag that replaced this one | Empty |
location_id and cost_centre are links rather than text, because free text cannot be grouped or counted.
Keep the physical location as a second tree (site, building, hall, bay) joined by location_id, because one line can run through two halls and the two trees diverge.
Mandatory fields by level
Rules by level stop a hierarchy filling with blank rows. Enforce them on save, not in a policy document.
| Field | Required from |
|---|---|
| asset_ | Every level |
| parent_ | All but the root |
| location_ | Area and below |
| cost_ | Area and below |
| criticality | Line and below |
| asset_ | Machine and below |
| manufacturer, model | Machine and below |
| serial_ | Machine only |
| commissioning_ | Machine |
| fixed_ | Whatever finance capitalised |
Note what is not mandatory on a component: a serial number. Most seals and belts have none, and demanding one teaches people to type "N/A".
Numbering: significant versus non-significant
A significant asset number encodes meaning in the string. A non-significant one is a sequence, and the meaning lives in fields.
| Question | Significant | Non-significant |
|---|---|---|
| Readable on a label | Yes | No |
| Survives a move | No | Yes |
| Needs fixed code lists | Yes, per segment | No |
| Runs out of room | Yes | No |
| Parsed by reports | Often, and that is the risk | Never |
A worked numbering example
Take the common significant scheme SS‑AAA‑LL‑CCC-NN: site, area, line, class, sequence.
- BG site, PKG area, 02 line, FIL class, 01 sequence.
- The tag is BG‑PKG‑02‑FIL-01, 16 characters, and it reads perfectly on a label.
- LL allows 99 lines and NN allows 99 fillers per line, which is enough.
It works until the filler moves to line 5 in the same hall.
The failure case, and both bad options
Option one is to retag it BG‑PKG‑05‑FIL-01. With asset_no as the primary key, that rename must cascade through every work order, reading, plan and part link, and it invalidates every printed label, document and archived report quoting the old string.
Option two is to leave the tag alone. The hierarchy is then right and the tag lies, so any report parsing the tag puts the machine on the wrong line.
Both are bad because the tag was asked to carry something that changes. The line is the most volatile segment in that scheme, and it is the one most schemes encode.
The rule that survives
Put in the tag only what stays true for the life of the asset: normally the site and the class, sometimes nothing at all.
BG‑FIL‑014 survives the move, because line, area and cost centre live in parent_asset_id, location_id and cost_centre, where a move is a one field edit.
If you already run a significant scheme, freeze it rather than ripping it out, and forbid reports from parsing the string.
Why the finance number is a different number
The finance register counts what was bought and capitalised. The maintenance register counts what can break.
| Event | What each register does |
|---|---|
| A whole line on one invoice | 1 fixed asset, 23 maintenance assets |
| Capitalise a 40,000 EUR gearbox | New fixed asset, same machine tag |
| Fully depreciated, still running | Gone from finance, still Operating |
| Spare motor on the shelf | Stock value, no asset row yet |
So fixed_asset_no is a field on the asset, allowed to be many to one and allowed to be empty. Using it as the shop floor tag breaks the moment finance splits or merges a number for a depreciation reason (see CMMS versus ERP).
Where to attach what
The level you attach each object to makes or breaks reporting. The default is the lowest level that is always known.
| Object | Attach at |
|---|---|
| Work order | Machine, or component if you go that deep |
| Failure record | Component, inside the work order |
| Meter (run hours) | Machine |
| Meter (units made) | Line, at the output counter |
| PM plan | Machine, steps naming components |
| Spare part link | Machine or component |
| Documents | The level the document describes |
| Downtime event | The machine that stopped |
| Criticality | Every level, assigned not inherited |
A PM plan belongs on the machine because that is where the maker's interval is written. On the line it becomes one job covering eleven machines, which cannot be scheduled or measured.
Production orders are a separate model and attach to the work centre, not to the maintenance asset (production work order data model).
What breaks when a work order is written against the line
This is the most common hierarchy mistake, and it stays invisible for about a year.
- The filler's history is empty while LINE‑02 carries 400 jobs, so machine MTBF cannot be calculated at all.
- Failure codes have nothing to hang on, because the problem was on a component of a machine nobody named.
- Spare consumption cannot be traced to what ate it, so a reorder point is guesswork (tool crib data model).
- Criticality driven planning stops working, since every job inherits the line's criticality.
Line level work orders fit a short, named list: line clean in place, a changeover, shared guarding and a full shutdown.
If a conveyor between two machines keeps collecting line level jobs, it should be its own asset row.
Rolling cost and downtime up the tree
A roll-up is a sum over the subtree of a node, computed at query time. Never store it as a total on the parent, because parent and children will one day disagree and nobody will know which is right.
1. The cost roll-up
Maintenance cost for LINE‑02 over one quarter, parts plus labour booked on each asset's own work orders.
| Asset | Own cost |
|---|---|
| LINE-02 (line level jobs) | 300 EUR |
| RIN-02 rinser | 640 EUR |
| FIL-02 filler | 410 EUR |
| FIL-02-VB valve block | 1,240 EUR |
| FIL-02-DRV main drive | 860 EUR |
| CAP-02 capper | 1,980 EUR |
| LAB-02 labeller | 720 EUR |
| PAL-02 palletiser | 1,150 EUR |
| LINE-02 subtree | 7,300 EUR |
- FIL‑02 rolled up = 410 + 1,240 + 860 = 2,510 EUR, its own jobs plus its two components.
- LINE‑02 rolled up = 300 + 640 + 2,510 + 1,980 + 720 + 1,150 = 7,300 EUR.
- Check it flat: the eight own cost rows also add to 7,300 EUR, because every cost sits on exactly one asset.
- Shares: the filler branch is 2,510 ÷ 7,300 = 34.4%, the capper 1,980 ÷ 7,300 = 27.1%.
2. The double counting trap
Now suppose the capper's 1,980 EUR rebuild was also logged against the line, because the line stopped and someone opened a record there too.
The subtree sum becomes 7,300 + 1,980 = 9,280 EUR. The line reads 27.1% high, exactly the capper's share, since it is the same 1,980 EUR counted twice.
Both rows are individually correct. Only the sum is wrong, and the sum is what goes to the budget meeting.
Two rules kill it: one event, one asset row, and a parent may hold its own work but never a copy of a child's. Where a line ticket exists beside a machine job, link them and count cost on the child only.
3. Downtime does not add up
Cost sums up the tree. Downtime does not, because two machines can be stopped at the same moment while the line stops once.
One shift on LINE‑02: 480 minutes less a 30 minute break gives 450 minutes of planned production time.
| Machine | Stop window |
|---|---|
| FIL-02 filler | 10:05 to 10:45 (40 min) |
| CAP-02 capper | 10:20 to 10:45 (25 min) |
| LAB-02 labeller | 13:10 to 13:25 (15 min) |
| Sum | 80 min |
| Union | 55 min |
The capper stopped because the filler upstream stopped, so its window sits inside the filler's. The union is 10:05 to 10:45 plus 13:10 to 13:25, so 40 + 15 = 55 minutes.
- Correct line availability = (450 minus 55) ÷ 450 = 395 ÷ 450 = 87.8%.
- Summing the machines = (450 minus 80) ÷ 450 = 370 ÷ 450 = 82.2%, understated by 5.6 points.
- Multiplying machine availabilities = 91.1% × 94.4% × 96.7% = 83.2%, wrong in a third direction.
- The machine figures are each right: 410 ÷ 450, 425 ÷ 450 and 435 ÷ 450.
Roll cost with a sum and roll downtime with a union of intervals, measured at the level you are reporting.
The capper's 25 minutes are still real downtime for the capper, and they need a reason code saying starved by upstream (downtime reason code design).
The same 55 minute union feeds the line's availability factor in OEE calculation, and our guide to unplanned downtime covers the cost side.
Moving, renaming and decommissioning
A machine will move, and the move is where most hierarchies quietly break. Treat it as a structural edit with a record, not a field someone overtypes.
| A move changes | A move must preserve |
|---|---|
| parent_ | asset_ |
| location_ | Every work order ever written |
| cost_ | Meter readings, unbroken |
| sort_ | PM plans and due points |
| Criticality, sometimes | Documents and spare links |
Write a move event row: asset_no, from parent, to parent, effective date, reason and who approved it. Six fields, and it answers "why does last year look different" forever.
The effective date problem
Overwrite parent_asset_id and every historical report re-parents last year's costs onto the new line, so the old line's history shrinks and nobody can say why.
- As of today. One parent field, reports always use the current structure. Fine where machines move rarely.
- As of date. Store parent_asset_id with valid_from and valid_to, so every roll-up takes a reporting date. Correct, and it costs a join in every query.
Print the choice in the report header. A cost per line report that does not say which structure it used is not auditable.
Renaming and deleting
Changing the name is free, because it is a label. Changing asset_no is not, because it is the key on labels, documents, archived reports and every child row.
If a tag must change, keep the old one as an alias on the same row, since two rows for one machine splits its history in half.
Never delete an asset. Set status to Decommissioned, block new work orders and keep the tag reserved forever, because deleting takes the costs and the failure history with it.
A machine rebuilt from two old ones
The wrong move is to edit one old row and pretend it is the new machine.
- Create a new asset row with its own tag and commissioning_date set to the rebuild handover.
- Set both donors to Decommissioned and fill superseded_by with the new tag on each.
- Re-parent the components that physically moved, so their history and meters follow the metal.
- Close the donors' meters and open a new run hour meter, with an offset if the counter was reused.
- Copy documents and spare part links; copy no work orders.
Reliability figures for the new machine start at its commissioning date, because gluing the donors' failures onto it describes a machine that no longer exists.
Criticality by level
Criticality is a judgement about the consequence of failure at one node. It is assigned at every level, never inherited or summed.
| Level | Question it answers |
|---|---|
| Area | Can another area cover this output |
| Line | What does the business lose if it stops for a shift |
| Machine | Does the line stop, slow, or run on from a buffer |
| Component | Does the machine stop, and is there a spare on the shelf |
A line's criticality is not the sum of its machines, and redundancy is why. Two transfer pumps, one duty and one standby, can each be class B while the function they serve never stops.
The reverse happens too. A class C line can hold a class A machine, because that vessel carries a safety consequence the line's output figure knows nothing about.
So a child may legitimately outrank its parent. Do not build a validation forcing the child to be less than or equal to the parent.
Keep three classes and define each in one sentence. Criticality drives PM frequency, spare stocking and who gets called at night (preventive maintenance schedule).
Five questions to ask a vendor
Ask for a number or a demonstration rather than a yes.
- How many levels, and is the depth fixed? The maximum, whether branches must be equal depth, and whether a level can be added after go live.
- What happens to history when a machine moves? Have them move one in the demo system, then rerun last year's cost report.
- Which objects attach at which level? Work order, meter, PM plan, spare link, document and downtime, each answered separately.
- Do reports roll up the subtree, and how is double counting prevented? Ask what happens when a parent and a child both carry one event.
- Can the tree be imported and re-imported from a spreadsheet? Ask what a re-import does to rows whose parent changed, and whether asset_no can be edited.
See also what is a CMMS and equipment maintenance software.
How Fabrico helps
Fabrico is an OEE platform with a full CMMS built in, and the machine registry carries a hierarchy, files, history and QR codes.
Your team scans a machine or a part from the iOS, Android or web app to open a work order against the right node, not whatever was easiest to find.
Work orders, preventive plans with recurring templates, approvals, shifts and inventory with min and max levels hang off the asset, with parts consumption booked per work order.
Analytics cover downtime, MTTR and MTBF by machine, and multi-plant view with cross-plant benchmarking handles the levels above the site.
Data from PLC connections, IoT sensors and AI cameras puts real run time and stop reasons beside the maintenance history, and the AI assistant answers questions about one machine.
What it does not do: your team creates every work order, and there is no production planning and no formal root cause investigation. The deeper material here, such as validity dated parents, is a specification to compare against.
Want your asset tree, work order history and machine data in one place? Book a 30 minute demo with a Fabrico consultant, no commitment, or contact us with your questions.
Frequently asked questions
What are the levels of an asset hierarchy?
Site, area, production line, machine and component, with an enterprise level on top for multi-plant groups. Process plants add a system level for utilities that cross lines.
How many levels should an asset hierarchy have?
Five or six physical levels below the enterprise, with seven as the ceiling. Add a level only when something must attach there that cannot attach above or below.
Should asset numbers encode the line and area?
No. Encode only what never changes, normally site and asset class, and keep line, area and cost centre in fields where a move is one edit.
Is the fixed asset number the same as the maintenance tag?
Almost never. One purchased line is one fixed asset and twenty or more maintenance assets, so store the finance number as a field, not as the key.
How do you roll downtime up to the line?
Take the union of the machine stop windows, not their sum, because two machines stopped at once stop the line only once. Above, 80 minutes of machine stops are 55 minutes of line downtime.
See how Fabrico unifies OEE and maintenance in one platform.
Request a demoRelated articles

Real Fabrico tiles, sample data.











