Skip to content

Opportunity Hub Data Model

🏗️ Primary Entities

Opportunities: One scored record per customer and vehicle, used to prioritize outreach

Signals: Recent activity measured per customer-vehicle pair (visits, invoices, reminders, declined services, bookings, messages)

Scores: A score part per signal, a total score, and priority buckets

🔗 Key Relationships

Many-to-One: Opportunity → Customer (join on STEER_CUSTOMER_ID to the Customer export)

Many-to-One: Opportunity → Vehicle (join on STEER_VEHICLE_ID to the Vehicle export)

Many-to-One: Opportunity → Shop / Tenant (the customer’s primary shop)

The customer-vehicle pair the opportunity is scored for. STEER_CUSTOMER_ID together with STEER_VEHICLE_ID identifies a record. STEER_VEHICLE_ID is null for customers scored without a vehicle, so do not enforce NOT NULL on it and treat null as a key value.

Field NameData TypeDescriptionRequired
STEER_TENANT_IDString (UUID)Unique tenant identifier (parent organization)Yes
STEER_SHOP_IDString (UUID)The customer’s primary shopYes
STEER_CUSTOMER_IDString (UUID)Customer identifierYes
STEER_VEHICLE_IDStringVehicle identifier (null when the customer has no vehicle)No
Field NameData TypeDescriptionRequired
OPPORTUNITY_LAST_VISIT_ATTimestampLast visit of the customer with this vehicleNo
OPPORTUNITY_LAST_INVOICE_CREATED_ATTimestampWhen the newest invoice for the customer and vehicle was writtenNo
OPPORTUNITY_MAINTENANCE_REMINDER_DUE_ATTimestampNearest maintenance reminder due date: overdue up to 180 days, or due within the next 60 daysNo

Each signal comes as a pair: OPPORTUNITY_VAL_<SIGNAL> holds the measured value, and OPPORTUNITY_<SIGNAL> holds the score part calculated from it. Both are null when the signal does not apply to the pair.

SignalValue fieldScore fieldMeasures
PACOPPORTUNITY_VAL_PACOPPORTUNITY_PACPast appointments count, last 365 days
DSLAOPPORTUNITY_VAL_DSLAOPPORTUNITY_DSLADays since last appointment, last 365 days
ABCOPPORTUNITY_VAL_ABCOPPORTUNITY_ABCAbandoned online bookings count, last 14 days
DSLABOPPORTUNITY_VAL_DSLABOPPORTUNITY_DSLABDays since last abandoned booking, last 14 days
DSMAOPPORTUNITY_VAL_DSMAOPPORTUNITY_DSMADays since a missed appointment not yet rebooked, last 45 days
DSGVOPPORTUNITY_VAL_DSGVOPPORTUNITY_DSGVDays since the customer last opened their Digital Glovebox, last 30 days
DSWFOPPORTUNITY_VAL_DSWFOPPORTUNITY_DSWFDays since the customer last submitted a web form, last 30 days
DSLPIOPPORTUNITY_VAL_DSLPIOPPORTUNITY_DSLPIDays since last paid invoice, last 365 days
NMROPPORTUNITY_VAL_NMROPPORTUNITY_NMRNumber of maintenance reminders: overdue up to 180 days, plus due within the next 60 days
NDSOPPORTUNITY_VAL_NDSOPPORTUNITY_NDSNumber of declined services, last 180 days
DSDSOPPORTUNITY_VAL_DSDSOPPORTUNITY_DSDSDays since last declined service, last 180 days
MRDIOPPORTUNITY_VAL_MRDIOPPORTUNITY_MRDIDays until the maintenance reminder is due (negative = overdue): from 180 days overdue to 60 days ahead
DSLIMOPPORTUNITY_VAL_DSLIMOPPORTUNITY_DSLIMDays since last incoming message, last 90 days
OQSOPPORTUNITY_VAL_OQSOPPORTUNITY_OQSNumber of opened quotes, last 180 days
PROPPORTUNITY_VAL_PROPPORTUNITY_PRWhether the customer has provided a review
Field NameData TypeDescriptionRequired
OPPORTUNITY_TOTALNumberTotal score: the sum of the signal score parts multiplied by OPPORTUNITY_OUTCOME_COEFFICIENTYes
OPPORTUNITY_OUTCOME_COEFFICIENTNumberMultiplier from the latest Hub outcome: 1 (no outcome), 0.05 (Won), 0.01 (Lost)Yes
OPPORTUNITY_STEER_NORMALIZED_VALUENumberTotal score normalized against all customers in Steer (z-score)No
OPPORTUNITY_TENANT_NORMALIZED_VALUENumberTotal score normalized against the customers of the tenant (z-score)No
OPPORTUNITY_SHOP_NORMALIZED_VALUENumberTotal score normalized against the customers of the shop (z-score)No
OPPORTUNITY_STEER_STANDARD_DIST_BUCKETNumberPriority bucket (1–4) based on all customers in SteerNo
OPPORTUNITY_TENANT_STANDARD_DIST_BUCKETNumberPriority bucket (1–4) based on the customers of the tenantNo
OPPORTUNITY_SHOP_STANDARD_DIST_BUCKETNumberPriority bucket (1–4) based on the customers of the shopNo
OPPORTUNITY_CITNumberNumber of customers in the tenantNo
OPPORTUNITY_CISNumberNumber of customers in the shopNo

OPPORTUNITY_*_STANDARD_DIST_BUCKET ranks a pair against the chosen population:

  • 4: Highest priority
  • 3: High priority
  • 2: Medium priority
  • 1: Low priority. Also assigned for 7 days after a Won or Lost outcome is recorded in the Hub

One record from an opportunity_hub export file:

{
"STEER_TENANT_ID": "ce96b905-5647-4901-8a83-8e7dbca90418",
"STEER_SHOP_ID": "2dc598c3-1e9e-408e-82df-b8d7acff380b",
"STEER_CUSTOMER_ID": "64e017ab-ead3-4149-8d4a-ec4598e33cd4",
"STEER_VEHICLE_ID": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"OPPORTUNITY_LAST_VISIT_AT": "2026-05-12 15:20:00.000",
"OPPORTUNITY_LAST_INVOICE_CREATED_AT": "2026-05-12 16:45:10.000",
"OPPORTUNITY_MAINTENANCE_REMINDER_DUE_AT": "2026-10-28 00:00:00.000",
"OPPORTUNITY_VAL_PAC": 2,
"OPPORTUNITY_PAC": 2,
"OPPORTUNITY_VAL_DSLA": 160,
"OPPORTUNITY_DSLA": 0.31,
"OPPORTUNITY_VAL_NMR": 1,
"OPPORTUNITY_NMR": 1,
"OPPORTUNITY_VAL_MRDI": 8,
"OPPORTUNITY_MRDI": 0.74,
"OPPORTUNITY_VAL_PR": 1,
"OPPORTUNITY_PR": 1,
"OPPORTUNITY_CIT": 18240,
"OPPORTUNITY_CIS": 6110,
"OPPORTUNITY_OUTCOME_COEFFICIENT": 1,
"OPPORTUNITY_TOTAL": 5.05,
"OPPORTUNITY_STEER_NORMALIZED_VALUE": 1.12,
"OPPORTUNITY_TENANT_NORMALIZED_VALUE": 1.31,
"OPPORTUNITY_SHOP_NORMALIZED_VALUE": 1.27,
"OPPORTUNITY_STEER_STANDARD_DIST_BUCKET": 3,
"OPPORTUNITY_TENANT_STANDARD_DIST_BUCKET": 3,
"OPPORTUNITY_SHOP_STANDARD_DIST_BUCKET": 3
}