Sari la conținut

Changelog

Changelog

Repere selectate din ultimele versiuni. Pentru versiunile complete de API și politica privind modificările incompatibile (breaking changes), consultați Versiunea API și politica LTS.

Modificări detaliate pentru fiecare endpoint în parte: Specificația OpenAPI și Referința API interactivă.


2026-08 · Cursorul keyset acum pe toate endpoint-urile de listă

  • Fix: Remedierea cursorului pentru GET /v1/codes și GET /v1/dpp (vezi mai jos) este acum implementată pentru toate celelalte liste paginate prin cursor: GET /v1/qr-codes/:id/comments, /v1/workspaces, /v1/gs1/identifiers, /v1/members, /v1/audit-logs, /v1/admin/orgs, /v1/admin/users și /v1/webhooks/:id/deliveries. Toate realizau paginarea doar după created_at; rândurile cu marcaj temporal identic (înregistrări de audit ale unei operațiuni batch, reîncercări de webhook, importuri de membri) puteau fi pierdute pe pagina următoare. Cheia de sortare este acum peste tot tuplul (created_at, id).
  • Modificare API: Pe aceste liste, meta.pagination.next_cursor este de acum înainte, de asemenea, o valoare opacă (base64url) în loc de un simplu marcaj temporal; cursorii ilizibili returnează 400, iar cursorii vechi de tip marcaj temporal vor fi acceptați în continuare ca măsură de tranziție. Excepție GET /v1/webhooks/:id/deliveries: acolo next_cursor rămâne ID-ul ultimei livrări (ID necunoscut → prima pagină). Clienții care returnează next_cursor nemodificat — Dashboard, CLI, SDK-urile, MCP — nu trebuie să schimbe nimic.
  • Impact: Nu este necesară nicio migrare. Dacă ați observat lipsa unor înregistrări la paginarea în una dintre aceste liste (de exemplu, jurnalul de audit sau jurnalul de livrări din Dashboard): acestea nu au dispărut niciodată — listele le afișează complet începând de acum.

2026-08 · Marcajele de timp după editare și ștergere sunt din nou conforme cu OpenAPI

  • Fix: După PATCH /v1/codes/{id}, updated_at a fost returnat în formatul SQLite fără fus orar (2026-08-17 09:00:00), deși specificația OpenAPI promite format: date-time iar crearea (POST) furnizează marcajul temporal ISO (2026-08-17T09:00:00.000Z). Același lucru a fost valabil pentru deleted_at/updated_at la soft-delete, precum și pentru căile de editare/ștergere ale cheilor API, organizațiilor, workspace-urilor, membrilor, comentariilor și webhook-urilor, precum și pentru last_used_at al cheilor API și last_triggered_at al webhook-urilor. Toate căile de scriere marchează acum timpul în formatul ISO 8601 (UTC, T și Z).
  • Impact: Clienții care parsează updated_at cu new Date(...) (SDK-uri, CLI, Dashboard) citeau formatul cu spațiu ca fiind ora locală — la codurile care fuseseră editate, CLI afișa ora deplasată cu decalajul de fus orar local (Viena: −2 h). Acest lucru a fost remediat. În plus, o migrare de date normalizează valorile deja salvate în vechiul format la ISO, astfel încât sortarea și comparările în seturile de date mixte să fie corecte. Nicio modificare a numelor de câmpuri sau a structurii de răspuns.
  • Context: Aceeași clasă de erori ca și cele două remedieri de mai jos (expirarea cheii API, limita de re-scanare): datetime('now') din SQLite scrie YYYY-MM-DD HH:MM:SS, în timp ce toți ceilalți scriitori folosesc ISO 8601. Un test de protecție a codului sursă va preveni aparițiile noi pe viitor.

2026-08 · Paginarea listelor nu mai pierde coduri batch

  • Fix: GET /v1/codes și GET /v1/dpp paginau exclusiv pe baza created_at. Cu toate acestea, codurile din POST /v1/codes/batch, POST /v1/dpp/batch și din importul CSV/XLSX partajează același marcaj temporal — de îndată ce un batch era mai mare decât limit (implicit 20), a doua pagină nu mai returna rândurile rămase cu același marcaj temporal. Codurile existau și puteau fi accesate prin GET /v1/codes/:id, dar nu apăreau niciodată în listă (Dashboard, CLI qr3 list, SDK-uri, MCP). Cursorul este acum un keyset pe baza (created_at, id).
  • Modificare API: meta.pagination.next_cursor este de acum o valoare opacă (base64url) în loc de un simplu marcaj temporal. Cei care returnează cursorul neschimbat ca ?cursor= — așa cum fac Dashboard, CLI, toate SDK-urile și serverul MCP — nu trebuie să modifice nimic. Cursorii vechi de tip marcaj temporal vor fi acceptați în continuare temporar; cursorii ilizibili returnează acum 400 în loc să returneze silențios prima pagină.
  • Impact: Dacă ați văzut mai puține coduri în listă după un import batch decât cele create: codurile nu au dispărut niciodată — lista le afișează acum în întregime. Nu este necesară nicio migrare.

2026-08 · Re-scanările de securitate rulează din nou la fiecare 24 de ore

  • Fix: Re-scanarea periodică a URL-urilor de destinație și a linkurilor de landing page (Google Web Risk) omitea codurile a căror ultimă scanare a avut loc în aceeași zi calendaristică cu limita de 24 de ore — în funcție de oră, re-scanarea era amânată cu până la încă o zi. Limita este acum calculată în același format ISO în care sunt stocate marcajele temporale de scanare.
  • Impact: Un URL de destinație clasificat ca nesigur după ultima scanare determină din nou suspendarea automată a codului în fereastra documentată de 24 de ore. Nicio modificare a API-ului sau a formatului de răspuns.

2026-08 · Cheile API expiră la momentul expirării

  • Fix: O cheie API a cărei valoare expires_at era în aceeași zi a continuat să fie acceptată până la miezul nopții UTC. Expirarea este acum comparată ca marcaj temporal în loc de șir de caractere — o cheie expirată returnează imediat 401.
  • Context: expires_at este salvat ca marcaj temporal ISO (2026-08-14T09:00:00Z), în timp ce partea de comparare furniza formatul cu spațiu (2026-08-14 09:00:00). Prin urmare, compararea brută a șirurilor de caractere era corectă doar dacă data era deja diferită.
  • Impact: Nu este necesară nicio migrare, formatul de răspuns al GET /v1/api-keys rămâne neschimbat. Valorile de expirare ilizibile sunt acum considerate expirate în loc de valide.

2026-08 · Referință API: Administrarea tenant-ului documentată

  • OpenAPI: Specificația — și, prin urmare, referința interactivă — documentează acum organizațiile (incl. GET /v1/organizations/usage), workspace-urile, membrii & rolurile și jurnalele de audit.
  • Billing: Prezentarea generală a tarifelor (GET /v1/billing/plans) este publică; finalizarea comenzii (POST /v1/billing/checkout) și portalul pentru clienți Stripe (GET /v1/billing/portal) sunt desemnate ca endpoint-uri pentru administratorii organizației.
  • Export scanări: Statisticile de scanare (GET /v1/codes/{id}/scans) și exportul de date brute (…/scans.csv, …/scans.xlsx) sunt complet documentate — inclusiv nota privind GDPR: ip_hash nu este niciodată inclus în export.
  • Comportament la erori: Nou documentat este și răspunsul 400 al validării cererii: corpul (body) este eroarea brută Zod, nu un document de problemă RFC-7807 — cu toate acestea, este livrat sub Content-Type-ul application/problem+json.

2026-08 · Copierea linkurilor publice ale fișierelor

  • Dashboard: Fișierele publice de pe pagina de detalii a unui cod au acum un buton care le copiază linkul public în clipboard – gata de folosit ca URL de destinație al unui cod QR, atunci când o scanare trebuie să deschidă imediat un anumit document în loc de pagina de destinație cu lista de fișiere.
  • API: Endpoint-urile pentru fișiere (/v1/files) returnează în plus public_url. Câmpul este setat doar pentru fișierele cu visibility: public – fișierele private nu primesc o adresă publică.
  • Comportament: Linkul nu necesită autentificare și deschide fișierul direct în browser. Butonul Înlocuiește nu îl modifică, așa că un cod QR tipărit cu acest link rămâne valabil. Detalii: Fișiere și fișe tehnice.

2026-07 · Roluri de echipă: Colaborator fără ștergere & facturare admin

  • Nou: Rolul de membru Colaborator (fără ștergere) — creează și editează coduri QR, fișiere și Digital Product Passports, dar nu poate șterge resurse și nu poate genera chei API. Toate endpoint-urile distructive verifică rolul pe server (403).
  • Facturare: Upgrade-urile de plan și portalul de clienți Stripe (POST /v1/billing/checkout, GET /v1/billing/portal) sunt acum rezervate exclusiv pentru Administratori ai organizației — toate celelalte roluri văd o prezentare generală a planului în mod doar-citire.
  • Dashboard: Acțiunile nepermise de rolul curent sunt ascunse în interfață: un Vizualizator nu vede, de exemplu, butoanele de creare, editare sau ștergere, în timp ce listele, descărcările și statisticile rămân accesibile. Detalii: Echipă & Roluri.

2026-06 · Linkuri externe pe landing page-ul codului

  • Landing page: Landing page-ul unui cod găzduit de qr3 poate acum să listeze linkuri externe auto-găzduite ({ label, url }) pe lângă sau în locul fișierelor încărcate – de exemplu pentru fișe tehnice de pe propriul tău site.
  • API: POST/PATCH /v1/codes acceptă un array links (0–20 intrări, http(s), ≤ 2048 de caractere). Fiecare URL este verificat cu Google Web Risk; un URL nesigur returnează 422. Un array gol șterge toate linkurile.
  • Dashboard: Adaugă, reordonează și elimină linkuri în pagina de detalii a codului.
  • Securitate: Linkurile randate rămân sigure împotriva XSS (cu escape, doar http(s)), iar pagina își păstrează antetul noindex.

2026-04 · Analize în Dashboard per cod QR

  • Dashboard: Butonul de analize din lista de coduri QR deschide acum pagina de statistici a codului QR respectiv la /dashboard/codes/{id}.
  • Routing: Aliasul /dashboard/codes redirecționează în continuare către /dashboard, dar nu mai interceptează rutele detaliate precum /dashboard/codes/{id}.
  • API: Pagina de detalii încarcă codul QR direct prin GET /v1/codes/:id; astfel, aceasta nu mai depinde de limitele de paginare ale listei.
  • Teste: Testele de regresie acoperă redirecționarea aliasului și încărcarea directă a codului.

2026-04 · Dialog de ștergere în Dashboard pentru codurile QR

  • Dashboard: Pictograma de coș de gunoi din lista de coduri QR deschide acum un dialog React dedicat, în locul unui popup nativ de browser.
  • Feedback: După ștergere, apare o notificare de tip toast pentru succes sau eroare.
  • Teste: packages/dashboard/tests/dashboard.test.ts previne regresiile pentru confirm() în fluxul de ștergere a codurilor QR.
  • Dashboard: Codurile scurte (shortcodes) din lista de coduri QR pot fi acum accesate direct ca linkuri externe de redirecționare. Pictograma de link extern de lângă, de exemplu, wu3qaa deschide https://qr3.app/{shortCode} într-o filă nouă.
  • i18n: S-au adăugat textele pentru tooltip în germană și engleză.
  • Teste: packages/dashboard/tests/dashboard.test.ts protejează href-ul linkului, comportamentul de filă nouă, noopener noreferrer și pictograma împotriva regresiilor.

2026-04 · Rută Redirect-Worker pentru coduri QR dinamice

  • Fix: Codurile QR dinamice de la https://qr3.app/{shortCode} sunt procesate din nou de Redirect-Worker. Ruta de producție folosește acum qr3.app/*, deoarece rutele Cloudflare Workers nu acceptă parametri de cale de tip :code.
  • Securizare: Căile care nu se potrivesc sunt redirecționate către originea paginii de destinație (landing origin), astfel încât paginile normale precum /de/pricing să nu fie blocate de Redirect-Worker.
  • Teste: packages/redirect/tests/unit/redirect.test.ts verifică ruta wildcard, procesarea codurilor scurte și trecerea directă către origine (origin pass-through).

2026-04 · Prezentare generală scanări DPP în Workspace (Q3.4.2)

  • Nou: GET /v1/workspace/stats/dpp?days=30 — agreghează toate scanările dpp_scans din spațiul de lucru (workspace) al cheii API (active_dpps, scans_by_day, top_dpps cu nume produs/categorie).
  • Dashboard: Card pe pagina principală (/dashboard) cu diagramă cu bare pe 30 de zile + liste de top — în paralel cu cardurile de coduri QR.
  • Public: Link scurt de marketing GET /dpp/dpp_<id> (un singur segment) pentru demo-uri live, în paralel cu /dpp/{gtin}/{serial}.

2026-04 · Analize scanări DPP (Q3.4.1)

  • Nou: GET /v1/dpp/:id/stats?days=30 — scanări agregate ale resolverului public GS1 per DPP. Câmpuri: total_scans, period_scans, scans_by_day, top_countries, top_devices, top_representations.
  • Nou: Tabelul dpp_scans (migrarea 0011) — separat de scans (Redirect-Worker). Adresele IP sunt criptate (hashed) cu un salt rotativ zilnic, adresele IP brute neajungând niciodată în D1.
  • Dashboard: Card cu mini-grafic (SVG, fără bibliotecă de grafice) pe /dashboard/dpp/:dppId cu bare pe 30 de zile + defalcări Top 3. Stare goală (empty state) de îndată ce un DPP este live, dar nu are încă scanări.

2026-04 · Simulator live de conformitate UE (Q3.3.7)

  • Nou: POST /v1/dpp/:id/validate-update — simulează actualizări parțiale stateless (status, listă de piețe, …) fără persistență. Răspunsul conține eu_compliance + preview.changed_fields.
  • Dashboard: Card simulator în detaliile DPP (/dashboard/dpp/:dppId) — cipuri pentru DE/AT/FR/IT/ES/NL + personalizat, meniu derulant pentru status, Preview EU impact / Save changes / Reset. Non-blocking prin Remix useFetcher.
  • Securizare: Funcții ajutătoare (helpers) de simulator externalizate (readUpdatePatchFromForm, marketCountriesKey) + 18 teste unitare noi; remediere bug: introducerea unei singure valori non-ISO nu mai șterge lista de piețe.

2026-04 · Previzualizare live a conformității UE în formularul de creare (Q3.3.6)

  • Modificat: POST /v1/dpp/validate returnează în plus eu_compliance — același validator ca GET /v1/dpp/:id/eu-compliance, stateless înainte de salvare.
  • Dashboard: Previzualizare sub panoul de validare existent + un nou banner de protecție la salvare (Save-Guard) înainte de butoanele de trimitere, dacă există erori/avertismente nerezolvate (pluralizare i18n DE/EN).

2026-04 · Validator UE + UI pentru textile (Q3.3.4 + Q3.3.5)

  • Nou: Validator de conformitate UE cu 5 reguli pentru textile (TEXTILE_AGEC_REQUIRED, TEXTILE_MICROPLASTICS_CONSISTENCY, TEXTILE_SVHC_THRESHOLD, TEXTILE_GREENWASHING, TEXTILE_ESPR_READY).
  • Nou: GET /v1/dpp/:id/eu-compliance cu compliant / espr_ready / issues[] / summary.
  • Dashboard: Secțiune de conformitate UE în detaliile DPP (dale de rezumat, carduri de probleme grupate, insignă ESPR-Ready în antet).

2026-04 · Schemă DPP pentru textile (Q3.3.1–Q3.3.3)

  • Nou: Categoria textile cu lanț obligatoriu AGEC (țesut/tricotat → vopsit/imprimat → confecționare), per fibră origin_country + recycled_pct, svhc_substances[], ESPR-Opt-in (PEF, durată de viață, Recyclability).
  • Nou: Câmp de bază market_countries: string[] (ISO 3166-1 alpha-2) pentru toate categoriile DPP — controlează regulile AGEC specifice Franței și nota obligatorie pentru consumatorii francezi.
  • Nou: Șablon HTML pentru consumatori cu casetă de avertizare AGEC pentru microplastic, lanț de origine în 3 etape (pastile cu steaguri), listă SVHC, secțiune de Durability și Recyclability.
  • Migrare: 0010_dpp_market_countries (D1).

2026-04 · Import în masă (Bulk) DPP (Q3.2.1–Q3.2.5)

  • Nou: POST /v1/dpp/import acceptă CSV și XLSX (compatibil cu Workers prin SheetJS xlsx, pachet gzip de ~283 KB).
  • Scalat: limită bazată pe plan (Free 100 → Enterprise 10k) + db.batch() fragmentat (chunked) de câte 100 + limită de 5 MB pentru body.
  • Nou: Raport de erori în format CSV în câmpul errors_csv al răspunsului 201; GET /v1/dpp/import/templates/:category?format=csv|xlsx oferă șabloane gata de utilizare pentru baterii și textile.
  • Dashboard: Încărcare prin glisare și plasare (drag-and-drop) la /dashboard/dpp/import cu proxy de șabloane și descărcare CSV inline.

Modificări non-breaking — Extinderi LTS

Toate modificările menționate mai sus sunt aditive:

  • Clienții existenți ai POST /v1/dpp/validate ignoră noul câmp eu_compliance fără modificări.
  • Fluxurile battery existente rămân neschimbate.
  • market_countries este opțional și are valoarea implicită [].

Consultați Versiunea API pentru politica privind modificările incompatibile (breaking changes).