Changelog
Changelog
Kuraterede højdepunkter fra de seneste udgivelser. For fuldstændige API-versioner og breaking change-politik, se API-versionering & LTS-politik.
Detaljerede ændringer for de enkelte endepunkter: OpenAPI-specifikation og interaktiv API-reference.
2026-08 · Keyset-cursor nu på alle liste-endpoints
- Fix: Cursor-rettelsen til
GET /v1/codesogGET /v1/dpp(se nedenfor) er nu rullet ud til alle øvrige cursor-paginerede lister:GET /v1/qr-codes/:id/comments,/v1/workspaces,/v1/gs1/identifiers,/v1/members,/v1/audit-logs,/v1/admin/orgs,/v1/admin/usersog/v1/webhooks/:id/deliveries. Alle paginerede udelukkende viacreated_at; rækker med identisk tidsstempel (audit-log-poster fra en batch-handling, webhook-retries, medlemsimporter) kunne gå tabt på den efterfølgende side. Sorteringsnøglen er nu overalt tuplen(created_at, id). - API-ændring: På disse lister er
meta.pagination.next_cursorfra nu af også en opak værdi (base64url) i stedet for et råt tidsstempel; ulæselige cursorer returnerer400, og gamle tidsstempel-cursorer accepteres fortsat i en overgangsperiode. UndtagelseGET /v1/webhooks/:id/deliveries: her forblivernext_cursorid’et på den sidste levering (ukendt id → første side). Klienter, der returnerernext_cursoruændret — Dashboard, CLI, SDKs, MCP —, skal ikke ændre noget. - Konsekvens: Ingen migrering nødvendig. Hvis du har manglet poster, når du bladrede i en af disse lister (f.eks. audit-log eller leveringslog i Dashboard): De var aldrig væk — listerne viser dem fuldstændigt fra nu af.
2026-08 · Tidsstempler efter redigering og sletning er igen OpenAPI-kompatible
- Fix: Efter
PATCH /v1/codes/{id}returneredeupdated_ati SQLite-format uden tidszone (2026-08-17 09:00:00), selvom OpenAPI-specifikationen angiverformat: date-timeog oprettelse (POST) leverer ISO-tidsstemplet (2026-08-17T09:00:00.000Z). Det samme gjaldt fordeleted_at/updated_atved soft-delete samt for redigerings-/sletningsstierne for API-Keys, organisationer, workspaces, medlemmer, kommentarer og webhooks, derudover forlast_used_atfor API-Keys oglast_triggered_atfor webhooks. Alle skrivestier stempler nu ISO 8601 (UTC,TogZ). - Konsekvens: Klienter, der parser
updated_atmednew Date(...)(SDKs, CLI, Dashboard), læste mellemrumsformatet som lokaltid — CLI’en viste for koder, der var blevet redigeret, klokkeslættet forskudt med det lokale offset (Wien: −2 t). Dette er rettet. Derudover normaliserer en datamigrering allerede gemte værdier i det gamle format til ISO, så sortering og sammenligninger i blandede datasæt stemmer. Ingen ændring af feltnavne eller svarstruktur. - Baggrund: Samme fejlklasse som de to rettelser nedenfor (API-Key-udløb, re-scan-cutoff): SQLites
datetime('now')skriverYYYY-MM-DD HH:MM:SS, alle andre skrivere skriver ISO 8601. En kildekods-guard-test forhindrer fremtidige forekomster.
2026-08 · Listepaginering mister ikke længere batch-koder
- Fix:
GET /v1/codesogGET /v1/dpppaginerede udelukkende viacreated_at. Koder fraPOST /v1/codes/batch,POST /v1/dpp/batchog CSV/XLSX-importen deler dog ét tidsstempel — så snart et batch var større endlimit(standard 20), leverede den anden side ikke længere de resterende rækker med det samme tidsstempel. Koderne eksisterede og var tilgængelige viaGET /v1/codes/:id, men dukkede aldrig op i listen (Dashboard, CLIqr3 list, SDKs, MCP). Cursoren er nu et keyset over(created_at, id). - API-ændring:
meta.pagination.next_cursorer fra nu af en opak værdi (base64url) i stedet for et råt tidsstempel. Hvis man returnerer cursoren uændret som?cursor=— ligesom Dashboard, CLI, alle SDKs og MCP-serveren gør — behøver man ikke at ændre noget. Gamle tidsstempel-cursorer accepteres fortsat i en overgangsperiode; ulæselige cursorer returnerer nu400i stedet for stiltiende at levere den første side. - Konsekvens: Hvis du efter en batch-import så færre koder i listen, end der blev oprettet: Koderne var aldrig væk — listen viser dem fuldstændigt fra nu af. Ingen migrering nødvendig.
2026-08 · Sikkerheds-re-scanninger kører igen i 24-timers intervaller
- Fix: Den periodiske re-scanning af destinations-URL’er og landingsside-links (Google Web Risk) sprang koder over, hvis seneste scanning lå på samme kalenderdag som 24-timers-cutoff’en — afhængigt af tidspunktet blev re-scanningen forsinket med op til en ekstra dag. Cutoff’en beregnes nu i samme ISO-format, som scannings-tidsstemplerne er gemt i.
- Konsekvens: En destinations-URL, der efter den seneste scanning klassificeres som usikker, fører igen til automatisk pausering af koden inden for det dokumenterede 24-timers vindue. Ingen ændringer i API eller svarformat.
2026-08 · API-nøgler udløber på udløbstidspunktet
- Fix: En API-nøgle, hvis
expires_atvar på samme dag, blev fortsat accepteret indtil midnat UTC. Udløbet sammenlignes nu som et tidsstempel i stedet for som en streng — en udløbet nøgle returnerer med det samme401. - Baggrund:
expires_atgemmes som et ISO-tidsstempel (2026-08-14T09:00:00Z), mens sammenligningssiden leverede formatet med mellemrum (2026-08-14 09:00:00). Den rå strengsammenligning stemte derfor kun, så længe selve datoen var forskellig. - Konsekvens: Ingen migrering nødvendig, svarformatet for
GET /v1/api-keysforbliver uændret. Ulæselige udløbsværdier betragtes nu som udløbne i stedet for som gyldige.
2026-08 · API-reference: Tenant-administration dokumenteret
- OpenAPI: Specifikationen — og dermed den interaktive reference — dokumenterer nu organisationer (inkl.
GET /v1/organizations/usage), workspaces, medlemmer & roller og audit-logs. - Billing: Abonnementsoversigten (
GET /v1/billing/plans) er offentlig; checkout (POST /v1/billing/checkout) og Stripe-kundeportal (GET /v1/billing/portal) er angivet som endpoints for organisationsadministratorer. - Scan-eksport: Scan-statistikker (
GET /v1/codes/{id}/scans) og rådata-eksport (…/scans.csv,…/scans.xlsx) er fuldt dokumenteret — inklusive GDPR-bemærkning:ip_hasher aldrig inkluderet i eksporten. - Fejladfærd: Også
400-svaret for forespørgselsvalidering er nu dokumenteret: Bodyen er den rå Zod-fejl, ikke et RFC-7807-problemdokument — den leveres dog stadig under Content-Typeapplication/problem+json.
2026-08 · Kopiering af offentlige fillinks
- Dashboard: Offentlige filer på en kodes detaljeside har nu en knap, der kopierer filens offentlige link til udklipsholderen. Linket kan bruges direkte som destinations-URL for en QR-kode, når en scanning straks skal åbne et bestemt dokument i stedet for landingssiden med fillisten.
- API: Fil-endpoints (
/v1/files) leverer desudenpublic_url. Feltet udfyldes kun for filer medvisibility: public– private filer får ingen offentlig adresse. - Adfærd: Linket kræver ikke login og åbner filen direkte i browseren. Hvis du bruger Erstat på filen, ændres linket ikke, og en allerede trykt QR-kode forbliver gyldig. Detaljer: Filer & datablade.
2026-07 · Teamroller: Bidragyder uden sletning & administratorfakturering
- Nyt: Medlemsrollen Bidragyder (uden sletning) — opretter og redigerer QR-koder, filer og Digital Product Passports, men kan ikke slette noget og ikke oprette API-Keys. Alle destruktive endpoints kontrollerer rollen på serversiden (
403). - Fakturering: Abonnementopgraderinger og Stripe-kundeportalen (
POST /v1/billing/checkout,GET /v1/billing/portal) er nu forbeholdt organisationsadministratorer — alle andre roller ser en skrivebeskyttet abonnementsoversigt. - Dashboard: Handlinger, som ens egen rolle ikke tillader, skjules: En Læser ser f.eks. ingen knapper til at oprette, redigere eller slette; lister, downloads og statistikker forbliver synlige. Detaljer: Team & roller.
2026-06 · Eksterne links på kodens landingsside
- Landingsside: En kodes qr3-hostede landingsside kan nu vise eksterne, selv-hostede links (
{ label, url }) ud over eller i stedet for uploadede filer – f.eks. til datablade på dit eget websted. - API:
POST/PATCH /v1/codesaccepterer etlinks-array (0–20 poster,http(s), ≤ 2048 tegn). Hver URL kontrolleres med Google Web Risk; en usikker URL returnerer422. Et tomt array rydder alle links. - Dashboard: Tilføj, omarranger og fjern links på kodens detaljeside.
- Sikkerhed: Gengivne links forbliver XSS-sikre (escaped, kun
http(s)), og siden bevarer sinnoindex-header.
2026-04 · Dashboard-analyse pr. QR-kode
- Dashboard: Analyse-knappen i QR-kodelisten åbner nu statistikside for den pågældende QR-kode under
/dashboard/codes/{id}. - Routing: Aliasset
/dashboard/codesviderestiller stadig til/dashboard, men fanger ikke længere detaljerede ruter som/dashboard/codes/{id}. - API: Detaljesiden indlæser QR-koden direkte via
GET /v1/codes/:id; derved er den ikke længere afhængig af grænser for listepaginering. - Tests: Regressionstest dækker alias-viderestillingen og den direkte indlæsning af koden.
2026-04 · Dashboard-slettedialog for QR-koder
- Dashboard: Skraldespandsikonet i QR-kodelisten åbner nu en dedikeret React-dialog i stedet for en nativ browser-popup.
- Feedback: Efter sletning vises en toast-besked for succes eller fejl.
- Tests:
packages/dashboard/tests/dashboard.test.tsforhindrer regressioner påconfirm()i QR-kode-sletteflowet.
2026-04 · Dashboard-kortlink-test for dynamiske QR-koder
- Dashboard: Shortcodes i QR-kodelisten er nu direkte klikbare som eksterne viderestillingslinks. Det eksterne link-ikon ved siden af f.eks.
wu3qaaåbnerhttps://qr3.app/{shortCode}i en ny fane. - i18n: Tooltip-tekster tilføjet for tysk og engelsk.
- Tests:
packages/dashboard/tests/dashboard.test.tsbeskytter link-href, ny fane-adfærd,noopener noreferrerog ikon mod regressioner.
2026-04 · Redirect-Worker-rute for dynamiske QR-koder
- Fix: Dynamiske QR-koder under
https://qr3.app/{shortCode}behandles igen af Redirect-Worker. Produktionsruten bruger nuqr3.app/*, fordi Cloudflare Worker-ruter ikke understøtter:code-stiparametre. - Hærdning: Ikke-matchende stier sendes videre til landing-origin, så normale sider som
/de/pricingikke blokeres af Redirect-Worker. - Tests:
packages/redirect/tests/unit/redirect.test.tstester wildcard-ruten, shortcode-behandling og origin-pass-through.
2026-04 · Workspace-DPP-scannings-oversigt (Q3.4.2)
- Ny:
GET /v1/workspace/stats/dpp?days=30— aggregerer alledpp_scansfor API-nøgle-workspacet (active_dpps,scans_by_day,top_dppsmed produktnavn/kategori). - Dashboard: Kort på startside (
/dashboard) med 30-dages søjlediagram + toplister — parallelt med QR-kode-kortene. - Public: Marketing-kortlink
GET /dpp/dpp_<id>(ét segment) til live-demoer, parallelt med/dpp/{gtin}/{serial}.
2026-04 · DPP-scanningsanalyse (Q3.4.1)
- Ny:
GET /v1/dpp/:id/stats?days=30— aggregerede scanninger fra den offentlige GS1-resolver pr. DPP. Felter:total_scans,period_scans,scans_by_day,top_countries,top_devices,top_representations. - Ny: Tabel
dpp_scans(migration0011) — adskilt frascans(Redirect-Worker). IP-adresser hashes med en dagligt roterende salt, rå IP’er når aldrig D1. - Dashboard: Mini-diagramkort (SVG, intet diagrambibliotek) på
/dashboard/dpp/:dppIdmed 30-dages søjler + top 3-opdelinger. Empty-state så snart et DPP er live, men endnu ikke har haft nogen scanninger.
2026-04 · Live EU-overensstemmelsessimulator (Q3.3.7)
- Ny:
POST /v1/dpp/:id/validate-update— simulerer delvise opdateringer stateless (status, markedsliste, …) uden persistens. Svaret indeholdereu_compliance+preview.changed_fields. - Dashboard: Simulatorkort i DPP-detaljer (
/dashboard/dpp/:dppId) — chips tilDE/AT/FR/IT/ES/NL+ Custom, status-dropdown, Forhåndsvis EU-indvirkning / Gem ændringer / Nulstil. Non-blocking via RemixuseFetcher. - Hærdning: Udflyttede simulator-hjælpere (
readUpdatePatchFromForm,marketCountriesKey) + 18 nye enhedstest; fejlretning: Enlig ikke-ISO-input sletter ikke længere markedslisten.
2026-04 · Live EU-overensstemmelsesforhåndsvisning i oprettelsesformularen (Q3.3.6)
- Ændret:
POST /v1/dpp/validateleverer yderligereeu_compliance— samme validator somGET /v1/dpp/:id/eu-compliance, stateless før lagring. - Dashboard: Forhåndsvisning under det eksisterende valideringspanel + nyt Save-Guard-banner før submit-knapperne, hvis der er udestående fejl/advarsler (i18n-pluralisering DE/EN).
2026-04 · EU-validator + tekstil-UI (Q3.3.4 + Q3.3.5)
- Ny: EU-overensstemmelsesvalidator med 5 tekstilregler (
TEXTILE_AGEC_REQUIRED,TEXTILE_MICROPLASTICS_CONSISTENCY,TEXTILE_SVHC_THRESHOLD,TEXTILE_GREENWASHING,TEXTILE_ESPR_READY). - Ny:
GET /v1/dpp/:id/eu-compliancemedcompliant/espr_ready/issues[]/summary. - Dashboard: EU-overensstemmelsessektion i DPP-detaljer (oversigtsfliser, grupperede problemkort, ESPR-Ready-badge i headeren).
2026-04 · Tekstil-DPP-skema (Q3.3.1–Q3.3.3)
- Ny: Kategori
textilemed obligatorisk AGEC-kæde (vævning/strikning → farvning/trykning → konfektionering), pr. fiberorigin_country+recycled_pct,svhc_substances[], ESPR-tilvalg (PEF, levetid, genanvendelighed). - Ny: Basisfelt
market_countries: string[](ISO 3166-1 alpha-2) på alle DPP-kategorier — styrer FR-specifikke AGEC-regler og den franske obligatoriske forbrugeroplysning. - Ny: Forbruger-HTML-skabelon med AGEC-mikroplastadvarselsboks, 3-trins oprindelseskæde (flag-piller), SVHC-liste, holdbarheds- og genanvendelighedssektion.
- Migration:
0010_dpp_market_countries(D1).
2026-04 · DPP-masseimport (Q3.2.1–Q3.2.5)
- Ny:
POST /v1/dpp/importaccepterer CSV og XLSX (Worker-kompatibel via SheetJSxlsx, ~283 KB gzip bundle). - Skaleret: abonnementsbaseret grænse (Free 100 → Enterprise 10k) + chunked
db.batch()à 100 + 5 MB body-grænse. - Ny: Fejlrapport som CSV i feltet
errors_csvi 201-svaret;GET /v1/dpp/import/templates/:category?format=csv|xlsxleverer færdige skabeloner til batteri og tekstil. - Dashboard: Drag-and-drop-upload under
/dashboard/dpp/importmed skabelon-proxy og inline CSV-download.
Ikke-breaking — LTS-udvidelser
Alle ovennævnte ændringer er additive:
- Eksisterende
POST /v1/dpp/validate-klienter ignorerer det nyeeu_compliance-felt uden ændringer. - Eksisterende
battery-flows er uændrede. market_countrieser valgfri og har standardværdien[].
Se API-versionering for breaking change-politikken.