diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..cb50e3a
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length = 88
+extend-ignore = E501
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..6313b56
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..92605ed
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,87 @@
+name: CI Pipeline
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+ workflow_dispatch:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ # --- JOB 1: Standards & Syntax ---
+ standards-and-syntax:
+ name: 🎨 Standards & Syntax
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ # Use 'true' (non-recursive) to fetch just the top level submodule.
+ # This works if you don't need the nested gitlab dependencies for linting.
+ submodules: true
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+ cache: 'pip'
+
+ - name: Install dependencies
+ run: python3 -m pip install -e ./ontology-management-base -e ".[dev]"
+
+ - name: Install pre-commit hooks
+ run: pre-commit install
+
+ - name: Run pre-commit (Lint + Syntax)
+ run: pre-commit run --all-files
+
+ # --- JOB 2: Examples Validation ---
+ validate-examples:
+ name: ⚖️ Validate Examples
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ # Do NOT set submodules here. We handle them manually.
+
+ - name: Fix Submodule URLs and Update
+ run: |
+ # 1. Fix top-level .gitmodules (GitHub SSH -> HTTPS)
+ sed -i 's/git@github.com:/https:\/\/github.com\//g' .gitmodules
+
+ # 2. Init and Update ONLY the top-level submodule first
+ git submodule update --init ontology-management-base
+
+ # 3. Now enter the submodule and fix ITS .gitmodules (GitLab SSH -> HTTPS)
+ cd ontology-management-base
+ sed -i 's/git@gitlab.com:/https:\/\/gitlab.com\//g' .gitmodules
+
+ # 4. Now safe to recurse inside
+ git submodule update --init --recursive
+
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+ cache: 'pip'
+
+ - name: Install dependencies
+ run: python3 -m pip install -e ./ontology-management-base -e ".[dev]"
+
+ - name: Generate Ontology from LinkML
+ run: python3 src/generate_from_linkml.py
+
+ - name: Run SHACL Validation on Examples
+ run: |
+ FILES=$(find examples -name "*.json" -o -name "*.jsonld")
+
+ if [ -z "$FILES" ]; then
+ echo "No example files found to test."
+ exit 0
+ fi
+
+ echo "Testing the following files:"
+ echo "$FILES"
+
+ python3 ontology-management-base/src/check_jsonld_against_shacl_schema.py $FILES --force-load
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
deleted file mode 100644
index 40e457b..0000000
--- a/.github/workflows/linter.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: Run Spectral on Pull Requests
-
-on:
- - pull_request
-
-jobs:
- build:
- name: Run Spectral
- runs-on: ubuntu-latest
- steps:
- # Check out the repository
- - uses: actions/checkout@v2
-
- # Run Spectral
- - uses: stoplightio/spectral-action@latest
- with:
- file_glob: '*.json'
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..076c410
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/.venv/
+/.vscode/
+**/__pycache__/
+*.log
+/generated/*/
+*.zip
+*.egg-info/
+.ontology_iri_cache.json
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..29328a4
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "ontology-management-base"]
+ path = ontology-management-base
+ url = git@github.com:GAIA-X4PLC-AAD/ontology-management-base.git
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..aee7f2f
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,41 @@
+---
+repos:
+ - repo: local
+ hooks:
+ - id: black
+ name: black
+ entry: black
+ language: system
+ types: [python]
+ args: ["--config=pyproject.toml"]
+ pass_filenames: true
+
+ - id: isort
+ name: isort
+ entry: isort
+ language: system
+ types: [python]
+ args: ["--settings=pyproject.toml"]
+ pass_filenames: true
+
+ - id: flake8
+ name: flake8
+ entry: flake8
+ language: system
+ types: [python]
+ args: ["--config=.flake8"]
+ pass_filenames: true
+
+ - id: jsonld-lint
+ name: JSON-LD Parser
+ entry: python ontology-management-base/src/utils/check_parse_jsonld.py
+ language: system
+ types: [json]
+ files: \.json$
+
+ - id: turtle-lint
+ name: Turtle Parser
+ entry: python ontology-management-base/src/utils/check_parse_turtle.py
+ language: system
+ types: [text]
+ files: \.(ttl)$
diff --git a/.spectral.yaml b/.spectral.yaml
deleted file mode 100644
index 1cac3b3..0000000
--- a/.spectral.yaml
+++ /dev/null
@@ -1 +0,0 @@
-extends: ["spectral:oas", "spectral:asyncapi"]
diff --git a/README.md b/README.md
index 3c40519..ff95a67 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,246 @@
-# DEMIM Credentials
-
-## Content
-A public repository containing examples for (verifiable) credentials, associated json-ld context definitions and json manifests. The crendetials are used in the [Decentralized Digital Membership Management](https://identity.ascs.digital).
-The DID of issuers and subjects and the UUIDs of the credentials have been aligned with the content of the following example [revocation registry](https://better-call.dev/ghostnet/KT1PZFXebyGvRFG8enbuVL9nrvTi4krYqeKt/storage.)
-
-## Examples
-There are two types of json-ld examples for the credentials. The member credentials and the user credential. The member credential is used to e.g. register a company with an application like e.g. [Simpulse](https://simpulse.de) for creating the company profile with minimal validated information. The user credential is used in asc(s ecosystem applications to set initial rights and roles.
-The examples are once given with an external context definition and also with the attributes defined inline in the credential context itself. This is necessary as third-party libraries like [didkit](https://github.com/spruceid/didkit) do not allow external context loading due to security implications.
-
-## Manifests
-The manifest files are provided to render an identity card in a SSI wallet like e.g. [altme](https://altme.io) according to the identity foundation [wallet rendering specification](https://identity.foundation/wallet-rendering/).
-
-## Todos
-The context json files need to be hosted at https://schema.ascs.digital/AscsUserCredential/v1.
-All terms need to be hosted as .pdf files at https://media.ascs.digital/terms/.
-
-## Resources
-* [Implementation Guide](https://www.w3.org/TR/vc-imp-guide/#creating-new-credential-types)
-* [w3c credentials v1](https://www.w3.org/2018/credentials/v1)
-* [w3c vc-json-schema](https://w3c.github.io/vc-json-schema/)
-* [json schema specification](https://json-schema.org/specification)
-* [public schemas](https://schema.org/)
-* [transform tools](https://transform.tools/)
-* [json-ld best practices](https://w3c.github.io/json-ld-bp/?specStatus=ED)
-* [version 4 uuid](https://www.uuidgenerator.net/version4)
-* [module: pkh-tezos](https://did.js.org/docs/api/modules/pkh_tezos/)
-* [did-pkh-method-draft](https://github.com/w3c-ccg/did-pkh/blob/main/did-pkh-method-draft.md)
-* [Multiassets](https://multiformats.io/)
-* [Content Identifier (CID)](https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid)
-* [POC Content Identifier](https://github.com/GAIA-X4PLC-AAD/poc-ipfs-content-identifier)
+# SimpulseID Credentials for the ENVITED Ecosystem
+
+This repository contains the **Verifiable Credential (VC)** building blocks used by
+[https://identity.ascs.digital/](https://identity.ascs.digital/)
+to manage identities and memberships in the **ENVITED Ecosystem** of the
+_Automotive Solution Center for Simulation e.V. (ASCS e.V.)_.
+
+The repository provides:
+
+- JSON-LD **contexts** for all SimpulseID credential types
+- Example **Verifiable Credentials** (VC v2, OIDC4VP-ready)
+- Example **did:web** DID documents for participants, programs, users, and admins
+- **Wallet manifests** for card rendering in SSI wallets (e.g. Altme)
+- RDF/OWL **ontologies** and SKOS vocabularies aligning with the Gaia-X Trust Framework and ENVITED Ecosystem Specifications (EVES)
+
+All of this is intended to be **publicly hostable** and consumable by wallets, verifiers and services in the ENVITED ecosystem.
+
+---
+
+## Cloning with submodules
+
+The repository depends on the follwing submodules:
+
+```markdown
+Root Project
+├── Submodule A
+│ └── Submodule B (Nested inside A)
+└── Submodule C
+```
+
+```bash
+# First time
+git clone --recurse-submodules git@github.com:ASCS-eV/credentials.git
+# Initialize after already having cloned
+git submodule update --init --recursive
+# Pull all changes also from submodules
+git pull --recurse-submodules
+```
+
+---
+
+## Installation & Configure `pre-commit`
+
+If you want to use the validation scripts from 📁 `ontology-management-base/src` then you need to isntall the following dependencies:
+
+```bash
+# On Windows use python instead of python3
+sudo apt-get install python3-full
+
+# 1. Create and activate a virtual environment
+python3 -m venv .venv/
+source .venv/bin/activate # On Windows use: source .venv/Scripts/activate
+
+# 2. Install dependencies (Submodule + Main Project + Dev Tools)
+# This reads both pyproject.toml files and handles all versions automatically.
+python3 -m pip install -e ./ontology-management-base -e ".[dev]"
+
+# 3. Verify
+pre-commit install
+pre-commit run --all-files
+```
+
+---
+
+## Generate and validate
+
+```bash
+# 1. Generate ontologies, SHACL shapes and Contexts from LinkML models
+# We generate artifacts for core, harbour, and simpulseid so they are available in generated/
+python3 src/generate_from_linkml.py # Auto-discovers *.yaml in linkml/
+
+# 2. Example check
+# The script now automatically finds the 'generated/' folder and 'ontology-management-base/' submodule
+python3 ontology-management-base/src/check_jsonld_against_shacl_schema.py examples/simpulseid-administrator-credential.json
+```
+
+---
+
+## Repository structure
+
+### `contexts/`
+
+JSON-LD context documents used by SimpulseID credentials, for example:
+
+- `SimpulseIdCredentials.json` – main context for:
+ - `simpulseid:Participant`
+ - `simpulseid:AscsBaseMembership`
+ - `simpulseid:AscsEnvitedMembership`
+ - `simpulseid:Administrator`
+ - `simpulseid:User`
+- `HarbourCredentials.json` – additional context for status / revocation information
+- SKOS / code list contexts (e.g. legal form vocabulary)
+
+These files are meant to be hosted under:
+
+- `https://schema.ascs.digital/...`
+
+and are referenced from the example credentials via their `@context` arrays.
+
+---
+
+### `examples/`
+
+Example **Verifiable Credentials** that show how the contexts and ontologies are intended to be used.
+
+Typical credential subjects include:
+
+- **Participant** – organizational identity (e.g. BMW)
+- **ASCS Base Membership** – base membership in ASCS e.V.
+- **ASCS ENVITED Membership** – ENVITED program membership, linked to base membership
+- **Administrator** – natural person with administrative rights in ENVITED / ASCS
+- **User** – natural person with initial roles/rights in ENVITED ecosystem applications
+
+Each VC uses:
+
+- `https://www.w3.org/2018/credentials#` (VC Data Model v2)
+- SimpulseID context from this repo
+- Harbour context for `credentialStatus`
+- `harbour:CRSetEntry` + `statusPurpose: "revocation"` for revocation status
+- `gx:*` terms to stay compatible with the **Gaia-X Credential Format** and Trust Framework
+
+#### `examples/did-web/`
+
+Example **did:web DID documents** that correspond to identifiers used in the credentials, e.g.:
+
+- Participants (`did:web:did.ascs.digital:participants:...`)
+- Programs (`did:web:did.ascs.digital:programs:...`)
+- Users & administrators (`did:web:did.ascs.digital:users:...`)
+- Services (`did:web:did.ascs.digital:services:...`)
+
+These demonstrate:
+
+- How organizational DIDs (ASCS, ENVITED programs, participants) are modelled
+- How user/admin DIDs are defined _without leaking personal data_
+- How to support key rotation and multiple chains (e.g. Tezos + Etherlink/EVM) via `blockchainAccountId`
+
+In production, these DID documents are intended to be hosted under:
+
+- `https://did.ascs.digital/...`
+
+---
+
+### `manifests/`
+
+Wallet **rendering manifests** for each credential type, following the
+[Decentralized Identity Foundation Wallet Rendering specification](https://identity.foundation/wallet-rendering/).
+
+They are used by wallets like **Altme** to:
+
+- Render credential “cards” with titles, subtitles and key properties
+- Show important fields such as:
+ - organization name, legal form, VAT ID
+ - membership program and hosting organization
+ - user/admin name, email, affiliation
+ - links to terms & conditions and privacy policies
+- Map `credentialSubject` properties and dates (`issuanceDate`, `expirationDate`) to UI elements
+
+Each manifest references:
+
+- A SimpulseID schema / type (e.g. `simpulseid:Participant`)
+- The issuer DID of the manifest (typically an ASCS did:web)
+
+---
+
+### `ontologies/`
+
+RDF/OWL ontologies and vocabularies that define the **formal semantics** of SimpulseID types and properties, aligned with:
+
+- **Gaia-X Trust Framework 24.11**
+- **ENVITED Ecosystem Specifications (EVES)**
+- **schema.org** and **vCard** where appropriate
+
+Key elements include:
+
+- `SimpulseIdOntology.ttl`
+ - Classes:
+ - `simpulseid:Participant` ⊑ `gx:LegalPerson`, `schema:Organization`
+ - `simpulseid:AscsBaseMembership`, `simpulseid:AscsEnvitedMembership` ⊑ `schema:ProgramMembership`
+ - `simpulseid:Administrator`, `simpulseid:User` ⊑ `gx:NaturalPerson`, `schema:Person`
+ - Program classes for base and ENVITED memberships
+ - Properties:
+ - `simpulseid:legalForm` → SKOS `simpulseid:LegalForm` concepts
+ - `simpulseid:termsAndConditions` → `gx:TermsAndConditions` resources
+ - `simpulseid:baseMembership` linking ENVITED membership to base membership
+ - Address modelling:
+ - `gx:Address` with **vCard** properties:
+ - `vcard:street-address`
+ - `vcard:postal-code`
+ - `vcard:locality`
+ - `vcard:region`
+ - `gx:countryCode` for ISO country codes
+
+- Legal form SKOS vocabulary (e.g. `legalForm-v1.jsonld`)
+ - Code list of legal forms (`AG`, `GmbH`, `LLC`, `BenCom`, etc.)
+ - Used via `simpulseid:LegalForm` and `simpulseid:legalForm` in credentials
+
+These ontologies are the **ground truth** for what the JSON-LD contexts and examples mean at RDF level.
+
+---
+
+## Intended usage within `https://identity.ascs.digital/`
+
+The artifacts in this repository are used by the **ENVITED Ecosystem identity services** to:
+
+- Issue and verify **Gaia-X compatible** Verifiable Credentials
+- Support **self-sovereign identity** login flows via the **SSI-to-OIDC bridge**
+- Provide consistent semantics for:
+ - ENVITED participants (organizations)
+ - ASCS base memberships
+ - ENVITED program memberships
+ - Administrative and user roles
+- Render credential cards in SSI wallets for a smooth UX
+
+Typical flow:
+
+1. A participant (organization) is onboarded and receives a **Participant VC**.
+2. The organization receives **ASCS base membership** and optionally **ENVITED membership** credentials.
+3. Individual administrators and users receive **Admin/User VCs**, bound to opaque did:web identifiers under `did.ascs.digital`.
+4. Wallets like Altme use the **contexts** and **manifests** from this repo to display these credentials.
+5. Services behind `identity.ascs.digital` use the **ontologies** and **Gaia-X compatible structures** to perform trust and membership checks.
+
+---
+
+## References
+
+Some relevant specifications and resources:
+
+- W3C Verifiable Credentials Data Model v2
+
+- W3C Verifiable Credential Vocabulary (VC v2)
+
+- Gaia-X Credential Format & Trust Framework (24.11)
+
+- DIF Wallet Rendering specification
+
+- JSON-LD 1.1 & best practices
+
+
+- JSON Schema
+
+- schema.org
+
+
+```
+
+```
diff --git a/contexts/AscsMemberCredential.json b/contexts/AscsMemberCredential.json
deleted file mode 100644
index 87f58f3..0000000
--- a/contexts/AscsMemberCredential.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "@version": 1.1,
- "@protected": true,
- "AscsMemberCredential": "https://schema.ascs.digital/AscsMemberCredential#",
- "AscsIssuer": {
- "@id": "https://schema.ascs.digital/AscsMemberCredential#AscsIssuer",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "url": "https://schema.org/url"
- }
- },
- "AscsMember": {
- "@id": "https://schema.ascs.digital/AscsMemberCredential#AscsMember",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "url": "https://schema.org/url",
- "address": "http://schema.org/address",
- "vatID": "http://schema.org/vatID",
- "isAscsMember": "http://schema.org/Boolean",
- "isEnvitedMember": "http://schema.org/Boolean",
- "privacyPolicy": "https://schema.org/termsOfService",
- "articlesOfAssociation": "https://schema.org/termsOfService",
- "contributionRules": "https://schema.org/termsOfService"
- }
- },
- "PostalAddress": {
- "@id": "http://schema.org/PostalAddress",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "streetAddress": "http://schema.org/streetAddress",
- "postalCode": "http://schema.org/postalCode",
- "addressLocality": "http://schema.org/addressLocality",
- "addressCountry": "https://schema.org/addressCountry"
- }
- }
-}
\ No newline at end of file
diff --git a/contexts/AscsUserCredential.json b/contexts/AscsUserCredential.json
deleted file mode 100644
index 2886fbc..0000000
--- a/contexts/AscsUserCredential.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "@version": 1.1,
- "@protected": true,
- "AscsUserCredential": "https://schema.ascs.digital/AscsUserCredential/v1#",
- "AscsIssuer": {
- "@id": "https://schema.ascs.digital/AscsUserCredential/v1#AscsIssuer",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "url": "https://schema.org/url"
- }
- },
- "AscsUser": {
- "@id": "https://schema.ascs.digital/AscsUserCredential/v1#AscsUser",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "email": "https://schema.org/email",
- "address": "http://schema.org/address",
- "isAscsMember": "http://schema.org/Boolean",
- "isEnvitedMember": "http://schema.org/Boolean",
- "privacyPolicy": "https://schema.org/termsOfService"
- }
- },
- "PostalAddress": {
- "@id": "http://schema.org/PostalAddress",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "streetAddress": "http://schema.org/streetAddress",
- "postalCode": "http://schema.org/postalCode",
- "addressLocality": "http://schema.org/addressLocality",
- "addressCountry": "https://schema.org/addressCountry"
- }
- }
-}
\ No newline at end of file
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..e37f945
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,155 @@
+# SimpulseID Credential Examples
+
+This folder contains **reference examples** for all Verifiable Credentials used in the
+ENVITED Ecosystem operated by ASCS e.V.
+
+These examples demonstrate:
+
+- the JSON-LD structure using the public contexts in `/contexts`
+- the semantics defined in `/ontologies`
+- correct use of did:web identifiers for:
+ - participants (organizations)
+ - ASCS programs (base membership, ENVITED membership)
+ - users and administrators (opaque non-PII identifiers)
+- correct Gaia-X–compatible modelling of addresses, legal forms, and terms & conditions
+- revocation status entries using the Harbour Credentials context
+
+The examples serve as a canonical blueprint for services integrating with
+****.
+
+---
+
+## Structure of the Examples
+
+### 1. Verifiable Credentials
+
+Each credential in this folder uses:
+
+- `https://www.w3.org/2018/credentials#` (VC Data Model v2)
+- `simpulseid_context.jsonld` (main context)
+- `harbour_context.jsonld` (credential status)
+- `harbour:CRSetEntry` with `statusPurpose: "revocation"`
+
+Types included:
+
+- **Participant Credential**
+ Identity of an organization (e.g., BMW), aligned with Gaia-X `gx:LegalPerson`.
+
+- **ASCS Base Membership Credential**
+ Proof of base membership in ASCS e.V.
+
+- **ENVITED Membership Credential**
+ Extends the base membership and links to a program DID.
+
+- **Administrator Credential**
+ Natural person with elevated rights, issued and controlled by ASCS.
+
+- **User Credential**
+ Natural person affiliated with a participant, issued by the participant’s admin.
+
+All credentials use **did:web subject identifiers** for users and admins:
+
+- opaque
+- non-PII
+- key-rotation capable
+- hosted under:
+ `https://did.ascs.digital/users/...`
+
+All credentials use the `evidence` field to show that the credential was requested by an admin before being signed by the service. Checking this is possible by:
+
+- checking the cryptographic and syntactical integrity of the `evidence`
+- retrieving the issuer's DID document, which is a participant `did:web`
+- iterating over the `verificationMethod` array
+ - retrieving DID document of `controller`
+ - checking if that document contains the `did:key` that signed the `evidence` vp
+- if a match was found, the `evidence` is valid
+
+---
+
+## 2. did:web Documents
+
+Examples under `examples/did-web/` illustrate:
+
+- Participant DIDs controlled by organizations
+ (`did:web:did.ascs.digital:participants:ascs`, `participants:bmw`, …)
+
+- Program DIDs controlled by ASCS
+ (`did:web:did.ascs.digital:programs:ascs-base-membership`, …)
+
+- User and Administrator DIDs:
+ Opaque, privacy-preserving identifiers that _only_ expose verification keys.
+
+Each DID document supports:
+
+- Tezos account (did:pkh)
+- Etherlink/EVM account (`blockchainAccountId: eip155:42793:...`)
+- Key rotation (through verificationMethod lists)
+
+No DID document contains personal data.
+
+---
+
+## 3. Wallet Rendering Manifests
+
+The manifests in `/manifests` define how SSI wallets such as **Altme** render cards using the
+Decentralized Identity Foundation **Wallet Rendering Specification**.
+
+Each manifest:
+
+- references the correct SimpulseID credential type
+- defines which properties appear on the card
+- includes human-readable fallback titles
+- is issued by the ASCS organizational DID (`did:web:did.ascs.digital:participants:ascs`)
+
+---
+
+## 4. Notes on Issuance Model
+
+### Participant Credentials
+
+Issued by ASCS upon onboarding of an organization into the ENVITED ecosystem.
+
+### Program Membership Credentials
+
+Base membership and ENVITED membership are issued by ASCS.
+
+### Administrator Credentials
+
+Issued by ASCS to individuals acting on behalf of ASCS or participants.
+
+### User Credentials
+
+Issued by participant administrators to individuals.
+These credentials use an opaque user DID under `did.ascs.digital` to support:
+
+- privacy (no PII in DID)
+- key rotation
+- multi-chain keys (Tezos + Etherlink)
+
+---
+
+## 5. Revocation
+
+Example credentials reference a `credentialStatus` entry:
+
+- `harbour:CRSetEntry`
+- `statusPurpose: "revocation"`
+- `id` pointing to a `did:web` revocation registry fragment
+
+The DID document for the registry includes a **service endpoint** pointing to the actual registry.
+
+---
+
+## 6. Tooling
+
+You may use:
+
+- **jsonld-cli** for JSON-LD normalization and checking
+- **didkit** for signing / verifying VC Data Model v2 credentials
+- **jq** for inspection and debugging
+- **JSON Schema** for linting examples where applicable
+
+---
+
+This folder is meant as a **reference implementation** for developers integrating
+SimpulseID credentials into ENVITED applications and services.
diff --git a/examples/did-web/README.md b/examples/did-web/README.md
new file mode 100644
index 0000000..975b0c5
--- /dev/null
+++ b/examples/did-web/README.md
@@ -0,0 +1,245 @@
+# Example did:web Documents for SimpulseID
+
+This folder contains example **did:web DID documents** for entities used in the
+SimpulseID / ENVITED identity ecosystem. These examples demonstrate how program,
+participant, administrator, and user identifiers are published under the
+`did.ascs.digital` domain.
+
+All documents in this folder are **examples only** and contain placeholder JWS
+signatures (`EXAMPLE_SIGNATURE_*`) and placeholder JWK values. When deploying
+these DIDs, replace the placeholder signatures and keys with real material
+generated by the appropriate entity (ASCS or delegated admin user).
+
+---
+
+## Core Trust Model (SimpulseID Best Practice)
+
+### did:web control
+
+SimpulseID uses **did:web**, which means:
+
+- The **controller in practice is always ASCS**, because ASCS operates the
+ `did.ascs.digital` web server.
+- All DID Documents declare:
+
+ ```json
+ "controller": "did:web:did.ascs.digital:services:trust-anchor"
+ ```
+
+ This expresses that all published DIDs are governed by the **ASCS trust
+ anchor service**.
+
+### Signatures = Attestations
+
+The `proof` section in each DID Document:
+
+- **does not grant control**,
+- it **attests** that ASCS (or BMW, where relevant) approves the content.
+
+The true controlling entity for all did:web documents is always the
+`services:trust-anchor` DID, because it owns the hosting infrastructure.
+
+---
+
+## Program DID Documents
+
+Programs represent SimpulseID system-level definitions. They have stable
+identifiers:
+
+- `did:web:did.ascs.digital:programs:ascs-base-membership`
+- `did:web:did.ascs.digital:programs:ascs-envited-membership`
+- `did:web:did.ascs.digital:programs:simpulseid-user`
+- `did:web:did.ascs.digital:programs:simpulseid-administrator`
+
+They must be hosted at:
+
+- `https://did.ascs.digital/programs//did.json`
+
+Programs are always:
+
+- **controlled by**: `services:trust-anchor`
+- **signed by**: `participants:ascs`
+- **never storing personal keys**
+- **never delegating signing authority**
+
+---
+
+## Participant DIDs
+
+Participant DIDs represent **Gaia-X Legal Persons**, such as:
+
+- `did:web:did.ascs.digital:participants:ascs`
+- `did:web:did.ascs.digital:participants:bmw`
+
+Participant DIDs contain:
+
+- organizational metadata (`schema:Organization`, `gx:LegalPerson`)
+- a list of **delegated admin user keys** in `verificationMethod`
+- **active delegated admin keys** in `assertionMethod`
+- **revoked delegated admin keys** in `verificationMethod`
+ with a `"revoked"` timestamp
+
+### Important: BMW has no own cryptographic keys
+
+BMW intentionally **does not hold a participant-level key**.
+
+Instead:
+
+- **admin users sign “on behalf of BMW”**
+- BMW’s DID lists **active admin keys** under `assertionMethod`
+- Old admin keys remain listed with:
+
+ ```json
+ "revoked": ""
+ ```
+
+ but their `id` (the hash fragment) stays **unchanged** so that
+ any existing references from credentials remain valid.
+
+### Hash fragment naming convention
+
+Because DID URLs with hash fragments are referenced from credentials and other
+documents, **fragments MUST be stable over the lifetime of the key**. They
+MUST NOT be renamed when the key is revoked.
+
+SimpulseID uses a simple, incremental naming scheme per network:
+
+```uri
+#-key-
+```
+
+Examples:
+
+- `#tezos-key-1`
+- `#etherlink-key-1`
+- `#etherlink-key-2`
+
+When a key is revoked:
+
+- keep the `id` (e.g. `#etherlink-key-2`) unchanged,
+- add a `"revoked": ""` field to the corresponding
+ `verificationMethod` entry,
+- remove that key from `assertionMethod`.
+
+---
+
+## User DIDs
+
+User DIDs live at:
+
+- `did:web:did.ascs.digital:users/`
+
+Properties:
+
+- **DID controlled by**: `services:trust-anchor`
+- **keys controlled by the user**:
+
+ ```json
+ "controller": "did:web:did.ascs.digital:users/"
+ ```
+
+- used for personal authentication and signatures
+- contain no organization metadata
+
+User DID Documents are signed by ASCS as attestation of correct structure.
+
+---
+
+## Administrator DIDs
+
+An administrator is **not** a different DID type.
+
+Admin status is expressed through:
+
+- an **AdministratorCredential** issued by ASCS
+- Harbour CRSet revocation for demotion
+- BMW (or other participant) updating its participant DID to include the
+ admin user's keys in `assertionMethod`
+
+Admin promotion/demotion is reflected only in:
+
+- **credentials**
+- **participant DID** (delegated key listing)
+
+The user DID does **not** structurally change when becoming an admin.
+
+---
+
+## Trust Anchor DID
+
+`did:web:did.ascs.digital:services:trust-anchor` is the authoritative DID that:
+
+- asserts ownership of the SimpulseID infrastructure
+- governs all did:web documents hosted under `did.ascs.digital`
+- signs all program, participant, user, admin, and service DIDs
+
+All other DIDs reference:
+
+```json
+"controller": "did:web:did.ascs.digital:services:trust-anchor"
+```
+
+---
+
+## Revocation Registry DID
+
+The revocation registry lives at:
+
+- `did:web:did.ascs.digital:services:revocation-registry`
+
+It contains a `CRSetRevocationRegistryService` with:
+
+- CRSet registry API URL
+- blockchain contract URN
+- GitHub repository link
+- scientific publication reference
+
+Credentials refer to status entries using:
+
+```json
+"credentialStatus": {
+ "type": "harbour:CRSetEntry",
+ "id": "did:web:did.ascs.digital:services:revocation-registry#"
+}
+```
+
+---
+
+## Deployment Notes
+
+To deploy these DIDs in production:
+
+1. Store each DID at:
+
+ ```url
+ https://did.ascs.digital/.../did.json
+ ```
+
+2. Replace placeholder values:
+
+ - `EXAMPLE_SIGNATURE_*`
+ - JWKs
+ - blockchain addresses
+
+3. Ensure:
+
+ - MIME type `application/did+json`
+ - correct hosting paths
+ - TLS integrity
+
+4. For key rotation:
+
+ - add new admin user keys
+ - update `assertionMethod`
+ - annotate old keys with `"revoked"` (without renaming their `id`)
+
+5. For admin lifecycle:
+
+ - issue or revoke `AdministratorCredential`
+ - update participant DID key status accordingly
+
+---
+
+These did:web examples form the public reference implementation for the
+SimpulseID trust anchor, identity lifecycle, and delegation model used in the
+ENVITED Ecosystem.
diff --git a/examples/did-web/simpulseid-participant-bmw-did.json b/examples/did-web/simpulseid-participant-bmw-did.json
new file mode 100644
index 0000000..ea49f79
--- /dev/null
+++ b/examples/did-web/simpulseid-participant-bmw-did.json
@@ -0,0 +1,78 @@
+{
+ "@context": [
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://www.w3.org/ns/did/v1",
+ "https://schema.org"
+ ],
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "alsoKnownAs": [
+ "https://did.ascs.digital/participants/bmw"
+ ],
+ "verificationMethod": [
+ {
+ "id": "did:web:did.ascs.digital:participants:bmw#wallet-key-1",
+ "type": "Ed25519VerificationKey2018",
+ "controller": "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e",
+ "publicKeyMultibase": "z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
+ },
+ {
+ "id": "did:web:did.ascs.digital:participants:bmw#wallet-key-2",
+ "type": "Ed25519VerificationKey2018",
+ "controller": "did:web:did.ascs.digital:users:21c7c8bc-6860-490b-8ec7-219c89d93e2c",
+ "publicKeyMultibase": "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
+ }
+ ],
+ "assertionMethod": [
+ "did:web:did.ascs.digital:participants:bmw#wallet-key-1",
+ "did:web:did.ascs.digital:participants:bmw#wallet-key-2"
+ ],
+ "service": [
+ {
+ "id": "did:web:did.ascs.digital:participants:bmw#org-metadata",
+ "type": "OrganizationMetadataService",
+ "serviceEndpoint": "https://www.bmwgroup.com/"
+ }
+ ],
+ "organization": {
+ "@id": "did:web:did.ascs.digital:participants:bmw",
+ "type": [
+ "simpulseid:Participant",
+ "gx:LegalPerson",
+ "schema:Organization"
+ ],
+ "legalName": "Bayerische Motoren Werke Aktiengesellschaft",
+ "legalForm": "AG",
+ "registrationNumber": {
+ "@type": "gx:VatID",
+ "countryCode": "DE",
+ "vatID": "DE129273398"
+ },
+ "duns": "313995269",
+ "email": "imprint@bmw.com",
+ "website": "https://www.bmwgroup.com/",
+ "legalAddress": {
+ "@type": "gx:Address",
+ "streetAddress": "Petuelring 130",
+ "postalCode": "80809",
+ "addressLocality": "München",
+ "countrySubdivisionCode": "DE-BY",
+ "country": "DE"
+ },
+ "headquartersAddress": {
+ "@type": "gx:Address",
+ "streetAddress": "Petuelring 130",
+ "postalCode": "80809",
+ "addressLocality": "München",
+ "countrySubdivisionCode": "DE-BY",
+ "country": "DE"
+ }
+ },
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:20:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.EXAMPLE_SIGNATURE_PAYLOAD_BMW"
+ }
+}
diff --git a/examples/did-web/simpulseid-program-administrator-did.json b/examples/did-web/simpulseid-program-administrator-did.json
new file mode 100644
index 0000000..4274981
--- /dev/null
+++ b/examples/did-web/simpulseid-program-administrator-did.json
@@ -0,0 +1,41 @@
+{
+ "@context": [
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://www.w3.org/ns/did/v1",
+ "https://schema.org"
+ ],
+ "id": "did:web:did.ascs.digital:programs:simpulseid-administrator",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "service": [
+ {
+ "id": "did:web:did.ascs.digital:programs:simpulseid-administrator#program-metadata",
+ "type": "ProgramMetadataService",
+ "serviceEndpoint": {
+ "@type": [
+ "schema:CreativeWork",
+ "simpulseid:AdministratorProgram"
+ ],
+ "@id": "https://did.ascs.digital/programs/simpulseid-administrator",
+ "name": "SimpulseID Administrator Program",
+ "description": "Program definition for SimpulseID administrators who manage participant onboarding, user roles, and membership credentials within the ENVITED Ecosystem.",
+ "about": "Administrator-level SimpulseID credentials with elevated permissions for managing organizations and memberships.",
+ "publisher": {
+ "@type": "schema:Organization",
+ "name": "Automotive Solution Center for Simulation e.V. (ASCS)",
+ "url": "https://ascs.digital/"
+ },
+ "inLanguage": "en",
+ "datePublished": "2025-08-05",
+ "termsOfService": "https://media.ascs.digital/terms/simpulse_id_terms_2025-08-05.pdf#cidv1",
+ "privacyPolicy": "https://media.ascs.digital/terms/administrator_privacy_policy_2025-08-05.pdf#cidv1"
+ }
+ }
+ ],
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:02:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImFzY3MtZGlkLXdlYi1rZXktMSJ9.EXAMPLE_SIGNATURE_SIMPULSEID_ADMIN_PROGRAM"
+ }
+}
diff --git a/examples/did-web/simpulseid-program-ascs-base-membership-did.json b/examples/did-web/simpulseid-program-ascs-base-membership-did.json
new file mode 100644
index 0000000..a7759f4
--- /dev/null
+++ b/examples/did-web/simpulseid-program-ascs-base-membership-did.json
@@ -0,0 +1,42 @@
+{
+ "@context": [
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://www.w3.org/ns/did/v1",
+ "https://schema.org"
+ ],
+ "id": "did:web:did.ascs.digital:programs:ascs-base-membership",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "alsoKnownAs": [
+ "https://did.ascs.digital/programs/ascs-base-membership"
+ ],
+ "service": [
+ {
+ "id": "did:web:did.ascs.digital:programs:ascs-base-membership#program-metadata",
+ "type": "ProgramMetadataService",
+ "serviceEndpoint": "https://did.ascs.digital/programs/ascs-base-membership"
+ }
+ ],
+ "program": {
+ "@type": [
+ "schema:Program",
+ "simpulseid:BaseMembershipProgram"
+ ],
+ "@id": "https://did.ascs.digital/programs/ascs-base-membership",
+ "name": "ASCS e.V. Base Membership",
+ "description": "Base membership program of the Automotive Solution Center for Simulation e.V. (ASCS e.V.).",
+ "hostingOrganization": {
+ "@id": "did:web:did.ascs.digital:participants:ascs",
+ "@type": "Organization",
+ "name": "Automotive Solution Center for Simulation e.V."
+ },
+ "articlesOfAssociation": "https://media.ascs.digital/terms/ascs_articles_of_association_2021-09-17.pdf#cidv1",
+ "contributionRules": "https://media.ascs.digital/terms/ascs_contribution_rules_2020-07-08.pdf#cidv1"
+ },
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:00:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.EXAMPLE_SIGNATURE_PAYLOAD"
+ }
+}
diff --git a/examples/did-web/simpulseid-program-ascs-envited-membership-did.json b/examples/did-web/simpulseid-program-ascs-envited-membership-did.json
new file mode 100644
index 0000000..7602e5b
--- /dev/null
+++ b/examples/did-web/simpulseid-program-ascs-envited-membership-did.json
@@ -0,0 +1,48 @@
+{
+ "@context": [
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://www.w3.org/ns/did/v1",
+ "https://schema.org"
+ ],
+ "id": "did:web:did.ascs.digital:programs:ascs-envited-membership",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "alsoKnownAs": [
+ "https://did.ascs.digital/programs/ascs-envited-membership"
+ ],
+ "service": [
+ {
+ "id": "did:web:did.ascs.digital:programs:ascs-envited-membership#program-metadata",
+ "type": "ProgramMetadataService",
+ "serviceEndpoint": "https://did.ascs.digital/programs/ascs-envited-membership"
+ }
+ ],
+ "program": {
+ "@type": [
+ "schema:Program",
+ "simpulseid:EnvitedMembershipProgram"
+ ],
+ "@id": "https://did.ascs.digital/programs/ascs-envited-membership",
+ "name": "ASCS e.V. ENVITED Membership",
+ "description": "ENVITED membership program of the Automotive Solution Center for Simulation e.V. (ASCS e.V.), providing access to the ENVITED ecosystem and related services.",
+ "hostingOrganization": {
+ "@id": "did:web:did.ascs.digital:participants:ascs",
+ "@type": "Organization",
+ "name": "Automotive Solution Center for Simulation e.V."
+ },
+ "articlesOfAssociation": "https://media.ascs.digital/terms/ascs_articles_of_association_2021-09-17.pdf#cidv1",
+ "contributionRules": "https://media.ascs.digital/terms/ascs_contribution_rules_2020-07-08.pdf#cidv1",
+ "ecosystem": {
+ "@type": "schema:DigitalEcosystem",
+ "name": "ENVITED-X Data Space",
+ "url": "https://envited-x.net/",
+ "description": "The ENVITED-X Data Space is a collaborative platform for secure data sharing and digital asset management in the ENVITED ecosystem."
+ }
+ },
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:05:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.EXAMPLE_SIGNATURE_PAYLOAD_ENVITED"
+ }
+}
diff --git a/examples/did-web/simpulseid-program-user-did.json b/examples/did-web/simpulseid-program-user-did.json
new file mode 100644
index 0000000..6007ad2
--- /dev/null
+++ b/examples/did-web/simpulseid-program-user-did.json
@@ -0,0 +1,41 @@
+{
+ "@context": [
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://www.w3.org/ns/did/v1",
+ "https://schema.org"
+ ],
+ "id": "did:web:did.ascs.digital:programs:simpulseid-user",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "service": [
+ {
+ "id": "did:web:did.ascs.digital:programs:simpulseid-user#program-metadata",
+ "type": "ProgramMetadataService",
+ "serviceEndpoint": {
+ "@type": [
+ "schema:CreativeWork",
+ "simpulseid:UserProgram"
+ ],
+ "@id": "https://did.ascs.digital/programs/simpulseid-user",
+ "name": "SimpulseID User Program",
+ "description": "Program definition for standard SimpulseID users in the ENVITED Ecosystem. Covers basic identity, login, and membership-related functionality for natural persons.",
+ "about": "User-level SimpulseID credentials and their usage within the ENVITED data space.",
+ "publisher": {
+ "@type": "schema:Organization",
+ "name": "Automotive Solution Center for Simulation e.V. (ASCS)",
+ "url": "https://ascs.digital/"
+ },
+ "inLanguage": "en",
+ "datePublished": "2025-08-05",
+ "termsOfService": "https://media.ascs.digital/terms/simpulse_id_terms_2025-08-05.pdf#cidv1",
+ "privacyPolicy": "https://media.ascs.digital/terms/privacy_policy_2025-08-05.pdf#cidv1"
+ }
+ }
+ ],
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:00:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImFzY3MtZGlkLXdlYi1rZXktMSJ9.EXAMPLE_SIGNATURE_SIMPULSEID_USER_PROGRAM"
+ }
+}
diff --git a/examples/did-web/simpulseid-service-revocation-registry-did.json b/examples/did-web/simpulseid-service-revocation-registry-did.json
new file mode 100644
index 0000000..fef2bf7
--- /dev/null
+++ b/examples/did-web/simpulseid-service-revocation-registry-did.json
@@ -0,0 +1,29 @@
+{
+ "@context": [
+ "https://schema.reachhaven.com/harbour/v1/credentials/",
+ "https://www.w3.org/ns/did/v1"
+ ],
+ "id": "did:web:did.ascs.digital:services:revocation-registry",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "service": [
+ {
+ "id": "did:web:did.ascs.digital:services:revocation-registry#crset",
+ "type": "CRSetRevocationRegistryService",
+ "serviceEndpoint": {
+ "@type": "harbour:CRSetServiceEndpoint",
+ "endpoint": "https://gatehouse.reachhaven.com/services/harbour/crset",
+ "statusPurpose": "revocation",
+ "contractURN": "urn:blockchain:eip155:42793:contract:0x646B92C8f21e55DF67E766047E4bD7bEdF8DfA14",
+ "sourceRepository": "https://github.com/ASCS-eV/smart-contracts",
+ "implementation": "https://arxiv.org/abs/2501.17089"
+ }
+ }
+ ],
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:30:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsImtpZCI6ImFzY3MtZXRoZXJsaW5rLWtleS0xIn0.EXAMPLE_SIGNATURE_REVOCATION_REGISTRY"
+ }
+}
diff --git a/examples/did-web/simpulseid-service-trust-anchor-did.json b/examples/did-web/simpulseid-service-trust-anchor-did.json
new file mode 100644
index 0000000..c89428f
--- /dev/null
+++ b/examples/did-web/simpulseid-service-trust-anchor-did.json
@@ -0,0 +1,54 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/did/v1",
+ "https://schema.org"
+ ],
+ "id": "did:web:did.ascs.digital:services:trust-anchor",
+ "controller": "did:web:did.ascs.digital:participants:ascs",
+ "verificationMethod": [
+ {
+ "id": "did:web:did.ascs.digital:participants:ascs#tezos-key-1",
+ "type": "EcdsaSecp256k1VerificationKey2019",
+ "controller": "did:web:did.ascs.digital:participants:ascs",
+ "blockchainAccountId": "tezos:NetXnHfVqm9iesp:tz1ZBYB7Lwmoc7xbwq59mHK4GbiPhfPaEo2g"
+ },
+ {
+ "id": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "type": "EcdsaSecp256k1VerificationKey2019",
+ "controller": "did:web:did.ascs.digital:participants:ascs",
+ "blockchainAccountId": "eip155:42793:0x71C7656EC7ab88b098defB751B7401B5f6d8976F"
+ }
+ ],
+ "assertionMethod": [
+ "did:web:did.ascs.digital:participants:ascs#tezos-key-1",
+ "did:web:did.ascs.digital:participants:ascs#etherlink-key-1"
+ ],
+ "service": [
+ {
+ "id": "did:web:did.ascs.digital:services:trust-anchor#owner",
+ "type": [
+ "TrustAnchorService",
+ "OrganizationMetadataService"
+ ],
+ "serviceEndpoint": {
+ "@type": "schema:Organization",
+ "@id": "did:web:did.ascs.digital:participants:ascs",
+ "name": "Automotive Solution Center for Simulation e.V. (ASCS)",
+ "url": "https://ascs.digital/",
+ "description": "Trust anchor and operator of the SimpulseID / ENVITED identity infrastructure at did.ascs.digital.",
+ "contactPoint": {
+ "@type": "schema:ContactPoint",
+ "contactType": "support",
+ "email": "info@ascs.digital"
+ }
+ }
+ }
+ ],
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:20:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.EXAMPLE_SIGNATURE_PAYLOAD_TRUST_ANCHOR"
+ }
+}
diff --git a/examples/did-web/simpulseid-user-21c7c8bc-6860-490b-8ec7-219c89d93e2c-did.json b/examples/did-web/simpulseid-user-21c7c8bc-6860-490b-8ec7-219c89d93e2c-did.json
new file mode 100644
index 0000000..97cb76f
--- /dev/null
+++ b/examples/did-web/simpulseid-user-21c7c8bc-6860-490b-8ec7-219c89d93e2c-did.json
@@ -0,0 +1,26 @@
+{
+ "@context": ["https://www.w3.org/ns/did/v1"],
+ "id": "did:web:did.ascs.digital:users:21c7c8bc-6860-490b-8ec7-219c89d93e2c",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "verificationMethod": [
+ {
+ "id": "did:web:did.ascs.digital:users:21c7c8bc-6860-490b-8ec7-219c89d93e2c#wallet-key-1",
+ "type": "Ed25519VerificationKey2018",
+ "controller": "did:web:did.ascs.digital:users:21c7c8bc-6860-490b-8ec7-219c89d93e2c",
+ "publicKeyMultibase": "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
+ }
+ ],
+ "authentication": [
+ "did:web:did.ascs.digital:users:21c7c8bc-6860-490b-8ec7-219c89d93e2c#tezos-key-1"
+ ],
+ "assertionMethod": [
+ "did:web:did.ascs.digital:users:21c7c8bc-6860-490b-8ec7-219c89d93e2c#wallet-key-1"
+ ],
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:05:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:bmw#etherlink-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.EXAMPLE_SIGNATURE_BMW_ADMIN"
+ }
+}
diff --git a/examples/did-web/simpulseid-user-44b982bb-ae61-4f6f-899f-a0982aaf367e-did.json b/examples/did-web/simpulseid-user-44b982bb-ae61-4f6f-899f-a0982aaf367e-did.json
new file mode 100644
index 0000000..1e99ab5
--- /dev/null
+++ b/examples/did-web/simpulseid-user-44b982bb-ae61-4f6f-899f-a0982aaf367e-did.json
@@ -0,0 +1,26 @@
+{
+ "@context": ["https://www.w3.org/ns/did/v1"],
+ "id": "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e",
+ "controller": "did:web:did.ascs.digital:services:trust-anchor",
+ "verificationMethod": [
+ {
+ "id": "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e#wallet-key-1",
+ "type": "Ed25519VerificationKey2018",
+ "controller": "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e",
+ "publicKeyMultibase": "z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
+ }
+ ],
+ "authentication": [
+ "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e#wallet-key-1"
+ ],
+ "assertionMethod": [
+ "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e#wallet-key-1"
+ ],
+ "proof": {
+ "type": "EcdsaSecp256k1Signature2019",
+ "created": "2025-08-06T10:10:00Z",
+ "verificationMethod": "did:web:did.ascs.digital:participants:bmw#tezos-key-1",
+ "proofPurpose": "assertionMethod",
+ "jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.EXAMPLE_SIGNATURE_BMW_ADMIN"
+ }
+}
diff --git a/examples/member-credential-full.json b/examples/member-credential-full.json
deleted file mode 100644
index a763fc2..0000000
--- a/examples/member-credential-full.json
+++ /dev/null
@@ -1,78 +0,0 @@
-{
- "@context": [
- "https://www.w3.org/2018/credentials/v1",
- {
- "@version": 1.1,
- "@protected": true,
- "AscsMemberCredential": "https://schema.ascs.digital/AscsMemberCredential/v1#",
- "AscsIssuer": {
- "@id": "https://schema.ascs.digital/AscsMemberCredential/v1#AscsIssuer",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "url": "https://schema.org/url"
- }
- },
- "AscsMember": {
- "@id": "https://schema.ascs.digital/AscsMemberCredential/v1#AscsMember",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "url": "https://schema.org/url",
- "address": "http://schema.org/address",
- "vatID": "http://schema.org/vatID",
- "isAscsMember": "http://schema.org/Boolean",
- "isEnvitedMember": "http://schema.org/Boolean",
- "privacyPolicy": "https://schema.org/termsOfService",
- "articlesOfAssociation": "https://schema.org/termsOfService",
- "contributionRules": "https://schema.org/termsOfService"
- }
- },
- "PostalAddress": {
- "@id": "http://schema.org/PostalAddress",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "streetAddress": "http://schema.org/streetAddress",
- "postalCode": "http://schema.org/postalCode",
- "addressLocality": "http://schema.org/addressLocality",
- "addressCountry": "https://schema.org/addressCountry"
- }
- }
- }
- ],
- "type": [
- "VerifiableCredential",
- "AscsMemberCredential"
- ],
- "issuanceDate": "2023-11-22T17:14:33Z",
- "expirationDate": "2102-09-15T17:14:33Z",
- "id": "urn:uuid:576fbefb-35e8-4b71-bb1a-53d1803c86de",
- "issuer": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1ggujjYjA7oYoaZBzTg1tYSXn3VMjcgDuv",
- "type": "AscsIssuer",
- "name": "Automotive Solution Center for Simulation e.V.",
- "url": "https://identity.ascs.digital/"
- },
- "credentialSubject": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1bpeJArd7apJyTUryfXH1SD6w8GL6Gwhj8",
- "type": "AscsMember",
- "name": "Testcompany GmbH",
- "url": "https://test.de/",
- "address": {
- "type": "PostalAddress",
- "streetAddress": "Teststraße 1",
- "postalCode": "12345",
- "addressLocality": "Munich",
- "addressCountry": "DE"
- },
- "vatID": "DE123456789",
- "isAscsMember": true,
- "isEnvitedMember": true,
- "privacyPolicy": "https://media.ascs.digital/terms/ascs_privacy_policy_2020-07-08.pdf#cidv1",
- "articlesOfAssociation": "https://media.ascs.digital/terms/ascs_articles_of_association_2021-09-17.pdf#cidv1",
- "contributionRules": "https://media.ascs.digital/terms/ascs_contribution_rules_2020-07-08.pdf#cidv1"
- }
-}
\ No newline at end of file
diff --git a/examples/member-credential.json b/examples/member-credential.json
deleted file mode 100644
index 3e7c2a7..0000000
--- a/examples/member-credential.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "@context": [
- "https://www.w3.org/2018/credentials/v1",
- "https://schema.ascs.digital/AscsMemberCredential/v1"
- ],
- "type": [
- "VerifiableCredential",
- "AscsMemberCredential"
- ],
- "issuanceDate": "2023-11-22T17:14:33Z",
- "expirationDate": "2102-09-15T17:14:33Z",
- "id": "urn:uuid:576fbefb-35e8-4b71-bb1a-53d1803c86de",
- "issuer": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1ggujjYjA7oYoaZBzTg1tYSXn3VMjcgDuv",
- "type": "AscsIssuer",
- "name": "Automotive Solution Center for Simulation e.V.",
- "url": "https://identity.ascs.digital/"
- },
- "credentialSubject": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1bpeJArd7apJyTUryfXH1SD6w8GL6Gwhj8",
- "type": "AscsMember",
- "name": "Testcompany GmbH",
- "url": "https://test.de/",
- "address": {
- "type": "PostalAddress",
- "streetAddress": "Teststraße 1",
- "postalCode": "12345",
- "addressLocality": "Munich",
- "addressCountry": "DE"
- },
- "vatID": "DE123456789",
- "isAscsMember": true,
- "isEnvitedMember": true,
- "privacyPolicy": "https://media.ascs.digital/terms/ascs_privacy_policy_2020-07-08.pdf#cidv1",
- "articlesOfAssociation": "https://media.ascs.digital/terms/ascs_articles_of_association_2021-09-17.pdf#cidv1",
- "contributionRules": "https://media.ascs.digital/terms/ascs_contribution_rules_2020-07-08.pdf#cidv1"
- }
-}
\ No newline at end of file
diff --git a/examples/simpulseid-administrator-credential.json b/examples/simpulseid-administrator-credential.json
new file mode 100644
index 0000000..1c8dee7
--- /dev/null
+++ b/examples/simpulseid-administrator-credential.json
@@ -0,0 +1,123 @@
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://www.w3.org/ns/credentials/status#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://schema.reachhaven.com/harbour/v1/credentials/"
+ ],
+ "type": [
+ "VerifiableCredential",
+ "harbour:VerifiableCredential",
+ "simpulseid:AdministratorCredential"
+ ],
+ "id": "urn:uuid:9d3a0c1b-4d4e-4f9a-9b0c-1d2e3f4a5b6d",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs",
+ "type": "simpulseid:Issuer",
+ "member": "did:web:did.ascs.digital:participants:ascs"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "expirationDate": "2030-08-05T00:00:00Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:users:21c7c8bc-6860-490b-8ec7-219c89d93e2c",
+ "type": [
+ "simpulseid:Administrator",
+ "gx:NaturalPerson",
+ "schema:Person"
+ ],
+ "memberOf": [
+ "did:web:did.ascs.digital:participants:bmw",
+ "did:web:did.ascs.digital:programs:simpulseid-administrator"
+ ],
+ "givenName": "Andreas",
+ "familyName": "Admin",
+ "email": "andreas.admin@bmw.com",
+ "address": {
+ "@type": "gx:Address",
+ "streetAddress": "Petuelring 130",
+ "postalCode": "80809",
+ "locality": "München",
+ "countryCode": "DE",
+ "region": "DE21"
+ },
+ "termsAndConditions": [
+ {
+ "@id": "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq",
+ "@type": "gx:TermsAndConditions",
+ "gx:url": {
+ "@value": "https://media.ascs.digital/terms/administrator_privacy_policy_2025-08-05.pdf",
+ "@type": "xsd:anyURI"
+ },
+ "gx:hash": "bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq"
+ }
+ ]
+ },
+ "credentialStatus": [
+ {
+ "id": "did:web:did.ascs.digital:services:revocation-registry#f8b8a8150acbbbf936df9692ed7ca809c9a6a66b190149ce9d4e9557587829ec",
+ "type": "harbour:CRSetEntry",
+ "statusPurpose": "revocation"
+ }
+ ],
+ "evidence": {
+ "type": [
+ "Evidence"
+ ],
+ "vp": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#"
+ ],
+ "id": "urn:uuid:89581491-c9d6-47d2-bd4b-e606fe6acd70",
+ "type": [
+ "VerifiablePresentation"
+ ],
+ "verifiableCredential": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ {
+ "EmailPass": "https://doc.wallet-provider.io/vc_type#emailpass",
+ "@vocab": "https://schema.org/"
+ }
+ ],
+ "id": "urn:uuid:f689875d-b324-11f0-9b28-0a1628958560",
+ "type": [
+ "VerifiableCredential",
+ "EmailPass"
+ ],
+ "credentialSubject": {
+ "id": "did:key:z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd",
+ "email": "admin1@asc-s.de",
+ "type": "EmailPass"
+ },
+ "issuer": "did:web:app.altme.io:issuer",
+ "issuanceDate": "2025-10-27T11:06:18Z",
+ "proof": {
+ "type": "Ed25519Signature2020",
+ "proofPurpose": "assertionMethod",
+ "proofValue": "z4u49jR8at57k6QoUVSeXbccqpiu2S6HQp6ueDpP3U9XNYaLpcTDf4Pm5vyNQjipnY6Fp7o3Ab5uaaEYvA9qSUxV",
+ "verificationMethod": "did:web:app.altme.io:issuer#key-1",
+ "created": "2025-10-27T11:06:18.539Z"
+ },
+ "expirationDate": "2026-10-27T11:06:18Z",
+ "credentialStatus": {
+ "id": "https://talao.co/sandbox/issuer/bitstringstatuslist/1#77900",
+ "type": "BitstringStatusListEntry",
+ "statusPurpose": "revocation",
+ "statusListIndex": "77900",
+ "statusSize": 1,
+ "statusListCredential": "https://talao.co/sandbox/issuer/bitstringstatuslist/1"
+ }
+ },
+ "proof": {
+ "type": "Ed25519Signature2018",
+ "proofPurpose": "authentication",
+ "challenge": "d39b1209 ISSUE_PAYLOAD 78df7503a43df57dc146a07d36e05163dcc9152627622bef62db1aaa37ccd428",
+ "verificationMethod": "did:key:z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd#z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd",
+ "created": "2023-11-29T14:12:48.142Z",
+ "domain": "https://ec80-2003-ee-af45-6c00-e0d1-7850-acea-8745.ngrok-free.app",
+ "jws": "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..cUfNpVhLFOmBIebiJO345ImTzKN0_G9Al2k8dJx7wcYvXCfyfWnxFdCGCi13c2tNj6bA-RbzFmo6qrEaQTxtAw"
+ },
+ "holder": "did:key:z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd"
+ }
+ }
+}
diff --git a/examples/simpulseid-ascs-base-membership-credential.json b/examples/simpulseid-ascs-base-membership-credential.json
new file mode 100644
index 0000000..7797ef3
--- /dev/null
+++ b/examples/simpulseid-ascs-base-membership-credential.json
@@ -0,0 +1,108 @@
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://www.w3.org/ns/credentials/status#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://schema.reachhaven.com/harbour/v1/credentials/"
+ ],
+ "type": [
+ "VerifiableCredential",
+ "harbour:VerifiableCredential",
+ "simpulseid:AscsBaseMembershipCredential"
+ ],
+ "id": "urn:uuid:7f3f7c6a-4b4d-4e9e-8f0a-9b1b2c3d4e5f",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs",
+ "type": "simpulseid:Issuer",
+ "member": "did:web:did.ascs.digital:participants:ascs"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "expirationDate": "2030-08-05T00:00:00Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "type": [
+ "simpulseid:AscsBaseMembership",
+ "schema:ProgramMembership"
+ ],
+ "memberOf": [
+ "did:web:did.ascs.digital:participants:ascs",
+ "did:web:did.ascs.digital:programs:ascs-base-membership"
+ ],
+ "programName": "ASCS e.V. Base Membership",
+ "hostingOrganization": {
+ "@id": "did:web:did.ascs.digital:participants:ascs",
+ "type": [
+ "schema:Organization",
+ "gx:LegalPerson"
+ ],
+ "legalName": "Automotive Solution Center for Simulation e.V."
+ },
+ "memberSince": "2023-01-01",
+ "termsAndConditions": [
+ {
+ "@id": "ipfs://bafybeihdwdcefgh4dqkjv67uzcmw7oj5thlvxnqxnxb4ji54m72w5foemq4",
+ "@type": "gx:TermsAndConditions",
+ "gx:url": {
+ "@value": "https://media.ascs.digital/terms/base_membership_terms_2025-08-05.pdf",
+ "@type": "xsd:anyURI"
+ },
+ "gx:hash": "bafybeihdwdcefgh4dqkjv67uzcmw7oj5thlvxnqxnxb4ji54m72w5foemq4"
+ }
+ ]
+ },
+ "credentialStatus": [
+ {
+ "id": "did:web:did.ascs.digital:services:revocation-registry#6239c5abac53d33fff4a9babaaae70f6c71ac495cface74d26ac1e3affee8c61",
+ "type": "harbour:CRSetEntry",
+ "statusPurpose": "revocation"
+ }
+ ],
+ "evidence": [
+ {
+ "type": [
+ "Evidence"
+ ],
+ "vp": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#"
+ ],
+ "type": [
+ "VerifiablePresentation"
+ ],
+ "verifiableCredential": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://www.w3.org/ns/credentials/status#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://schema.reachhaven.com/harbour/v1/credentials/"
+ ],
+ "type": [
+ "VerifiableCredential",
+ "harbour:VerifiableCredential",
+ "simpulseid:ParticipantCredential"
+ ],
+ "id": "urn:uuid:576fbefb-35e8-4b71-bb1a-53d1803c86de",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "type": [
+ "simpulseid:Participant",
+ "gx:LegalPerson"
+ ],
+ "legalName": "Bayerische Motoren Werke Aktiengesellschaft"
+ }
+ }
+ }
+ }
+ ],
+ "proof": {
+ "type": "JsonWebSignature2020",
+ "created": "2025-08-06T10:15:22Z",
+ "proofPurpose": "assertionMethod",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#key-1",
+ "jws": "eyJhbGciOiJQUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MHNj..."
+ }
+}
diff --git a/examples/simpulseid-ascs-envited-membership-credential.json b/examples/simpulseid-ascs-envited-membership-credential.json
new file mode 100644
index 0000000..1a439dd
--- /dev/null
+++ b/examples/simpulseid-ascs-envited-membership-credential.json
@@ -0,0 +1,107 @@
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://www.w3.org/ns/credentials/status#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://schema.reachhaven.com/harbour/v1/credentials/"
+ ],
+ "type": [
+ "VerifiableCredential",
+ "harbour:VerifiableCredential",
+ "simpulseid:AscsEnvitedMembershipCredential"
+ ],
+ "id": "urn:uuid:8e3a0c1b-4d4e-4f9a-9b0c-1d2e3f4a5b6c",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs",
+ "type": "simpulseid:Issuer",
+ "member": "did:web:did.ascs.digital:participants:ascs"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "expirationDate": "2030-08-05T00:00:00Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "type": [
+ "simpulseid:AscsEnvitedMembership",
+ "schema:ProgramMembership"
+ ],
+ "memberOf": [
+ "did:web:did.ascs.digital:participants:ascs",
+ "did:web:did.ascs.digital:programs:ascs-base-membership",
+ "did:web:did.ascs.digital:programs:ascs-envited-membership"
+ ],
+ "programName": "ASCS e.V. ENVITED Membership",
+ "hostingOrganization": {
+ "@id": "did:web:did.ascs.digital:participants:ascs",
+ "type": [
+ "schema:Organization",
+ "gx:LegalPerson"
+ ],
+ "legalName": "Automotive Solution Center for Simulation e.V."
+ },
+ "memberSince": "2023-01-01",
+ "baseMembershipCredential": "urn:uuid:7f3f7c6a-4b4d-4e9e-8f0a-9b1b2c3d4e5f",
+ "termsAndConditions": [
+ {
+ "@id": "ipfs://bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic7jc6he43m",
+ "@type": "gx:TermsAndConditions",
+ "gx:url": {
+ "@value": "https://media.ascs.digital/terms/envited_membership_terms_2025-08-05.pdf",
+ "@type": "xsd:anyURI"
+ },
+ "gx:hash": "bafybeifx7yeb55armcsxwwitkymga5xf53dxiarykms3ygqic7jc6he43m"
+ }
+ ]
+ },
+ "credentialStatus": [
+ {
+ "id": "did:web:did.ascs.digital:services:revocation-registry#b8ca800e6cf1807ed35c682ca7c84f07df55ad53a20784fe0ee896f279a6a047",
+ "type": "harbour:CRSetEntry",
+ "statusPurpose": "revocation"
+ }
+ ],
+ "evidence": [
+ {
+ "type": [
+ "Evidence"
+ ],
+ "vp": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#"
+ ],
+ "type": [
+ "VerifiablePresentation"
+ ],
+ "verifiableCredential": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/"
+ ],
+ "type": [
+ "VerifiableCredential",
+ "simpulseid:AscsBaseMembershipCredential"
+ ],
+ "id": "urn:uuid:7f3f7c6a-4b4d-4e9e-8f0a-9b1b2c3d4e5f",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "type": [
+ "simpulseid:AscsBaseMembership",
+ "schema:ProgramMembership"
+ ],
+ "programName": "ASCS e.V. Base Membership"
+ }
+ }
+ }
+ }
+ ],
+ "proof": {
+ "type": "JsonWebSignature2020",
+ "created": "2025-08-06T10:15:22Z",
+ "proofPurpose": "assertionMethod",
+ "verificationMethod": "did:web:did.ascs.digital:participants:ascs#key-1",
+ "jws": "eyJhbGciOiJQUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..Y2Fi..."
+ }
+}
diff --git a/examples/simpulseid-participant-credential.json b/examples/simpulseid-participant-credential.json
new file mode 100644
index 0000000..dd8b35d
--- /dev/null
+++ b/examples/simpulseid-participant-credential.json
@@ -0,0 +1,137 @@
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://www.w3.org/ns/credentials/status#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://schema.reachhaven.com/harbour/v1/credentials/",
+ {
+ "lf": "https://schema.ascs.digital/SimpulseId/v1/legalForm/"
+ }
+ ],
+ "type": [
+ "VerifiableCredential",
+ "harbour:VerifiableCredential",
+ "simpulseid:ParticipantCredential"
+ ],
+ "id": "urn:uuid:576fbefb-35e8-4b71-bb1a-53d1803c86de",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs",
+ "type": "simpulseid:Issuer",
+ "member": "did:web:did.ascs.digital:participants:ascs"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "expirationDate": "2030-08-05T00:00:00Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "type": [
+ "simpulseid:Participant",
+ "gx:LegalPerson",
+ "schema:Organization"
+ ],
+ "legalName": "Bayerische Motoren Werke Aktiengesellschaft",
+ "legalForm": "AG",
+ "duns": "313995269",
+ "registrationNumber": {
+ "@type": "gx:VatID",
+ "countryCode": "DE",
+ "vatID": "DE129273398"
+ },
+ "email": "imprint@bmw.com",
+ "website": "https://www.bmwgroup.com/",
+ "legalAddress": {
+ "@type": "gx:Address",
+ "streetAddress": "Petuelring 130",
+ "postalCode": "80809",
+ "locality": "München",
+ "countryCode": "DE",
+ "region": "DE21"
+ },
+ "headquartersAddress": {
+ "@type": "gx:Address",
+ "streetAddress": "Petuelring 130",
+ "postalCode": "80809",
+ "locality": "München",
+ "countryCode": "DE",
+ "region": "DE21"
+ },
+ "termsAndConditions": [
+ {
+ "@id": "ipfs://bafybeigdyj2p5rxbqzqx3g2m5qw4ftheq7l3z5v7j7nw2q7q5q5zq7q5q4",
+ "@type": "gx:TermsAndConditions",
+ "gx:url": {
+ "@value": "https://media.ascs.digital/terms/simpulse_id_terms_2025-08-05.pdf",
+ "@type": "xsd:anyURI"
+ },
+ "gx:hash": "bafybeigdyj2p5rxbqzqx3g2m5qw4ftheq7l3z5v7j7nw2q7q5q5zq7q5q4"
+ }
+ ]
+ },
+ "credentialStatus": [
+ {
+ "id": "did:web:did.ascs.digital:services:revocation-registry#608101d3a8430e61f60dcf1be0f42ab3ceb52b6abffb9f75b6f36c80362fc25a",
+ "type": "harbour:CRSetEntry",
+ "statusPurpose": "revocation"
+ }
+ ],
+ "evidence": {
+ "type": [
+ "Evidence"
+ ],
+ "vp": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#"
+ ],
+ "id": "urn:uuid:89581491-c9d6-47d2-bd4b-e606fe6acd70",
+ "type": [
+ "VerifiablePresentation"
+ ],
+ "verifiableCredential": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ {
+ "EmailPass": "https://doc.wallet-provider.io/vc_type#emailpass",
+ "@vocab": "https://schema.org/"
+ }
+ ],
+ "id": "urn:uuid:f689875d-b324-11f0-9b28-0a1628958560",
+ "type": [
+ "VerifiableCredential",
+ "EmailPass"
+ ],
+ "credentialSubject": {
+ "id": "did:key:z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd",
+ "email": "admin1@asc-s.de",
+ "type": "EmailPass"
+ },
+ "issuer": "did:web:app.altme.io:issuer",
+ "issuanceDate": "2025-10-27T11:06:18Z",
+ "proof": {
+ "type": "Ed25519Signature2020",
+ "proofPurpose": "assertionMethod",
+ "proofValue": "z4u49jR8at57k6QoUVSeXbccqpiu2S6HQp6ueDpP3U9XNYaLpcTDf4Pm5vyNQjipnY6Fp7o3Ab5uaaEYvA9qSUxV",
+ "verificationMethod": "did:web:app.altme.io:issuer#key-1",
+ "created": "2025-10-27T11:06:18.539Z"
+ },
+ "expirationDate": "2026-10-27T11:06:18Z",
+ "credentialStatus": {
+ "id": "https://talao.co/sandbox/issuer/bitstringstatuslist/1#77900",
+ "type": "BitstringStatusListEntry",
+ "statusPurpose": "revocation",
+ "statusListIndex": "77900",
+ "statusSize": 1,
+ "statusListCredential": "https://talao.co/sandbox/issuer/bitstringstatuslist/1"
+ }
+ },
+ "proof": {
+ "type": "Ed25519Signature2018",
+ "proofPurpose": "authentication",
+ "challenge": "d3931310 ISSUE_PAYLOAD 4d50761d2d4c28f93eb268b7b0b442bcef039b5a8672113e8ff53de73c13c189",
+ "verificationMethod": "did:key:z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd#z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd",
+ "created": "2023-11-29T14:12:48.142Z",
+ "domain": "https://ec80-2003-ee-af45-6c00-e0d1-7850-acea-8745.ngrok-free.app",
+ "jws": "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..cUfNpVhLFOmBIebiJO345ImTzKN0_G9Al2k8dJx7wcYvXCfyfWnxFdCGCi13c2tNj6bA-RbzFmo6qrEaQTxtAw"
+ },
+ "holder": "did:key:z6MkkdC46uhBGjMYS2ZDLUwCrTWdaqZdTD3596sN4397oRNd"
+ }
+ }
+}
diff --git a/examples/simpulseid-user-censored-credential.json b/examples/simpulseid-user-censored-credential.json
new file mode 100644
index 0000000..5c4df6d
--- /dev/null
+++ b/examples/simpulseid-user-censored-credential.json
@@ -0,0 +1,112 @@
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://www.w3.org/ns/credentials/status#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://schema.reachhaven.com/harbour/v1/credentials/"
+ ],
+ "type": [
+ "VerifiableCredential",
+ "harbour:VerifiableCredential",
+ "simpulseid:UserCredential"
+ ],
+ "id": "urn:uuid:6a0e7e84-2e88-4b9a-977b-9e92a6d87a0f",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "type": "simpulseid:Issuer",
+ "member": "did:web:did.ascs.digital:participants:bmw"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "expirationDate": "2030-08-05T00:00:00Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e",
+ "type": [
+ "simpulseid:User",
+ "gx:NaturalPerson",
+ "schema:Person"
+ ],
+ "censored": true,
+ "memberOf": [
+ "did:web:did.ascs.digital:participants:bmw",
+ "did:web:did.ascs.digital:programs:simpulseid-user"
+ ],
+ "termsAndConditions": [
+ {
+ "@id": "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq",
+ "@type": "gx:TermsAndConditions",
+ "gx:url": {
+ "@value": "https://media.ascs.digital/terms/privacy_policy_2025-08-05.pdf",
+ "@type": "xsd:anyURI"
+ },
+ "gx:hash": "bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq"
+ }
+ ]
+ },
+ "credentialStatus": [
+ {
+ "id": "did:web:did.ascs.digital:services:revocation-registry#9396f1d42a2a5eaa93a1a3211e4b0db85c8185d533b835984cd98d24ecba6440",
+ "type": "harbour:CRSetEntry",
+ "statusPurpose": "revocation"
+ }
+ ],
+ "evidence": {
+ "type": [
+ "Evidence"
+ ],
+ "vp": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#"
+ ],
+ "id": "urn:uuid:89581491-c9d6-47d2-bd4b-e606fe6acd70",
+ "type": [
+ "VerifiablePresentation"
+ ],
+ "verifiableCredential": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ {
+ "EmailPass": "https://doc.wallet-provider.io/vc_type#emailpass",
+ "@vocab": "https://schema.org/"
+ }
+ ],
+ "id": "urn:uuid:f689875d-b324-11f0-9b28-0a1628958560",
+ "type": [
+ "VerifiableCredential",
+ "EmailPass"
+ ],
+ "credentialSubject": {
+ "id": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
+ "email": "admin1@bmw.de",
+ "type": "EmailPass"
+ },
+ "issuer": "did:web:app.altme.io:issuer",
+ "issuanceDate": "2025-10-27T11:06:18Z",
+ "proof": {
+ "type": "Ed25519Signature2020",
+ "proofPurpose": "assertionMethod",
+ "proofValue": "z4u49jR8at57k6QoUVSeXbccqpiu2S6HQp6ueDpP3U9XNYaLpcTDf4Pm5vyNQjipnY6Fp7o3Ab5uaaEYvA9qSUxV",
+ "verificationMethod": "did:web:app.altme.io:issuer#key-1",
+ "created": "2025-10-27T11:06:18.539Z"
+ },
+ "expirationDate": "2026-10-27T11:06:18Z",
+ "credentialStatus": {
+ "id": "https://talao.co/sandbox/issuer/bitstringstatuslist/1#77901",
+ "type": "BitstringStatusListEntry",
+ "statusPurpose": "revocation",
+ "statusListIndex": "77901",
+ "statusSize": 1,
+ "statusListCredential": "https://talao.co/sandbox/issuer/bitstringstatuslist/1"
+ }
+ },
+ "proof": {
+ "type": "Ed25519Signature2018",
+ "proofPurpose": "authentication",
+ "challenge": "da9b1009 ISSUE_PAYLOAD",
+ "verificationMethod": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
+ "created": "2023-11-29T14:12:48.142Z",
+ "jws": "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9.."
+ },
+ "holder": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
+ }
+ }
+}
diff --git a/examples/simpulseid-user-credential.json b/examples/simpulseid-user-credential.json
new file mode 100644
index 0000000..1bcd74d
--- /dev/null
+++ b/examples/simpulseid-user-credential.json
@@ -0,0 +1,116 @@
+{
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ "https://www.w3.org/ns/credentials/status#",
+ "https://schema.ascs.digital/simpulseid/v1/credentials/",
+ "https://schema.reachhaven.com/harbour/v1/credentials/"
+ ],
+ "type": [
+ "VerifiableCredential",
+ "harbour:VerifiableCredential",
+ "simpulseid:UserCredential"
+ ],
+ "id": "urn:uuid:6a0e7e84-2e88-4b9a-977b-9e92a6d87a0f",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "type": "simpulseid:Issuer",
+ "member": "did:web:did.ascs.digital:participants:bmw"
+ },
+ "issuanceDate": "2025-08-06T10:15:22Z",
+ "expirationDate": "2030-08-05T00:00:00Z",
+ "credentialSubject": {
+ "id": "did:web:did.ascs.digital:users:44b982bb-ae61-4f6f-899f-a0982aaf367e",
+ "type": [
+ "simpulseid:User",
+ "gx:NaturalPerson",
+ "schema:Person"
+ ],
+ "censored": false,
+ "memberOf": [
+ "did:web:did.ascs.digital:participants:bmw",
+ "did:web:did.ascs.digital:programs:simpulseid-user"
+ ],
+ "givenName": "Max",
+ "familyName": "Mustermann",
+ "email": "max.mustermann@bmw.com",
+ "termsAndConditions": [
+ {
+ "@id": "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq",
+ "@type": "gx:TermsAndConditions",
+ "gx:url": {
+ "@value": "https://media.ascs.digital/terms/privacy_policy_2025-08-05.pdf",
+ "@type": "xsd:anyURI"
+ },
+ "gx:hash": "bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq"
+ }
+ ]
+ },
+ "credentialStatus": [
+ {
+ "id": "did:web:did.ascs.digital:services:revocation-registry#9396f1d42a2a5eaa93a1a3211e4b0db85c8185d533b835984cd98d24ecba6440",
+ "type": "harbour:CRSetEntry",
+ "statusPurpose": "revocation"
+ }
+ ],
+ "evidence": {
+ "type": [
+ "Evidence"
+ ],
+ "vp": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#"
+ ],
+ "id": "urn:uuid:89581491-c9d6-47d2-bd4b-e606fe6acd70",
+ "type": [
+ "VerifiablePresentation"
+ ],
+ "verifiableCredential": {
+ "@context": [
+ "https://www.w3.org/2018/credentials#",
+ {
+ "EmailPass": "https://doc.wallet-provider.io/vc_type#emailpass",
+ "@vocab": "https://schema.org/"
+ }
+ ],
+ "id": "urn:uuid:f689875d-b324-11f0-9b28-0a1628958560",
+ "type": [
+ "VerifiableCredential",
+ "EmailPass"
+ ],
+ "credentialSubject": {
+ "id": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
+ "email": "admin1@bmw.de",
+ "type": "EmailPass"
+ },
+ "issuer": "did:web:app.altme.io:issuer",
+ "issuanceDate": "2025-10-27T11:06:18Z",
+ "proof": {
+ "type": "Ed25519Signature2020",
+ "proofPurpose": "assertionMethod",
+ "proofValue": "z4u49jR8at57k6QoUVSeXbccqpiu2S6HQp6ueDpP3U9XNYaLpcTDf4Pm5vyNQjipnY6Fp7o3Ab5uaaEYvA9qSUxV",
+ "verificationMethod": "did:web:app.altme.io:issuer#key-1",
+ "created": "2025-10-27T11:06:18.539Z"
+ },
+ "expirationDate": "2026-10-27T11:06:18Z",
+ "credentialStatus": {
+ "id": "https://talao.co/sandbox/issuer/bitstringstatuslist/1#77901",
+ "type": "BitstringStatusListEntry",
+ "statusPurpose": "revocation",
+ "statusListIndex": "77901",
+ "statusSize": 1,
+ "statusListCredential": "https://talao.co/sandbox/issuer/bitstringstatuslist/1"
+ }
+ },
+ "proof": {
+ "type": "Ed25519Signature2018",
+ "proofPurpose": "authentication",
+ "challenge": "da9b1009 ISSUE_PAYLOAD d0450062b3c4c9168ac8266f0806d62f5d95ed96894d5a9a0aaddf4298317eaa",
+ "verificationMethod": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH",
+ "created": "2023-11-29T14:12:48.142Z",
+ "domain": "https://ec80-2003-ee-af45-6c00-e0d1-7850-acea-8745.ngrok-free.app",
+ "jws": "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..cUfNpVhLFOmBIebiJO345ImTzKN0_G9Al2k8dJx7wcYvXCfyfWnxFdCGCi13c2tNj6bA-RbzFmo6qrEaQTxtAw"
+ },
+ "holder": "did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH"
+ }
+ }
+}
diff --git a/examples/user-credential-full.json b/examples/user-credential-full.json
deleted file mode 100644
index 574d2e4..0000000
--- a/examples/user-credential-full.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "@context": [
- "https://www.w3.org/2018/credentials/v1",
- {
- "@version": 1.1,
- "@protected": true,
- "AscsUserCredential": "https://schema.ascs.digital/AscsUserCredential/v1#",
- "AscsIssuer": {
- "@id": "https://schema.ascs.digital/AscsUserCredential/v1#AscsIssuer",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "url": "https://schema.org/url"
- }
- },
- "AscsUser": {
- "@id": "https://schema.ascs.digital/AscsUserCredential/v1#AscsUser",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "name": "https://schema.org/name",
- "email": "https://schema.org/email",
- "address": "http://schema.org/address",
- "isAscsMember": "http://schema.org/Boolean",
- "isEnvitedMember": "http://schema.org/Boolean",
- "privacyPolicy": "https://schema.org/termsOfService"
- }
- },
- "PostalAddress": {
- "@id": "http://schema.org/PostalAddress",
- "@context": {
- "@version": 1.1,
- "@protected": true,
- "streetAddress": "http://schema.org/streetAddress",
- "postalCode": "http://schema.org/postalCode",
- "addressLocality": "http://schema.org/addressLocality",
- "addressCountry": "https://schema.org/addressCountry"
- }
- }
- }
- ],
- "type": [
- "VerifiableCredential",
- "AscsUserCredential"
- ],
- "issuanceDate": "2023-11-22T17:14:33Z",
- "expirationDate": "2102-09-15T17:14:33Z",
- "id": "urn:uuid:cf1f329d-9c4c-458e-ba0a-a762a296b79c",
- "issuer": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1bpeJArd7apJyTUryfXH1SD6w8GL6Gwhj8",
- "type": "AscsIssuer",
- "name": "Testcompany GmbH",
- "url": "https://test.de/"
- },
- "credentialSubject": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1SfdVU1mor3Sgej3FmmwMH4HM1EjTzqqeE",
- "type": "AscsUser",
- "name": "User",
- "email": "mailto:user@test.de",
- "address": {
- "type": "PostalAddress",
- "streetAddress": "Teststraße 1",
- "postalCode": "12345",
- "addressLocality": "Munich",
- "addressCountry": "DE"
- },
- "isAscsMember": true,
- "isEnvitedMember": true,
- "privacyPolicy": "https://media.ascs.digital/terms/ascs_privacy_policy_2020-07-08.pdf#cidv1"
- }
-}
\ No newline at end of file
diff --git a/examples/user-credential.json b/examples/user-credential.json
deleted file mode 100644
index dfbbc09..0000000
--- a/examples/user-credential.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "@context": [
- "https://www.w3.org/2018/credentials/v1",
- "https://schema.ascs.digital/AscsUserCredential/v1"
- ],
- "type": [
- "VerifiableCredential",
- "AscsUserCredential"
- ],
- "issuanceDate": "2023-11-22T17:14:33Z",
- "expirationDate": "2102-09-15T17:14:33Z",
- "id": "urn:uuid:cf1f329d-9c4c-458e-ba0a-a762a296b79c",
- "issuer": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1bpeJArd7apJyTUryfXH1SD6w8GL6Gwhj8",
- "type": "AscsIssuer",
- "name": "Testcompany GmbH",
- "url": "https://test.de/"
- },
- "credentialSubject": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1SfdVU1mor3Sgej3FmmwMH4HM1EjTzqqeE",
- "type": "AscsUser",
- "name": "User",
- "email": "mailto:user@test.de",
- "address": {
- "type": "PostalAddress",
- "streetAddress": "Teststraße 1",
- "postalCode": "12345",
- "addressLocality": "Munich",
- "addressCountry": "DE"
- },
- "isAscsMember": true,
- "isEnvitedMember": true,
- "privacyPolicy": "https://media.ascs.digital/terms/ascs_privacy_policy_2020-07-08.pdf#cidv1"
- }
-}
\ No newline at end of file
diff --git a/generated/README.md b/generated/README.md
new file mode 100644
index 0000000..7c23b89
--- /dev/null
+++ b/generated/README.md
@@ -0,0 +1,144 @@
+# SimpulseID Generated Artefacts: Contexts & Ontologies
+
+This folder contains the downstream artefacts (JSON-LD contexts, SHACL shapes, and RDF/OWL ontologies) generated from the LinkML schemas. These files define the formal semantics and JSON mappings for SimpulseID credentials in the ENVITED Ecosystem.
+
+## Directory Structure
+
+Artefacts are generated into subfolders based on their schema model:
+
+```txt
+generated/
+├── simpulseid/
+│ ├── simpulseid_context.jsonld
+│ ├── simpulseid_ontology.ttl
+│ └── simpulseid_shacl.ttl
+├── harbour/
+│ ├── harbour_context.jsonld
+│ ├── harbour_ontology.ttl
+│ └── harbour_shacl.ttl
+└── core/
+ ├── core_context.jsonld
+ ├── core_ontology.ttl
+ └── core_shacl.ttl
+```
+
+---
+
+## 1. JSON-LD Contexts
+
+The JSON-LD context documents define how JSON properties, classes, and identifiers in credentials are expanded into stable IRIs and how they map to the SimpulseID ontology, Gaia-X definitions, schema.org, and vCard.
+
+All contexts are intended to be hosted under:
+
+```txt
+
+```
+
+with the following MIME type:
+
+```txt
+Content-Type: application/ld+json
+```
+
+Hosting contexts in this way ensures:
+
+- OIDC4VP clients can dereference the contexts reliably.
+- SSI wallets can resolve schemas consistently.
+- JSON-LD processors interpret IRIs deterministically.
+
+### `simpulseid/simpulseid_context.jsonld`
+
+The main JSON-LD context for SimpulseID credentials. It defines all SimpulseID-specific classes and properties:
+
+- Participant (`simpulseid:Participant`)
+- ASCS Base Membership (`simpulseid:AscsBaseMembership`)
+- ASCS ENVITED Membership (`simpulseid:AscsEnvitedMembership`)
+- Administrator (`simpulseid:Administrator`)
+- User (`simpulseid:User`)
+
+It maps JSON fields to:
+
+- SimpulseID ontology terms.
+- Gaia-X identity primitives (`gx:LegalPerson`, `gx:Address`, `gx:VatID`, etc.).
+- vCard properties for address modelling (`street-address`, `locality`, `region`).
+- Legal form vocabulary entries.
+- Terms & conditions references (`simpulseid:termsAndConditions`).
+
+The context uses `@protected: true` to guarantee a stable schema.
+
+### `harbour/harbour_context.jsonld`
+
+Context for revocation metadata following the Harbour Status model.
+
+Defines:
+
+- `harbour:CRSetEntry`
+- `statusPurpose` (typed as `xsd:string`)
+- `harbour:VerifiableCredential`
+
+Each SimpulseID credential uses this context in `credentialStatus`.
+
+### `legalForm-v1.jsonld` (Vocabulary)
+
+A SKOS vocabulary for legal forms (e.g., AG, GmbH, LLC, CIC, BenCom). Each entry is a `skos:Concept` inside the `simpulseid:LegalForm` concept scheme.
+
+Credentials reference these IRIs like:
+
+```txt
+
+```
+
+---
+
+## 2. RDF/OWL Ontologies
+
+The ontologies define the formal semantics for all classes and properties used in SimpulseID credentials. They provide the canonical IRIs referenced by the JSON-LD contexts and are interpreted by verifiers, wallets, and backend services.
+
+### Purpose
+
+The ontology defines:
+
+- The **SimpulseID credential model** (Participant, Memberships, User, Admin).
+- The **relationships** between these classes.
+- Alignment with:
+ - **Gaia‑X Trust Framework**
+ - **schema.org**
+ - **vCard**
+ - **SKOS vocabularies**
+
+By using shared IRIs and clear semantics, SimpulseID ensures interoperability across the ENVITED Ecosystem and other data spaces.
+
+### `simpulseid/simpulseid_ontology.ttl`
+
+Defines:
+
+- **Classes:**
+ - `simpulseid:Participant`
+ - `simpulseid:AscsBaseMembership`
+ - `simpulseid:AscsEnvitedMembership`
+ - `simpulseid:Administrator`
+ - `simpulseid:User`
+- **Properties:**
+ - `simpulseid:legalForm`
+ - `simpulseid:termsAndConditions`
+ - `simpulseid:baseMembership`
+ - Address fields using Gaia‑X and vCard IRIs.
+ - Organizational membership relations (`schema:memberOf`).
+
+---
+
+## Why Gaia-X Terms Are Used (`gx:*`)
+
+The Gaia-X Trust Framework provides well-defined, audited semantic identifiers for legal entities, natural persons, addresses, registration numbers, and terms & conditions. SimpulseID reuses these IRIs because:
+
+1. **Strong interoperability:** Credentials can be reused across Gaia-X–aligned ecosystems.
+2. **Regulatory alignment:** Gaia-X definitions follow European governance requirements.
+3. **Semantic completeness:** Classes such as `gx:LegalPerson` and `gx:VatID` match ENVITED needs.
+4. **RDF correctness:** JSON-LD expansion produces a clean RDF graph aligned with the Gaia-X Credential Format.
+5. **Reusability in EVES:** The ENVITED Ecosystem Specifications align with Gaia-X to avoid duplicating definitions.
+
+## Relation between Contexts and Ontologies
+
+- **JSON-LD Contexts** define the _mapping_ (how JSON keys become IRIs).
+- **Ontologies** define the _meaning_ (relations, hierarchy, and properties of those IRIs).
+- Together, they create a robust, machine‑interpretable credential model essential for trust interoperability and schema validation.
diff --git a/linkml/README.md b/linkml/README.md
new file mode 100644
index 0000000..c3955ff
--- /dev/null
+++ b/linkml/README.md
@@ -0,0 +1,11 @@
+# SimpulseID
+
+## Implementation Choice: Address Property Aliasing
+
+To ensure consistency with the Verifiable Credentials Data Model and other CamelCase properties in the Gaia-X ecosystem (e.g., `gx:countryCode`), this model aliases standard vCard address properties to CamelCase keys in the JSON-LD payload.
+
+- `streetAddress` -> `vcard:street-address`
+- `postalCode` -> `vcard:postal-code`
+- `locality` -> `vcard:locality`
+
+This decouples the JSON interface from specific ontology predicates and maintains a uniform style across the credential payload.
diff --git a/linkml/core.yaml b/linkml/core.yaml
new file mode 100644
index 0000000..f00a9e9
--- /dev/null
+++ b/linkml/core.yaml
@@ -0,0 +1,30 @@
+id: https://schema.reachhaven.com/linkml/v1#Core
+name: core
+
+prefixes:
+ linkml: https://w3id.org/linkml/
+ xsd: http://www.w3.org/2001/XMLSchema#
+ rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
+ core: https://schema.reachhaven.com/harbour/v1/core/
+
+default_prefix: core
+default_range: string
+
+imports:
+ - linkml:types
+
+slots:
+ id:
+ # Now this will resolve to core:id (https://schema.reachhaven.com/harbour/v1/core/id)
+ description: The stable identifier for the entity (becomes @id in JSON-LD).
+ identifier: true
+ required: true
+ range: uri
+
+ type:
+ # This remains rdf:type
+ description: The semantic type of the entity (becomes @type in JSON-LD).
+ designates_type: true
+ slot_uri: rdf:type
+ multivalued: true
+ range: uri
diff --git a/linkml/harbour.yaml b/linkml/harbour.yaml
new file mode 100644
index 0000000..19cb414
--- /dev/null
+++ b/linkml/harbour.yaml
@@ -0,0 +1,208 @@
+id: https://schema.reachhaven.com/linkml/v1#Harbour
+name: harbour
+description: >
+ LinkML schema for Harbour credentials vocabulary.
+ Defines the base structures for Evidence, Status, Trust Anchors, and Revocation Registries.
+
+prefixes:
+ linkml: https://w3id.org/linkml/
+ harbour: https://schema.reachhaven.com/harbour/v1/credentials/
+ core: https://schema.reachhaven.com/harbour/v1/core/
+ gx: https://w3id.org/gaia-x/development#
+ xsd: http://www.w3.org/2001/XMLSchema#
+ cs: https://www.w3.org/ns/credentials/status#
+ cred: https://www.w3.org/2018/credentials#
+ schema: http://schema.org/
+ did: https://www.w3.org/ns/did#
+
+default_prefix: harbour
+default_range: string
+
+imports:
+ - linkml:types
+ - ./core
+ - ../ontology-management-base/service-characteristics/linkml/gaia-x
+
+slots:
+ # --- Core Identifiers ---
+ # id and type are imported from core / types
+
+ controller:
+ slot_uri: did:controller
+ range: string
+
+ # --- DID Service Slots ---
+ service_endpoint:
+ slot_uri: did:serviceEndpoint
+ range: Any # Defaults to Any, but specialized in classes via slot_usage
+ required: true
+
+ # --- Revocation Registry (CRSet) Slots ---
+ status_purpose:
+ slot_uri: cs:statusPurpose
+ range: string
+ required: false
+ aliases: [statusPurpose]
+
+ harbour_endpoint:
+ description: Service endpoint IRI for the CRSet.
+ slot_uri: harbour:endpoint
+ range: uri
+ required: false
+ aliases: [endpoint]
+
+ contract_urn:
+ slot_uri: harbour:contractURN
+ range: uri
+ required: false
+ aliases: [contractURN]
+
+ source_repository:
+ slot_uri: harbour:sourceRepository
+ range: uri
+ required: false
+ aliases: [sourceRepository]
+
+ implementation:
+ slot_uri: harbour:implementation
+ range: uri
+ required: false
+
+ # --- Trust Anchor / Organization Slots ---
+ # name, url, description, email, contactPoint are imported from gaia-x / slots
+
+ contact_type:
+ slot_uri: schema:contactType
+ range: string
+ aliases: [contactType]
+
+ # --- Credential / Evidence Slots ---
+ evidence:
+ slot_uri: cred:evidence
+ range: Evidence
+ multivalued: true
+ required: false
+
+ vp:
+ slot_uri: harbour:vp
+ range: string
+ required: false
+
+classes:
+ Any:
+ class_uri: linkml:Any
+ description: "Generic class for any type of value."
+
+ # ==========================================
+ # 1. ROOT DOCUMENT (Optional Wrapper)
+ # ==========================================
+ DIDDocument:
+ class_uri: did:DIDDocument
+ slots:
+ - id
+ - controller
+ attributes:
+ service:
+ slot_uri: did:service
+ multivalued: true
+ inlined: true
+ range: ServiceUnion
+ verificationMethod:
+ slot_uri: did:verificationMethod
+ multivalued: true
+ range: VerificationMethod
+
+ # ==========================================
+ # 2. SERVICES
+ # ==========================================
+
+ # A Union Class to allow polymorphic services in the list
+ ServiceUnion:
+ union_of:
+ - TrustAnchorService
+ - CRSetRevocationRegistryService
+
+ # --- Trust Anchor Service ---
+ TrustAnchorService:
+ class_uri: harbour:TrustAnchorService
+ slots:
+ - id
+ - type
+ - service_endpoint
+ slot_usage:
+ service_endpoint:
+ range: OrganizationEndpoint
+ inlined: true
+
+ OrganizationEndpoint:
+ class_uri: schema:Organization
+ slots:
+ - name
+ - url
+ - description
+ - contactPoint
+ slot_usage:
+ contactPoint:
+ range: ContactPoint
+ inlined: true
+
+ ContactPoint:
+ class_uri: schema:ContactPoint
+ slots:
+ - contact_type
+ - email
+
+ # --- Revocation Registry Service ---
+ CRSetRevocationRegistryService:
+ class_uri: harbour:CRSetRevocationRegistryService
+ slots:
+ - id
+ - type
+ - service_endpoint
+ slot_usage:
+ service_endpoint:
+ range: CRSetServiceEndpoint
+ inlined: true
+
+ CRSetServiceEndpoint:
+ class_uri: harbour:CRSetServiceEndpoint
+ slots:
+ - harbour_endpoint
+ - status_purpose
+ - contract_urn
+ - source_repository
+ - implementation
+
+ # ==========================================
+ # 3. CREDENTIALS & EVIDENCE
+ # ==========================================
+ HarbourVerifiableCredential:
+ class_uri: harbour:VerifiableCredential
+ slots:
+ - evidence
+
+ Evidence:
+ class_uri: cred:Evidence
+ slots:
+ - type
+ - vp
+
+ CRSetEntry:
+ class_uri: harbour:CRSetEntry
+ slots:
+ - id
+ - type
+ - status_purpose
+
+ # ==========================================
+ # 4. HELPERS (For DID Doc structure)
+ # ==========================================
+ VerificationMethod:
+ class_uri: did:VerificationMethod
+ slots:
+ - id
+ - type
+ - controller
+ attributes:
+ blockchainAccountId:
+ range: string
diff --git a/linkml/simpulseid.yaml b/linkml/simpulseid.yaml
new file mode 100644
index 0000000..0b87143
--- /dev/null
+++ b/linkml/simpulseid.yaml
@@ -0,0 +1,299 @@
+id: https://schema.ascs.digital/linkml/v1#SimpulseId
+name: simpulseid
+description: >
+ LinkML schema for SimpulseID credentials.
+ Inherits Evidence structure from Harbour and enforces specific business rules.
+ Extends the Gaia-X Service Characteristics ontology.
+
+prefixes:
+ linkml: https://w3id.org/linkml/
+ simpulseid: https://schema.ascs.digital/simpulseid/v1/credentials/
+ harbour: https://schema.reachhaven.com/harbour/v1/credentials/
+ core: https://schema.reachhaven.com/harbour/v1/core/
+ cs: https://www.w3.org/ns/credentials/status#
+ gx: https://w3id.org/gaia-x/development#
+ schema: http://schema.org/
+ cred: https://www.w3.org/2018/credentials#
+ vcard: http://www.w3.org/2006/vcard/ns#
+ xsd: http://www.w3.org/2001/XMLSchema#
+ skos: http://www.w3.org/2004/02/skos/core#
+ lf: https://schema.ascs.digital/SimpulseId/v1/legalForm/
+
+default_prefix: simpulseid
+default_range: string
+
+imports:
+ - linkml:types
+ - ./core
+ - ../service-characteristics/linkml/gaia-x
+ - ./harbour
+
+slots:
+ # --- Verifiable Credential Slots (Standard W3C) ---
+ # These are not defined in Gaia-X upstream and must be defined locally.
+ issuer:
+ slot_uri: cred:issuer
+ range: SimpulseIdIssuer
+ required: true
+ aliases: [issuer]
+
+ issuance_date:
+ slot_uri: cred:issuanceDate
+ range: datetime
+ required: true
+ aliases: [issuanceDate]
+
+ expiration_date:
+ slot_uri: cred:expirationDate
+ range: datetime
+ required: false
+ aliases: [expirationDate]
+
+ credential_subject:
+ slot_uri: cred:credentialSubject
+ range: CredentialSubject
+ required: true
+ aliases: [credentialSubject]
+
+ credential_status:
+ slot_uri: cred:credentialStatus
+ range: CRSetEntry
+ multivalued: true
+ required: false
+ aliases: [credentialStatus]
+
+ proof:
+ slot_uri: cred:proof
+ range: string
+ required: false
+ aliases: [proof]
+
+ # --- SimpulseID Specific Business Slots ---
+
+ duns:
+ description: The Data Universal Numbering System (DUNS) number.
+ slot_uri: simpulseid:duns
+ range: string
+ aliases: [duns]
+
+ censored:
+ description: Flag indicating if the credential subject data has been redacted.
+ slot_uri: simpulseid:censored
+ range: boolean
+ required: false
+ aliases: [censored]
+
+ base_membership_credential:
+ description: Reference to the base membership credential required for nested memberships.
+ slot_uri: simpulseid:baseMembershipCredential
+ range: uri
+ aliases: [baseMembershipCredential]
+
+ # --- Schema.org Mappings (Natural Person & Memberships) ---
+ # Gaia-X upstream focuses on LegalPerson; these map generic Schema.org concepts.
+
+ given_name:
+ slot_uri: schema:givenName
+ range: string
+ aliases: [givenName]
+
+ family_name:
+ slot_uri: schema:familyName
+ range: string
+ aliases: [familyName]
+
+ member_of:
+ slot_uri: schema:memberOf
+ multivalued: true
+ range: uri
+ aliases: [memberOf]
+
+ program_name:
+ slot_uri: schema:programName
+ range: string
+ aliases: [programName]
+
+ hosting_organization:
+ slot_uri: schema:hostingOrganization
+ range: SimpulseIdHostingOrganization
+ aliases: [hostingOrganization]
+
+ member_since:
+ slot_uri: schema:memberSince
+ range: date
+ aliases: [memberSince]
+
+ # --- Missing Upstream Slots ---
+ # 'legalForm' is missing from upstream slots.yaml and legal-person.yaml.
+
+ legalForm:
+ description: The legal form of the entity (e.g., AG, GmbH).
+ slot_uri: gx:legalForm
+ range: SimpulseIdLegalForm
+ aliases: [legalForm]
+
+enums:
+ SimpulseIdLegalForm:
+ permissible_values:
+ LLC: { meaning: lf:LLC }
+ Corporation: { meaning: lf:Corporation }
+ LimitedPartnership: { meaning: lf:LimitedPartnership }
+ NonprofitCorporation: { meaning: lf:NonprofitCorporation }
+ GmbH: { meaning: lf:GmbH }
+ AG: { meaning: lf:AG }
+ Einzelunternehmen: { meaning: lf:Einzelunternehmen }
+ GbR: { meaning: lf:GbR }
+ OHG: { meaning: lf:OHG }
+ KG: { meaning: lf:KG }
+ UG: { meaning: lf:UG }
+ SoleTrader: { meaning: lf:SoleTrader }
+ UnincorporatedAssociation: { meaning: lf:UnincorporatedAssociation }
+ Partnership: { meaning: lf:Partnership }
+ Trust: { meaning: lf:Trust }
+ LimitedCompany: { meaning: lf:LimitedCompany }
+ LLP: { meaning: lf:LLP }
+ CIC: { meaning: lf:CIC }
+ CIO: { meaning: lf:CIO }
+ CooperativeSociety: { meaning: lf:CooperativeSociety }
+ BenCom: { meaning: lf:BenCom }
+ other: { meaning: lf:other }
+
+classes:
+ SimpulseIdIssuer:
+ is_a: Issuer
+ class_uri: simpulseid:Issuer
+
+ SimpulseIdAddress:
+ is_a: Address
+ class_uri: gx:Address
+ slots:
+ - streetAddress # Imported from Gaia-X slots.yaml
+ - postalCode # Imported from Gaia-X slots.yaml
+ - locality # Imported from Gaia-X slots.yaml
+ - countryCode # Imported from Gaia-X slots.yaml
+ - region # Imported from Gaia-X slots.yaml
+ slot_usage:
+ countryCode:
+ required: true
+ region:
+ required: false
+
+ CredentialSubject:
+ abstract: true
+ class_uri: schema:Thing
+ # 'termsAndConditions' is imported from Gaia-X slots.yaml
+ slots: [id, type, termsAndConditions]
+ slot_usage:
+ # Upstream range is string; we override to TermsAndConditions for nested object structure
+ termsAndConditions:
+ range: TermsAndConditions
+ multivalued: true
+
+ NaturalPerson:
+ # NaturalPerson is not defined in the upstream list provided; defining locally.
+ class_uri: gx:NaturalPerson
+ slots:
+ - given_name
+ - family_name
+ - email # Imported from Gaia-X slots.yaml
+ - member_of
+ - address
+ slot_usage:
+ address: { range: SimpulseIdAddress, required: false, aliases: [address] }
+
+ Administrator:
+ is_a: NaturalPerson
+ mixins: [CredentialSubject]
+ class_uri: simpulseid:Administrator
+ slot_usage:
+ address: { required: true }
+ given_name: { required: true }
+ family_name: { required: true }
+ email: { required: true }
+
+ User:
+ is_a: NaturalPerson
+ mixins: [CredentialSubject]
+ class_uri: simpulseid:User
+ slots: [censored]
+
+ SimpulseIdHostingOrganization:
+ is_a: LegalPerson
+ class_uri: gx:LegalPerson
+ slots: [legalName] # Imported from Gaia-X slots.yaml
+ slot_usage:
+ legalName: { aliases: [legalName] }
+ legalAddress: { required: false, aliases: [legalAddress] }
+ headquartersAddress: { required: false, aliases: [headquartersAddress] }
+
+ SimpulseidParticipant:
+ is_a: LegalPerson
+ mixins: [CredentialSubject]
+ class_uri: simpulseid:Participant
+ slots:
+ - legalName # Imported from Gaia-X slots.yaml
+ - legalForm # Local (Missing Upstream)
+ - legalAddress # Imported from Gaia-X slots.yaml
+ - headquartersAddress # Imported from Gaia-X slots.yaml
+ - email # Imported from Gaia-X slots.yaml
+ - url # Imported from Gaia-X slots.yaml (replaces simpulse_website)
+ - duns # Local
+ - termsAndConditions # Imported from Gaia-X slots.yaml
+ slot_usage:
+ legalName: { aliases: [legalName] }
+ legalForm: { range: SimpulseIdLegalForm, aliases: [legalForm] }
+ legalAddress: { range: SimpulseIdAddress, required: true, aliases: [legalAddress] }
+ headquartersAddress: { range: SimpulseIdAddress, aliases: [headquartersAddress] }
+ # Map generic 'url' to 'website' alias
+ url: { aliases: [website] }
+ duns: { aliases: [duns] }
+ # Override upstream 'termsAndConditions' range (string) to TermsAndConditions
+ termsAndConditions: { range: TermsAndConditions, multivalued: true }
+
+ AscsBaseMembership:
+ is_a: CredentialSubject
+ class_uri: simpulseid:AscsBaseMembership
+ slots: [program_name, hosting_organization, member_of, member_since]
+
+ AscsEnvitedMembership:
+ is_a: CredentialSubject
+ class_uri: simpulseid:AscsEnvitedMembership
+ slots: [program_name, hosting_organization, member_of, member_since, base_membership_credential]
+
+ VerifiableCredential:
+ class_uri: cred:VerifiableCredential
+ slots: [id, type, issuer, issuance_date, expiration_date, credential_subject, credential_status, evidence, proof]
+
+ ParticipantCredential:
+ is_a: VerifiableCredential
+ class_uri: simpulseid:ParticipantCredential
+ slot_usage:
+ credential_subject: { range: SimpulseidParticipant, required: true }
+ evidence: { required: true }
+
+ AscsBaseMembershipCredential:
+ is_a: VerifiableCredential
+ class_uri: simpulseid:AscsBaseMembershipCredential
+ slot_usage:
+ credential_subject: { range: AscsBaseMembership, required: true }
+ evidence: { required: true }
+
+ AscsEnvitedMembershipCredential:
+ is_a: VerifiableCredential
+ class_uri: simpulseid:AscsEnvitedMembershipCredential
+ slot_usage:
+ credential_subject: { range: AscsEnvitedMembership, required: true }
+ evidence: { required: true }
+
+ AdministratorCredential:
+ is_a: VerifiableCredential
+ class_uri: simpulseid:AdministratorCredential
+ slot_usage:
+ credential_subject: { range: Administrator, required: true }
+
+ UserCredential:
+ is_a: VerifiableCredential
+ class_uri: simpulseid:UserCredential
+ slot_usage:
+ credential_subject: { range: User, required: true }
+ evidence: { required: true }
diff --git a/manifests/README.md b/manifests/README.md
new file mode 100644
index 0000000..a7645f8
--- /dev/null
+++ b/manifests/README.md
@@ -0,0 +1,58 @@
+# Wallet Rendering Manifests for SimpulseID Credentials
+
+This folder contains **wallet rendering manifests** for each credential type.
+These files follow the **Decentralized Identity Foundation (DIF) Wallet Rendering**
+specification and define how SSI wallets (such as Altme) should display the
+credential to end users.
+
+## Purpose
+
+Manifests control:
+
+- Title and subtitle displayed on the credential card
+- Key fields shown on the card (e.g., name, organization, membership type)
+- How credentials appear in credential lists and detail views
+- Icons, colors, and layout options (if supported by the wallet)
+
+All manifest files correspond 1:1 to credential types found in:
+
+```txt
+../examples/
+```
+
+and are intended for use by wallets integrated with:
+
+****
+
+## Files
+
+### `SimpulseIdParticipantCredentialManifest.json`
+
+Defines card rendering for Participant Credentials (gx:LegalPerson).
+
+### `SimpulseIdAscsBaseMembershipCredentialManifest.json`
+
+Defines rendering for ASCS Base Membership credentials.
+
+### `SimpulseIdAscsEnvitedMembershipCredentialManifest.json`
+
+Rendering for ENVITED Program Membership credentials.
+
+### `SimpulseIdAdministratorCredentialManifest.json`
+
+Rendering of administrator credentials issued by ASCS.
+
+### `SimpulseIdUserCredentialManifest.json`
+
+Rendering of user credentials issued by participant administrators.
+
+## Usage
+
+Wallets use these manifests to visually render credentials when they are:
+
+- Added to the wallet
+- Displayed in a card list
+- Displayed in detail view
+- Offered for presentation via OIDC4VP
+
+They do **not** affect cryptographic validity—only **UX rendering**.
diff --git a/manifests/SimpulseIdAdministratorCredentialManifest.json b/manifests/SimpulseIdAdministratorCredentialManifest.json
new file mode 100644
index 0000000..1125598
--- /dev/null
+++ b/manifests/SimpulseIdAdministratorCredentialManifest.json
@@ -0,0 +1,181 @@
+{
+ "id": "SimpulseIdAdministratorManifest",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs",
+ "name": "Automotive Solution Center for Simulation e.V."
+ },
+ "output_descriptors": [
+ {
+ "id": "https://schema.ascs.digital/simpulseid/v1/credentials/AdministratorManifest",
+ "schema": "https://schema.ascs.digital/simpulseid/v1/credentials/Administrator",
+ "styles": {
+ "background": {
+ "color": "#60ac24"
+ },
+ "text": {
+ "color": "#ffffff"
+ }
+ },
+ "display": {
+ "title": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "BMW Administrator Credential"
+ },
+ "subtitle": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Automotive Solution Center for Simulation e.V."
+ },
+ "description": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "This credential certifies the administrator's role at BMW, granting specific permissions and responsibilities."
+ },
+ "properties": [
+ {
+ "path": [
+ "$.credentialSubject.givenName",
+ "$.credentialSubject.familyName"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Full Name"
+ },
+ {
+ "path": [
+ "$.credentialSubject.email"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Email Address"
+ },
+ {
+ "path": [
+ "$.credentialSubject.memberOf"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Organization"
+ },
+ {
+ "path": [
+ "$.credentialSubject.address.streetAddress"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Street Address"
+ },
+ {
+ "path": [
+ "$.credentialSubject.address.postalCode"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Postal Code"
+ },
+ {
+ "path": [
+ "$.credentialSubject.address.addressLocality"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "City"
+ },
+ {
+ "path": [
+ "$.credentialSubject.address.countrySubdivisionCode"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "State"
+ },
+ {
+ "path": [
+ "$.credentialSubject.address.country"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Country"
+ },
+ {
+ "path": [
+ "$.credentialSubject.termsAndConditions[0].@id"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "uri"
+ },
+ "fallback": "Unknown",
+ "label": "Terms & Conditions"
+ },
+ {
+ "path": [
+ "$.issuanceDate"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "date"
+ },
+ "fallback": "Unknown",
+ "label": "Issued On"
+ },
+ {
+ "path": [
+ "$.expirationDate"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "date"
+ },
+ "fallback": "Unknown",
+ "label": "Expires On"
+ }
+ ]
+ }
+ }
+ ],
+ "presentation_definition": {
+ "input_descriptors": [
+ {
+ "constraints": {
+ "fields": [
+ {
+ "filter": {
+ "pattern": "TezosAssociatedAddress",
+ "type": "string"
+ },
+ "path": [
+ "$.type"
+ ]
+ }
+ ]
+ },
+ "id": "f2a7402b-f649-11ed-834e-0a1628958560",
+ "purpose": "Select a Tezos address for verification"
+ }
+ ]
+ }
+}
diff --git a/manifests/AscsMemberCredentialManifest.json b/manifests/SimpulseIdAscsBaseMembershipCredentialManifest.json
similarity index 63%
rename from manifests/AscsMemberCredentialManifest.json
rename to manifests/SimpulseIdAscsBaseMembershipCredentialManifest.json
index b9156e7..d05f912 100644
--- a/manifests/AscsMemberCredentialManifest.json
+++ b/manifests/SimpulseIdAscsBaseMembershipCredentialManifest.json
@@ -1,16 +1,16 @@
{
- "id": "AscsMemberCredentialManifest",
+ "id": "SimpulseIdAscsBaseMembershipManifest",
"issuer": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1ggujjYjA7oYoaZBzTg1tYSXn3VMjcgDuv",
+ "id": "did:web:did.ascs.digital:participants:ascs",
"name": "Automotive Solution Center for Simulation e.V."
},
"output_descriptors": [
{
- "id": "https://schema.ascs.digital/AscsMemberCredential/v1#Manifest",
- "schema": "AscsMemberCredential",
+ "id": "https://schema.ascs.digital/simpulseid/v1/credentials/AscsBaseMembershipManifest",
+ "schema": "https://schema.ascs.digital/simpulseid/v1/credentials/AscsBaseMembership",
"styles": {
"background": {
- "color": "#60ac24"
+ "color": "#0066cc"
},
"text": {
"color": "#ffffff"
@@ -22,7 +22,7 @@
"schema": {
"type": "string"
},
- "fallback": "asc(s Member Credential"
+ "fallback": "ASCS Base Membership"
},
"subtitle": {
"path": [],
@@ -36,103 +36,102 @@
"schema": {
"type": "string"
},
- "fallback": "A certificate that attests the organizations membership in the asc(s and optionally the ENVITED research cluster confering the mandate to perform a number of actions on behalf of that organisation."
+ "fallback": "This credential certifies the base membership in ASCS e.V., granting access to core services and benefits."
},
"properties": [
{
"path": [
- "$.credentialSubject.name"
+ "$.credentialSubject.programName"
],
"schema": {
- "type": "text"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "Organization name"
+ "label": "Membership Program"
},
{
"path": [
- "$.credentialSubject.address.addressCountry"
+ "$.credentialSubject.hostingOrganization.name"
],
"schema": {
- "type": "text"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "Country"
+ "label": "Hosting Organization"
},
{
"path": [
- "$.credentialSubject.isAscsMember"
+ "$.credentialSubject.member"
],
"schema": {
- "type": "boolean"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "asc(s membership"
+ "label": "Member"
},
{
"path": [
- "$.credentialSubject.isEnvitedMember"
+ "$.credentialSubject.memberOf[0]"
],
"schema": {
- "type": "boolean"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "ENVITED membership"
+ "label": "Member Of (Organization)"
},
{
"path": [
- "$.credentialSubject.privacyPolicy"
+ "$.credentialSubject.memberOf[1]"
],
"schema": {
- "type": "string",
- "format": "uri"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "Privacy policy"
+ "label": "Member Of (Program)"
},
{
"path": [
- "$.credentialSubject.articlesOfAssociation"
+ "$.credentialSubject.memberSince"
],
"schema": {
"type": "string",
- "format": "uri"
+ "format": "date"
},
"fallback": "Unknown",
- "label": "Articles of association"
+ "label": "Member Since"
},
{
"path": [
- "$.credentialSubject.contributionRules"
+ "$.credentialSubject.termsAndConditions[0].@id"
],
"schema": {
"type": "string",
"format": "uri"
},
"fallback": "Unknown",
- "label": "Contribution rules"
+ "label": "Terms & Conditions"
},
{
"path": [
"$.issuanceDate"
],
"schema": {
- "type": "text",
+ "type": "string",
"format": "date"
},
"fallback": "Unknown",
- "label": "Issue date"
+ "label": "Issued On"
},
{
"path": [
"$.expirationDate"
],
"schema": {
- "type": "text",
+ "type": "string",
"format": "date"
},
"fallback": "Unknown",
- "label": "Expiration date"
+ "label": "Expires On"
}
]
}
@@ -155,8 +154,8 @@
]
},
"id": "f2a7402b-f649-11ed-834e-0a1628958560",
- "purpose": "Select a Tezos address"
+ "purpose": "Select a Tezos address for verification"
}
]
}
-}
\ No newline at end of file
+}
diff --git a/manifests/SimpulseIdAscsEnvitedMembershipCredentialManifest.json b/manifests/SimpulseIdAscsEnvitedMembershipCredentialManifest.json
new file mode 100644
index 0000000..fdf7815
--- /dev/null
+++ b/manifests/SimpulseIdAscsEnvitedMembershipCredentialManifest.json
@@ -0,0 +1,181 @@
+{
+ "id": "SimpulseIdAscsEnvitedMembershipManifest",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs",
+ "name": "Automotive Solution Center for Simulation e.V."
+ },
+ "output_descriptors": [
+ {
+ "id": "https://schema.ascs.digital/simpulseid/v1/credentials/AscsEnvitedMembershipManifest",
+ "schema": "https://schema.ascs.digital/simpulseid/v1/credentials/AscsEnvitedMembership",
+ "styles": {
+ "background": {
+ "color": "#008080"
+ },
+ "text": {
+ "color": "#ffffff"
+ }
+ },
+ "display": {
+ "title": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "ASCS ENVITED Membership"
+ },
+ "subtitle": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Automotive Solution Center for Simulation e.V."
+ },
+ "description": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "This credential certifies the ENVITED membership in ASCS e.V., granting access to advanced services and collaboration tools."
+ },
+ "properties": [
+ {
+ "path": [
+ "$.credentialSubject.programName"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Membership Program"
+ },
+ {
+ "path": [
+ "$.credentialSubject.hostingOrganization.name"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Hosting Organization"
+ },
+ {
+ "path": [
+ "$.credentialSubject.member"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Member"
+ },
+ {
+ "path": [
+ "$.credentialSubject.memberOf[0]"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Member Of (Organization)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.memberOf[1]"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Member Of (Base Program)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.memberOf[2]"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Member Of (ENVITED Program)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.memberSince"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "date"
+ },
+ "fallback": "Unknown",
+ "label": "Member Since"
+ },
+ {
+ "path": [
+ "$.credentialSubject.baseMembership"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Base Membership ID"
+ },
+ {
+ "path": [
+ "$.credentialSubject.termsAndConditions[0].@id"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "uri"
+ },
+ "fallback": "Unknown",
+ "label": "Terms & Conditions"
+ },
+ {
+ "path": [
+ "$.issuanceDate"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "date"
+ },
+ "fallback": "Unknown",
+ "label": "Issued On"
+ },
+ {
+ "path": [
+ "$.expirationDate"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "date"
+ },
+ "fallback": "Unknown",
+ "label": "Expires On"
+ }
+ ]
+ }
+ }
+ ],
+ "presentation_definition": {
+ "input_descriptors": [
+ {
+ "constraints": {
+ "fields": [
+ {
+ "filter": {
+ "pattern": "TezosAssociatedAddress",
+ "type": "string"
+ },
+ "path": [
+ "$.type"
+ ]
+ }
+ ]
+ },
+ "id": "f2a7402b-f649-11ed-834e-0a1628958560",
+ "purpose": "Select a Tezos address for verification"
+ }
+ ]
+ }
+}
diff --git a/manifests/SimpulseIdParticipantCredentialManifest.json b/manifests/SimpulseIdParticipantCredentialManifest.json
new file mode 100644
index 0000000..b214fd2
--- /dev/null
+++ b/manifests/SimpulseIdParticipantCredentialManifest.json
@@ -0,0 +1,261 @@
+{
+ "id": "SimpulseIdParticipantManifest",
+ "issuer": {
+ "id": "did:web:did.ascs.digital:participants:ascs",
+ "name": "Automotive Solution Center for Simulation e.V."
+ },
+ "output_descriptors": [
+ {
+ "id": "https://schema.ascs.digital/simpulseid/v1/credentials/ParticipantManifest",
+ "schema": "https://schema.ascs.digital/simpulseid/v1/credentials/Participant",
+ "styles": {
+ "background": {
+ "color": "#003366"
+ },
+ "text": {
+ "color": "#ffffff"
+ }
+ },
+ "display": {
+ "title": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Company Participant Credential"
+ },
+ "subtitle": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Automotive Solution Center for Simulation e.V."
+ },
+ "description": {
+ "path": [],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "This credential certifies the company's participation in the ASCS ecosystem, enabling access to collaborative services and resources."
+ },
+ "properties": [
+ {
+ "path": [
+ "$.credentialSubject.legalName"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Company Name"
+ },
+ {
+ "path": [
+ "$.credentialSubject.legalForm"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Legal Form"
+ },
+ {
+ "path": [
+ "$.credentialSubject.registrationNumber.vatID"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "VAT ID"
+ },
+ {
+ "path": [
+ "$.credentialSubject.duns"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "DUNS Number"
+ },
+ {
+ "path": [
+ "$.credentialSubject.email"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Email"
+ },
+ {
+ "path": [
+ "$.credentialSubject.website"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "uri"
+ },
+ "fallback": "Unknown",
+ "label": "Website"
+ },
+ {
+ "path": [
+ "$.credentialSubject.legalAddress.streetAddress"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Legal Address (Street)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.legalAddress.postalCode"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Legal Address (Postal Code)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.legalAddress.addressLocality"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Legal Address (City)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.legalAddress.countrySubdivisionCode"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Legal Address (State)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.legalAddress.country"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Legal Address (Country)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.headquartersAddress.streetAddress"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Headquarters (Street)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.headquartersAddress.postalCode"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Headquarters (Postal Code)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.headquartersAddress.addressLocality"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Headquarters (City)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.headquartersAddress.countrySubdivisionCode"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Headquarters (State)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.headquartersAddress.country"
+ ],
+ "schema": {
+ "type": "string"
+ },
+ "fallback": "Unknown",
+ "label": "Headquarters (Country)"
+ },
+ {
+ "path": [
+ "$.credentialSubject.termsAndConditions[0].@id"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "uri"
+ },
+ "fallback": "Unknown",
+ "label": "Terms & Conditions"
+ },
+ {
+ "path": [
+ "$.issuanceDate"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "date"
+ },
+ "fallback": "Unknown",
+ "label": "Issued On"
+ },
+ {
+ "path": [
+ "$.expirationDate"
+ ],
+ "schema": {
+ "type": "string",
+ "format": "date"
+ },
+ "fallback": "Unknown",
+ "label": "Expires On"
+ }
+ ]
+ }
+ }
+ ],
+ "presentation_definition": {
+ "input_descriptors": [
+ {
+ "constraints": {
+ "fields": [
+ {
+ "filter": {
+ "pattern": "TezosAssociatedAddress",
+ "type": "string"
+ },
+ "path": [
+ "$.type"
+ ]
+ }
+ ]
+ },
+ "id": "f2a7402b-f649-11ed-834e-0a1628958560",
+ "purpose": "Select a Tezos address for verification"
+ }
+ ]
+ }
+}
diff --git a/manifests/AscsUserCredentialManifest.json b/manifests/SimpulseIdUserCredentialManifest.json
similarity index 55%
rename from manifests/AscsUserCredentialManifest.json
rename to manifests/SimpulseIdUserCredentialManifest.json
index dc80ccc..6c729e6 100644
--- a/manifests/AscsUserCredentialManifest.json
+++ b/manifests/SimpulseIdUserCredentialManifest.json
@@ -1,13 +1,13 @@
{
- "id": "AscsUserCredentialManifest",
+ "id": "SimpulseIdUserManifest",
"issuer": {
- "id": "did:pkh:tezos:NetXnHfVqm9iesp:tz1bpeJArd7apJyTUryfXH1SD6w8GL6Gwhj8",
- "name": "Testcompany GmbH"
+ "id": "did:web:did.ascs.digital:participants:bmw",
+ "name": "Bayerische Motoren Werke Aktiengesellschaft"
},
"output_descriptors": [
{
- "id": "https://schema.ascs.digital/AscsUserCredential/v1#Manifest",
- "schema": "AscsUserCredential",
+ "id": "https://schema.ascs.digital/simpulseid/v1/credentials/UserManifest",
+ "schema": "https://schema.ascs.digital/simpulseid/v1/credentials/User",
"styles": {
"background": {
"color": "#7891bb"
@@ -22,105 +22,86 @@
"schema": {
"type": "string"
},
- "fallback": "asc(s User Credential"
+ "fallback": "BMW User Credential"
},
"subtitle": {
"path": [],
"schema": {
"type": "string"
},
- "fallback": "Automotive Solution Center for Simulation e.V."
+ "fallback": "Bayerische Motoren Werke AG"
},
"description": {
"path": [],
"schema": {
"type": "string"
},
- "fallback": "A certificate that attests the users affiliation with an organization holding a membership in the asc(s and optionally the ENVITED research cluster confering the mandate to access services within the ecosystem."
+ "fallback": "This credential certifies the user's affiliation with BMW, granting access to ecosystem services."
},
"properties": [
{
"path": [
- "$.credentialSubject.name"
+ "$.credentialSubject.givenName",
+ "$.credentialSubject.familyName"
],
"schema": {
- "type": "text"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "User name"
- },
- {
- "path": [
- "$.credentialSubject.address.addressCountry"
- ],
- "schema": {
- "type": "text"
- },
- "fallback": "Unknown",
- "label": "Country"
+ "label": "Full Name"
},
{
"path": [
"$.credentialSubject.email"
],
"schema": {
- "type": "text"
- },
- "fallback": "Unknown",
- "label": "E-Mail"
- },
- {
- "path": [
- "$.credentialSubject.isAscsMember"
- ],
- "schema": {
- "type": "boolean"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "asc(s membership"
+ "label": "Email Address"
},
{
"path": [
- "$.credentialSubject.isEnvitedMember"
+ "$.credentialSubject.memberOf"
],
"schema": {
- "type": "boolean"
+ "type": "string"
},
"fallback": "Unknown",
- "label": "ENVITED membership"
+ "label": "Organization"
},
{
"path": [
- "$.credentialSubject.privacyPolicy"
+ "$.credentialSubject.termsAndConditions[0].@id"
],
"schema": {
"type": "string",
"format": "uri"
},
"fallback": "Unknown",
- "label": "Privacy policy"
+ "label": "Terms & Conditions"
},
{
"path": [
"$.issuanceDate"
],
"schema": {
- "type": "text",
+ "type": "string",
"format": "date"
},
"fallback": "Unknown",
- "label": "Issue date"
+ "label": "Issued On"
},
{
"path": [
"$.expirationDate"
],
"schema": {
- "type": "text",
+ "type": "string",
"format": "date"
},
"fallback": "Unknown",
- "label": "Expiration date"
+ "label": "Expires On"
}
]
}
@@ -143,8 +124,8 @@
]
},
"id": "f2a7402b-f649-11ed-834e-0a1628958560",
- "purpose": "Select a Tezos address"
+ "purpose": "Select a Tezos address for verification"
}
]
}
-}
\ No newline at end of file
+}
diff --git a/ontology-management-base b/ontology-management-base
new file mode 160000
index 0000000..427c840
--- /dev/null
+++ b/ontology-management-base
@@ -0,0 +1 @@
+Subproject commit 427c8405c4d2c1df83b7fa15bb2e13c4ce69a703
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..cca1998
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,29 @@
+[build-system]
+requires = ["setuptools>=61.0"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "credentials"
+version = "2.0.0"
+requires-python = ">=3.12"
+dependencies = [
+ "linkml>=1.9.6",
+ "linkml-runtime>=1.9.5",
+ "pyld>=2.0.4",
+ "PyYAML>=6.0.3",
+ "click>=8.0.0, <8.2",
+]
+
+[project.optional-dependencies]
+dev = [
+ "black>=25.12.0",
+ "flake8>=7.1.2",
+ "isort>=7.0.0",
+ "pre-commit>=4.5.1",
+]
+
+[tool.black]
+line-length = 88
+
+[tool.isort]
+profile = "black"
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..6b7884d
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,53 @@
+# Generated artefacts
+
+This folder contains downstream artefacts generated from LinkML schemas:
+
+- JSON-LD context (`*_context.jsonld`)
+- SHACL shapes (`*_shacl.ttl`)
+- OWL ontology (`*_ontology.ttl`)
+
+Each schema is generated into its own subfolder:
+
+- `generated/simpulseid/`
+- `generated/harbour/`
+- `generated/gx/`
+
+## 1) Generate
+
+From repository root:
+
+```bash
+python3 src/generate_from_linkml.py \
+ --model linkml/simpulseid.yaml \
+ --model linkml/harbour.yaml \
+ --model service-characteristics/linkml/gaia-x.yaml \
+ --out-root generated
+```
+
+## 2) Validate examples against generated SHACL + schema (recommended)
+
+Examples are validated using the `ontology-management-base` validator.
+Point `--root` to `generated/` so it can resolve:
+
+- generated contexts
+- generated SHACL files
+- generated ontologies
+
+Example:
+
+```bash
+python3 ontology-management-base/src/check_jsonld_against_shacl_schema.py \
+ examples/simpulseid-administrator-credential.json \
+ --root generated/
+```
+
+## Notes on `id` / `@id`
+
+In JSON-LD, the node identifier is the keyword `@id`. Many JSON-LD contexts (including VC contexts) map a compact term like `id` to `@id`, but the underlying mechanism is JSON-LD itself.
+
+For LinkML, the robust modelling pattern is to define a shared slot once (e.g., in a small `core.yaml`) with:
+
+- `slot_uri: "@id"` for the `id` slot
+- `slot_uri: "@type"` for the `type` slot
+
+and import that shared definition into all schemas that need it. This prevents “conflicting URIs for item: id” during import merges.
diff --git a/src/generate_from_linkml.py b/src/generate_from_linkml.py
new file mode 100644
index 0000000..814f093
--- /dev/null
+++ b/src/generate_from_linkml.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python3
+"""
+Generate downstream artefacts (JSON-LD context, SHACL shapes, OWL ontology)
+from one or more LinkML schemas.
+"""
+
+import argparse
+import os
+from pathlib import Path
+from typing import Dict, List, Optional
+from urllib.parse import urlparse
+
+from linkml.generators.jsonldcontextgen import ContextGenerator
+from linkml.generators.owlgen import OwlSchemaGenerator
+from linkml.generators.shaclgen import ShaclGenerator as _BaseShaclGenerator
+from linkml_runtime.utils.schemaview import SchemaView
+
+# Post-processing replacement to satisfy oxigraph/pyshacl fragments
+URI_TWEAKS = {
+ # Gaia-X
+ "https://w3id.org/gaia-x/development#": "https://w3id.org/gaia-x/development/",
+}
+
+
+def apply_artifact_replacements(content: str) -> str:
+ """Replaces URIs in generated content to prevent double hash fragments in validation tools."""
+ for original, replacement in URI_TWEAKS.items():
+ content = content.replace(original, replacement)
+ return content
+
+
+def debug(msg: str) -> None:
+ print(f"[DEBUG] {msg}")
+
+
+def ensure_dir(path: Path) -> None:
+ path.mkdir(parents=True, exist_ok=True)
+
+
+def find_repo_root(start: Path) -> Path:
+ current = start
+ while current != current.parent:
+ if (current / "ontology-management-base").is_dir() or (
+ current / ".git"
+ ).is_dir():
+ return current
+ current = current.parent
+ return start.parent
+
+
+def build_import_map(repo_root: Path) -> Dict[str, str]:
+ candidates = [
+ repo_root / "ontology-management-base" / "service-characteristics" / "linkml",
+ repo_root / "service-characteristics" / "linkml",
+ ]
+ gaiax_linkml_dir = next((d for d in candidates if d.is_dir()), None)
+
+ import_map: Dict[str, str] = {}
+
+ if not gaiax_linkml_dir:
+ debug(f"Gaia-X linkml dir not found in candidates: {candidates}")
+ return import_map
+
+ for yaml_file in gaiax_linkml_dir.glob("*.yaml"):
+ abs_path = str(yaml_file.with_suffix("").resolve())
+ import_map[yaml_file.stem] = abs_path
+ legacy_path = f"../service-characteristics/linkml/{yaml_file.stem}"
+ import_map[legacy_path] = abs_path
+ import_map[f"{legacy_path}.yaml"] = abs_path
+
+ debug(f"Built import_map with {len(import_map)} entries from {gaiax_linkml_dir}")
+ return import_map
+
+
+def iri_to_model_name(iri: str) -> str:
+ path = urlparse(iri).path
+ parts = [p for p in path.split("/") if p]
+ return parts[0].lower() if parts else "unknown"
+
+
+class FixedShaclGenerator(_BaseShaclGenerator):
+ """Ensure SchemaView is built with the same importmap/base_dir as the loader."""
+
+ def __post_init__(self) -> None:
+ from linkml.utils.generator import Generator as BaseGenerator
+
+ BaseGenerator.__post_init__(self)
+ self.schemaview = SchemaView(
+ self.schema, importmap=self.importmap or {}, base_dir=self.base_dir
+ )
+ self.generate_header()
+
+
+def set_linkml_model_path(repo_root: Path) -> None:
+ gaiax_linkml_dirs = [
+ repo_root / "ontology-management-base" / "service-characteristics" / "linkml",
+ repo_root / "service-characteristics" / "linkml",
+ ]
+ local_linkml_dir = repo_root / "linkml"
+
+ search_paths: List[str] = []
+
+ for d in gaiax_linkml_dirs:
+ if d.is_dir():
+ search_paths.append(str(d))
+
+ if local_linkml_dir.is_dir():
+ search_paths.append(str(local_linkml_dir))
+
+ existing_env = os.environ.get("LINKML_MODEL_PATH")
+ if existing_env:
+ search_paths.append(existing_env)
+
+ if search_paths:
+ os.environ["LINKML_MODEL_PATH"] = os.pathsep.join(search_paths)
+ debug(f"LINKML_MODEL_PATH set to: {os.environ['LINKML_MODEL_PATH']}")
+
+
+def schema_id_for(
+ model_path: Path, import_map: Dict[str, str], base_dir: str
+) -> Optional[str]:
+ sv = SchemaView(str(model_path), importmap=import_map, base_dir=base_dir)
+ return getattr(sv.schema, "id", None)
+
+
+def generate_one(model_path: Path, out_root: Path, import_map: Dict[str, str]) -> None:
+ base_dir = str(model_path.parent)
+
+ sid = schema_id_for(model_path, import_map, base_dir)
+ model_name = iri_to_model_name(sid) if sid else model_path.stem.lower()
+
+ out_dir = out_root / model_name
+ ensure_dir(out_dir)
+
+ out_context = out_dir / f"{model_name}_context.jsonld"
+ out_shacl = out_dir / f"{model_name}_shacl.ttl"
+ out_owl = out_dir / f"{model_name}_ontology.ttl"
+
+ debug(f"Model: {model_path}")
+ debug(f"schema_id={sid!r} -> model_name={model_name!r}")
+ debug(f"Outputs: {out_dir}")
+
+ old_cwd = Path.cwd()
+ os.chdir(model_path.parent)
+ try:
+ print(f"Using LinkML model: {model_path}")
+
+ print(f"Generating JSON-LD context -> {out_context}")
+ # The ContextGenerator handles @id/@type automatically due to identifier: true and designates_type: true
+ ctx_gen = ContextGenerator(
+ str(model_path), importmap=import_map, base_dir=base_dir
+ )
+ out_context.write_text(
+ apply_artifact_replacements(ctx_gen.serialize()), encoding="utf-8"
+ )
+
+ print(f"Generating SHACL shapes -> {out_shacl}")
+ shacl_gen = FixedShaclGenerator(
+ str(model_path), importmap=import_map, base_dir=base_dir
+ )
+ out_shacl.write_text(
+ apply_artifact_replacements(shacl_gen.serialize()), encoding="utf-8"
+ )
+
+ print(f"Generating OWL ontology -> {out_owl}")
+ owl_gen = OwlSchemaGenerator(
+ str(model_path), importmap=import_map, base_dir=base_dir
+ )
+ out_owl.write_text(
+ apply_artifact_replacements(owl_gen.serialize()), encoding="utf-8"
+ )
+
+ print(f"Done: {model_name}")
+ finally:
+ os.chdir(old_cwd)
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser(
+ description="Generate JSON-LD context, SHACL shapes and OWL ontology from one or more LinkML models."
+ )
+ parser.add_argument(
+ "--model",
+ action="append",
+ required=False,
+ help="Path to a LinkML YAML schema. If not provided, defaults to all *.yaml files in the 'linkml' directory (non-recursive).",
+ )
+ parser.add_argument(
+ "--out-root",
+ default="generated",
+ help="Root output folder (default: generated). Each schema is generated into generated//",
+ )
+
+ args = parser.parse_args()
+
+ if args.model:
+ models = [Path(m).resolve() for m in args.model]
+ else:
+ repo_root = find_repo_root(Path.cwd())
+ linkml_dir = repo_root / "linkml"
+
+ if not linkml_dir.is_dir():
+ linkml_dir = Path("linkml").resolve()
+
+ if not linkml_dir.is_dir():
+ raise SystemExit(
+ f"Error: No --model provided and 'linkml' directory not found at {repo_root / 'linkml'}"
+ )
+
+ print(f"No --model specified. Auto-detecting *.yaml in {linkml_dir}...")
+ models = sorted(list(linkml_dir.glob("*.yaml")))
+
+ if not models:
+ raise SystemExit(f"Error: No .yaml files found in {linkml_dir}")
+
+ for mp in models:
+ if not mp.exists():
+ raise SystemExit(f"LinkML model not found: {mp}")
+
+ repo_root = find_repo_root(models[0].parent)
+ debug(f"repo_root: {repo_root}")
+
+ import_map = build_import_map(repo_root)
+ set_linkml_model_path(repo_root)
+
+ out_root = Path(args.out_root).resolve()
+ ensure_dir(out_root)
+
+ for mp in models:
+ generate_one(mp, out_root, import_map)
+
+
+if __name__ == "__main__":
+ main()