Ga naar inhoud

Changelog

Changelog

Gecureerde highlights van de laatste releases. Voor volledige API-versies en het breaking-change-beleid, zie de API-versiebeheer & LTS-beleid.

Gedetailleerde wijzigingen aan afzonderlijke endpoints: OpenAPI-specificatie en interactieve API-referentie.


2026-08 · Keyset-cursor nu op alle lijst-endpoints

  • Fix: De cursor-fix voor GET /v1/codes en GET /v1/dpp (zie hieronder) is nu uitgerold naar alle overige lijsten met cursor-paginering: GET /v1/qr-codes/:id/comments, /v1/workspaces, /v1/gs1/identifiers, /v1/members, /v1/audit-logs, /v1/admin/orgs, /v1/admin/users en /v1/webhooks/:id/deliveries. Deze bladerden allemaal uitsluitend op basis van created_at; rijen met een identieke tijdstempel (audit-vermeldingen van een batch-operatie, webhook-retries, importen van leden) konden op de volgende pagina verloren gaan. De sorteersleutel is nu overal de tuple (created_at, id).
  • API-wijziging: Op deze lijsten is meta.pagination.next_cursor vanaf nu ook een opake waarde (base64url) in plaats van een kale tijdstempel; onleesbare cursors retourneren 400, oude tijdstempel-cursors worden tijdelijk nog geaccepteerd. Uitzondering GET /v1/webhooks/:id/deliveries: daar blijft next_cursor de ID van de laatste aflevering (onbekende ID → eerste pagina). Clients die next_cursor ongewijzigd terugsturen — Dashboard, CLI, SDKs, MCP —, hoeven niets te wijzigen.
  • Impact: Geen migratie vereist. Als je in een van deze lijsten (bijv. het audit-log of afleverlogboek in het Dashboard) bij het bladeren items hebt gemist: ze waren nooit weg — de lijsten tonen ze vanaf nu volledig.

2026-08 · Tijdstempels na bewerken en verwijderen weer OpenAPI-conform

  • Fix: Na PATCH /v1/codes/{id} kwam updated_at terug in SQLite-formaat zonder tijdzone (2026-08-17 09:00:00), hoewel de OpenAPI-specificatie format: date-time belooft en het aanmaken (POST) de ISO-tijdstempel (2026-08-17T09:00:00.000Z) levert. Hetzelfde gold voor deleted_at/updated_at bij soft-delete en voor de bewerk-/verwijderpaden van API-keys, organisaties, workspaces, leden, reacties en webhooks, evenals voor last_used_at van API-keys en last_triggered_at van webhooks. Alle schrijfpaden stempelen nu ISO 8601 (UTC, T en Z).
  • Impact: Clients die updated_at parseren met new Date(...) (SDKs, CLI, Dashboard), lazen het formaat met de spatie als lokale tijd — de CLI toonde bij eenmaal bewerkte codes de tijd verschoven met de lokale offset (Wenen: −2 u). Dit is opgelost. Daarnaast normaliseert een datamigratie reeds opgeslagen waarden in het oude formaat naar ISO, zodat sortering en vergelijkingen in gemengde datasets kloppen. Geen wijziging in veldnamen of antwoordstructuur.
  • Achtergrond: Zelfde foutklasse als de twee fixes hieronder (API-key-verloop, re-scan-cutoff): SQLite’s datetime('now') schrijft YYYY-MM-DD HH:MM:SS, alle overige schrijvers ISO 8601. Een guard-test in de broncode voorkomt in de toekomst nieuwe gevallen.

2026-08 · Lijst-paginering verliest geen batch-codes meer

  • Fix: GET /v1/codes en GET /v1/dpp pagineerden uitsluitend op basis van created_at. Codes uit POST /v1/codes/batch, POST /v1/dpp/batch en de CSV/XLSX-import delen echter één tijdstempel — zodra een batch groter was dan limit (standaard 20), leverde de tweede pagina de resterende rijen met dezelfde tijdstempel niet meer. De codes bestonden en waren via GET /v1/codes/:id bereikbaar, maar doken in de lijst (Dashboard, CLI qr3 list, SDKs, MCP) nooit op. De cursor is nu een keyset over (created_at, id).
  • API-wijziging: meta.pagination.next_cursor is vanaf nu een opake waarde (base64url) in plaats van een kale tijdstempel. Wie de cursor ongewijzigd als ?cursor= retourneert — zoals het Dashboard, de CLI, alle SDKs en de MCP-server dat doen — hoeft niets te veranderen. Oude tijdstempel-cursors worden tijdelijk nog geaccepteerd; onleesbare cursors leveren nu een 400 op in plaats van stilzwijgend de eerste pagina te tonen.
  • Impact: Voor wie na een batch-import minder codes in de lijst zag dan er waren aangemaakt: de codes zijn nooit weggeweest — de lijst toont ze vanaf nu volledig. Geen migratie nodig.

2026-08 · Beveiligings-re-scans worden weer om de 24 uur uitgevoerd

  • Fix: Het periodiek re-scannen van doel-URL’s en landingspagina-links (Google Web Risk) sloeg codes over waarvan de laatste scan op dezelfde kalenderdag viel als de 24-uurs-cutoff — afhankelijk van het tijdstip werd de re-scan met maximaal een extra dag vertraagd. De cutoff wordt nu berekend in hetzelfde ISO-formaat waarin de scan-tijdstempels zijn opgeslagen.
  • Impact: Een doel-URL die na de laatste scan als onveilig wordt geclassificeerd, leidt nu weer binnen het gedocumenteerde 24-uursvenster tot het automatisch pauzeren van de code. Geen wijzigingen in de API of het antwoordformaat.

2026-08 · API-keys verlopen op het verlooptijdstip

  • Fix: Een API-key waarvan expires_at op dezelfde dag viel, werd tot middernacht UTC geaccepteerd. De vervaltijd wordt nu vergeleken als een tijdstempel in plaats van een string — een verlopen key retourneert nu direct 401.
  • Achtergrond: expires_at wordt opgeslagen als een ISO-tijdstempel (2026-08-14T09:00:00Z), de vergelijkingszijde leverde het formaat met een spatie (2026-08-14 09:00:00). De ruwe stringvergelijking klopte daarom alleen zolang de datum al verschilde.
  • Impact: Geen migratie vereist, het antwoordformaat van GET /v1/api-keys blijft ongewijzigd. Onleesbare vervalwaarden worden nu als verlopen beschouwd in plaats van als geldig.

2026-08 · API-referentie: Tenant-beheer gedocumenteerd

  • OpenAPI: De specificatie — en daarmee de interactieve referentie — documenteert nu organisaties (incl. GET /v1/organizations/usage), workspaces, leden & rollen en audit-logs.
  • Billing: Het tarievenoverzicht (GET /v1/billing/plans) is openbaar; checkout (POST /v1/billing/checkout) en Stripe-klantenportaal (GET /v1/billing/portal) zijn aangemerkt als endpoints voor organisatiebeheerders.
  • Scan-export: Scanstatistieken (GET /v1/codes/{id}/scans) en de ruwe data-export (…/scans.csv, …/scans.xlsx) zijn volledig gedocumenteerd — inclusief AVG-opmerking: De ip_hash is nooit in de export opgenomen.
  • Foutgedrag: Ook nieuw gedocumenteerd is het 400-antwoord van de request-validatie: De body is de ruwe Zod-fout, geen RFC-7807-probleemdocument — deze wordt desondanks geleverd met de Content-Type application/problem+json.
  • Dashboard: Openbare bestanden op de detailpagina van de code hebben nu een knop die hun openbare link naar het klembord kopieert – direct bruikbaar als doel-URL van een QR-code wanneer een scan direct een specifiek document moet openen in plaats van de landingspagina met de bestandslijst.
  • API: De bestands-endpoints (/v1/files) leveren daarnaast public_url. Dit veld is alleen ingevuld bij bestanden met visibility: public – privébestanden krijgen geen openbaar adres.
  • Gedrag: De link vereist geen aanmelding en opent het bestand direct in de browser. Het vervangen van het bestand laat de link ongewijzigd, waardoor een daarop gedrukte code geldig blijft. Details: Bestanden & datasheets.

2026-07 · Teamrollen: Bewerker zonder verwijderen & admin-facturering

  • Nieuw: Lidrol Bewerker (zonder verwijderen) — maakt QR-codes, bestanden en Digital Product Passports aan en bewerkt deze, maar kan niets verwijderen en geen API-keys aanmaken. Alle destructieve endpoints controleren de rol aan de serverzijde (403).
  • Facturering: Abonnementsupgrades en het Stripe-klantenportaal (POST /v1/billing/checkout, GET /v1/billing/portal) zijn nu voorbehouden aan organisatiebeheerders — alle andere rollen zien een alleen-lezen abonnementsverzicht.
  • Dashboard: Acties die de eigen rol niet toestaat, worden verborgen: een Lezer ziet bijvoorbeeld geen knoppen voor het aanmaken, bewerken of verwijderen; lijsten, downloads en statistieken blijven zichtbaar. Details: Team & rollen.
  • Landingspagina: De door qr3 gehoste landingspagina van een code kan nu externe, zelfgehoste links ({ label, url }) tonen – naast of in plaats van geüploade bestanden, bijvoorbeeld voor datasheets op de eigen website.
  • API: POST/PATCH /v1/codes accepteren een links-array (0–20 items, http(s), ≤ 2048 tekens). Elke URL wordt gecontroleerd met Google Web Risk; een onveilige URL retourneert 422. Een lege array verwijdert alle links.
  • Dashboard: Links toevoegen, sorteren en verwijderen op de detailpagina van de code.
  • Beveiliging: Gerenderde links blijven XSS-veilig (escaped, alleen http(s)) en de pagina behoudt zijn noindex-header.

2026-04 · Dashboard-statistieken per QR-code

  • Dashboard: De statistiekenknop in de QR-codelijst opent nu de statistiekenpagina van de betreffende QR-code onder /dashboard/codes/{id}.
  • Routing: De alias /dashboard/codes stuurt nog steeds door naar /dashboard, maar vangt geen detailroutes zoals /dashboard/codes/{id} meer af.
  • API: De detailpagina laadt de QR-code direct via GET /v1/codes/:id; hierdoor is deze niet meer afhankelijk van paginalimieten van de lijst.
  • Tests: Regressietests dekken de alias-redirect en het direct laden van de code af.

2026-04 · Dashboard-verwijderdialoog voor QR-codes

  • Dashboard: De prullenbak in de QR-codelijst opent nu een eigen React-dialoogvenster in plaats van een native browser-popup.
  • Feedback: Na het verwijderen verschijnt een toast-melding voor succes of fouten.
  • Tests: packages/dashboard/tests/dashboard.test.ts voorkomt regressies op confirm() in de QR-code-verwijderflow.

2026-04 · Dashboard-kortelinktest voor dynamische QR-codes

  • Dashboard: Shortcodes in de QR-codelijst zijn nu direct klikbaar als externe redirect-links. Het externe-link-icoon naast bijv. wu3qaa opent https://qr3.app/{shortCode} in een nieuw tabblad.
  • i18n: Tooltip-teksten voor Duits en Engels toegevoegd.
  • Tests: packages/dashboard/tests/dashboard.test.ts beschermt link-href, nieuw tabbladgedrag, noopener noreferrer en icoon tegen regressies.

2026-04 · Redirect-Worker-route voor dynamische QR-codes

  • Fix: Dynamische QR-codes onder https://qr3.app/{shortCode} worden weer verwerkt door de redirect-Worker. De productie-route gebruikt nu qr3.app/*, omdat Cloudflare Worker-routes geen :code-padparameters ondersteunen.
  • Beveiliging: Niet-overeenkomende paden worden doorgestuurd naar de landing-origin, zodat normale pagina’s zoals /de/pricing niet worden geblokkeerd door de redirect-Worker.
  • Tests: packages/redirect/tests/unit/redirect.test.ts controleert de wildcard-route, shortcode-verwerking en origin-pass-through.

2026-04 · Workspace DPP-scanoverzicht (Q3.4.2)

  • Nieuw: GET /v1/workspace/stats/dpp?days=30 — aggregeert alle dpp_scans van de API-key-workspace (active_dpps, scans_by_day, top_dpps met productnaam/categorie).
  • Dashboard: Kaart op de startpagina (/dashboard) met 30-dagen staafdiagram + toplijsten — parallel aan de QR-codekaarten.
  • Openbaar: Marketing-shortlink GET /dpp/dpp_<id> (één segment) voor live demo’s, parallel aan /dpp/{gtin}/{serial}.

2026-04 · DPP-scanstatistieken (Q3.4.1)

  • Nieuw: GET /v1/dpp/:id/stats?days=30 — geaggregeerde scans van de openbare GS1-resolver per DPP. Velden: total_scans, period_scans, scans_by_day, top_countries, top_devices, top_representations.
  • Nieuw: Tabel dpp_scans (migratie 0011) — gescheiden van scans (redirect-Worker). IP-adressen worden gehasht met een dagelijks roterende salt, ruwe IP’s bereiken D1 nooit.
  • Dashboard: Mini-grafiekkaart (SVG, geen grafiekbibliotheek) op /dashboard/dpp/:dppId met 30-dagen balken + top-3 breakdowns. Empty state zodra een DPP live is maar nog geen scans heeft gehad.

2026-04 · Live EU-compliance-simulator (Q3.3.7)

  • Nieuw: POST /v1/dpp/:id/validate-update — simuleert gedeeltelijke updates stateless (status, marktlijst, …) zonder persistentie. Antwoord bevat eu_compliance + preview.changed_fields.
  • Dashboard: Simulatorkaart in het DPP-detail (/dashboard/dpp/:dppId) — chips voor DE/AT/FR/IT/ES/NL + custom, status-dropdown, Preview EU impact / Save changes / Reset. Non-blocking via Remix useFetcher.
  • Beveiliging: Uitbestede simulator-helpers (readUpdatePatchFromForm, marketCountriesKey) + 18 nieuwe unit-tests; Bugfix: een enkele niet-ISO-invoer wist de marktlijst niet meer.

2026-04 · Live EU-compliance-preview in het aanmaakformulier (Q3.3.6)

  • Gewijzigd: POST /v1/dpp/validate levert daarnaast eu_compliance — dezelfde validator als GET /v1/dpp/:id/eu-compliance, stateless vóór het opslaan.
  • Dashboard: Preview onder het bestaande validatiepaneel + nieuwe Save-Guard-banner vóór de submit-knoppen als er fouten/waarschuwingen openstaan (i18n-pluralisatie DE/EN).

2026-04 · EU-validator + textiel-UI (Q3.3.4 + Q3.3.5)

  • Nieuw: EU-compliance-validator met 5 textielregels (TEXTILE_AGEC_REQUIRED, TEXTILE_MICROPLASTICS_CONSISTENCY, TEXTILE_SVHC_THRESHOLD, TEXTILE_GREENWASHING, TEXTILE_ESPR_READY).
  • Nieuw: GET /v1/dpp/:id/eu-compliance met compliant / espr_ready / issues[] / summary.
  • Dashboard: EU-compliance-sectie in het DPP-detail (samenvattingstegels, gegroepeerde issue-kaarten, ESPR-Ready-badge in de header).

2026-04 · Textiel-DPP-schema (Q3.3.1–Q3.3.3)

  • Nieuw: Categorie textile met verplichte AGEC-keten (weven/breien → verven/bedrukken → confectie), per vezel origin_country + recycled_pct, svhc_substances[], ESPR-opt-in (PEF, levensduur, Recyclability).
  • Nieuw: Basisveld market_countries: string[] (ISO 3166-1 alpha-2) op alle DPP-categorieën — stuurt FR-specifieke AGEC-regels en de Franse verplichte consumentennotitie aan.
  • Nieuw: Consumenten-HTML-template met AGEC-microplastic-waarschuwingsbox, herkomstketen in 3 stappen (vlag-pills), SVHC-lijst, Durability- en Recyclability-sectie.
  • Migratie: 0010_dpp_market_countries (D1).

2026-04 · DPP bulk-import (Q3.2.1–Q3.2.5)

  • Nieuw: POST /v1/dpp/import accepteert CSV en XLSX (Worker-compatibel via SheetJS xlsx, ~283 KB gzip-bundel).
  • Geschaald: abonnement-gebaseerde limiet (Free 100 → Enterprise 10k) + chunked db.batch() à 100 + 5 MB body-limiet.
  • Nieuw: Foutrapportage als CSV in het errors_csv-veld van het 201-antwoord; GET /v1/dpp/import/templates/:category?format=csv|xlsx levert kant-en-klare sjablonen voor batterij en textiel.
  • Dashboard: Drag-and-drop-upload onder /dashboard/dpp/import met template-proxy en inline CSV-download.

Non-breaking — LTS-uitbreidingen

Alle bovengenoemde wijzigingen zijn additief:

  • Bestaande POST /v1/dpp/validate-clients negeren het nieuwe eu_compliance-veld zonder wijzigingen.
  • Bestaande battery-flows zijn ongewijzigd.
  • market_countries is optioneel en heeft als standaardwaarde [].

Zie API-versiebeheer voor het breaking-change-beleid.