Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
188 commits
Select commit Hold shift + click to select a range
7eb2767
chore(deps-dev): bump vite-plugin-static-copy from 4.1.0 to 4.1.1
dependabot[bot] Jul 17, 2026
543e1c3
chore(deps): bump @tailwindcss/vite from 4.3.0 to 4.3.3
dependabot[bot] Jul 17, 2026
abf3d3a
chore(deps): bump tailwindcss from 4.3.0 to 4.3.3
dependabot[bot] Jul 17, 2026
9258cb2
docs: correct the access-control model against the primary text
LKSNDRTMLKV Jul 28, 2026
44bd73f
docs(landing): disclose scan telemetry on the trust page as an aggreg…
LKSNDRTMLKV Aug 20, 2026
afcfee6
chore: ignore local-only asset and tooling directories so they cannot…
LKSNDRTMLKV Aug 20, 2026
6f099aa
chore(docs): resync the vendored OpenAPI spec from the engine, droppi…
LKSNDRTMLKV Aug 20, 2026
5a1cf5e
docs: withdraw the electronics page and its claim of an ESPR delegate…
LKSNDRTMLKV Aug 20, 2026
d164a96
chore: add link and leakage gates, restate private-repo pointers inli…
LKSNDRTMLKV Aug 20, 2026
4358662
Merge branch 'chore/resync-openapi' into chore/ci-gates
LKSNDRTMLKV Aug 20, 2026
d406c6d
chore: untrack local-only asset and tooling directories that were sta…
LKSNDRTMLKV Aug 20, 2026
840e3f6
Merge branch 'chore/ignore-local-assets' into chore/ci-gates
LKSNDRTMLKV Aug 20, 2026
68ed727
ci: run the link, leakage and API-spec gates on every change, and sco…
LKSNDRTMLKV Aug 20, 2026
bd98b84
Merge branch 'docs/retract-electronics-act' into docs/claim-families
LKSNDRTMLKV Aug 20, 2026
24d626f
Merge branch 'docs/access-control-primary-text' into docs/claim-families
LKSNDRTMLKV Aug 20, 2026
ff5e7bb
docs: correct the regulatory citations, security-property claims, reg…
LKSNDRTMLKV Aug 20, 2026
3a8a71c
docs: publish licensing without a restated dependency-licence table, …
LKSNDRTMLKV Aug 20, 2026
ec48fe3
chore(docs): resync the vendored API spec to pick up the corrected cr…
LKSNDRTMLKV Aug 20, 2026
8b430ec
chore(deps): upgrade both sites to Astro 7, migrating the Starlight s…
LKSNDRTMLKV Aug 20, 2026
8a734c0
ci: fail the build on a critical dependency advisory
LKSNDRTMLKV Aug 20, 2026
9f3c7e5
ci: pin the vendored API spec to an explicit engine commit so the dri…
LKSNDRTMLKV Aug 20, 2026
bbea8d8
Revert "chore(docs): resync the vendored API spec to pick up the corr…
LKSNDRTMLKV Aug 20, 2026
73bbd1c
Merge branch 'docs/retract-electronics-act' into staging
LKSNDRTMLKV Aug 20, 2026
97890af
Merge branch 'docs/access-control-primary-text' into staging
LKSNDRTMLKV Aug 20, 2026
dd1f1db
Merge branch 'docs/claim-families' into staging
LKSNDRTMLKV Aug 20, 2026
8e0f5f6
Merge branch 'docs/remaining-claims' into staging
LKSNDRTMLKV Aug 20, 2026
9a4c526
Merge branch 'chore/astro-7' into staging
LKSNDRTMLKV Aug 20, 2026
d1d3254
docs: move licensing out of the engine section into orientation, and …
LKSNDRTMLKV Aug 20, 2026
054865f
docs: disclose scan telemetry on the data-boundary page, fix the poin…
LKSNDRTMLKV Aug 20, 2026
6864bed
docs: correct the README's claim that the type-checker checks links, …
LKSNDRTMLKV Aug 20, 2026
27eae1d
docs: point the README at the pages that exist rather than at a remov…
LKSNDRTMLKV Aug 20, 2026
7859a03
docs: describe deploys as promotions into main rather than direct pushes
LKSNDRTMLKV Aug 20, 2026
5a6a51c
ci: pin every action to a commit SHA, and add the API-spec sync workflow
LKSNDRTMLKV Aug 21, 2026
e5311fb
chore(docs): resync the vendored OpenAPI spec
LKSNDRTMLKV Aug 28, 2026
056eb05
chore(docs): sync the vendored OpenAPI spec to engine v0.13.0
LKSNDRTMLKV Sep 13, 2026
0c5bbd0
docs(engine): tell retirement and archiving apart
LKSNDRTMLKV Sep 17, 2026
84cbcf2
chore(ci): pin the actions and scope the token
LKSNDRTMLKV Sep 19, 2026
f3a7567
feat(seo): make the sites legible to search engines and agents
LKSNDRTMLKV Sep 19, 2026
17b7d30
fix(seo): point llms.txt only at pages that exist, and gate it
LKSNDRTMLKV Sep 19, 2026
c83fbfe
feat(landing): unblock the roadmap and add an operable access page
LKSNDRTMLKV Sep 19, 2026
2ef70df
feat(landing): add the lifecycle, proposed home and product-group pages
LKSNDRTMLKV Sep 19, 2026
ef85ab0
fix(landing): restore spaces Astro trims where prose meets a link
LKSNDRTMLKV Sep 19, 2026
928981e
chore(ci): run the spacing and product-group drift gates
LKSNDRTMLKV Sep 19, 2026
dbc37ce
feat(landing): rebuild the roadmap against what the repositories actu…
LKSNDRTMLKV Sep 19, 2026
8052c72
feat(landing): trim the nav to one destination and mark off-site links
LKSNDRTMLKV Sep 19, 2026
8f6c18b
feat(landing): one button, one card and one link style across the site
LKSNDRTMLKV Sep 19, 2026
9d9d0ee
fix(web): publish security.txt and fix the docs link preview
LKSNDRTMLKV Sep 22, 2026
605e39d
fix(web): point security.txt at the org policy
LKSNDRTMLKV Sep 22, 2026
9743970
feat(landing): add Explore and Product groups menus, rename who-sees-…
LKSNDRTMLKV Sep 25, 2026
311bbeb
feat(landing): rewrite lifecycle and product-group pages in plain lan…
LKSNDRTMLKV Sep 25, 2026
1cb161f
feat(landing): rewrite the visibility page so its headline matches Ar…
LKSNDRTMLKV Sep 25, 2026
f2ce09d
fix(landing): take the em dashes out of every page's copy except the …
LKSNDRTMLKV Sep 25, 2026
eb63cac
feat(landing): rebuild the roadmap around capabilities and their vari…
LKSNDRTMLKV Sep 25, 2026
7e757a9
fix(landing): correct the home page's deadline, standards, licence, r…
LKSNDRTMLKV Sep 25, 2026
f2ecfb0
chore(landing): remove dead markup and unused props, clear every chec…
LKSNDRTMLKV Sep 25, 2026
b958672
fix(deps): move both sites to Astro 7.3.5 for the critical AVIF RCE a…
LKSNDRTMLKV Sep 25, 2026
cc32c57
feat(landing): vendor dpp-core's instrument registry and generate the…
LKSNDRTMLKV Sep 25, 2026
65d2585
feat(landing): add a build-on-odal page and reach both new pages from…
LKSNDRTMLKV Sep 25, 2026
d28460a
feat(landing): name two shipped capabilities the site never mentioned…
LKSNDRTMLKV Sep 25, 2026
da2f795
fix(landing): stop the prose measure from capping card grids marked n…
LKSNDRTMLKV Sep 25, 2026
0641ac4
feat(landing): read the home page's deadline cards from the instrumen…
LKSNDRTMLKV Sep 25, 2026
09e45a8
feat(landing): add /verify, a browser twin of the node's dossier veri…
LKSNDRTMLKV Sep 25, 2026
db8b94a
fix(landing): give prose its spacing and list markers back, restore t…
LKSNDRTMLKV Sep 25, 2026
e40ddaa
fix(landing): link the home page's verify promise to /verify, drop th…
LKSNDRTMLKV Sep 25, 2026
5ec3292
fix(landing): replace the lifecycle's unbuilt evidence station with c…
LKSNDRTMLKV Sep 25, 2026
2c8dcab
fix(landing): compare authorities with the legitimate-interest class,…
LKSNDRTMLKV Sep 25, 2026
a6fb06d
fix(landing): say an act was confirmed in force rather than checked a…
LKSNDRTMLKV Sep 26, 2026
f3fab5d
fix(docs): date the construction passport from Art. 22(7) instead of …
LKSNDRTMLKV Sep 26, 2026
ef5974e
style(landing): space the regulations basis legend from its lead-in
LKSNDRTMLKV Sep 26, 2026
aba34b9
fix(docs): move licensing to Getting started, describe the node as th…
LKSNDRTMLKV Sep 26, 2026
7c2c402
fix(landing): drop rule updates as a way in because a signed bundle c…
LKSNDRTMLKV Sep 26, 2026
4a2ea98
fix(docs): list licensing under Getting started and redirect its old …
LKSNDRTMLKV Sep 26, 2026
b88b961
feat(landing): add a planned status for the TypeScript packages and t…
LKSNDRTMLKV Sep 26, 2026
330053a
fix(landing): frame headlines positively, name the roadmap section by…
LKSNDRTMLKV Sep 26, 2026
24fa7e2
feat(landing): add the shipped capabilities the roadmap missed, resto…
LKSNDRTMLKV Sep 26, 2026
16920b0
fix(landing): say the verify page may contact only this site rather t…
LKSNDRTMLKV Sep 26, 2026
10cde1f
feat(landing): split the nav into How it works, Resources and Product…
LKSNDRTMLKV Sep 26, 2026
53514e3
fix(landing): describe construction by what its passport carries, say…
LKSNDRTMLKV Sep 26, 2026
8442405
feat(landing): make the waitlist say who it is for and what to send, …
LKSNDRTMLKV Sep 26, 2026
24e1d9d
fix(landing): say the node keeps a per-row import record and shows on…
LKSNDRTMLKV Sep 26, 2026
649889f
fix(landing): drop the privacy page's zero-collection claim, say wher…
LKSNDRTMLKV Sep 26, 2026
144d808
fix(landing): say groups without adopted access rules still hold a fe…
LKSNDRTMLKV Sep 26, 2026
ce09d48
feat(landing): list the sixteen other acts the software applies on /r…
LKSNDRTMLKV Sep 26, 2026
462102b
feat(docs): add an acts-and-standards reference built from the code, …
LKSNDRTMLKV Sep 26, 2026
d6ef585
fix(landing): add Verify to the home timeline, stop saying the node n…
LKSNDRTMLKV Sep 26, 2026
6c0b58e
fix(landing): describe pages by what they match rather than how they …
LKSNDRTMLKV Sep 26, 2026
50e258d
fix(docs): bring every page in line with engine v0.14.0: passports ar…
LKSNDRTMLKV Sep 26, 2026
97e77f4
feat(docs): add a Using the node section covering import, lifecycle, …
LKSNDRTMLKV Sep 26, 2026
c51a05c
feat(docs): sync the API reference to engine v0.14.0, drop the alpha …
LKSNDRTMLKV Sep 26, 2026
0d76c4b
feat(docs): add configuration, production deployment, backup and upgr…
LKSNDRTMLKV Sep 26, 2026
aca444d
feat(landing): add an example battery passport sorted by reader, a gl…
LKSNDRTMLKV Sep 26, 2026
d87c0e1
Add webhook events, error reference and troubleshooting guides to the…
LKSNDRTMLKV Sep 26, 2026
719d24b
Add toy, detergent, construction, vehicle and phone regulatory pages …
LKSNDRTMLKV Sep 26, 2026
f01380a
State the EU registry's start as July 2026, the date the texts suppor…
LKSNDRTMLKV Sep 26, 2026
1f4dad3
Add a landing timeline of passport dates, legal milestones and the Co…
LKSNDRTMLKV Sep 26, 2026
8c5f389
Add a passport check to the landing that answers from the same record…
LKSNDRTMLKV Sep 26, 2026
6fb0709
Stop claiming access credentials are non-bearer, since the node check…
LKSNDRTMLKV Sep 26, 2026
2f429d8
Split the landing nav into How it works, Compliance, Developers and R…
LKSNDRTMLKV Sep 26, 2026
2d713ff
Add landing pages for repairers and recyclers and for authorities, li…
LKSNDRTMLKV Sep 26, 2026
4f9e2d3
Give each landing page, product group and act its own share image, dr…
LKSNDRTMLKV Sep 26, 2026
0b1b7e5
Fix every automated accessibility finding on the landing (one h1 per …
LKSNDRTMLKV Sep 26, 2026
ea8b143
Point cross-site links at the matching preview or dev site instead of…
LKSNDRTMLKV Sep 26, 2026
52cf31b
Build the nav and a full-width footer from one site map that fails th…
LKSNDRTMLKV Sep 26, 2026
85b6acd
Add a site map page and llms.txt indexes for agents on both sites, an…
LKSNDRTMLKV Sep 26, 2026
a410ed4
Merge #19 for its scan-count disclosure on the data-boundary page; it…
LKSNDRTMLKV Sep 26, 2026
9f6850e
Merge #20 for the README's staging workflow, commit-pinned actions an…
LKSNDRTMLKV Sep 26, 2026
52c02bb
Merge #22 for cancelling superseded CI runs; its pins were already re…
LKSNDRTMLKV Sep 26, 2026
129ed10
Merge #24 for the docs site's share image and security.txt, with both…
LKSNDRTMLKV Sep 26, 2026
5ec6bc1
Merge #23 for machine-readable content signals, AI-training crawler o…
LKSNDRTMLKV Sep 26, 2026
db79984
Merge #4, bumping vite-plugin-static-copy to 4.1.1 with the lockfile …
LKSNDRTMLKV Sep 26, 2026
0734ec1
Merge #7, bumping tailwindcss to 4.3.3 together with @tailwindcss/vit…
LKSNDRTMLKV Sep 26, 2026
645340f
Merge #6; its @tailwindcss/vite 4.3.3 bump already landed with #7.
LKSNDRTMLKV Sep 26, 2026
406115a
Explain an older-format or unknown-member proof file on /verify inste…
LKSNDRTMLKV Sep 26, 2026
60ca24a
Say precisely what /verify guarantees: the page does not upload the f…
LKSNDRTMLKV Sep 26, 2026
9353526
Add a tested script that installs a Cloudflare edge rate limit on /ve…
LKSNDRTMLKV Sep 26, 2026
a8424b8
Reorder the Resources menu and drop the footer's waitlist link, as ed…
LKSNDRTMLKV Sep 26, 2026
08213c8
Rephrase the accessibility statement around the standard, the automat…
LKSNDRTMLKV Sep 26, 2026
0e5d9a0
Reorder the How it works menu, as edited by the founder.
LKSNDRTMLKV Sep 26, 2026
3fca6ea
Serve the passport check as the picker with answers hidden, so it no …
LKSNDRTMLKV Sep 26, 2026
9d65470
Remove the separate Docs link from the nav, since Developers carries …
LKSNDRTMLKV Sep 26, 2026
c064bed
Rename the example passport's invented company to Musterzelle GmbH, s…
LKSNDRTMLKV Sep 26, 2026
8ea32db
fix(privacy): send privacy requests to contact@, say what happens to …
LKSNDRTMLKV Sep 28, 2026
121b1b8
fix(verify): say a pass proves the file and not who holds its keys, r…
LKSNDRTMLKV Sep 28, 2026
03a7e95
fix(landing): open the passport check on the empty picker when a shar…
LKSNDRTMLKV Sep 28, 2026
0e7c856
fix(landing): show the brand mark as one cached image instead of inli…
LKSNDRTMLKV Sep 28, 2026
ac9ac76
fix(docs): fix what the keyboard and axe pass found in the docs: focu…
LKSNDRTMLKV Sep 28, 2026
258ba35
chore(docs): tighten the alpha banner, drop an empty header slot and …
LKSNDRTMLKV Sep 28, 2026
f7ba000
feat(web): serve HSTS and a Content-Security-Policy from both sites, …
LKSNDRTMLKV Sep 28, 2026
aa10f90
refactor(tokens): move the Tailwind @theme block into its own theme.c…
LKSNDRTMLKV Sep 28, 2026
f18aebe
chore(dev): fix the landing dev server on 4321 and the docs on 4325 s…
LKSNDRTMLKV Sep 28, 2026
4e45c40
chore(deps): drop vite-plugin-static-copy, which neither site uses an…
LKSNDRTMLKV Sep 28, 2026
e22ef94
ci: fail the audit on high advisories, make the cache purge manual si…
LKSNDRTMLKV Sep 28, 2026
92135ce
fix(landing): stop naming a private-repo document in a home-page comm…
LKSNDRTMLKV Sep 28, 2026
222c7fd
docs(readme): record the dev ports, the full gate list, the keyboard …
LKSNDRTMLKV Sep 28, 2026
faa819e
fix(landing): say self-hosting starts from the public source with a s…
LKSNDRTMLKV Sep 28, 2026
204aed4
feat(docs): add a harmonised-standards page giving each of the six ci…
LKSNDRTMLKV Sep 28, 2026
0d8b268
feat(landing): link the European DPP standards entry to the docs page…
LKSNDRTMLKV Sep 28, 2026
6c4cc1b
docs: drop check dates and our own repo versions and branches from bo…
LKSNDRTMLKV Sep 28, 2026
0eaa6ef
docs: rewrite the docs in plainer language without em dashes or stock…
LKSNDRTMLKV Sep 28, 2026
bbe65ba
fix(landing): rewrite the landing copy in plainer language, drop the …
LKSNDRTMLKV Sep 28, 2026
382e4be
fix(landing): regenerate the /verify example dossiers with the histor…
LKSNDRTMLKV Sep 28, 2026
edd8f62
docs: say what odal init, odal update and ODAL_VERSION do once the no…
LKSNDRTMLKV Sep 29, 2026
fcd19de
fix(docs): say the node and resolver images are not public yet so a n…
LKSNDRTMLKV Sep 29, 2026
7bcad7c
fix(web): say the core library now has the extra identifier schemes a…
LKSNDRTMLKV Sep 29, 2026
527cc85
chore(landing): vendor dpp-core v0.21.0, which leaves the constructio…
LKSNDRTMLKV Sep 29, 2026
589eaeb
fix(web): give the node and the core library their own structured-dat…
LKSNDRTMLKV Sep 29, 2026
c8e6a61
fix(landing): say the site has been checked by automated tools but no…
LKSNDRTMLKV Sep 29, 2026
0c06f74
fix(landing): restore the accessibility statement's hand-testing sent…
LKSNDRTMLKV Sep 29, 2026
4c7a7a3
fix(landing): name the person responsible in a privacy policy that no…
LKSNDRTMLKV Sep 29, 2026
9b701c0
feat(web): add a legal notice and put a not-legal-advice line with le…
LKSNDRTMLKV Sep 29, 2026
d63df8c
fix(landing): stop calling the release images inspectable while they …
LKSNDRTMLKV Sep 29, 2026
6a9491f
chore(landing): trim the opening sentence of the unpublished about draft
LKSNDRTMLKV Sep 29, 2026
7eb0a52
fix(landing): re-copy the /verify example dossiers from dpp-engine fa…
LKSNDRTMLKV Sep 29, 2026
1887aa5
feat(web): give every sitemap entry a lastmod from the last commit th…
LKSNDRTMLKV Sep 29, 2026
89026f4
ci: check that both sitemaps list every indexable page with its canon…
LKSNDRTMLKV Sep 29, 2026
af2126c
fix(landing): keep anchor targets clear of the sticky nav with one sc…
LKSNDRTMLKV Sep 29, 2026
7aae05e
feat(landing): fill the verify page's paste box with the chosen examp…
LKSNDRTMLKV Sep 29, 2026
0e888dc
fix(landing): stop calling the example battery passport complete, mar…
LKSNDRTMLKV Sep 29, 2026
46d7827
test(landing): hold the browser verifier to UTF-16 key order on the b…
LKSNDRTMLKV Sep 29, 2026
04633e7
fix(landing): list the /verify examples' readable payload keys in the…
LKSNDRTMLKV Sep 29, 2026
b4835ad
chore(deps): bump the build-time undici to 8.11.2 for three high advi…
LKSNDRTMLKV Sep 29, 2026
d41fb8c
test(landing): say the /verify examples are the engine's regenerated …
LKSNDRTMLKV Sep 29, 2026
adddb04
fix(landing): show real battery passports in the /verify examples, fr…
LKSNDRTMLKV Sep 29, 2026
c23a452
fix(web): stop saying the node discards import files, and say instead…
LKSNDRTMLKV Sep 30, 2026
813a1bc
feat(web): list the acts the software is preparing for, and correct w…
LKSNDRTMLKV Sep 30, 2026
24654be
test(landing): point the verify corpus at dpp-engine main after #431
LKSNDRTMLKV Sep 30, 2026
04f7c80
chore(docs): merge staging, and finish the retire rename across the docs
LKSNDRTMLKV Sep 30, 2026
9b90c97
chore(web): sync the engine API spec, demo dossiers and example passp…
LKSNDRTMLKV Sep 30, 2026
14b8a2b
refactor(landing): move the passport check's answer card and script i…
LKSNDRTMLKV Sep 30, 2026
4ea7986
feat(landing): build every email link to us in one place, prefilled w…
LKSNDRTMLKV Sep 30, 2026
c852379
feat(landing): give every product group that needs a passport a print…
LKSNDRTMLKV Sep 30, 2026
9384fed
feat(landing): put the passport check in the home page's hero, with a…
LKSNDRTMLKV Sep 30, 2026
14184c2
revert(landing): put the brand mark back in the hero in place of the …
LKSNDRTMLKV Sep 30, 2026
26bac43
feat(landing): add a community page under Developers that points to t…
LKSNDRTMLKV Sep 30, 2026
d657eb3
fix(landing): open the community page with an invitation to help shap…
LKSNDRTMLKV Sep 30, 2026
7ab89b2
refactor(landing): move the example passport's sorting into a shared …
LKSNDRTMLKV Sep 30, 2026
36f8da3
feat(landing): link each product group's checklist from its group pag…
LKSNDRTMLKV Sep 30, 2026
cbf1f84
feat(landing): rebuild the home page around a passport read three way…
LKSNDRTMLKV Sep 30, 2026
770b068
fix(landing): keep the passport preview one height by reserving the w…
LKSNDRTMLKV Sep 30, 2026
777ebbf
feat(landing): add eighteen capabilities to the roadmap from a scan o…
LKSNDRTMLKV Sep 30, 2026
c55b65b
fix(landing): darken the passport check's answer label so it meets co…
LKSNDRTMLKV Sep 30, 2026
ca0af94
feat(landing): add nineteen glossary terms the site uses without expl…
LKSNDRTMLKV Sep 30, 2026
01ad808
fix(landing): say the node records the unsold-goods disclosure, since…
LKSNDRTMLKV Sep 30, 2026
227a7ae
Merge #30 for the home page redesign, the community page, the product…
LKSNDRTMLKV Sep 30, 2026
2f445ca
fix(web): correct the seal, handover, identifier and registry wording…
LKSNDRTMLKV Oct 1, 2026
ae70907
fix(web): send Cache-Control no-transform on HTML so Cloudflare stops…
LKSNDRTMLKV Oct 1, 2026
1bced9b
chore: merge main back into staging after the release squash
LKSNDRTMLKV Oct 1, 2026
3863040
docs(web): rewrite the README around how the sites are built, checked…
LKSNDRTMLKV Oct 1, 2026
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
6 changes: 3 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
## Checklist

CI runs these on the pull request; run them locally first, since a push to
`staging` alone runs no CI. Links, spacing and llms.txt read the build, so build first.
`staging` alone runs no CI. Links, spacing, llms.txt and sitemaps read the build, so build first.

- [ ] `pnpm -r build` and `pnpm -r check`
- [ ] `pnpm run check:links`, `check:spacing`, `check:leakage` and `check:llms`
- [ ] `pnpm run test:scripts` and `pnpm --filter dpp-landing run test:verify`
- [ ] `pnpm run check:links`, `check:spacing`, `check:leakage`, `check:llms` and `check:sitemaps`
- [ ] `pnpm run test:scripts`, `pnpm --filter dpp-landing run test:verify` and `pnpm audit --audit-level high`
- [ ] If vendored data changed: `pnpm run check:openapi` and `pnpm --filter dpp-landing run check:core` (need the sibling repositories; see the README)
- [ ] No secrets, credentials, or `.env` files in the diff
184 changes: 63 additions & 121 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,161 +1,103 @@
# Odal Node Web

**Public-facing web properties: landing page and documentation**

[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
[![CI](https://github.com/odal-node/dpp-web/actions/workflows/ci.yml/badge.svg)](https://github.com/odal-node/dpp-web/actions/workflows/ci.yml)
[![Node 22.13+](https://img.shields.io/badge/Node-22.13%2B-brightgreen.svg)](https://nodejs.org/)
[![Status: Active Development](https://img.shields.io/badge/Status-Active%20Development-green.svg)](https://odal-node.io/roadmap)

The two public-facing web properties for Odal Node, organised as a pnpm workspace and deployed as two independent Cloudflare Pages projects.
The two Odal Node websites, as one pnpm workspace deployed as two Cloudflare Pages projects.

| Project | Domain | Stack | Deploy target |
| Folder | Site | Stack | Pages project |
|---|---|---|---|
| `site/dpp-landing/` | `odal-node.io` | Astro + Tailwind 4 | Cloudflare Pages (`odal-node-landing`) |
| `site/dpp-docs/` | `docs.odal-node.io` | Astro + Starlight | Cloudflare Pages (`odal-node-docs`) |
| `packages/brand-tokens/` | — | Internal workspace package | Consumed by both sites |

Each Astro project has its own `package.json` and its own Cloudflare Pages project. They share the `@odal/brand-tokens` package — colour palette, typography, spacing — so brand polish stays in sync without effort.

---

## Independent Deploys, Shared Brand
| `site/dpp-landing/` | `odal-node.io`, `www.odal-node.io` | Astro + Tailwind 4 | `odal-node-landing` |
| `site/dpp-docs/` | `docs.odal-node.io` | Astro + Starlight, Scalar on `/api` | `odal-node-docs` |
| `packages/brand-tokens/` | | Colours, type, spacing for both sites | |

The architectural commitment of this repository is *independence at the deployment layer, coherence at the brand layer*. A promotion into `main` that only touches `site/dpp-docs/src/content/docs/quick-start.mdx` produces a single docs deploy and zero landing deploys. One that touches `packages/brand-tokens/` produces two deploys, because a token change genuinely should re-render both surfaces. This is enforced via Cloudflare Pages [build watch paths](https://developers.cloudflare.com/pages/configuration/build-watch-paths/) rather than at the Git layer.
Each site has its own README for its layout and Pages build settings.

---
## Develop

## Repository Layout
Node 22.13+ and pnpm (version pinned in `package.json`, via corepack).

```
dpp-web/
├── package.json # workspace root, scripts proxy to projects
├── pnpm-workspace.yaml # declares site/* projects and packages/*
├── pnpm-lock.yaml # single lockfile for the whole workspace
├── README.md # this file
│
├── scripts/ # CI gates: link crawler, leakage scan
│
├── packages/
│ └── brand-tokens/ # @odal/brand-tokens — colour, type, spacing
│
├── site/dpp-landing/ # odal-node.io (Tailwind 4, CSS-first — no tailwind.config)
│ ├── astro.config.mjs
│ └── src/{layouts,components,pages,data,styles}
│
└── site/dpp-docs/ # docs.odal-node.io (Starlight)
├── astro.config.mjs
└── src/{assets,content/docs,styles}
```bash
pnpm install
pnpm dev:landing # http://localhost:4321
pnpm dev:docs # http://localhost:4325; run both and they link to each other
```

---
## Checks

## Quick Start
CI (`.github/workflows/ci.yml`) runs all of these on every pull request and every push to `main`. Pushes to `staging` run no CI, so run them locally first. `check:links`, `check:spacing`, `check:llms` and `check:sitemaps` read the build, so build first.

```bash
git clone https://github.com/odal-node/dpp-web.git
cd dpp-web

# Install everything for the whole workspace
pnpm install

# Run a dev server for either site
pnpm dev:landing # http://localhost:4321 → site/dpp-landing
pnpm dev:docs # http://localhost:4325 → site/dpp-docs
# Run both at once and links between them point at each other.

# Build for production (same command Cloudflare runs)
pnpm -r build

# Type-check templates and content-collection references
pnpm -r check

# The gates CI runs. Links and spacing read the build, so build first.
pnpm run check:links # crawl both dist trees for internal links that 404
pnpm run check:spacing # words glued together across a line break in Astro markup
pnpm run check:leakage # internal vocabulary / private-repo paths, incl. public/
pnpm run check:openapi # vendored API spec still matches its pinned engine commit
pnpm --filter dpp-landing run check:core # vendored core records match their pin
pnpm --filter dpp-landing run test:verify # the browser verifier agrees with the node's
pnpm run test:scripts # the rate-limit and external-link scripts
pnpm -r check # types and content collections, not links
pnpm run check:links # internal links in both builds
pnpm run check:spacing # words glued across a line break
pnpm run check:leakage # internal names and private paths
pnpm run check:llms # llms.txt matches the pages
pnpm run check:sitemaps # sitemaps and their lastmod dates
pnpm run test:scripts
pnpm --filter dpp-landing run check:core # vendored core data matches its pin (DPP_CORE_DIR)
pnpm --filter dpp-landing run test:verify # /verify agrees with the engine's verifier
pnpm run check:openapi # vendored API spec matches its pin (DPP_ENGINE_DIR)
pnpm audit --audit-level high

# Not a pull-request gate: run weekly by .github/workflows/external-links.yml.
pnpm run check:external # links to other sites (EUR-Lex, GitHub …); fails only on a 404 or 410
pnpm run check:external # outside links; weekly in CI, not a PR gate
```

`pnpm -r check` does **not** check links, and never did — a markdown link target is an opaque
string to `astro check`. That is why `check:links` exists separately and reads the built output
rather than the source: four `[Licensing](/engine/licensing)` links once passed `check` and
404'd in production.
## Vendored inputs

Prerequisites: Node.js 22.13+ (LTS 24 recommended — pnpm 11 requires `node:sqlite`, unavailable before 22.13) and pnpm (managed via [corepack](https://nodejs.org/api/corepack.html) — the exact version is pinned in `package.json` `packageManager`).
| What | Pin | Refresh |
|---|---|---|
| Product groups and EU acts from `dpp-core` | `site/dpp-landing/core-source.json` | `pnpm --filter dpp-landing run sync:core` |
| API spec from `dpp-engine` | `site/dpp-docs/openapi-source.json` | `pnpm run sync:openapi`, or the nightly workflow |

---
Never edit the vendored files by hand; bump the pin and sync.

## What Lives Elsewhere
## Releasing

This repository contains marketing copy and technical documentation, not source code for the Odal Node product itself.
`main` is what Cloudflare publishes. Its ruleset matches `dpp-core` and `dpp-engine`: pull request required, squash only, `build` must pass on an up-to-date branch, no force-push, no deletion, no bypass.

The [`dpp-core`](https://github.com/odal-node/dpp-core) repository (Apache-2.0) holds the regulatory-standard Rust library — domain types, port traits, cryptography, GS1 Digital Link, schema validation, the compliance calculators, the Wasm plugin ABI. The docs site documents `dpp-core`; it does not contain its source.
1. Land work on `staging`, through a pull request or a direct push once the checks pass.
2. Review the previews: `staging.odal-node-landing.pages.dev` and `staging.odal-node-docs.pages.dev`.
3. New or reworked pages get a hand screen-reader and keyboard pass, which `/accessibility` promises.
4. Open a pull request from `staging` to `main` and squash-merge it.
5. Merge `main` back into `staging` (no file changes), so the next promotion carries only new commits.
6. If pages were added or moved, resubmit both sitemaps in Search Console.

The [`dpp-engine`](https://github.com/odal-node/dpp-engine) repository (BSL-1.1, with a production self-host grant) holds the deployment layer — HTTP services, persistence, authentication, telemetry, the public resolver, the Wasm plugin sandbox. The docs site documents `dpp-engine`; it does not contain its source.
A squash merge sets the sitemap `lastmod` of every page it touches to the merge date. Dates come from git history (`scripts/git-lastmod.mjs`).

The relationship between the repositories — the open-core boundary, the dependency direction, the licensing rationale — is covered on the docs site under [Core Concepts](https://docs.odal-node.io/core-concepts) and [Licensing](https://docs.odal-node.io/getting-started/licensing), and in the parent project's strategy documents.
## Cloudflare

---

## Status

The original phased build (workspace foundations → landing MVP → docs IA → polish) is complete through its first three phases, and the **June 2026 redesign** re-skinned both sites onto the navy/ice brand, replaced retired messaging with *"Signed by you. Verified by anyone."*, and moved editable content into data files. `LICENSE` is settled (Apache-2.0).

An **August 2026 audit** of both sites read every published page against primary regulatory text and against the engine's source. It found a delegated act that does not exist described as adopted, roughly twenty misattributed citations, four security-property claims the code contradicted, and a registry described as unbuilt eight months after it went live. Those are corrected; the findings register lives outside this repository.

The hand pass the landing's accessibility page describes (a person, with a screen reader and a keyboard alone) was done by the founder before promotion. Pages added or reworked later need the same pass before they are published. What remains before public launch: a named data controller in the privacy policy — which is blocked on a registered entity existing, not on a copy edit.

The keyboard pass is done. On 2026-09-27 every page of both sites was walked with Tab alone at 1280px and 375px in headless Chromium: every control shows a focus ring, nothing traps focus, the first Tab on the landing reaches "Skip to content", and the menus, the passport check and /verify work from the keyboard. axe-core 4.13 (WCAG 2.0–2.2 A and AA, plus best practice) ran on every page of both sites at both widths and, on the docs, in both themes. The landing is clean. What it still reports is inside Scalar's API reference on `/api` (ARIA attributes on the wrong roles, a few icon buttons with no name, a second banner landmark on a phone, a scrolling list that cannot take focus) and Expressive Code's unnamed code-block regions on the docs, a best-practice rule rather than a WCAG one. Those are third-party markup this repository does not render.

The API reference does not relay requests through a third party. Checked at runtime on 2026-09-27: in headless Chromium, "Test Request → Send" on `/api` went straight to the spec's server (`http://localhost:8001/vault/api/v1/dpp`), and the session made no request to any `scalar.com` host. That rests on `proxyUrl: ''` in `site/dpp-docs/src/scripts/mount-api-reference.ts`; re-check it after upgrading `@scalar/api-reference`.

## Rate limit on /verify

/verify checks files in the browser, so there is no server of ours to limit. The limit is a
Cloudflare rate-limiting rule on the `odal-node.io` zone: paths starting with `/verify`, 20
requests per 10 seconds per IP address, then 429 for 10 seconds. That is the most the Free plan
allows, and well above one person's use (a visit is the page plus at most five example files).
It covers the custom domain only; `*.pages.dev` previews are not in the zone.

The zone is not managed as code elsewhere, so `scripts/cloudflare-rate-limit.mjs` is the rule's
source of truth. It replaces only its own rule and keeps any other:

```bash
# Dry run: prints the ruleset it would write. The token needs "Zone WAF: Edit".
CLOUDFLARE_API_TOKEN=… CLOUDFLARE_ZONE_ID=… pnpm run rate-limit:verify

# Write it
CLOUDFLARE_API_TOKEN=… CLOUDFLARE_ZONE_ID=… pnpm run rate-limit:verify -- --apply
```
- **Pages:** each project builds from the repository root (see the site READMEs). Production is `main`. Every branch gets a preview at `<branch>.<project>.pages.dev`, which Cloudflare marks `noindex`.
- **Headers:** each site's `public/_headers` sets HSTS, a same-origin CSP and caching.
- **`no-transform` on HTML:** the free plan injects a bot-detection script into every HTML page, and it cannot be switched off. The script sets a `cf_clearance` cookie, which the privacy page says the sites do not set. `Cache-Control: no-transform` on HTML stops that injection and Cloudflare's email obfuscation, at the cost of Cloudflare no longer compressing HTML. Other files stay compressed.
- **Editing cache rules:** Pages joins two values of one header with a comma. A rule that sets its own `Cache-Control` must first detach the inherited one with `! Cache-Control`, and no two cache rules may match the same file.
- **Zone:** the `/verify` rate-limit rule (20 requests per 10 s per IP) is kept as code in `scripts/cloudflare-rate-limit.mjs` (`pnpm run rate-limit:verify`, add `-- --apply` to write; the token needs "Zone WAF: Edit"). It does not cover `pages.dev` previews.
- **Cache purge:** run `.github/workflows/deploy.yml` by hand.

## How changes land
## Automation

`main` is what Cloudflare Pages publishes, so nothing lands on it directly.
| Workflow | When | What |
|---|---|---|
| `ci.yml` | Pull requests, pushes to `main` | The checks above |
| `sync-openapi.yml` | Nightly, 03:17 UTC | Opens a pull request into `staging` when the engine's spec changes |
| `external-links.yml` | Mondays, 04:41 UTC | `check:external` |
| Dependabot | Weekly | npm and Actions updates. Its pull requests target `main`; retarget them to `staging` |

- **`staging`** is the integration branch. Work branches off it and merges back through a pull request.
- Promotion is a second pull request, `staging` → `main`, reviewed on its own.
- `main` carries a ruleset matching the other repositories: pull request required, squash-only, CI must pass, no force-push, no deletion, and **no bypass for anyone** — including the owner.
Scheduled workflows run from `main` only.

CI (`.github/workflows/ci.yml`) runs build, type-check, and the gates listed above on every pull request and every push to `main`, with the workflow token scoped to `contents: read` and every action pinned to a commit. A push to `staging` alone runs no CI, so run the gates locally before pushing there.
## Search and agents

---
Both sites publish `sitemap-index.xml`, `robots.txt` (content signals: `search=yes, ai-input=yes, ai-train=no`) and `llms.txt`. On the landing, `src/lib/site-map.ts` is the one list of pages behind the nav, footer, `/sitemap` and `llms.txt`; on the docs, `src/sidebar.mjs` is. Submit both sitemaps in Search Console.

## License
No page loads anything from another origin (the CSP allows only the site itself), and there is no analytics. The API reference sends "Test request" straight to the reader's node (`proxyUrl: ''` in `site/dpp-docs/src/scripts/mount-api-reference.ts`); check that this still holds after upgrading `@scalar/api-reference`.

[Apache License 2.0](LICENSE) — the source of both sites (markup, styling, docs prose, brand tokens) for consistency with `dpp-core` (one licence story, not two). The deployed sites' content is freely readable; the source licence governs reuse of the markup and styling work.
## Elsewhere

## Security
The product's source is in [`dpp-core`](https://github.com/odal-node/dpp-core) (Apache-2.0) and [`dpp-engine`](https://github.com/odal-node/dpp-engine) (BSL-1.1). This repository holds only the websites.

Do **not** open public issues for security vulnerabilities (e.g. XSS, exposed secrets, dependency CVEs). Report privately to **security@odal-node.io**.
## License and security

---
[Apache-2.0](LICENSE) for the sites' source. It grants no use of the Odal Node name or logo.

*Odal Node — built by [Odal Node](https://odal-node.io)*
Report vulnerabilities privately to **security@odal-node.io**, never in a public issue.
2 changes: 1 addition & 1 deletion site/dpp-docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ site/dpp-docs/
├── astro.config.mjs # Starlight config: redirects, head (JSON-LD, share image), dev server on 4325
├── openapi-source.json # the dpp-engine commit public/openapi.yaml is vendored from
├── public/
│ ├── _headers # Cloudflare Pages headers: HSTS, CSP, caching
│ ├── _headers # Cloudflare Pages headers: HSTS, CSP, caching, no-transform on HTML (root README)
│ ├── favicon.svg # the brand mark
│ └── openapi.yaml # the engine's API spec, vendored (do not edit here)
├── scripts/
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 @@ -21,7 +21,7 @@ site/dpp-landing/
├── astro.config.mjs # Astro + Tailwind 4 (@tailwindcss/vite) + sitemap; dev server on 4321
├── core-source.json # the dpp-core commit the vendored records in src/data/ come from
├── public/
│ ├── _headers # Cloudflare Pages headers: HSTS, CSP, caching
│ ├── _headers # Cloudflare Pages headers: HSTS, CSP, caching, no-transform on HTML (root README)
│ ├── favicon.svg # the brand mark (also shown in the nav, hero and footer)
│ ├── apple-touch-icon.png # 180px PNG of the mark, for iOS
│ ├── og-image.png # site-wide share image
Expand Down
Loading