Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion public/brand/favicon.svg

This file was deleted.

2 changes: 1 addition & 1 deletion site/dpp-docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ site/dpp-docs/
│ └── custom.css # Starlight overrides via @odal/brand-tokens
```

Brand assets shared with the landing site come from the workspace-root `../../public/brand/`, copied into the build by `viteStaticCopy` (see `astro.config.mjs`).
Brand assets live in this site’s own `public/` and `src/assets/`. There is no shared asset directory — the two sites are deployed independently, and a cross-site copy step was removed because it published a duplicate favicon at a path nothing referenced.

The sidebar structure is declared in `astro.config.mjs` and mirrored by the file-system layout under `src/content/docs/`. Renamed or removed slugs keep a redirect (e.g. `/design/proof-bound` → `/getting-started/what-odal-can-and-cannot-see`); the full redirect map is in `astro.config.mjs`, which is the source of truth for the information architecture.

Expand Down
11 changes: 2 additions & 9 deletions site/dpp-docs/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import { viteStaticCopy } from 'vite-plugin-static-copy';

export default defineConfig({
site: 'https://docs.odal-node.io',
Expand All @@ -9,10 +8,7 @@ export default defineConfig({
// Design pages removed; redirect to the closest living equivalent.
'/design/no-touch-data': '/getting-started/what-odal-can-and-cannot-see',
'/design/proof-bound': '/getting-started/what-odal-can-and-cannot-see',
// Points at the licence table rather than at /engine/licensing, whose
// source is underscore-prefixed and therefore never routed. Repoint it back
// when that page is published.
'/design/open-core': '/introduction',
'/design/open-core': '/engine/licensing',
'/design/adr': '/core-concepts',
'/design/why-no-capability-gating': '/core-concepts',
// Core consolidated from per-crate/type pages into three concept pages.
Expand Down Expand Up @@ -82,7 +78,7 @@ export default defineConfig({
{ label: 'Operating securely', link: '/engine/security' },
{ label: 'Self-Hosting', link: '/engine/self-hosted' },
{ label: 'The CLI', link: '/engine/cli' },
// { label: 'Licensing', link: '/engine/licensing' },
{ label: 'Licensing', link: '/engine/licensing' },
],
},
{
Expand All @@ -108,8 +104,5 @@ export default defineConfig({
customCss: ['./src/styles/custom.css'],
}),
],
vite: {
plugins: [viteStaticCopy({ targets: [{ src: '../../public/brand', dest: '' }] })],
},
output: 'static',
});
8 changes: 7 additions & 1 deletion site/dpp-docs/src/content/docs/core/standards.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ A passport is only useful if the rest of the world can read it. The core speaks

## The European system standards, tracked clause by clause

The European DPP system standards — written by CEN/CENELEC JTC 24 — are landing in stages. Six were published in May 2026 — **EN 18216, 18219, 18220, 18221, 18222, 18223** — covering exchange, identifiers, data carriers, storage, lifecycle APIs, and interoperability. The remaining two — **EN 18239** (access rights, security, business confidentiality) and **EN 18246** (data authentication) — are at FprEN stage, expected around September 2026. Odal tracks them clause by clause in a maintained conformance matrix, and the core's identifier, carrier, API, and authentication semantics align to the published texts. One honest nuance: even a published standard is *available* but not yet *harmonised* (cited in the Official Journal) — so we build to them today and claim presumption of conformity only when that citation lands.
The European DPP system standards — written by CEN/CENELEC JTC 24, in the EN 182xx series — are landing in stages, covering exchange, identifiers, data carriers, storage, lifecycle APIs, interoperability, access rights and data authentication.

We are **tracking** that series, not claiming conformance to it, and the distinction is deliberate. These are paid standards and we have not purchased the texts. Nobody here has read them, so there is no clause-by-clause matrix and no basis on which we could assert that our identifier, carrier, API or authentication semantics align with what they actually say. We would rather state that plainly than describe an alignment nobody could check.

What we have built to instead are the open, published specifications those standards draw on — GS1 Digital Link, W3C Verifiable Credentials, `did:web`, the IDTA Asset Administration Shell — all of which are readable by anyone evaluating this claim. When the EN texts are purchased and read, this page will say what was found, including where it disagrees with what we built.

One further nuance that will still apply then: even a published standard is *available* but not yet *harmonised* (cited in the Official Journal), so presumption of conformity is a claim for the day that citation lands, not before.

## Read next

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,19 @@ Each `dpp-engine` release ships with a specific change date in its licence heade

## Dependency licences

`dpp-engine` builds on `dpp-core` (Apache-2.0) and other open-source dependencies. Each crate's `Cargo.toml` declares its full dependency tree. The key third-party licences are:

- **Axum / Tokio** — MIT (HTTP framework and async runtime).
- **wasmtime** — Apache-2.0 (the sector-plugin sandbox).
- **ed25519-dalek** — BSD 3-Clause (signing).
- **PostgreSQL** — PostgreSQL Licence (liberal, BSD-style).
- **Redis** — BSD 3-Clause (resolver cache).
- **NATS** — Apache-2.0 (event bus).

No dependency introduces a copyleft obligation that would propagate to `dpp-engine` users.
`dpp-engine` builds on `dpp-core` (Apache-2.0) and a tree of open-source Rust crates.

This page deliberately does **not** reproduce a table of those licences. A restated licence
list is a claim that goes stale silently: the licence lives in the dependency's own metadata,
changes on the dependency's schedule rather than ours, and a copy here would keep asserting the
old terms long after they changed. That is not hypothetical — a previous version of this page
carried a licence for one component that had been wrong since 2024.

The authoritative answer for any given build is the build itself. `cargo license` or
`cargo deny` over the workspace enumerates every crate and its licence from the resolved
dependency graph, and `Cargo.lock` is committed, so the result is reproducible for any tagged
release. Anyone evaluating the engine for licence compatibility should run it against the
version they intend to deploy rather than trust a list written against some earlier one.

## Read next

Expand Down
2 changes: 1 addition & 1 deletion site/dpp-docs/src/content/docs/regulatory/espr.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Odal covers the articles of ESPR that are technically substantive for a passport
**Articles 24 & 25** — the disclosure duty for discarded unsold consumer products (Art. 24) and the destruction ban for unsold textiles and footwear (Art. 25, Annex VII — in force for large companies since 19 July 2026). Odal carries a dedicated unsold-goods passport variant that records the disposal pathway as a verifiable record.

<Aside type="tip" title="The implementation matrix">
A row-by-row matrix mapping each ESPR article to where it is implemented is maintained in the `dpp-core` repository.
The `dpp-core` repository documents the regulatory basis for what it implements, in `docs/regulatory/` — which rules exist, which are placeholders, and what unblocks each one.
</Aside>

## Which sectors are covered
Expand Down
12 changes: 8 additions & 4 deletions site/dpp-docs/src/pages/api.astro
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import logoDark from '../assets/logo-dark.svg';

// Same alpha banner Starlight renders on every docs page (content.config.ts
// schema default) and the same shared CSS (banner.css) — this page skips the
// Starlight layout entirely so neither comes for free here.
// Starlight layout entirely so neither comes for free here. The text is
// imported from site-meta so the two banners cannot drift apart.
import '../styles/banner.css';
import { ALPHA_BANNER_TEXT } from '../site-meta';

// Full-page OpenAPI reference, mounted client-side from the **bundled**
// @scalar/api-reference — no CDN, no third-party runtime dependency, so the
Expand Down Expand Up @@ -79,9 +81,11 @@ import '../styles/banner.css';
</a>
<div class="odal-header-right"></div>
</header>
<!-- Scalar renders the alpha banner through its supported plugin-view
slot, which keeps it inside the docs content area without relying on
brittle DOM mutation. -->
<!-- Rendered here rather than through a Scalar plugin slot: this is static
markup that no upgrade to the bundled reference can silently drop. An
earlier plugin-based attempt was disabled and left this page as the one
docs page carrying no alpha notice at all. -->
<div class="odal-banner">{ALPHA_BANNER_TEXT}</div>
<div id="scalar-api-reference"></div>
<script>
import '../scripts/mount-api-reference';
Expand Down
26 changes: 8 additions & 18 deletions site/dpp-docs/src/scripts/mount-api-reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,8 @@
// like any other module script — see api.astro for why the page needs a
// script at all (full-page Scalar reference, mounted outside Starlight).
import { createApiReference } from '@scalar/api-reference';
// import { h } from 'vue';
// import { ALPHA_BANNER_TEXT } from '../site-meta';

// const AlphaBannerView = (props: { text: string }) => h('div', { class: 'odal-banner' }, props.text);

// const alphaBannerPlugin = () => ({
// name: 'odal-alpha-banner',
// extensions: [],
// views: {
// 'content.start': [
// {
// component: AlphaBannerView,
// props: {
// text: ALPHA_BANNER_TEXT,
// },
// },
// ],
// },
// }) as any;

createApiReference('#scalar-api-reference', {
url: '/openapi.yaml',
Expand All @@ -34,8 +17,15 @@ createApiReference('#scalar-api-reference', {
// The page has no theme toggle of its own: Starlight's setting (written by
// the docs shell's ThemeSelect) is the single source of truth, applied
// before first paint by the inline script in api.astro and kept live below.
// Scalar's request client defaults to relaying through proxy.scalar.com. A
// reader trying an endpoint against their own node would send the request —
// and any API key they typed in — through a third party. No proxy: requests
// go direct or not at all.
// Empty string, not undefined: the bundle resolves this with a `?? ""`
// fallback, so an undefined value falls through to the library default
// rather than overriding it.
proxyUrl: '',
hideDarkModeToggle: true,
// plugins: [alphaBannerPlugin],
});

// Keep the resolved theme live after first paint, mirroring exactly what
Expand Down
2 changes: 1 addition & 1 deletion site/dpp-landing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ site/dpp-landing/
│ └── global.css # Tailwind 4 layers + @odal/brand-tokens (CSS-first, no tailwind.config)
```

Brand assets (mark SVGs, OG image, apple-touch-icon) are **not** stored here — they live in the workspace-root `../../public/` and are copied into the build by `viteStaticCopy` (see `astro.config.mjs`), so both sites stay in sync from one source.
Brand assets (mark SVGs, OG image) live in this site’s own `public/` and `src/assets/`. Design tokens — the one thing that genuinely must not drift between the sites — are shared through the `@odal/brand-tokens` package instead.

Pages prefixed with `_` are drafts: Astro does not build them into routes. They are intentionally excluded from launch and will ship in a future pass.

Expand Down
2 changes: 0 additions & 2 deletions site/dpp-landing/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
import { defineConfig } from "astro/config";
import tailwindcss from "@tailwindcss/vite";
import sitemap from "@astrojs/sitemap";
import { viteStaticCopy } from 'vite-plugin-static-copy';

export default defineConfig({
site: "https://odal-node.io",
integrations: [sitemap()],
vite: {
plugins: [
tailwindcss(),
viteStaticCopy({ targets: [{ src: '../../public/**/*', dest: '' }] }),
],
},
// Static output — deployed to Cloudflare Pages.
Expand Down
1 change: 0 additions & 1 deletion site/dpp-landing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
},
"devDependencies": {
"@astrojs/check": "^0.9",
"@types/react": "^19.2.16",
"typescript": "^5",
"vite-plugin-static-copy": "^4.1.0"
}
Expand Down
6 changes: 3 additions & 3 deletions site/dpp-landing/src/components/GetStarted.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
// (node internal port 8000, mapped to host 8001 by default).
const commands = [
"git clone https://github.com/odal-node/dpp-engine",
"cd dpp-engine/docker && docker compose up -d",
"curl localhost:8001/health",
"cargo build -p dpp-cli --release",
"./target/release/odal up",
];
---

Expand All @@ -16,7 +16,7 @@ const commands = [
<p class="mb-3 text-xs font-semibold uppercase tracking-widest text-primary-300">
Get started
</p>
<h2 class="mb-6 text-3xl font-bold text-white">Three commands to a running node.</h2>
<h2 class="mb-6 text-3xl font-bold text-white">Three commands to a running node — the first build takes a few minutes.</h2>
<div class="max-w-2xl rounded-md border border-primary-800 bg-primary-800/60 p-5 font-mono text-sm leading-7 text-primary-100">
{commands.map((c) => (
<p class="m-0 whitespace-pre-wrap break-all">
Expand Down
8 changes: 4 additions & 4 deletions site/dpp-landing/src/data/deadlines.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"who": "Large companies",
"summary": "Destruction of unsold textiles and footwear is banned for large companies, and destruction practices must be disclosed.",
"citation": "ESPR (EU) 2024/1781, Art. 25",
"_verify": "Confirmed: Art. 25; large companies from 19 Jul 2026; medium-sized from 19 Jul 2030; micro/small exempt. Destruction exceptions in Delegated Reg. C(2026) 659."
"_verify": "Confirmed: Art. 25; large companies from 19 Jul 2026; medium-sized from 19 Jul 2030; micro/small exempt. Destruction exceptions in Delegated Regulation (EU) 2026/296."
},
{
"date": "2027-02-18",
Expand All @@ -17,16 +17,16 @@
"who": "EV, industrial (>2 kWh), LMT",
"summary": "Every battery in scope placed on the EU market needs a digital battery passport, registered in the EU central registry.",
"citation": "Regulation (EU) 2023/1542, Art. 77",
"_verify": "Solid per internal docs; re-confirm registry-registration modalities when the spec lands."
"_verify": "Art. 77(1) verified verbatim against the OJ text: from 18 Feb 2027, each LMT battery, each industrial battery above 2 kWh and each EV battery. Registration modalities depend on the Art. 13(5) implementing act."
},
{
"date": "2030-12-31",
"date": "2026-12-31",
"dateLabel": "Next, from 2026",
"title": "Priority sectors next",
"who": "Textiles, iron & steel, furniture, tyres",
"summary": "The ESPR 2025–2030 working plan sets the order: textiles and iron & steel lead the first delegated acts, each fixing its own DPP application date when adopted. Electronics is not a priority sector in this plan.",
"citation": "ESPR 2025–2030 Working Plan, COM(2025) 187",
"_verify": "Working plan confirmed (adopted 16 Apr 2025; six priority groups: textiles, furniture, mattresses, tyres, iron & steel, aluminium). Update per-sector dates as each delegated act is adopted."
"_verify": "Secondary-sourced only — the working plan PDF has not been read here. Adoption 16 Apr 2025 and six priority groups (textiles, furniture, mattresses, tyres, iron & steel, aluminium) come from secondary reporting. Read COM(2025) 187 before treating any of it as verified, and update per-sector dates as each delegated act is adopted."
}
]
}
6 changes: 3 additions & 3 deletions site/dpp-landing/src/data/roadmap.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
{ "label": "End-to-end node", "detail": "Create, sign, publish, and resolve a passport end to end" },
{ "label": "Full lifecycle provenance", "detail": "Suspend, archive, typed end-of-life, and dual-signed transfer of responsibility — on a tamper-evident, hash-chained audit trail" },
{ "label": "Evidence dossiers + offline verification", "detail": "Export a signed dossier and verify it with zero network — no trust in Odal required" },
{ "label": "Registry-ready outbox", "detail": "Registration intent survives crashes and drains with backoff; the live connector activates when the EU publishes its API" },
{ "label": "Registry-ready outbox", "detail": "Registration intent survives crashes and drains with backoff; the live connector is not yet activated" },
{ "label": "Signed compliance-ruleset channel", "detail": "Rulesets arrive as Ed25519-signed bundles, verified fail-closed and hot-swapped; a production node refuses placeholder trust adapters" },
{ "label": "Bulk import", "detail": "CSV and Excel with dry-run validation and per-row errors" }
]
Expand All @@ -25,7 +25,7 @@
"description": "Under active work with a defined target.",
"items": [
{ "label": "Electronics sector", "detail": "Schema and plugin, prepared ahead of an electronics delegated act" },
{ "label": "EU Central Registry connector", "detail": "Ready for the registry API; activates when the specification publishes" },
{ "label": "EU Central Registry connector", "detail": "Interface modelled against the registry that went live in July 2026; activation still gated on upstream blockers" },
{ "label": "eIDAS qualified-seal path", "detail": "Qualified trust service provider selection in progress" },
{ "label": "Unsold-goods disclosure export", "detail": "Report artifact for the July 2026 textile obligation" },
{ "label": "Operator dashboard", "detail": "Passport management UI for managed and self-hosted nodes" }
Expand All @@ -39,7 +39,7 @@
{ "label": "Multi-operator hosting", "detail": "Isolated per-operator deployments at fleet scale" },
{ "label": "Edge-cached public resolver", "detail": "CDN-cached passport pages for global scan latency" },
{ "label": "Further sectors", "detail": "Construction, tyres, furniture, detergents — as delegated acts finalise" },
{ "label": "Conformance services", "detail": "Verification badge against EN 18222/18223 once the standards are final" },
{ "label": "Conformance services", "detail": "Verification badge against the CEN/CENELEC DPP standards, once those texts have been purchased and read" },
{ "label": "EBSI did:ebsi", "detail": "EU-operated DID method as an alternative issuer-identity path, if registry requirements call for it" }
]
}
Expand Down
4 changes: 2 additions & 2 deletions site/dpp-landing/src/pages/_about.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const description =
<Base title={title} description={description}>
<Section eyebrow="About" title="A small team, a public standard, and a long view.">
<p>
Odal Node is built in Skopje, North Macedonia, by a small team focused on
Odal Node is built in Skopje, North Macedonia. It is early-stage and small, and
one specific job: providing the open-source infrastructure that lets
manufacturers comply with the EU Digital Product Passport requirements
under the Ecodesign for Sustainable Products Regulation. The project is
Expand All @@ -24,7 +24,7 @@ const description =
<p>
The credibility of an open-source standard implementation comes from the
ecosystem that recognises it. The project implements
<strong>GS1 Digital Link 1.2</strong> for resolution, is applying for
<strong>GS1 Digital Link</strong> for resolution, has applied for
observer participation in <strong>CIRPASS-2</strong> — the EU project
building out the Digital Product Passport ecosystem — and tracks the
<strong>CEN/CENELEC JTC 24</strong> schema work, updating the relevant
Expand Down
Loading
Loading