Identifier
factory-non-device-things
Submitter Contact Information
[email protected]
Domain or Industry
Factory Automation / Manufacturing
Introduction
A modern factory is more than the machines on its shop floor. It is an interconnected ecosystem of physical equipment, business processes, people, and materials. Beyond the injection moulders, fillers, motors, and sensors, there are work orders that direct what is to be produced, shifts that organize when work happens, operators who execute that work, and material lots that track what is consumed. The information that gives machine telemetry meaning lives in the relationships between these entities - a temperature reading is just a number until it is associated with the active product recipe, the responsible operator, and the work order being executed.
We are at an early stage of designing an industrial edge platform that aims to act as a single source of truth for the factory. Today, what we have working is an OPC UA ingestion pipeline: data from the shop floor reaches our edge gateway, is buffered, and is persisted for downstream analytics. We plan to add other industrial protocols (Modbus, MQTT, BACnet, EtherNet/IP, vendor-specific) in subsequent phases.
The harder design question, and the reason we are filing this use case, is what happens at the layer above the protocol bindings. Should the platform's semantic model, built on W3C Web of Things, describe only physical devices, or should it also describe the business-domain entities (work orders, shifts, operators, material lots, recipes, quality records) that give device data its meaning?
Before committing our architecture to either approach, we would value the Working Group's guidance. The Architecture spec's wording suggests both options are within scope ("a Thing is an abstraction of a physical or a virtual entity"), but the existing examples and tooling in the WoT ecosystem are heavily oriented toward devices. We have a working hypothesis about how non-device entities could be modelled as Things, and we describe it in the Solution Proposal section, but we are explicitly asking for the WG's opinion before treating it as the right answer.
WoT Usage
Thing Description
Today we use TD as the canonical representation for the device assets we are ingesting from OPC UA - physical machines exposed by a customer's OPC UA server, modeled as Things hosted by our Eclipse-VO-Stack-based edge runtime. We are also considering, and would like the WG's opinion on, extending TD to non-device entities (Work Orders, Shifts, Operators, Material Lots) by giving each its own TD hosted by the same edge runtime acting as a WoT Servient/Intermediary.
We intend to target TD 2.0 once it is closer to Recommendation.
Discovery
We plan to use a Thing Description Directory at the edge as the catalogue for all TDs. The question of whether the TDD should host both device TDs and non-device entity TDs is part of the broader question we are asking.
Bindings
For non-device entities (the design hypothesis), we are considering HTTP/SSE bindings to the edge gateway, with the gateway acting as a WoT Intermediary that translates to whichever system of record holds the authoritative copy of the data (SAP, Microsoft Dynamics, Siemens Opcenter, customer-specific workforce systems). The intent is that consumer-facing forms always point to the edge - preserving policy validation, identity domain, audit trail, and offline tolerance - while the location of the SoR is expressed only as link metadata. We have not yet implemented this and are seeking guidance on whether this pattern is the right interpretation of WoT bindings.
Technical Environment
Industrial protocols (southbound, device-facing):
- OPC UA (primary, including subscription-based change ingestion at sustained rates of 80,000+ tag changes per second per gateway)
- MQTT (also used as the on-edge transport between services)
- Modbus TCP/RTU, MQTT, BACnet, EtherNet/IP, vendor-specific protocols - planned for subsequent phases, not implemented yet.
Devices: PLCs, SCADA systems, intelligent sensors and actuators, robots.
Edge runtime: Eclipse VO Stack (https://projects.eclipse.org/proposals/eclipse-vostack) running at the customer site. We plan to extend the VO Stack with multi-Thing servient hosting, an orchestration layer for VO lifecycle, northbound HTTP and MCP proxies, and a policy enforcement service for control operations. We intend to contribute these extensions back to the Eclipse VO Stack project.
Backend systems (northbound, business-facing): SAP S/4HANA, Microsoft Dynamics, Siemens Opcenter, various MES/CMMS/QMS platforms, customer-specific workforce management systems. The integration layer (we are considering Eclipse Volttron agents acting as WoT Consumers/Intermediaries) is also at the design stage.
Standards we align with: W3C WoT, ISA-95 hierarchy.
Problem
Overall Problem
In a manufacturing setting, the value of a digital twin platform comes from semantically connecting physical machine state with the business context that gives it meaning: which work order is being executed, which material lot is loaded, which shift is on, which operator is responsible, which quality plan applies. Without this context, machine telemetry is just data; with it, it becomes information that can drive automation, AI co-pilots, and integration with enterprise systems.
W3C WoT is well-suited to describing physical devices and their composition, and the spec explicitly acknowledges that a Thing can be "an abstraction of a physical or a virtual entity." However, the use cases, examples, and supporting tooling in the WoT ecosystem are heavily oriented towards devices. It is unclear whether the Working Group considers it appropriate to model business-domain entities - Work Orders, Shifts, Operators, Material Lots, Recipes, Quality Records - as Things, alongside the machines they relate to.
If yes, the architectural payoff is significant:
- A single TDD becomes the catalogue of everything operationally relevant in the factory.
- Consumers (MES, AI agents, MCP tools, dashboards) interact uniformly with all entities through one model - Properties, Actions, Events.
- Relationships between machines and business entities are expressed as
links, navigable in both directions.
- The same security, observation, and action semantics apply uniformly.
- A single onboarding pipeline (Thing Models → Thing Descriptions) can produce both device and business-entity catalogues.
If no, we have to maintain two parallel modeling layers - one in WoT for devices, one in something else (GraphQL schemas, REST resources, custom JSON-LD ontologies) for business entities - and join them at the application layer. This loses much of the architectural benefit and forces consumers to understand two different semantic models.
A second, related problem: many of these business entities have their authoritative copy in a system of record outside the edge (SAP, Opcenter, etc.). The edge representation is a "shadow" or "projection" of that authoritative state, kept eventually consistent by an Intermediary. We believe TDs whose forms point to the Intermediary (with o3:origin link metadata identifying the SoR) are the right pattern, but this is not explicitly described in the current specs.
Missing parts of the specifications
Thing Description
- Explicit guidance on whether the
Thing abstraction is intended for non-physical, business-domain entities (work orders, shifts, operators, material lots, production orders, recipes, quality records, financial entities like cost centers) - or whether Thing should remain a device-focused concept.
- Best practices for declaring, in a TD, that a Thing is a shadow or projection of authoritative data held in an external system of record. We intend to use a custom
o3:origin link relation, but a standardized link relation type or vocabulary term would benefit interoperability.
- Guidance on stable identifiers for edge-originated entities whose ID is later assigned by a SoR (e.g., a Work Order created at the edge during an SAP outage, then reconciled when SAP becomes reachable). We intend to use the URN-first identity pattern with a
secondaryId property and an o3:origin link populated post-sync.
Discovery
- Guidance on whether a single TDD should host both device TDs and business-entity TDs, or whether they should be separated. Our current design uses one TDD; we are not aware of a reason to split, but want to confirm.
- Patterns for filtering TDD queries by relationships to other Things (e.g., "all Work Orders where
o3:performedOn points to machine X").
Bindings
- Confirmation that TDs whose forms point to a WoT Intermediary (the edge), while the authoritative data lives in an external system of record reachable only by that Intermediary, are within the intent of the WoT Binding mechanism. We believe this is correct, but want explicit confirmation, because the alternative - declaring forms that point directly at the SoR - would bypass the policy enforcement, identity domain, and audit trail that the edge provides, and is in practice often not network-reachable from consumers.
Expectation
We would like the Working Group's opinion on the following questions, in order of importance:
-
Scope of the Thing abstraction. Is it within the intent of W3C WoT to model business-domain entities (Work Orders, Shifts, Operators, Material Lots, Recipes, Quality Records, etc.) as Things, alongside physical devices? The Architecture spec's wording "abstraction of a physical or a virtual entity" suggests yes, but the ecosystem's tooling and examples suggest otherwise. We need explicit guidance.
-
Patterns for shadows of external systems of record. If the answer to (1) is yes, are there recommended patterns for TDs that represent edge-side shadows of data whose authoritative copy lives in an external system (SAP, Opcenter, etc.)? Specifically: how to express the SoR origin in metadata; how to express field-level authority split (edge vs. SoR vs. co-mutated); how to handle edge-originated identity that later reconciles to a SoR-assigned ID.
-
Bindings always pointing at the Intermediary. Confirmation that the correct pattern is for consumer-facing forms to bind to the edge Intermediary (preserving policy validation, identity domain, audit trail, offline tolerance), with the SoR location expressed only as link metadata - never as a runtime form href.
-
Documentation home. If the WG sees value in this guidance, where would it live? In the Use Cases note? As a Best Practices document? As an example pattern in the Architecture or TD spec? We have no preference, but would like to support whatever path the WG considers appropriate.
-
Negative answer scenario. If the WG concludes that non-device entities should not be modeled as WoT Things, what is the recommended boundary? What mechanism should we use for non-device entities that need to interact semantically with Things (e.g., a Work Order that executes on a Machine and consumes a Material Lot)? Pure JSON-LD without WoT semantics? AAS submodels referenced from TDs? A separate registry?
We are not asking for a specification change. We are asking for clarity on intent and best practice from the WG, ideally formalized somewhere durable. Our team is happy to contribute draft text, example TDs, or example Thing Models to whichever artifact the WG considers the right home.
Solution Proposal
The following describes the modelling approach we are considering. It is a design hypothesis we are asking the Working Group to validate (or correct), not a description of what we have built today.
Our current pipeline ingests OPC UA data and instantiates device-class Thing Descriptions from class-level Thing Models for the machines on the customer's shop floor. The hypothesis we want WG's opinion on is whether to extend this to non-device entities by treating the following as Things:
- Machines and submodules (devices): conventional WoT modeling, OPC UA / Modbus / etc. Protocol Bindings, hosted by the Eclipse VO Stack runtime, composed via links (rel: item / rel: collection). This is the part we have closest to working today.
- Work Orders (hypothesis): TDs hosted by the edge gateway, forms binding to edge HTTP endpoints, an
o3:origin link pointing to the URL in the SoR (e.g., a SAP PM notification), and o3:performedOn / o3:assignedTo / o3:partOfShift links pointing to the related Machine, Operator, and Shift TDs.
- Shifts (hypothesis): TDs with planned and actual start/end timestamps (split authority - planned would be SoR-authoritative, actual would be edge-authoritative), links to operators (
o3:employs), the production line (o3:covers), and the next shift (next).
- Operators (hypothesis): lightweight TDs with shift links (
o3:partOfShift), current assignment (o3:currentlyAssigned), and readOnly skill certifications projected from the workforce SoR.
- Material Lots (hypothesis): TDs with consumption tracking, links to active Machines (
o3:loadedOn) and the Work Orders consuming them.
Composition between Things would use standard links with rel: item / rel: collection for hierarchical containment, and custom o3: link relations for domain-specific relationships. Field-level authority between edge and SoR would be declared on Property affordances via a custom o3:authoritativeOrigin annotation (edge, sor, coMutated).
Below is an abbreviated TD 2.0-targeted example of what a Work Order Thing might look like in this hypothesis. Forms point at the edge; the SoR location is metadata only.
{
"@context": [
"https://www.w3.org/ns/wot-next/td",
{
"o3": "https://schema.o3.example/v1/",
"schema": "https://schema.org/"
}
],
"id": "urn:o3:workorder:WO-2026-04-24-0119",
"@type": ["o3:WorkOrder"],
"title": "Replenish PET resin for PET001",
"description": "Replenishment work order raised in response to a MaterialLevelCritical event on PET injection moulder PET001.",
"base": "https://edge.factory.example/things/workorders/WO-2026-04-24-0119/",
"securityDefinitions": {
"oauth2_sc": {
"scheme": "oauth2",
"flow": "code",
"token": "https://casdoor.factory.example/api/login/oauth/access_token"
}
},
"security": "oauth2_sc",
"links": [
{ "rel": "o3:performedOn",
"href": "https://edge.factory.example/things/PET001",
"type": "application/td+json" },
{ "rel": "o3:assignedTo",
"href": "https://edge.factory.example/things/operators/OP-JDOE",
"type": "application/td+json" },
{ "rel": "o3:partOfShift",
"href": "https://edge.factory.example/things/shifts/2026-04-24-B",
"type": "application/td+json" },
{ "rel": "o3:raisedBy",
"href": "https://edge.factory.example/things/PET001/events/materialLevelCritical",
"type": "application/td+json" },
{ "rel": "o3:origin",
"href": "https://erp.customer.example/api/maintenance/work-orders/WO-2026-04-24-0119",
"type": "application/json" }
],
"properties": {
"kind": {
"@type": "o3:WorkOrderKind",
"title": "Work order kind",
"description": "Domain classification of the work order.",
"type": "string",
"enum": ["planned", "unplanned", "predictive", "corrective", "preventive"],
"readOnly": true,
"forms": [{ "op": "readproperty", "href": "properties/kind" }]
},
"priority": {
"title": "Priority",
"type": "string",
"enum": ["P1", "P2", "P3", "P4"],
"observable": true,
"forms": [
{ "op": "readproperty", "href": "properties/priority" },
{ "op": "observeproperty", "href": "properties/priority",
"contentType": "text/event-stream", "subprotocol": "sse" }
]
},
"status": {
"@type": "o3:WorkOrderStatus",
"title": "Status",
"type": "string",
"enum": ["draft", "dispatched", "inProgress", "paused",
"completed", "cancelled"],
"readOnly": true,
"observable": true,
"forms": [
{ "op": "readproperty", "href": "properties/status" },
{ "op": "observeproperty", "href": "properties/status",
"contentType": "text/event-stream", "subprotocol": "sse" }
]
},
"createdAt": {
"title": "Created at",
"description": "Time at which the work order was first created.",
"type": "string",
"format": "date-time",
"readOnly": true,
"forms": [{ "op": "readproperty", "href": "properties/createdAt" }]
},
"dueAt": {
"title": "Due at",
"description": "Target completion time. Co-mutated with the system of record.",
"type": "string",
"format": "date-time",
"observable": true,
"forms": [
{ "op": "readproperty", "href": "properties/dueAt" },
{ "op": "observeproperty", "href": "properties/dueAt",
"contentType": "text/event-stream", "subprotocol": "sse" }
]
},
"dispatchedAt": {
"title": "Dispatched at",
"type": "string",
"format": "date-time",
"readOnly": true,
"forms": [{ "op": "readproperty", "href": "properties/dispatchedAt" }]
},
"startedAt": {
"title": "Started at",
"description": "Time at which work was actually started on the floor (edge-authoritative).",
"type": "string",
"format": "date-time",
"readOnly": true,
"forms": [{ "op": "readproperty", "href": "properties/startedAt" }]
},
"completedAt": {
"title": "Completed at",
"type": "string",
"format": "date-time",
"readOnly": true,
"forms": [{ "op": "readproperty", "href": "properties/completedAt" }]
},
"estimatedDurationMinutes": {
"title": "Estimated duration in minutes",
"type": "integer",
"minimum": 0,
"forms": [{ "op": "readproperty",
"href": "properties/estimatedDurationMinutes" }]
},
"summary": {
"title": "Summary",
"description": "Free-text summary of the work to be performed.",
"type": "string",
"forms": [{ "op": "readproperty", "href": "properties/summary" }]
}
},
"actions": {
"changeState": {
"title": "Change state",
"description": "Transition the work order to a new lifecycle state.",
"synchronous": false,
"input": {
"type": "object",
"properties": {
"targetState": {
"type": "string",
"enum": ["dispatched", "inProgress", "paused",
"completed", "cancelled"]
},
"technicianRef": {
"type": "string",
"format": "uri",
"description": "Required when transitioning to dispatched."
},
"outcome": {
"type": "string",
"enum": ["resolved", "deferred", "noFaultFound"],
"description": "Required when transitioning to completed."
},
"actualDurationMinutes": {
"type": "integer",
"minimum": 0,
"description": "Optional when transitioning to completed."
},
"reason": {
"type": "string",
"description": "Free-text reason. Required for paused and cancelled."
},
"notes": { "type": "string" }
},
"required": ["targetState"]
},
"forms": [{ "op": "invokeaction", "href": "actions/changeState" }]
},
"updateAttributes": {
"title": "Update attributes",
"description": "Update one or more mutable attributes (priority, due date, assignee, summary). State transitions are not handled here — use changeState. Each field is policy-validated independently.",
"synchronous": false,
"input": {
"type": "object",
"properties": {
"priority": { "type": "string", "enum": ["P1", "P2", "P3", "P4"] },
"dueAt": { "type": "string", "format": "date-time" },
"assigneeRef": { "type": "string", "format": "uri" },
"summary": { "type": "string" },
"reason": { "type": "string" }
}
},
"forms": [{ "op": "invokeaction", "href": "actions/updateAttributes" }]
}
},
"events": {
"statusChanged": {
"title": "Status changed",
"description": "Emitted whenever the status property changes, regardless of origin (consumer-invoked changeState action or a status update projected from the system of record).",
"data": {
"type": "object",
"properties": {
"previousStatus": { "type": "string" },
"currentStatus": { "type": "string" },
"changedBy": { "type": "string", "format": "uri" },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"forms": [
{ "op": "subscribeevent", "href": "events/statusChanged",
"contentType": "text/event-stream", "subprotocol": "sse" }
]
},
"assigneeChanged": {
"title": "Assignee changed",
"description": "Emitted whenever the assigned operator changes (initial dispatch or reassignment).",
"data": {
"type": "object",
"properties": {
"previousAssignee": { "type": "string", "format": "uri" },
"currentAssignee": { "type": "string", "format": "uri" },
"reason": { "type": "string" },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"forms": [
{ "op": "subscribeevent", "href": "events/assigneeChanged",
"contentType": "text/event-stream", "subprotocol": "sse" }
]
},
"priorityChanged": {
"title": "Priority changed",
"data": {
"type": "object",
"properties": {
"previousPriority": { "type": "string" },
"currentPriority": { "type": "string" },
"changedBy": { "type": "string", "format": "uri" },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"forms": [
{ "op": "subscribeevent", "href": "events/priorityChanged",
"contentType": "text/event-stream", "subprotocol": "sse" }
]
}
}
}
We would be happy to contribute fuller examples (machine + submodule composite, Shift, Operator, Material Lot) and the corresponding Thing Models to the wot-usecases repository if the WG considers this a valid direction.
Comments
Background context. We are building this on the Eclipse VO Stack and intend to contribute back orchestration, multi-Thing servient hosting, northbound HTTP/MCP proxies, and policy enforcement capabilities to that project as open source. We are committed to following W3C WoT standards as they evolve, and will track TD 2.0 through Recommendation.
Security considerations. All consumer-facing TDs declare OAuth 2.0 (via Casdoor as the central IdP, with OIDC federation to customer IdPs). For business-entity TDs that shadow data from external SoRs, the credentials to the SoR are held by the edge Intermediary; consumers never see them. We mint short-lived scoped delegation tokens at the edge for VO-internal command flows, so even within the cluster a raw consumer JWT cannot directly mutate a Thing without going through the policy enforcement layer. This appears consistent with the WoT security model, but we would welcome input.
Privacy considerations. Operator TDs contain personally identifiable information (name, role, certifications, current assignment) and are subject to GDPR/CCPA in customer deployments. We expose only operationally necessary fields and use readOnly aggressively for fields whose authoritative copy is in HR/workforce systems. Cross-border deployments require attention to where the TDD itself is hosted (must be on-premise or in a jurisdiction-aligned region). The WoT Discovery spec's privacy considerations apply but do not specifically address PII in business-entity TDs.
Identifier
factory-non-device-things
Submitter Contact Information
[email protected]
Domain or Industry
Factory Automation / Manufacturing
Introduction
A modern factory is more than the machines on its shop floor. It is an interconnected ecosystem of physical equipment, business processes, people, and materials. Beyond the injection moulders, fillers, motors, and sensors, there are work orders that direct what is to be produced, shifts that organize when work happens, operators who execute that work, and material lots that track what is consumed. The information that gives machine telemetry meaning lives in the relationships between these entities - a temperature reading is just a number until it is associated with the active product recipe, the responsible operator, and the work order being executed.
We are at an early stage of designing an industrial edge platform that aims to act as a single source of truth for the factory. Today, what we have working is an OPC UA ingestion pipeline: data from the shop floor reaches our edge gateway, is buffered, and is persisted for downstream analytics. We plan to add other industrial protocols (Modbus, MQTT, BACnet, EtherNet/IP, vendor-specific) in subsequent phases.
The harder design question, and the reason we are filing this use case, is what happens at the layer above the protocol bindings. Should the platform's semantic model, built on W3C Web of Things, describe only physical devices, or should it also describe the business-domain entities (work orders, shifts, operators, material lots, recipes, quality records) that give device data its meaning?
Before committing our architecture to either approach, we would value the Working Group's guidance. The Architecture spec's wording suggests both options are within scope ("a Thing is an abstraction of a physical or a virtual entity"), but the existing examples and tooling in the WoT ecosystem are heavily oriented toward devices. We have a working hypothesis about how non-device entities could be modelled as Things, and we describe it in the Solution Proposal section, but we are explicitly asking for the WG's opinion before treating it as the right answer.
WoT Usage
Thing Description
Today we use TD as the canonical representation for the device assets we are ingesting from OPC UA - physical machines exposed by a customer's OPC UA server, modeled as Things hosted by our Eclipse-VO-Stack-based edge runtime. We are also considering, and would like the WG's opinion on, extending TD to non-device entities (Work Orders, Shifts, Operators, Material Lots) by giving each its own TD hosted by the same edge runtime acting as a WoT Servient/Intermediary.
We intend to target TD 2.0 once it is closer to Recommendation.
Discovery
We plan to use a Thing Description Directory at the edge as the catalogue for all TDs. The question of whether the TDD should host both device TDs and non-device entity TDs is part of the broader question we are asking.
Bindings
For non-device entities (the design hypothesis), we are considering HTTP/SSE bindings to the edge gateway, with the gateway acting as a WoT Intermediary that translates to whichever system of record holds the authoritative copy of the data (SAP, Microsoft Dynamics, Siemens Opcenter, customer-specific workforce systems). The intent is that consumer-facing forms always point to the edge - preserving policy validation, identity domain, audit trail, and offline tolerance - while the location of the SoR is expressed only as link metadata. We have not yet implemented this and are seeking guidance on whether this pattern is the right interpretation of WoT bindings.
Technical Environment
Industrial protocols (southbound, device-facing):
Devices: PLCs, SCADA systems, intelligent sensors and actuators, robots.
Edge runtime: Eclipse VO Stack (https://projects.eclipse.org/proposals/eclipse-vostack) running at the customer site. We plan to extend the VO Stack with multi-Thing servient hosting, an orchestration layer for VO lifecycle, northbound HTTP and MCP proxies, and a policy enforcement service for control operations. We intend to contribute these extensions back to the Eclipse VO Stack project.
Backend systems (northbound, business-facing): SAP S/4HANA, Microsoft Dynamics, Siemens Opcenter, various MES/CMMS/QMS platforms, customer-specific workforce management systems. The integration layer (we are considering Eclipse Volttron agents acting as WoT Consumers/Intermediaries) is also at the design stage.
Standards we align with: W3C WoT, ISA-95 hierarchy.
Problem
Overall Problem
In a manufacturing setting, the value of a digital twin platform comes from semantically connecting physical machine state with the business context that gives it meaning: which work order is being executed, which material lot is loaded, which shift is on, which operator is responsible, which quality plan applies. Without this context, machine telemetry is just data; with it, it becomes information that can drive automation, AI co-pilots, and integration with enterprise systems.
W3C WoT is well-suited to describing physical devices and their composition, and the spec explicitly acknowledges that a Thing can be "an abstraction of a physical or a virtual entity." However, the use cases, examples, and supporting tooling in the WoT ecosystem are heavily oriented towards devices. It is unclear whether the Working Group considers it appropriate to model business-domain entities - Work Orders, Shifts, Operators, Material Lots, Recipes, Quality Records - as Things, alongside the machines they relate to.
If yes, the architectural payoff is significant:
links, navigable in both directions.If no, we have to maintain two parallel modeling layers - one in WoT for devices, one in something else (GraphQL schemas, REST resources, custom JSON-LD ontologies) for business entities - and join them at the application layer. This loses much of the architectural benefit and forces consumers to understand two different semantic models.
A second, related problem: many of these business entities have their authoritative copy in a system of record outside the edge (SAP, Opcenter, etc.). The edge representation is a "shadow" or "projection" of that authoritative state, kept eventually consistent by an Intermediary. We believe TDs whose forms point to the Intermediary (with
o3:originlink metadata identifying the SoR) are the right pattern, but this is not explicitly described in the current specs.Missing parts of the specifications
Thing Description
Thingabstraction is intended for non-physical, business-domain entities (work orders, shifts, operators, material lots, production orders, recipes, quality records, financial entities like cost centers) - or whetherThingshould remain a device-focused concept.o3:originlink relation, but a standardized link relation type or vocabulary term would benefit interoperability.secondaryIdproperty and ano3:originlink populated post-sync.Discovery
o3:performedOnpoints to machine X").Bindings
Expectation
We would like the Working Group's opinion on the following questions, in order of importance:
Scope of the
Thingabstraction. Is it within the intent of W3C WoT to model business-domain entities (Work Orders, Shifts, Operators, Material Lots, Recipes, Quality Records, etc.) as Things, alongside physical devices? The Architecture spec's wording "abstraction of a physical or a virtual entity" suggests yes, but the ecosystem's tooling and examples suggest otherwise. We need explicit guidance.Patterns for shadows of external systems of record. If the answer to (1) is yes, are there recommended patterns for TDs that represent edge-side shadows of data whose authoritative copy lives in an external system (SAP, Opcenter, etc.)? Specifically: how to express the SoR origin in metadata; how to express field-level authority split (edge vs. SoR vs. co-mutated); how to handle edge-originated identity that later reconciles to a SoR-assigned ID.
Bindings always pointing at the Intermediary. Confirmation that the correct pattern is for consumer-facing forms to bind to the edge Intermediary (preserving policy validation, identity domain, audit trail, offline tolerance), with the SoR location expressed only as link metadata - never as a runtime form
href.Documentation home. If the WG sees value in this guidance, where would it live? In the Use Cases note? As a Best Practices document? As an example pattern in the Architecture or TD spec? We have no preference, but would like to support whatever path the WG considers appropriate.
Negative answer scenario. If the WG concludes that non-device entities should not be modeled as WoT Things, what is the recommended boundary? What mechanism should we use for non-device entities that need to interact semantically with Things (e.g., a Work Order that executes on a Machine and consumes a Material Lot)? Pure JSON-LD without WoT semantics? AAS submodels referenced from TDs? A separate registry?
We are not asking for a specification change. We are asking for clarity on intent and best practice from the WG, ideally formalized somewhere durable. Our team is happy to contribute draft text, example TDs, or example Thing Models to whichever artifact the WG considers the right home.
Solution Proposal
The following describes the modelling approach we are considering. It is a design hypothesis we are asking the Working Group to validate (or correct), not a description of what we have built today.
Our current pipeline ingests OPC UA data and instantiates device-class Thing Descriptions from class-level Thing Models for the machines on the customer's shop floor. The hypothesis we want WG's opinion on is whether to extend this to non-device entities by treating the following as Things:
o3:originlink pointing to the URL in the SoR (e.g., a SAP PM notification), ando3:performedOn/o3:assignedTo/o3:partOfShiftlinks pointing to the related Machine, Operator, and Shift TDs.o3:employs), the production line (o3:covers), and the next shift (next).o3:partOfShift), current assignment (o3:currentlyAssigned), and readOnly skill certifications projected from the workforce SoR.o3:loadedOn) and the Work Orders consuming them.Composition between Things would use standard links with
rel: item/rel: collectionfor hierarchical containment, and customo3:link relations for domain-specific relationships. Field-level authority between edge and SoR would be declared on Property affordances via a customo3:authoritativeOriginannotation (edge, sor, coMutated).Below is an abbreviated TD 2.0-targeted example of what a Work Order Thing might look like in this hypothesis. Forms point at the edge; the SoR location is metadata only.
{ "@context": [ "https://www.w3.org/ns/wot-next/td", { "o3": "https://schema.o3.example/v1/", "schema": "https://schema.org/" } ], "id": "urn:o3:workorder:WO-2026-04-24-0119", "@type": ["o3:WorkOrder"], "title": "Replenish PET resin for PET001", "description": "Replenishment work order raised in response to a MaterialLevelCritical event on PET injection moulder PET001.", "base": "https://edge.factory.example/things/workorders/WO-2026-04-24-0119/", "securityDefinitions": { "oauth2_sc": { "scheme": "oauth2", "flow": "code", "token": "https://casdoor.factory.example/api/login/oauth/access_token" } }, "security": "oauth2_sc", "links": [ { "rel": "o3:performedOn", "href": "https://edge.factory.example/things/PET001", "type": "application/td+json" }, { "rel": "o3:assignedTo", "href": "https://edge.factory.example/things/operators/OP-JDOE", "type": "application/td+json" }, { "rel": "o3:partOfShift", "href": "https://edge.factory.example/things/shifts/2026-04-24-B", "type": "application/td+json" }, { "rel": "o3:raisedBy", "href": "https://edge.factory.example/things/PET001/events/materialLevelCritical", "type": "application/td+json" }, { "rel": "o3:origin", "href": "https://erp.customer.example/api/maintenance/work-orders/WO-2026-04-24-0119", "type": "application/json" } ], "properties": { "kind": { "@type": "o3:WorkOrderKind", "title": "Work order kind", "description": "Domain classification of the work order.", "type": "string", "enum": ["planned", "unplanned", "predictive", "corrective", "preventive"], "readOnly": true, "forms": [{ "op": "readproperty", "href": "properties/kind" }] }, "priority": { "title": "Priority", "type": "string", "enum": ["P1", "P2", "P3", "P4"], "observable": true, "forms": [ { "op": "readproperty", "href": "properties/priority" }, { "op": "observeproperty", "href": "properties/priority", "contentType": "text/event-stream", "subprotocol": "sse" } ] }, "status": { "@type": "o3:WorkOrderStatus", "title": "Status", "type": "string", "enum": ["draft", "dispatched", "inProgress", "paused", "completed", "cancelled"], "readOnly": true, "observable": true, "forms": [ { "op": "readproperty", "href": "properties/status" }, { "op": "observeproperty", "href": "properties/status", "contentType": "text/event-stream", "subprotocol": "sse" } ] }, "createdAt": { "title": "Created at", "description": "Time at which the work order was first created.", "type": "string", "format": "date-time", "readOnly": true, "forms": [{ "op": "readproperty", "href": "properties/createdAt" }] }, "dueAt": { "title": "Due at", "description": "Target completion time. Co-mutated with the system of record.", "type": "string", "format": "date-time", "observable": true, "forms": [ { "op": "readproperty", "href": "properties/dueAt" }, { "op": "observeproperty", "href": "properties/dueAt", "contentType": "text/event-stream", "subprotocol": "sse" } ] }, "dispatchedAt": { "title": "Dispatched at", "type": "string", "format": "date-time", "readOnly": true, "forms": [{ "op": "readproperty", "href": "properties/dispatchedAt" }] }, "startedAt": { "title": "Started at", "description": "Time at which work was actually started on the floor (edge-authoritative).", "type": "string", "format": "date-time", "readOnly": true, "forms": [{ "op": "readproperty", "href": "properties/startedAt" }] }, "completedAt": { "title": "Completed at", "type": "string", "format": "date-time", "readOnly": true, "forms": [{ "op": "readproperty", "href": "properties/completedAt" }] }, "estimatedDurationMinutes": { "title": "Estimated duration in minutes", "type": "integer", "minimum": 0, "forms": [{ "op": "readproperty", "href": "properties/estimatedDurationMinutes" }] }, "summary": { "title": "Summary", "description": "Free-text summary of the work to be performed.", "type": "string", "forms": [{ "op": "readproperty", "href": "properties/summary" }] } }, "actions": { "changeState": { "title": "Change state", "description": "Transition the work order to a new lifecycle state.", "synchronous": false, "input": { "type": "object", "properties": { "targetState": { "type": "string", "enum": ["dispatched", "inProgress", "paused", "completed", "cancelled"] }, "technicianRef": { "type": "string", "format": "uri", "description": "Required when transitioning to dispatched." }, "outcome": { "type": "string", "enum": ["resolved", "deferred", "noFaultFound"], "description": "Required when transitioning to completed." }, "actualDurationMinutes": { "type": "integer", "minimum": 0, "description": "Optional when transitioning to completed." }, "reason": { "type": "string", "description": "Free-text reason. Required for paused and cancelled." }, "notes": { "type": "string" } }, "required": ["targetState"] }, "forms": [{ "op": "invokeaction", "href": "actions/changeState" }] }, "updateAttributes": { "title": "Update attributes", "description": "Update one or more mutable attributes (priority, due date, assignee, summary). State transitions are not handled here — use changeState. Each field is policy-validated independently.", "synchronous": false, "input": { "type": "object", "properties": { "priority": { "type": "string", "enum": ["P1", "P2", "P3", "P4"] }, "dueAt": { "type": "string", "format": "date-time" }, "assigneeRef": { "type": "string", "format": "uri" }, "summary": { "type": "string" }, "reason": { "type": "string" } } }, "forms": [{ "op": "invokeaction", "href": "actions/updateAttributes" }] } }, "events": { "statusChanged": { "title": "Status changed", "description": "Emitted whenever the status property changes, regardless of origin (consumer-invoked changeState action or a status update projected from the system of record).", "data": { "type": "object", "properties": { "previousStatus": { "type": "string" }, "currentStatus": { "type": "string" }, "changedBy": { "type": "string", "format": "uri" }, "timestamp": { "type": "string", "format": "date-time" } } }, "forms": [ { "op": "subscribeevent", "href": "events/statusChanged", "contentType": "text/event-stream", "subprotocol": "sse" } ] }, "assigneeChanged": { "title": "Assignee changed", "description": "Emitted whenever the assigned operator changes (initial dispatch or reassignment).", "data": { "type": "object", "properties": { "previousAssignee": { "type": "string", "format": "uri" }, "currentAssignee": { "type": "string", "format": "uri" }, "reason": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" } } }, "forms": [ { "op": "subscribeevent", "href": "events/assigneeChanged", "contentType": "text/event-stream", "subprotocol": "sse" } ] }, "priorityChanged": { "title": "Priority changed", "data": { "type": "object", "properties": { "previousPriority": { "type": "string" }, "currentPriority": { "type": "string" }, "changedBy": { "type": "string", "format": "uri" }, "timestamp": { "type": "string", "format": "date-time" } } }, "forms": [ { "op": "subscribeevent", "href": "events/priorityChanged", "contentType": "text/event-stream", "subprotocol": "sse" } ] } } }We would be happy to contribute fuller examples (machine + submodule composite, Shift, Operator, Material Lot) and the corresponding Thing Models to the wot-usecases repository if the WG considers this a valid direction.
Comments
Background context. We are building this on the Eclipse VO Stack and intend to contribute back orchestration, multi-Thing servient hosting, northbound HTTP/MCP proxies, and policy enforcement capabilities to that project as open source. We are committed to following W3C WoT standards as they evolve, and will track TD 2.0 through Recommendation.
Security considerations. All consumer-facing TDs declare OAuth 2.0 (via Casdoor as the central IdP, with OIDC federation to customer IdPs). For business-entity TDs that shadow data from external SoRs, the credentials to the SoR are held by the edge Intermediary; consumers never see them. We mint short-lived scoped delegation tokens at the edge for VO-internal command flows, so even within the cluster a raw consumer JWT cannot directly mutate a Thing without going through the policy enforcement layer. This appears consistent with the WoT security model, but we would welcome input.
Privacy considerations. Operator TDs contain personally identifiable information (name, role, certifications, current assignment) and are subject to GDPR/CCPA in customer deployments. We expose only operationally necessary fields and use
readOnlyaggressively for fields whose authoritative copy is in HR/workforce systems. Cross-border deployments require attention to where the TDD itself is hosted (must be on-premise or in a jurisdiction-aligned region). The WoT Discovery spec's privacy considerations apply but do not specifically address PII in business-entity TDs.