Frontend application for visualizing, searching, and comparing Digital Product Passport (DPP) data with specialized rendering for the CIRPASS-2 ontology.
Main functions are:
- DPP visualization: Renders DPPs in JSON or JSON-LD format with specialized components for CIRPASS-2 ontology entities.
- DPP comparison: Side-by-side comparison of multiple DPPs with difference highlighting and tabular view.
- DPP search: Advanced search over indexed DPP data with dynamic filtering capabilities.
- QR code scanning: Direct visualization of DPPs via mobile camera scanning.- DPP Validation Resources: Upload, browse, and inspect JSON schemas and RDF templates used to validate Digital Product Passports. © CIRPASS-2 Consortium, 2024-2027
The CIRPASS-2 project receives funding under the European Union's DIGITAL EUROPE PROGRAMME under GA No 101158775.
Important disclaimer: All software and artifacts produced by the CIRPASS-2 consortium are designed for exploration and are provided for information purposes only. They should not be interpreted as being complete, exhaustive, or normative. The CIRPASS-2 consortium partners are not liable for any damage that could result from making use of this information.
Technical interpretations of the European Digital Product Passport system expressed in these artifacts are those of the author(s) only and do not necessarily reflect those of the European Union, European Commission, or the European Health and Digital Executive Agency (HADEA). Neither the European Union, the European Commission nor the granting authority can be held responsible for them. These interpretations should not be understood as reflecting those of CEN-CENELEC JTC 24.
This Angular application provides a comprehensive frontend for Digital Product Passport (DPP) data visualization and management. It connects to CIRPASS-2 backend services to retrieve, search, and compare DPPs while offering specialized rendering components for the CIRPASS-2 ontology.
- Dual-mode JSON-LD rendering: Specialized components for CIRPASS-2 ontology entities with universal fallback for unknown vocabularies.
- Ontology-aware visualization: Purpose-built renderers for Products, Actors, Facilities, Substances, LCA data, Documents, and Quantitative Properties.
- Advanced DPP comparison: Multi-DPP tabular comparison with ontology-based property extraction and difference highlighting.
- Dynamic search interface: Auto-configured search forms based on backend capabilities with filter operators and pagination.
- QR code integration: Mobile-friendly QR scanning for direct DPP import and visualization.
- DPP Validation Resources management: Role-restricted UI to upload, browse, search, and inspect JSON schemas and RDF templates used for DPP validation.
- OpenID Connect authentication with configurable role-based access control and token claim mapping.
- Responsive design built with Angular 17+ and PrimeNG components.
The application operates in two distinct rendering modes:
When the DPP document complies with the CIRPASS-2 core ontology, specialized renderer components provide optimized visualization:
- ProductRendererComponent: Product metadata, identifiers, dimensions
- ActorRendererComponent: Legal/natural persons, economic roles, facilities
- SubstanceRendererComponent: Chemical substances, substances of concern, regulatory data
- FacilityRendererComponent: Manufacturing facilities, locations, certifications
- LcaRendererComponent: Environmental impact data, carbon footprints, life cycle assessments
- DocumentRendererComponent: Digital instructions, compliance documents, certificates
- QuantitativePropertyRendererComponent: Measurements with units, thresholds, ranges
- DppInfoRendererComponent: DPP administrative metadata, status, validity
- ClassificationCodeRendererComponent: HS codes, ECLASS codes, taxonomic identifiers
When the vocabulary is unknown or unsupported, the AbstractRendererComponent provides:
- Universal property extraction: Automatic discovery and rendering of all JSON-LD properties
- Circular reference prevention: Intelligent traversal with visited node tracking
- Ontology-agnostic labels: Human-readable property names via ontology registry
- Hierarchical visualization: Multi-level nested property support
- Overview
- Quick Start
- Configuration
- Features & Components
- Backend API Integration
- Deployment
- Authentication & Authorization
- License
- Contributing
- Support
- Node.js 18+
- npm 9+
- Angular CLI 17+
- Access to CIRPASS-2 backend services (DPP Renderer BE, DPP Data Extractor)
- Optional: OpenID Connect provider (e.g., Keycloak)
npm installng serveNavigate to http://localhost:4200/. The application will automatically reload when you change source files.
# Development build
ng build
# Production build
ng build --configuration productionBuild artifacts will be stored in the dist/ directory.
# Build image
docker build -t dpp-renderer .
# Run container
docker run -p 4200:80 dpp-rendererThe application uses dynamic environment configuration via assets/env.js, allowing runtime configuration without rebuilding the application.
| Variable | Description | Default |
|---|---|---|
backendUrl |
DPP Renderer Backend API URL | http://localhost:8085 |
capabilitiesUrl |
DPP Data Extractor API URL | http://localhost:8084 |
validatorUrl |
DPP Validation Resources Backend API URL | http://localhost:8083 |
oidcIssuer |
OpenID Connect issuer URL | http://localhost:8180/realms/cirpass-2 |
oidcClientId |
OIDC client identifier | web-portal-fe |
oidcHttps |
Force HTTPS for OIDC | true |
rolesClaimName |
Dot-separated path to the roles array in the JWT access token | roles |
rolesMappings |
Comma-separated externalRole:INTERNAL_ROLE mapping pairs |
admin:ADMIN,eo:EO,eu:EU |
Development (assets/env.js):
(function (window) {
window['env'] = window['env'] || {};
window['env']['backendUrl'] = 'http://localhost:8085';
window['env']['capabilitiesUrl'] = 'http://localhost:8084';
window['env']['validatorUrl'] = 'http://localhost:8083';
window['env']['oidcIssuer'] = 'http://localhost:8180/realms/cirpass-2';
window['env']['oidcClientId'] = 'web-portal-fe';
window['env']['oidcHttps'] = false;
window['env']['rolesClaimName'] = 'roles';
window['env']['rolesMappings'] = 'admin:ADMIN,eo:EO,eu:EU';
})(this);Production (assets/env.template.js):
(function (window) {
window['env'] = window['env'] || {};
window['env']['production'] = `${PRODUCTION}`;
window['env']['backendUrl'] = '${BACKEND_URL}';
window['env']['capabilitiesUrl'] = '${CAPABILITIES_URL}';
window['env']['validatorUrl'] = '${VALIDATOR_URL}';
window['env']['oidcIssuer'] = '${OIDC_ISSUER}';
window['env']['oidcClientId'] = '${OIDC_CLIENT_ID}';
window['env']['oidcHttps'] = '${OIDC_HTTPS}';
window['env']['rolesClaimName'] = '${ROLES_CLAIM_NAME}';
window['env']['rolesMappings'] = '${ROLES_MAPPINGS}';
})(this);The application requires two backend services:
- Fetch API: DPP retrieval and format conversion
- Comparison API: Multi-DPP property extraction and comparison
- Search API: DPP search with filtering and pagination
- Capabilities API: Available search fields and filter operators
- Configuration API: Runtime search configuration management
- Validation Resources API: Upload, retrieve, search, and delete JSON schemas and RDF templates
version: '3.8'
services:
dpp-renderer:
image: dpp-renderer:latest
ports:
- "4200:80"
environment:
BACKEND_URL: "https://api.example.com"
CAPABILITIES_URL: "https://capabilities.example.com"
VALIDATOR_URL: "https://validator.example.com"
OIDC_ISSUER: "https://auth.example.com/realms/cirpass"
OIDC_CLIENT_ID: "dpp-renderer-client"
OIDC_HTTPS: "true"
ROLES_CLAIM_NAME: "realm_access.roles"
ROLES_MAPPINGS: "admin:ADMIN,eo:EO,eu:EU"
volumes:
- ./env.js:/usr/share/nginx/html/assets/env.js:ro
depends_on:
- dpp-renderer-be
- data-extractor
dpp-renderer-be:
image: ghcr.io/cirpass-2/dpp-renderer-be:latest
ports:
- "8085:8080"
environment:
QUARKUS_DATASOURCE_REACTIVE_URL: "vertx-reactive:postgresql://postgres:5432/dpp"
QUARKUS_DATASOURCE_USERNAME: "dpp_user"
QUARKUS_DATASOURCE_PASSWORD: "${DB_PASSWORD}"
QUARKUS_OIDC_AUTH_SERVER_URL: "https://auth.example.com/realms/cirpass"
QUARKUS_OIDC_CLIENT_ID: "dpp-backend"
QUARKUS_OIDC_CREDENTIALS_SECRET: "${BACKEND_SECRET}"
data-extractor:
image: ghcr.io/cirpass-2/dpp-data-extractor:latest
ports:
- "8084:8080"
environment:
QUARKUS_DATASOURCE_REACTIVE_URL: "vertx-reactive:postgresql://postgres:5432/extractor"
QUARKUS_DATASOURCE_USERNAME: "extractor_user"
QUARKUS_DATASOURCE_PASSWORD: "${DB_PASSWORD}"
postgres:
image: postgres:15
environment:
POSTGRES_DB: dpp
POSTGRES_USER: dpp_user
POSTGRES_PASSWORD: "${DB_PASSWORD}"
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:apiVersion: v1
kind: ConfigMap
metadata:
name: dpp-renderer-config
data:
env.js: |
(function (window) {
window['env'] = window['env'] || {};
window['env']['backendUrl'] = 'https://api.cluster.local';
window['env']['capabilitiesUrl'] = 'https://capabilities.cluster.local';
window['env']['oidcIssuer'] = 'https://auth.cluster.local/realms/cirpass';
window['env']['oidcClientId'] = 'dpp-renderer-k8s';
window['env']['oidcHttps'] = 'true';
})(this);
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dpp-renderer
spec:
replicas: 3
selector:
matchLabels:
app: dpp-renderer
template:
metadata:
labels:
app: dpp-renderer
spec:
containers:
- name: dpp-renderer
image: dpp-renderer:latest
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /usr/share/nginx/html/assets/env.js
subPath: env.js
volumes:
- name: config
configMap:
name: dpp-renderer-config
---
apiVersion: v1
kind: Service
metadata:
name: dpp-renderer-service
spec:
selector:
app: dpp-renderer
ports:
- port: 80
targetPort: 80
type: ClusterIPThe core visualization engine supports multiple input formats and provides specialized rendering for CIRPASS-2 ontology entities.
- JSON: Direct JSON structure visualization
- JSON-LD: Ontology-aware rendering with specialized components
- RDF formats: Automatic conversion to JSON-LD (RDF-XML, Turtle, N3, N-Quads, N-Triples) performed by the backend.
Main Controller:
- DppViewerComponent: URL input, QR scanning, format detection, rendering orchestration
Format-Specific Renderers:
- PlainJsonRendererComponent: Generic JSON structure visualization
- DppRendererComponent: JSON-LD orchestrator with ontology awareness
Ontology-Specialized Renderers: (See JSON-LD Rendering Architecture)
Advanced search interface with dynamic form generation based on backend capabilities.
- SearchFieldComponent: Individual search field with type-specific input controls
- SearchFiltersComponent: Filter management with logical operators
- SearchResultsComponent: Paginated results with action buttons
- Dynamic field discovery: Backend-driven search form configuration
- Type-aware filtering: String, decimal, integer, boolean operations
- Logical operators: EQ, GT, GTE, LT, LTE, LIKE support
- Quick actions: Direct navigation to DPP viewer from results
| Field Type | Available Operators | Example |
|---|---|---|
| STRING | EQ, LIKE | 'EcoPhone', '%Phone%' |
| DECIMAL | EQ, GT, GTE, LT, LTE | 45.8, > 100.0 |
| INTEGER | EQ, GT, GTE, LT, LTE | 2024, >= 2020 |
| BOOLEAN | EQ | true, false |
Multi-DPP comparison with property extraction and tabular visualization.
- ComparerStepperComponent: Step-by-step comparison wizard
- OntologyTreeComponent: Property selection via ontology tree
- DppComparisonComponent: Tabular comparison view with difference highlighting
- DppUrisComponent: DPP URL input and management
- Property path extraction: Configurable JSON-LD property traversal
- Difference highlighting: Visual emphasis on differing values across DPPs
- Ontology-aware: Leverage semantic types for intelligent property matching
- Export capabilities: Table data export and sharing options
- Filter differences: Option to show only properties with differing values
hasProperty[*@type=CarbonFootprint].numericalValue
| Component | Description |
|---|---|
hasProperty |
RDF property to navigate from root |
[*@type=CarbonFootprint] |
Filter: only nodes with matching type |
.numericalValue |
Target property within matched node |
Mobile-optimized QR code scanning for direct DPP import.
- ScannerComponent: QR scanner with camera access and result handling
- Camera integration: Access device camera for QR scanning
- Direct navigation: Seamless transition from scan to DPP viewer
- Error handling: User-friendly error messages for scan failures
Role-protected section for managing the JSON schemas and RDF templates used to validate Digital Product Passports. Accessible only to users whose token roles map to ADMIN or EU (configurable via rolesMappings).
- ValidatorResourcesTableComponent: Searchable, paginated table of resources (templates or schemas), accessible at
/validator/templatesand/validator/schemas. - ValidatorResourceUploadComponent: Dialog for uploading a new resource (file + metadata).
- ValidatorResourceViewComponent: Displays resource metadata and raw content, with automatic JSON pretty-print for schemas.
| Type | Description | Supported Formats |
|---|---|---|
| Schema | JSON Schema used to validate DPP payload structure | json |
| Template | RDF template describing semantic constraints | turtle, rdf_xml, rdf_json, n_triples, n_quads, n3 |
- Browse & search: Filter by name, version, and description with server-side pagination.
- Upload: Multi-part form upload (file + JSON metadata). Required fields: name, version (semver), payload type, file. Templates additionally accept an optional
contextUri. - View: Full raw content display; JSON schemas are automatically pretty-printed.
- Delete: Confirmation-gated deletion.
- Role guard: The sidebar entry for Validation Resources is shown only when
AuthService.hasAnyRole('ADMIN', 'EU')returnstrue.
# Upload a new resource
POST /resource/v1/{payloadType}
Content-Type: multipart/form-data
file: <binary>
meta: <ResourceMetadata JSON blob>
# Get resource content by ID
GET /resource/v1/{resourceType}/{id}
# Get resource content by name and version
GET /resource/v1/{resourceType}/{name}/{version}
# Search resources (all params optional)
GET /resource/v1/{resourceType}?name=&version=&description=&offset=0&limit=10
# Delete a resource
DELETE /resource/v1/{resourceType}/{id}Fetch API:
GET /fetch/v1?url={dppUrl}- Retrieves DPP from decentralized repository
- Returns JSON or expanded JSON-LD based on source format
- Supports all RDF serializations with on-the-fly conversion
Search API:
POST /search/v1
Content-Type: application/json
{
"filters": [
{ "property": "productName", "op": "LIKE", "literal": "'EcoPhone'" },
{ "property": "carbonFootprint", "op": "GT", "literal": "40.0" }
],
"offset": 0,
"limit": 20
}Comparison API:
POST /comparison/v1
Content-Type: application/json
{
"dppUrls": ["http://dpp1.example.com", "http://dpp2.example.com"],
"propertyPaths": {
"productName": [
{ "namespace": "http://dpp.taltech.ee/EUDPP#", "path": "productName" }
],
"carbonFootprint": [
{ "namespace": "http://dpp.taltech.ee/EUDPP#", "path": "hasProperty[*@type=CarbonFootprint].numericalValue" }
]
}
}Capabilities API:
GET /capabilities/v1Returns available search fields:
[
{ "fieldName": "productName", "targetType": "STRING" },
{ "fieldName": "carbonFootprint", "targetType": "DECIMAL" },
{ "fieldName": "carbonFootprintUom", "targetType": "STRING", "dependsOn": "carbonFootprint" }
]All backend requests include OpenID Connect Bearer tokens:
Authorization: Bearer <access_token>The application uses OpenID Connect (OIDC) for authentication with support for multiple identity providers.
window['env']['oidcIssuer'] = 'https://auth.example.com/realms/cirpass-2';
window['env']['oidcClientId'] = 'dpp-renderer-client';
window['env']['oidcHttps'] = 'true';The application maps external roles from the JWT access token to internal application roles (ADMIN, EO, EU) via two configurable properties:
| Variable | Purpose | Example |
|---|---|---|
rolesClaimName |
Dot-separated path to the roles array/value inside the JWT payload | realm_access.roles (Keycloak), roles (plain) |
rolesMappings |
Comma-separated externalRole:INTERNAL_ROLE pairs |
admin:ADMIN,eo:EO,eu:EU |
One external role can map to several internal roles by repeating the external key:
admin:ADMIN,admin:EO,eo:EO,eu:EU
External roles that have no mapping entry are passed through as-is.
Role resolution is performed by AuthService.roles (returns a Set<string>) and AuthService.hasAnyRole(...roles).
This project is licensed under the Apache License 2.0.
Copyright 2024-2027 CIRPASS-2
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Contributions are welcome. To contribute:
- Open a Pull Request on GitHub with your changes.
- Include tests for all modifications:
- Bug fixes must include tests that verify the fix.
- New features must include comprehensive test coverage.
- UI changes should include component tests.
- Request a review from the maintainers.
- Ensure all existing tests pass and that the code follows the project's coding standards.
- Update documentation for significant changes.
- Angular style guide: Follow official Angular coding conventions
- Component architecture: Use standalone components with modern Angular patterns
- Testing: Maintain test coverage above 80% for critical paths
- Accessibility: Ensure WCAG 2.1 AA compliance
- Performance: Follow Angular performance best practices
All contributions will be reviewed before being merged.
For questions, issues, or support requests, please contact: marco.volpini@extrared.it
ng e2eAngular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
For more information on using the Angular CLI, including detailed command references, visit the Angular CLI Overview and Command Reference page.
