Most fleets don't have an analytics problem. They have a data-entry problem wearing an analytics costume.
You can buy the best telematics stack, hire a data scientist, stand up a dashboard — and still get garbage predictions, because the raw material feeding all of it is twelve years of inconsistent work orders where "brake job," "brakes," "BRK FRT," and "replaced pads" all describe the same repair. No model survives that. No benchmark survives that. You end up with analysts spending most of their time cleaning records instead of finding insights, which is the single most common failure pattern when fleets try to go from reactive to predictive.
This article is narrow on purpose. It covers the work order record itself — the minimum fields you need, how to code faults so they're actually queryable, what separates a usable record from a useless one, and how to drag legacy data into that standard without halting the shop. Get this layer right and almost everything downstream gets easier.
Turning inconsistent work order records into something your models can actually use
> WO #44871 — Unit 212 — "truck pulling to right, tech found front end issue, fixed and road tested, also topped off fluids" — Labor 3.5 — Parts: see invoice — Closed
-
What system failed? (Steering? Alignment? Tire? Brake drag? You can't tell.)
-
What part was replaced? ("See invoice" — which lives in a different system.)
-
Was this a repeat failure on Unit 212? (No code to match against.)
-
Did the "front end issue" cause the pull, or the "fluids"? (Two jobs buried in one record.)
A record like this is invisible to analytics. It can't be grouped, counted, trended, or predicted against. Multiply it by 40,000 historical work orders and you understand why the predictive maintenance pilot stalls.
The record that breaks everything: a real before-and-after
Here's what a typical bad record looks like, pulled from a mid-size regional delivery fleet (names and numbers altered, but the shape is exact):
Prevent costly breakdowns with proactive maintenance.
Fleetelyly helps you schedule, track, and manage every vehicle service efficiently.
- Automated maintenance reminders
- Real-time service tracking
- Parts inventory integration
No credit card required
> WO #44871 > - assetid: 212 > - jobtype: CORRECTIVE > - systemcode: STEER > - componentcode: STEER-TIEROD-OUTER-R > - faultcode: WEAR-EXCESSIVE > - symptomcode: PULL-RIGHT > - causecode: COMPONENT-WORN > - actioncode: REPLACE > - laborhours: 2.0 > - partnumber: TR-4471-OE (qty 1) > - odometer: 148,320 > - complaint_source: DRIVER-REPORT
That second version answers every question above instantly — and more importantly, it answers them the same way every time so a machine can read ten thousand of them. The fluid top-off becomes its own line, never buried inside the primary fault record.
The minimal schema: required fields and nothing you won't use
The temptation with data standards is to design a 60-field schema that captures everything. Don't. Every required field you add is a field a technician will rush, skip, or fake at 4:45pm on a Friday. The goal is the smallest set of fields that still supports reliable grouping and prediction.
| Field | Type | Required | Why it matters for analytics |
|---|---|---|---|
| workorderid | unique ID | Yes | Primary key, must never be reused |
| asset_id | controlled (fleet master) | Yes | Ties event to vehicle lifecycle |
| odometer / engine_hours | number | Yes | Normalizes failures by usage, not calendar |
| job_type | enum | Yes | Separates PM, corrective, accident, campaign |
| system_code | controlled list | Yes | Top-level grouping (brakes, steering, HVAC) |
| component_code | controlled list | Yes | The actual thing that failed |
| fault_code | controlled list | Yes | What was wrong with it |
| action_code | enum | Yes | Replace / repair / adjust / inspect |
| complaint_source | enum | Yes | Driver, PM inspection, telematics, roadside |
| labor_hours | number | Yes | Cost + MTTR analytics |
| openedat / closedat | timestamp | Yes | Cycle-time and downtime math |
Fields that should be captured but can stay optional or flexible: free-text notes (keep them — just never make them the primary data), photos, part numbers (strongly encouraged but sometimes come from a linked parts system), and cause_code (useful but harder to enforce reliably).
The hard rule underneath all of this: anything you plan to filter, group, or predict on must be a controlled value, not free text. Free text is for humans reading one record. Controlled codes are for machines reading a million. Confusing those two is the root cause of most analytics failures.
Fault-coding taxonomy: the part everyone gets wrong
Fault codes are where good intentions go to die. Teams either make the list so short it's useless ("mechanical / electrical / other") or so long that nobody can find the right code and they default to whatever's at the top of the dropdown.
The structure that actually holds up over years is a layered taxonomy with a small, stable top and a controlled-but-growing bottom.
Layer 1 — System (keep this under roughly 20 values, almost never changes):
BRAKE, STEER, SUSP, ENGINE, DRIVETRAIN, ELEC, HVAC, BODY, TIRE, HV-BATT (for EVs), etc.
Layer 2 — Component (controlled, grows slowly):
BRAKE-PAD-FRONT, BRAKE-CALIPER-R, STEER-PUMP, HV-BATT-COOLANT-PUMP...
Layer 3 — Fault (controlled, describes the failure mode):
WEAR-EXCESSIVE, LEAK, CRACK, NO-OUTPUT, INTERMITTENT, CORROSION, OVERHEAT, SENSOR-FAULT...
Keep symptom and cause separate from fault when you can. A driver reports a symptom ("pulls right"). The tech finds a fault ("tie rod worn"). The cause might be "pothole impact" or "normal wear." Collapsing these three into one field kills root-cause analysis — you lose the ability to ask how many brake faults came from caliper seizing versus pad wear versus contamination.
A practical starting point: pre-seed Layer 3 fault codes from existing industry standards like SAE/ATA VMRS rather than inventing your own from scratch. You'll adapt it, but starting from an established spine saves you from the "we invented 400 overlapping codes" trap.
Good vs bad fault records
-
fault
"broken"
-
fault
"see notes"
-
fault
"customer complaint" (that's a symptom, not a fault)
-
system
ENGINE, component: (blank), fault: LEAK → leak of what, from where?
-
system
ENGINE, component: ENGINE-WATER-PUMP, fault: LEAK, cause: SEAL-FAILURE
-
system
ELEC, component: ELEC-ALT, fault: NO-OUTPUT, cause: BEARING-FAILURE
-
system
TIRE, component: TIRE-FRONT-L, fault: WEAR-IRREGULAR, cause: ALIGNMENT-OUT
The good records share one trait: every one is a complete sentence a machine can parse — this component, had this failure, for this reason.
When a strict standard is a bad idea
This makes sense when: you're running more than roughly 50 assets, you want predictive maintenance or real benchmarking, you have mixed makes/models where free text hides patterns, or you're trying to tie maintenance signals to CAPEX and warranty decisions. At that scale, the cost of bad data compounds fast.
This is a bad idea when: you've got a handful of vehicles and one mechanic who knows every unit by heart. The overhead of a controlled taxonomy outweighs the analytics payoff. Don't build an ATA-grade coding system for 12 vans.
Who should NOT roll this out all at once: anyone whose shop is already at capacity with a high backlog. Drop a 15-field mandatory schema on a team that's underwater and they'll game it — picking the first dropdown value every time, producing confidently wrong data that's worse than honest free text. Fix throughput first, then tighten data standards. Phasing matters more than purity.
Migrating legacy data without stopping the shop
The hardest part isn't the new standard — it's the 40,000 old records. You can't retype history, and you shouldn't try.
Here's a migration sequence that works without freezing operations:
The diagram below shows the sequence and decision points for migrating legacy free-text work orders into the controlled schema.
Keep the mapping table as a living asset and show provenance for every back-filled record so analysts can filter or weight migrated data.
-
Freeze the schema going forward first. Before touching history, turn on the new required fields for new work orders. Stop the bleeding. Every day you wait, the legacy pile grows.
-
Profile what you actually have. Pull a frequency count of your existing free-text descriptions. In most fleets, the top 100–200 phrases cover 80%+ of all work orders. You don't need to map 40,000 unique strings — you need to map the common ones. This is the step teams skip, and it's the one that makes the whole project tractable.
-
Build a mapping table. For each common legacy phrase, assign a system/component/fault triplet. "brakes front," "frt brakes," "replaced front pads" →
BRAKE / BRAKE-PAD-FRONT / WEAR-EXCESSIVE. This mapping table becomes a reusable asset — keep it. -
Auto-code the high-confidence matches. Run the mapping against history. Anything that matches a known phrase gets coded automatically. Flag everything else.
-
Triage the long tail by value, not volume. The remaining 20% is messy. Don't code all of it. Prioritize records on assets you still operate and systems you care about predicting. A 2016 record on a vehicle you sold in 2021 isn't worth a human minute.
-
Mark provenance. Add a field like
data_sourceMIGRATED vs
NATIVE. Analysts need to know which records were back-filled by mapping versus captured clean. Migrated data is useful but carries more uncertainty, and models should be able to weight it accordingly. -
Spot-audit the auto-coding. Pull a random sample of around 100 auto-coded records and have a tech verify the mapping held. If accuracy is below roughly 90%, your mapping table has collisions — fix the phrases, re-run.
Prioritize triage by current asset ownership and systems you actively monitor so human effort focuses on high-value records.
You will never get legacy data to the quality of native clean capture. The goal isn't perfection — it's enough consistency that trends become visible. A fault category that's 85% correctly coded still reveals patterns that 100% free text completely hides.
A short real scenario
A regional refrigerated-transport fleet — around 180 units, mostly reefer trucks — couldn't figure out why their cooling-unit failures kept recurring. Every repair was logged as free text: "reefer down," "cooling fault," "fixed refrigeration." Warranty recovery was weak and their reliability analyst basically couldn't work.
They didn't rebuild everything. They froze a minimal schema going forward, then mapped their top 140 or so legacy descriptions to a system/component/fault taxonomy focused only on the reefer and electrical systems — the stuff that was actually costing them. Migration touched maybe 60% of records, intentionally.
Within about a quarter of clean capture plus the mapped history, the pattern was obvious: a specific condenser fan motor was failing on one trailer make at roughly two to three times the rate of the others, almost always coded ELEC / REEFER-FAN-MOTOR / BEARING-FAILURE. That had been invisible for years inside free text. They pushed it back as a warranty and spec issue. Avoided repeat failures plus recovered warranty came to somewhere in the low-to-mid five figures annually, and the analyst stopped spending most of her week cleaning records.
Nothing exotic happened. They just made the data groupable.
The quiet multiplier
This schema isn't a one-time project — it's the foundation that every other maintenance initiative quietly depends on. Benchmarking across vehicle types needs consistent system codes. Predictive models need consistent fault codes and usage-based odometer fields. Warranty recovery needs component-level precision. Root-cause analysis needs symptom, fault, and cause kept separate. Every one of those efforts fails or succeeds based on whether the underlying work order record was captured against a standard.
Modern maintenance platforms — particularly those built around AI-powered operational workflows — help here mostly by enforcing the boring part: making controlled fields required at close-out, surfacing the right fault codes based on the system selected, flagging the "see invoice" style records before they're saved, and keeping legacy mapping applied automatically going forward. That said, the software matters less than the discipline it enforces. A well-structured spreadsheet with ruthless validation beats an expensive system where everyone free-texts.
Start smaller than feels satisfying. Eleven required fields, a three-layer fault taxonomy, a mapping table for your top 150 legacy phrases. That's enough to turn years of unusable history into something your analysts — and eventually your models — can finally read.
Start smaller than feels satisfying. Eleven required fields, a three-layer fault taxonomy, a mapping table for your top 150 legacy phrases. That's enough to turn years of unusable history into something your analysts — and eventually your models — can finally read.
Ready to maximize fleet uptime and reduce maintenance costs?
Join 2,000+ fleet managers using Fleetelyly to streamline maintenance workflows and improve vehicle reliability.