Gå til indhold

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/codes og GET /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/users og /v1/webhooks/:id/deliveries. Alle paginerede udelukkende via created_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_cursor fra nu af også en opak værdi (base64url) i stedet for et råt tidsstempel; ulæselige cursorer returnerer 400, og gamle tidsstempel-cursorer accepteres fortsat i en overgangsperiode. Undtagelse GET /v1/webhooks/:id/deliveries: her forbliver next_cursor id’et på den sidste levering (ukendt id → første side). Klienter, der returnerer next_cursor uæ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} returnerede updated_at i SQLite-format uden tidszone (2026-08-17 09:00:00), selvom OpenAPI-specifikationen angiver format: date-time og oprettelse (POST) leverer ISO-tidsstemplet (2026-08-17T09:00:00.000Z). Det samme gjaldt for deleted_at/updated_at ved soft-delete samt for redigerings-/sletningsstierne for API-Keys, organisationer, workspaces, medlemmer, kommentarer og webhooks, derudover for last_used_at for API-Keys og last_triggered_at for webhooks. Alle skrivestier stempler nu ISO 8601 (UTC, T og Z).
  • Konsekvens: Klienter, der parser updated_at med new 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') skriver YYYY-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/codes og GET /v1/dpp paginerede udelukkende via created_at. Koder fra POST /v1/codes/batch, POST /v1/dpp/batch og CSV/XLSX-importen deler dog ét tidsstempel — så snart et batch var større end limit (standard 20), leverede den anden side ikke længere de resterende rækker med det samme tidsstempel. Koderne eksisterede og var tilgængelige via GET /v1/codes/:id, men dukkede aldrig op i listen (Dashboard, CLI qr3 list, SDKs, MCP). Cursoren er nu et keyset over (created_at, id).
  • API-ændring: meta.pagination.next_cursor er 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 nu 400 i 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_at var 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 samme 401.
  • Baggrund: expires_at gemmes 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-keys forbliver 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_hash er 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-Type application/problem+json.
  • 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 desuden public_url. Feltet udfyldes kun for filer med visibility: 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.
  • 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/codes accepterer et links-array (0–20 poster, http(s), ≤ 2048 tegn). Hver URL kontrolleres med Google Web Risk; en usikker URL returnerer 422. 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 sin noindex-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/codes viderestiller 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.ts forhindrer regressioner på confirm() i QR-kode-sletteflowet.
  • Dashboard: Shortcodes i QR-kodelisten er nu direkte klikbare som eksterne viderestillingslinks. Det eksterne link-ikon ved siden af f.eks. wu3qaa åbner https://qr3.app/{shortCode} i en ny fane.
  • i18n: Tooltip-tekster tilføjet for tysk og engelsk.
  • Tests: packages/dashboard/tests/dashboard.test.ts beskytter link-href, ny fane-adfærd, noopener noreferrer og 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 nu qr3.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/pricing ikke blokeres af Redirect-Worker.
  • Tests: packages/redirect/tests/unit/redirect.test.ts tester 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 alle dpp_scans for API-nøgle-workspacet (active_dpps, scans_by_day, top_dpps med 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 (migration 0011) — adskilt fra scans (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/:dppId med 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 indeholder eu_compliance + preview.changed_fields.
  • Dashboard: Simulatorkort i DPP-detaljer (/dashboard/dpp/:dppId) — chips til DE/AT/FR/IT/ES/NL + Custom, status-dropdown, Forhåndsvis EU-indvirkning / Gem ændringer / Nulstil. Non-blocking via Remix useFetcher.
  • 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/validate leverer yderligere eu_compliance — samme validator som GET /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-compliance med compliant / 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 textile med obligatorisk AGEC-kæde (vævning/strikning → farvning/trykning → konfektionering), pr. fiber origin_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/import accepterer CSV og XLSX (Worker-kompatibel via SheetJS xlsx, ~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_csv i 201-svaret; GET /v1/dpp/import/templates/:category?format=csv|xlsx leverer færdige skabeloner til batteri og tekstil.
  • Dashboard: Drag-and-drop-upload under /dashboard/dpp/import med skabelon-proxy og inline CSV-download.

Ikke-breaking — LTS-udvidelser

Alle ovennævnte ændringer er additive:

  • Eksisterende POST /v1/dpp/validate-klienter ignorerer det nye eu_compliance-felt uden ændringer.
  • Eksisterende battery-flows er uændrede.
  • market_countries er valgfri og har standardværdien [].

Se API-versionering for breaking change-politikken.