-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathopendpp-dpp-shapes.ttl
More file actions
185 lines (172 loc) · 7.77 KB
/
Copy pathopendpp-dpp-shapes.ttl
File metadata and controls
185 lines (172 loc) · 7.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# OpenDPP DPP / battery SHACL starter shapes
#
# OpenDPP-authored · NON-NORMATIVE · Apache-2.0 · a starter contribution, offered to
# CIRPASS-2; NOT an EU/CIRPASS-2-official conformance suite.
#
# These shapes validate OpenDPP's PUBLIC `application/ld+json` Digital Product Passport
# (the JSON-LD door, e.g. `GET /passport/{id}` with `Accept: application/ld+json`) for the
# DPP / battery (ESPR) vertical. They are deliberately a STARTER set: reasonable coverage of
# the fields OpenDPP authoritatively models, not an exhaustive ESPR battery-regulation rulebook.
#
# They are designed against the ACTUAL RDF the sample passport expands to under its inline
# `@context` (see ../samples/battery-passport.jsonld and `validate/validate.mjs shacl`). Only
# terms present in that inline context survive JSON-LD → RDF expansion, so the shapes target the
# `dpp:DigitalProductPassport` root and use property paths; nested `economicOperator` / `Facility`
# nodes are constrained by PRESENCE (their inner fields are not in the inline context and so do not
# survive expansion — class-targeting them would be unsound).
#
# Why these exist: the CIRPASS-2 `dpp-validator` ships PLACEHOLDER `example.org` SHACL shapes; this
# fills that gap with shapes authored against OpenDPP's real DPP vocabulary. Offered as a
# contribution to CIRPASS-2 — it is NOT accepted, normative, or an EU conformance oracle.
#
# Copyright 2026 OpenDPP UAB. Licensed under the Apache License, Version 2.0 (see ../LICENSE).
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix opdppsh: <https://opendpp-node.eu/shapes/dpp#> .
@prefix dpp: <https://opendpp-node.eu/ns/dpp#> .
@prefix dppx: <https://opendpp-node.eu/contexts/dpp/v1#> .
# ── Digital Product Passport ──────────────────────────────────────────────────────────────────
# Targets every node typed dpp:DigitalProductPassport. Constraints reflect what OpenDPP
# authoritatively emits on the PUBLIC JSON-LD passport.
opdppsh:DigitalProductPassportShape
a sh:NodeShape ;
sh:targetClass dpp:DigitalProductPassport ;
# Lifecycle status — one of OpenDPP's real Passport lifecycle values. "BOGUS_STATUS" fails here.
sh:property [
sh:path dpp:status ;
sh:name "status" ;
sh:description "OpenDPP passport lifecycle status." ;
sh:datatype xsd:string ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:in ( "DRAFT" "ACTIVE" "PUBLISHED" "ARCHIVED" "DECOMMISSIONED" "RECYCLED" ) ;
] ;
# Economic operator — present (one node). Its inner fields (name / regId / role) are not in the
# inline JSON-LD context and so do not survive expansion, so we constrain presence only.
sh:property [
sh:path dpp:economicOperator ;
sh:name "economicOperator" ;
sh:description "The responsible economic operator (ESPR Art. 2). Presence-checked." ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:nodeKind sh:BlankNodeOrIRI ;
] ;
# Manufacturing facility — present (one node). The GLN / country live on a nested node not
# carried by the inline context; presence is what holds in the expanded RDF.
sh:property [
sh:path dpp:manufacturingFacility ;
sh:name "manufacturingFacility" ;
sh:description "The manufacturing facility (carries a GS1 GLN-13 on the full record)." ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:nodeKind sh:BlankNodeOrIRI ;
] ;
# Battery / ESPR metadata block — present, and its public battery fields are shape-checked.
sh:property [
sh:path dpp:metadata ;
sh:name "metadata" ;
sh:description "The public product metadata block (battery characteristics, carbon footprint, durability)." ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:nodeKind sh:BlankNodeOrIRI ;
sh:node opdppsh:BatteryMetadataShape ;
] ;
# eIDAS seal material — the vendor MerkleTreeAttestationProof seal + the signing public key.
sh:property [
sh:path dpp:digitalSeal ;
sh:name "digitalSeal" ;
sh:description "The product-passport digital seal (vendor MerkleTreeAttestationProof signature)." ;
sh:datatype xsd:string ;
sh:minCount 1 ;
sh:maxCount 1 ;
] ;
sh:property [
sh:path dpp:signingPublicKey ;
sh:name "signingPublicKey" ;
sh:description "PEM-encoded public key that verifies the seal." ;
sh:datatype xsd:string ;
sh:minCount 1 ;
sh:maxCount 1 ;
sh:pattern "-----BEGIN PUBLIC KEY-----" ;
] ;
# Flattened (top-level) battery fields — OpenDPP mirrors the metadata battery fields at the
# root too; require the load-bearing ESPR-battery ones with the same value constraints.
sh:property [
sh:path dppx:category ;
sh:name "category" ;
sh:datatype xsd:string ;
sh:minCount 1 ;
] ;
sh:property [
sh:path dppx:batteryCategory ;
sh:name "batteryCategory" ;
sh:description "EU Battery Regulation category." ;
sh:datatype xsd:string ;
sh:in ( "lmt" "industrial" "ev" "portable" "sli" ) ;
] ;
sh:property [
sh:path dppx:ratedCapacity ;
sh:name "ratedCapacity" ;
sh:description "Rated capacity (non-negative integer)." ;
sh:datatype xsd:integer ;
sh:minInclusive 0 ;
] .
# ── Battery / ESPR metadata block ─────────────────────────────────────────────────────────────
# Applied to the dpp:metadata node. These terms ARE in the inline JSON-LD context, so they survive
# expansion and can be value-constrained.
opdppsh:BatteryMetadataShape
a sh:NodeShape ;
sh:property [
sh:path dppx:category ;
sh:name "category" ;
sh:description "Product category (e.g. \"batteries\")." ;
sh:datatype xsd:string ;
sh:minCount 1 ;
sh:maxCount 1 ;
] ;
sh:property [
sh:path dppx:batteryCategory ;
sh:name "batteryCategory" ;
sh:description "EU Battery Regulation category." ;
sh:datatype xsd:string ;
sh:in ( "lmt" "industrial" "ev" "portable" "sli" ) ;
sh:maxCount 1 ;
] ;
sh:property [
sh:path dppx:chemistry ;
sh:name "chemistry" ;
sh:description "Cell chemistry (free text, e.g. \"LFP (Lithium Iron Phosphate)\")." ;
sh:datatype xsd:string ;
sh:maxCount 1 ;
] ;
sh:property [
sh:path dppx:ratedCapacity ;
sh:name "ratedCapacity" ;
sh:datatype xsd:integer ;
sh:minInclusive 0 ;
sh:maxCount 1 ;
] ;
# Carbon footprint — present (ESPR Art. 7 carbon-footprint declaration). Its inner co2eKg / unit
# fields are not in the inline context, so we check presence only.
sh:property [
sh:path dppx:carbonFootprint ;
sh:name "carbonFootprint" ;
sh:description "Carbon-footprint declaration. Presence-checked." ;
sh:minCount 1 ;
sh:maxCount 1 ;
] ;
# Durability — present (ESPR durability declaration: cycle life, calendar life).
sh:property [
sh:path dppx:durability ;
sh:name "durability" ;
sh:description "Durability declaration (cycle life / calendar life). Presence-checked." ;
sh:minCount 1 ;
sh:maxCount 1 ;
] ;
# Material composition — present, repeatable (one node per declared material).
sh:property [
sh:path dppx:materialComposition ;
sh:name "materialComposition" ;
sh:description "Declared material composition. Presence-checked (repeatable)." ;
sh:minCount 1 ;
] .