Przejdź do głównej zawartości

Changelog

Changelog

Wybrane najważniejsze zmiany z ostatnich wydań. Pełne wersje API i zasady wprowadzania zmian niekompatybilnych wstecz (Breaking-Change-Policy) znajdują się w sekcji Wersjonowanie API i polityka LTS.

Szczegółowe zmiany w poszczególnych punktach końcowych: Specyfikacja OpenAPI oraz interaktywna referencja API.


2026-08 · Kursor typu keyset teraz na wszystkich endpointach list

  • Poprawka: Poprawka kursora dla GET /v1/codes i GET /v1/dpp (patrz poniżej) została teraz wdrożona dla wszystkich pozostałych list z paginacją opartą na kursorze: GET /v1/qr-codes/:id/comments, /v1/workspaces, /v1/gs1/identifiers, /v1/members, /v1/audit-logs, /v1/admin/orgs, /v1/admin/users oraz /v1/webhooks/:id/deliveries. Wszystkie one stronicowały wyłącznie po created_at; wiersze o identycznym znaczniku czasu (wpisy audytowe operacji wsadowej, ponowne próby webhooków, importy członków) mogły zostać pominięte na kolejnej stronie. Kluczem sortowania jest teraz wszędzie krotka (created_at, id).
  • Zmiana w API: Na tych listach meta.pagination.next_cursor jest od teraz również wartością nieprzezroczystą (base64url) zamiast zwykłego znacznika czasu; nieczytelne kursory zwracają 400, a stare kursory oparte na znacznikach czasu będą tymczasowo nadal akceptowane. Wyjątek stanowi GET /v1/webhooks/:id/deliveries: tam next_cursor pozostaje identyfikatorem ostatniego doręczenia (nieznany identyfikator → pierwsza strona). Klienci, którzy zwracają next_cursor bez zmian — Dashboard, CLI, SDKs, MCP — nie muszą nic zmieniać.
  • Wpływ: Brak konieczności migracji. Jeśli na którejś z tych list (np. dzienniku audytu lub dzienniku doręczeń w Dashboardzie) brakowało Ci wpisów podczas stronicowania: nigdy nie zniknęły — od teraz listy wyświetlają je w całości.

2026-08 · Znaczniki czasu po edycji i usunięciu ponownie zgodne z OpenAPI

  • Poprawka: Po wykonaniu PATCH /v1/codes/{id} pole updated_at było zwracane w formacie SQLite bez strefy czasowej (2026-08-17 09:00:00), mimo że specyfikacja OpenAPI deklaruje format: date-time, a tworzenie (POST) zwraca znacznik czasu ISO (2026-08-17T09:00:00.000Z). To samo dotyczyło deleted_at/updated_at przy soft-delete, a także ścieżek edycji i usuwania kluczy API, organizacji, obszarów roboczych, członków, komentarzy i webhooków, jak również last_used_at dla kluczy API i last_triggered_at dla webhooków. Wszystkie ścieżki zapisu generują teraz znaczniki czasu w formacie ISO 8601 (UTC, T i Z).
  • Wpływ: Klienty, które parsują updated_at za pomocą new Date(...) (SDKs, CLI, Dashboard), odczytywały format ze spacją jako czas lokalny — CLI wyświetlało dla kodów, które były już edytowane, godzinę przesuniętą o lokalny offset (Wiedeń: −2 h). Zostało to naprawione. Dodatkowo migracja danych normalizuje już zapisane wartości w starym formacie do standardu ISO, aby sortowanie i porównania w mieszanych zbiorach danych działały poprawnie. Brak zmian w nazwach pól czy strukturze odpowiedzi.
  • Tło: Ta sama klasa błędu, co w przypadku dwóch poniższych poprawek (wygaśnięcie klucza API, punkt odcięcia ponownego skanowania): funkcja datetime('now') w SQLite zapisuje YYYY-MM-DD HH:MM:SS, podczas gdy wszystkie inne procesy zapisu używają ISO 8601. Test zabezpieczający w kodzie źródłowym zapobiegnie ponownemu wystąpieniu tego problemu w przyszłości.

2026-08 · Paginacja list nie gubi już kodów tworzonych wsadowo

  • Poprawka: Metody GET /v1/codes i GET /v1/dpp realizowały paginację wyłącznie na podstawie created_at. Jednak kody z POST /v1/codes/batch, POST /v1/dpp/batch oraz importu CSV/XLSX współdzielą jeden znacznik czasu — gdy tylko partia była większa niż limit (domyślnie 20), druga strona nie zwracała już pozostałych wierszy z tym samym znacznikiem czasu. Kody istniały i były dostępne przez GET /v1/codes/:id, ale nigdy nie pojawiały się na liście (Dashboard, CLI qr3 list, SDKs, MCP). Kursor jest teraz zestawem kluczy (keyset) opartym na (created_at, id).
  • Zmiana w API: meta.pagination.next_cursor jest od teraz wartością nieprzezroczystą (base64url) zamiast zwykłego znacznika czasu. Każdy, kto przekazuje kursor w niezmienionej formie jako ?cursor= — tak jak robią to Dashboard, CLI, wszystkie SDKs i serwer MCP — nie musi nic zmieniać. Stare kursory oparte na znacznikach czasu będą tymczasowo nadal akceptowane; nieczytelne kursory zwracają teraz błąd 400 zamiast po cichu zwracać pierwszą stronę.
  • Wpływ: Jeśli po imporcie wsadowym na liście widocznych było mniej kodów niż utworzono: kody te nigdy nie zniknęły — od teraz lista wyświetla je w całości. Brak konieczności migracji.

2026-08 · Ponowne skanowanie bezpieczeństwa znów działa w cyklu 24-godzinnym

  • Poprawka: Okresowe ponowne skanowanie docelowych adresów URL i linków stron docelowych (Google Web Risk) pomijało kody, których ostatnie skanowanie przypadało na ten sam dzień kalendarzowy, co 24-godzinny punkt odcięcia — w zależności od godziny ponowne skanowanie opóźniało się o maksymalnie kolejny dzień. Punkt odcięcia jest teraz obliczany w tym samym formacie ISO, w którym zapisywane są znaczniki czasu skanowania.
  • Wpływ: Docelowy adres URL, który po ostatnim skanowaniu zostanie sklasyfikowany jako niebezpieczny, ponownie powoduje automatyczne wstrzymanie kodu w udokumentowanym 24-godzinnym oknie. Brak zmian w API lub formacie odpowiedzi.

2026-08 · Klucze API wygasają w momencie wygaśnięcia

  • Poprawka: Klucz API, którego expires_at przypadał na ten sam dzień, był akceptowany do północy UTC. Wygaśnięcie jest teraz porównywane jako znacznik czasu, a nie jako ciąg znaków — wygasły klucz natychmiast zwraca 401.
  • Tło: expires_at jest zapisywany jako znacznik czasu ISO (2026-08-14T09:00:00Z), natomiast strona porównująca dostarczała format ze spacją (2026-08-14 09:00:00). Surowe porównanie ciągów znaków działało poprawnie tylko wtedy, gdy różniła się już sama data.
  • Wpływ: Brak konieczności migracji, format odpowiedzi GET /v1/api-keys pozostaje bez zmian. Nieczytelne wartości wygaśnięcia są teraz traktowane jako wygasłe, a nie jako ważne.

2026-08 · Referencja API: Zarządzanie tenantami udokumentowane

  • OpenAPI: Specyfikacja — a tym samym interaktywna referencja — dokumentuje teraz organizacje (w tym GET /v1/organizations/usage), workspaces, członków i role oraz dzienniki audytu.
  • Billing: Przegląd planów taryfowych (GET /v1/billing/plans) jest publiczny; proces płatności (POST /v1/billing/checkout) oraz portal klienta Stripe (GET /v1/billing/portal) są oznaczone jako punkty końcowe dla administratorów organizacji.
  • Eksport skanów: Statystyki skanowania (GET /v1/codes/{id}/scans) oraz eksport surowych danych (…/scans.csv, …/scans.xlsx) są w pełni udokumentowane — w tym uwaga dotycząca RODO: ip_hash nigdy nie jest zawarty w eksporcie.
  • Obsługa błędów: Nowo udokumentowana jest również odpowiedź 400 walidacji żądania: treść (body) to surowy błąd Zod, a nie dokument błędu RFC-7807 — niemniej jednak jest on dostarczany z nagłówkiem Content-Type application/problem+json.

2026-08 · Kopiowanie publicznych linków do plików

  • Dashboard: Pliki publiczne na stronie szczegółów kodu mają teraz przycisk, który kopiuje ich link publiczny do schowka – wystarczy wkleić go jako docelowy adres URL kodu QR, gdy zeskanowanie ma od razu otwierać konkretny dokument zamiast strony docelowej z listą plików.
  • API: Endpointy plików (/v1/files) zwracają dodatkowo public_url. Pole jest ustawiane tylko przy plikach z visibility: public – pliki prywatne nie mają publicznego adresu.
  • Zachowanie: Link nie wymaga logowania i otwiera plik bezpośrednio w przeglądarce. Opcja Zamień nie zmienia tego adresu, więc wydrukowany kod QR pozostaje ważny. Szczegóły: Pliki i karty danych.

2026-07 · Role zespołowe: Współtwórca bez usuwania i rozliczenia dla Administratorów

  • Nowość: Rola członka Współtwórca (bez usuwania) — tworzy i edytuje kody QR, pliki oraz Digital Product Passports, ale nie może niczego usuwać ani tworzyć kluczy API. Wszystkie destrukcyjne endpointy sprawdzają rolę po stronie serwera (403).
  • Rozliczenia: Ulepszenia planów i portal klienta Stripe (POST /v1/billing/checkout, GET /v1/billing/portal) są teraz zarezerwowane dla Administratorów organizacji — wszystkie pozostałe role widzą podgląd planu tylko do odczytu.
  • Dashboard: Akcje, na które nie pozwala własna rola, są ukrywane: Widz nie widzi na przykład przycisków do tworzenia, edycji ani usuwania; listy, pobieranie plików i statystyki pozostają widoczne. Szczegóły: Zespół i role.

2026-06 · Linki zewnętrzne na stronie docelowej kodu

  • Strona docelowa: Hostowana przez qr3 strona docelowa kodu może teraz wyświetlać zewnętrzne, samodzielnie hostowane linki ({ label, url }) obok przesłanych plików lub zamiast nich – na przykład dla kart katalogowych na Twojej własnej stronie.
  • API: POST/PATCH /v1/codes przyjmują tablicę links (0–20 wpisów, http(s), ≤ 2048 znaków). Każdy adres URL jest sprawdzany za pomocą Google Web Risk; niebezpieczny URL zwraca 422. Pusta tablica usuwa wszystkie linki.
  • Dashboard: Dodawanie, zmiana kolejności i usuwanie linków na stronie szczegółów kodu.
  • Bezpieczeństwo: Wyrenderowane linki pozostają bezpieczne pod kątem XSS (z zastosowaniem znaków ucieczki, tylko http(s)), a strona zachowuje swój nagłówek noindex.

2026-04 · Analityka dla pojedynczego kodu QR w Dashboardzie

  • Dashboard: Przycisk analityki na liście kodów QR otwiera teraz stronę statystyk danego kodu QR pod adresem /dashboard/codes/{id}.
  • Routing: Alias /dashboard/codes nadal przekierowuje na /dashboard, ale nie przechwytuje już tras szczegółowych, takich jak /dashboard/codes/{id}.
  • API: Strona szczegółów ładuje kod QR bezpośrednio przez GET /v1/codes/:id; dzięki temu nie zależy już od limitów stronicowania listy.
  • Testy: Testy regresyjne obejmują przekierowanie aliasu oraz bezpośrednie ładowanie kodu.

2026-04 · Okno dialogowe usuwania kodu QR w Dashboardzie

  • Dashboard: Ikona kosza na liście kodów QR otwiera teraz dedykowane okno dialogowe React zamiast natywnego wyskakującego okienka przeglądarki.
  • Informacja zwrotna: Po usunięciu pojawia się powiadomienie typu toast informujące o sukcesie lub błędzie.
  • Testy: Plik packages/dashboard/tests/dashboard.test.ts zapobiega regresjom związanym z confirm() w procesie usuwania kodu QR.

2026-04 · Test krótkiego linku dla dynamicznych kodów QR w Dashboardzie

  • Dashboard: Krótkie kody (shortcodes) na liście kodów QR można teraz klikać bezpośrednio jako zewnętrzne linki przekierowujące. Ikona linku zewnętrznego obok np. wu3qaa otwiera https://qr3.app/{shortCode} w nowej karcie.
  • i18n: Dodano teksty podpowiedzi (tooltips) dla języka niemieckiego i angielskiego.
  • Testy: Plik packages/dashboard/tests/dashboard.test.ts chroni przed regresjami atrybut linku href, zachowanie otwierania w nowej karcie, noopener noreferrer oraz ikonę.

2026-04 · Trasa Redirect-Worker dla dynamicznych kodów QR

  • Poprawka: Dynamiczne kody QR pod adresem https://qr3.app/{shortCode} są ponownie przetwarzane przez Redirect-Worker. Trasa produkcyjna używa teraz qr3.app/*, ponieważ trasy Cloudflare Workers nie obsługują parametrów ścieżki :code.
  • Zabezpieczenie: Niedopasowane ścieżki są przekazywane do landing origin, aby standardowe strony, takie jak /de/pricing, nie były blokowane przez Redirect-Worker.
  • Testy: Plik packages/redirect/tests/unit/redirect.test.ts weryfikuje trasę wieloznaczną (wildcard), przetwarzanie krótkich kodów oraz przekazywanie do origin.

2026-04 · Przegląd skanowań DPP w przestrzeni roboczej (Q3.4.2)

  • Nowość: GET /v1/workspace/stats/dpp?days=30 — agreguje wszystkie dpp_scans dla przestrzeni roboczej klucza API (active_dpps, scans_by_day, top_dpps z nazwą produktu/kategorią).
  • Dashboard: Karta na stronie głównej (/dashboard) z 30-dniowym wykresem słupkowym + listami najpopularniejszych — równolegle do kart kodów QR.
  • Publiczne: Krótki link marketingowy GET /dpp/dpp_<id> (jeden segment) do prezentacji na żywo, równolegle do /dpp/{gtin}/{serial}.

2026-04 · Analityka skanowań DPP (Q3.4.1)

  • Nowość: GET /v1/dpp/:id/stats?days=30 — zagregowane skanowania publicznego resolvera GS1 dla każdego DPP. Pola: total_scans, period_scans, scans_by_day, top_countries, top_devices, top_representations.
  • Nowość: Tabela dpp_scans (migracja 0011) — oddzielona od scans (Redirect-Worker). Adresy IP są haszowane przy użyciu codziennie rotowanej soli (salt), surowe adresy IP nigdy nie trafiają do D1.
  • Dashboard: Karta z miniwykresem (SVG, bez zewnętrznej biblioteki wykresów) pod adresem /dashboard/dpp/:dppId z 30-dniowymi słupkami + zestawieniem top 3. Stan pusty (empty state), gdy DPP jest aktywny, ale nie ma jeszcze skanowań.

2026-04 · Symulator zgodności z przepisami UE na żywo (Q3.3.7)

  • Nowość: POST /v1/dpp/:id/validate-update — symuluje częściowe aktualizacje w sposób bezstanowy (stateless) (status, lista rynków itp.) bez zapisywania danych. Odpowiedź zawiera eu_compliance + preview.changed_fields.
  • Dashboard: Karta symulatora w szczegółach DPP (/dashboard/dpp/:dppId) — znaczniki (chips) dla DE/AT/FR/IT/ES/NL + niestandardowe, lista rozwijana statusu, Preview EU impact / Save changes / Reset. Bez blokowania interfejsu dzięki Remix useFetcher.
  • Zabezpieczenie: Wydzielone funkcje pomocnicze symulatora (readUpdatePatchFromForm, marketCountriesKey) + 18 nowych testów jednostkowych; poprawka błędu: pojedyncza wartość wejściowa spoza standardu ISO nie powoduje już wyczyszczenia listy rynków.

2026-04 · Podgląd zgodności z przepisami UE na żywo w formularzu tworzenia (Q3.3.6)

  • Zmieniono: POST /v1/dpp/validate zwraca dodatkowo eu_compliance — ten sam walidator co GET /v1/dpp/:id/eu-compliance, działający bezstanowo przed zapisaniem.
  • Dashboard: Podgląd pod istniejącym panelem walidacji + nowy baner ostrzegawczy (Save-Guard-Banner) przed przyciskami zapisu, jeśli występują błędy/ostrzeżenia (pluralizacja i18n DE/EN).

2026-04 · EU-Validator + Textil-UI (Q3.3.4 + Q3.3.5)

  • Nowość: Walidator zgodności z przepisami UE z 5 regułami dla tekstyliów (TEXTILE_AGEC_REQUIRED, TEXTILE_MICROPLASTICS_CONSISTENCY, TEXTILE_SVHC_THRESHOLD, TEXTILE_GREENWASHING, TEXTILE_ESPR_READY).
  • Nowość: GET /v1/dpp/:id/eu-compliance z polami compliant / espr_ready / issues[] / summary.
  • Dashboard: Sekcja zgodności z przepisami UE w szczegółach DPP (kafelki podsumowania, pogrupowane karty problemów, plakietka ESPR-Ready w nagłówku).

2026-04 · Textil-DPP-Schema (Q3.3.1–Q3.3.3)

  • Nowość: Kategoria textile z obowiązkowym łańcuchem AGEC (tkanie/dzianie → barwienie/drukowanie → konfekcjonowanie), dla każdego włókna origin_country + recycled_pct, svhc_substances[], ESPR-Opt-in (PEF, żywotność, Recyclability).
  • Nowość: Podstawowe pole market_countries: string[] (ISO 3166-1 alpha-2) we wszystkich kategoriach DPP — steruje specyficznymi dla Francji regułami AGEC oraz francuską obowiązkową notą dla konsumentów.
  • Nowość: Szablon HTML dla konsumenta z ostrzeżeniem AGEC o mikroplastiku, 3-stopniowym łańcuchem pochodzenia (pigułki z flagami), listą SVHC oraz sekcjami Durability i Recyclability.
  • Migracja: 0010_dpp_market_countries (D1).

2026-04 · DPP-Bulk-Import (Q3.2.1–Q3.2.5)

  • Nowość: POST /v1/dpp/import akceptuje pliki CSV i XLSX (kompatybilne z Workers dzięki SheetJS xlsx, paczka gzip o rozmiarze ok. 283 KB).
  • Skalowanie: limit zależny od planu (Free 100 → Enterprise 10k) + wsadowe db.batch() po 100 + limit rozmiaru żądania (body) 5 MB.
  • Nowość: Raport o błędach jako CSV w polu errors_csv odpowiedzi 201; GET /v1/dpp/import/templates/:category?format=csv|xlsx dostarcza gotowe szablony dla baterii i tekstyliów.
  • Dashboard: Przesyłanie metodą przeciągnij i upuść (drag-and-drop) pod adresem /dashboard/dpp/import z proxy szablonów i pobieraniem CSV inline.

Zmiany nie-breaking — rozszerzenia LTS

Wszystkie wyżej wymienione zmiany mają charakter addytywny:

  • Istniejący klienci POST /v1/dpp/validate ignorują nowe pole eu_compliance bez konieczności wprowadzania zmian.
  • Istniejące procesy (battery-Flows) pozostają bez zmian.
  • Pole market_countries jest opcjonalne i domyślnie przyjmuje wartość [].

Zasady wprowadzania zmian niekompatybilnych wstecz (Breaking-Change-Policy) opisano w sekcji Wersjonowanie API.