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-10 · Kolory w Dashboardzie

  • Nowość: strona szczegółów kodu ma kartę Kolory: pierwszy plan i tło jako wartość szesnastkowa, przezroczyste tło, podgląd przez rzeczywistą ścieżkę obrazu. Kontrola jest taka sama jak w PATCH /v1/codes/{id}: pary krytyczne wymagają potwierdzenia, pary poniżej 1,5:1 nie dają się zapisać.
  • Przywrócenie czarnego na białym dostarcza we wszystkich czterech formatach znów te same bajty co bez kolorów. Kody bez kolorów się nie zmieniają.
  • Przezroczyste kody pojawiają się na szachownicy we wszystkich podglądach Dashboardu. Szczegóły: Kolory w Dashboardzie.

2026-10 · Kolory w PDF i EPS

  • Nowość: qr.pdf i qr.eps renderują fg i bg, jako parametry oraz jako zapisane kolory. Czerń i każda szarość są zapisywane jako skala szarości (tylko czarna płyta), a każdy inny kolor jako CMYK w pełnych procentach, na przykład 1F4E79 jako C74 M36 Y0 K53.
  • Tło jak w SVG: Gdy tylko zostanie wybrany kolor, za kodem i jego strefą ochronną znajduje się kryjący obszar, biały lub bg. bg=transparent nie renderuje tła. Tytuł pozostaje czarny, a płyta logo biała.
  • Brak zmian bez kolorów: Bez fg/bg i bez zapisanych kolorów oba formaty dostarczają te same bajty co wcześniej. Plik PDF paszportu produktu pozostaje bezbarwny.
  • Ograniczenia: brak profilu ICC, brak PDF/X. Szczegóły: Kolory w druku.

2026-09 · Statyczne kody bez pamięci podręcznej przekierowań, jednoczesne usuwanie

  • Zmieniono: Statyczne kody nie znajdują się już w pamięci podręcznej przekierowań. Wywołanie ich krótkiego linku (redirect_url) zawsze odczytuje aktualny stan. Dlatego po DELETE /v1/account statyczny kod nie przekierowuje już przy następnym wywołaniu (wcześniej trwało to do 24 godzin). Również zmiana taryfy działa natychmiast w przypadku statycznych kodów. Usuwanie konta czyści kody dynamiczne tak jak dotychczas. Wydrukowane kody statyczne zawierają swój cel bezpośrednio i ta zmiana ich nie dotyczy.
  • Naprawiono: Dwa jednoczesne żądania DELETE /v1/codes/:id do tego samego kodu zwracają raz 200, a raz 404. Webhook qr.deleted jest wysyłany dokładnie raz, wcześniej dwukrotnie.
  • Nowość: POST i DELETE /v1/codes/:id/logo odpowiadają kodem 409 (errors/conflict), jeśli inne żądanie jednocześnie zmieniło logo tego samego kodu, i wtedy nic nie zmieniają. Wcześniej przesłane logo mogło pozostać zapisane i nieużywane. Dwa jednoczesne żądania DELETE /v1/codes/:id/logo zwracają w obu przypadkach 200. Szczegóły: Logo.

2026-09 · TypeScript-SDK 1.2.0

  • Nowość w @qr3/sdk 1.2.0: client.codes.update() przyjmuje appearance i zwraca wyniki testu kontrastu jako issues w wyniku; przy braku uwag pole to nie występuje. client.codes.imageUrl() przyjmuje fg, bg i ecc. Każdy kod zwracany przez API (get, list, create, update, batchCreate) zawiera title i appearance.
  • Aktualizacja: npm install @qr3/sdk@latest. Python, Go i PHP wkrótce. Szczegóły: SDKs & CLI oraz Zapisywanie kolorów w kodzie.

2026-09 · Zmieniony czas wygaśnięcia obowiązuje w ciągu około minuty

  • Naprawiono: Żądanie PATCH na expires_at czyści teraz pamięć podręczną przekierowań kodu. Nowy czas wygaśnięcia obowiązuje dzięki temu w ciągu około minuty, zamiast dopiero do 24 godzin później. Poprzednio usunięty lub przesunięty czas wygaśnięcia nadal zwracał 410 przez maksymalnie 24 godziny, a czas wygaśnięcia ustawiony na “teraz” pozwalał na dalsze działanie przekierowania przez maksymalnie 24 godziny.
  • Naprawiono: Kod utworzony z expires_at wygasa terminowo również wtedy, gdy wygaśnięcie następuje w ciągu pierwszych 24 godzin.
  • Naprawiono: Jeśli kod zostanie usunięty podczas przesyłania lub usuwania jego logo, POST oraz DELETE /v1/codes/:id/logo odpowiadają statusem 404 i nie modyfikują usuniętego kodu, podobnie jak miało to już miejsce w przypadku PATCH.
  • Naprawiono: Również kod statyczny, którego krótki link (redirect_url) został wywołany, znajduje się w pamięci podręcznej przekierowań. Modyfikacja, wstrzymanie i usunięcie również go teraz czyszczą, a nie tylko w przypadku kodów dynamicznych.

2026-09 · Zapisywanie kolorów dla kodu

  • Nowość: PATCH /v1/codes/:id akceptuje appearance z foreground_color i background_color (#RRGGBB, tło również transparent). qr.svg i qr.png rysują zapisane kolory bez żadnych parametrów; parametr zapytania, taki jak ?fg=000000, nadal ma pierwszeństwo. PDF i EPS będą rysować kolory dopiero w późniejszej wersji.
  • Kontrola kontrastu: Para poniżej 1,5:1 zwraca 422. Słabsze pary są zapisywane i zgłaszane w meta.issues jako warning lub critical; przezroczyste tło jest zawsze traktowane jako critical, nigdy blokowane.
  • Scalanie: Pominięte pola zachowują swoją zapisaną wartość, null resetuje ustawienia. Jednoczesne zmiany w tym samym kodzie nie nadpisują się już wzajemnie.
  • W każdej odpowiedzi kodu: appearance znajduje się w każdej odpowiedzi kodu oraz w webhookach qr.created i qr.updated. POST, proces wsadowy (batch) oraz import odrzucają je z błędem 422.
  • Brak zmian dla istniejących kodów: Bez zapisanych kolorów każdy kod dostarcza te same bajty co wcześniej. Szczegóły: Zapisywanie kolorów dla kodu.

2026-09 · Kolory i korekcja błędów jako parametry ścieżek obrazu

  • Nowość: Wszystkie cztery ścieżki obrazu akceptują fg (kolor pierwszego planu), bg (kolor tła lub transparent) oraz ecc (korekcja błędów L, M, Q, H). SVG i PNG renderują kolory; PDF i EPS akceptują je, ale będą je renderować dopiero w późniejszym wydaniu. ecc działa we wszystkich czterech formatach, a logo nadal wymusza H.
  • Przezroczystość: bg=transparent zwraca SVG bez tła oraz PNG z prawdziwym kanałem alfa. Podłoże musi być jasne i pozostawiać wolną strefę ciszy.
  • Nigdy nie powoduje błędu: Nieprawidłowe wartości są ignorowane; obraz jest wtedy zwracany dokładnie tak samo, jak bez parametrów.
  • Pamięć podręczna: Każdy skuteczny parametr zwraca Cache-Control: public, max-age=300 zamiast 24 godzin dla obrazu standardowego.
  • Brak zmian w zachowaniu bez parametrów: Każdy istniejący kod zwraca we wszystkich czterech formatach te same bajty co wcześniej.
  • Dostępne w każdym planie. Szczegóły: Kolory i korekcja błędów.
  • Rozszerzenie: qr.pdf i qr.eps osadzają teraz ustawione logo dokładnie tak samo jak qr.svg i qr.png (patrz poniżej) — jako osadzony obraz (PDF poprzez Image XObject, EPS poprzez słownik obrazu w PostScript, tam tylko z %%LanguageLevel: 3), wyśrodkowany na tym samym obszarze, z tym samym podniesieniem korekcji błędów do H. Oba formaty do tej pory nie dostarczały logo; zostało to teraz naprawione.
  • Pamięć podręczna: Przy ustawionym logo również qr.pdf i qr.eps zwracają teraz Cache-Control: public, max-age=300 zamiast zwykłych 24 godzin — dokładnie tak samo jak SVG/PNG.
  • Wariant awaryjny: Jeśli sam obraz logo nie może zostać przetworzony (na przykład uszkodzony zapisany obiekt), korekcja błędów pozostaje na poziomie H, ale zarezerwowany obszar pozostaje pusty zamiast obrazu — nigdy nie powoduje to błędu serwera.
  • Brak zmian w zachowaniu bez logo: Kody bez logo nadal dostarczają qr.pdf/ qr.eps w identycznej postaci bajtowej, z niezmienioną 24-godzinną pamięcią podręczną.
  • Szczegóły i wskazówki dotyczące druku: Logo w kodzie QR.

2026-09 · Logo w kodzie QR — Dashboard i API

  • Nowość: Kod może teraz zawierać logo na środku. W Dashboardzie strona szczegółów kodu tworzy dedykowaną kartę logo: Wybierz logo, przy pierwszym dodaniu lub przy usuwaniu potwierdź ostrzeżenie z wymaganym polem wyboru (obie czynności zmieniają wzór punktowy), a następnie Prześlij logo/Usuń logo. Zastąpienie nie wymaga potwierdzenia — zmienia się tylko obraz, a nie wzór. Rola viewer widzi status i podgląd, ale nie ma dostępu do żadnej z trzech akcji.
  • API: POST /v1/codes/{id}/logo (pole typu multipart file; PNG, JPEG lub WebP, maksymalnie 1 MB, SVG jest odrzucane) tworzy lub zastępuje logo; DELETE /v1/codes/{id}/logo usuwa je i jest idempotentne. Zbyt duży obraz zwraca 413, nieobsługiwany format 422, a rola viewer zwraca 403.
  • Renderowanie: qr.svg i qr.png osadzają logo jako rzeczywiste piksele (512 × 512, znormalizowane) i w tym celu podnoszą poziom korekcji błędów do H. Dodanie i usunięcie zmieniają tym samym wzór punktowy (M ↔ H), natomiast zastąpienie go nie zmienia. qr.pdf i qr.eps nie osadzają logo i pozostają bez zmian. Wydrukowany już kod działa w każdym przypadku dalej, ponieważ zakodowany cel nie zależy od logo — ponowny wydruk jest konieczny tylko wtedy, gdy chce się zobaczyć (nowy) wygląd logo również na materiale, i nie należy przy tym mieszać starych i nowych plików do druku.
  • Pamięć podręczna: Przy ustawionym logo qr.svg i qr.png zwracają Cache-Control: public, max-age=300 zamiast zazwyczaj stosowanych 24 godzin. Szczegóły, limity i wskazówki dotyczące drukowania: Logo w kodzie QR.

2026-08 · operationId dla wszystkich 75 operacji oraz instrukcja „kiedy używać” dla agentów

  • Uzupełnienie: Wszystkie 75 operacji w specyfikacji OpenAPI posiada teraz operationId — listCodes, createCode, getCodeStats, archiveWorkspace i tak dalej. Do tej pory tego pola brakowało we wszystkich miejscach, przez co każdy generator musiał wyprowadzać nazwę metody z metody HTTP i ścieżki (postV1Codes). Takie nazwy są powiązane ze ścieżką i zmieniają się przy każdej modyfikacji ścieżki. Format nazw jest taki sam we wszystkich 75 miejscach: list/get/create/update/replace/delete, w innych przypadkach czasownik określający operację biznesową (validateDpp, registerGs1Identifier, pingWebhook). Czasownik wynika z logiki biznesowej, a nie z metody HTTP — archiveWorkspace to DELETE, a importDpps to POST.
  • Wpływ na samodzielnie generowane klienty: Każdy, kto generuje swoje SDK ze specyfikacji, przy kolejnym uruchomieniu otrzyma zmienione nazwy metod (postV1Codes → createCode). Taki jest cel tej zmiany, ale wiąże się to ze zmianą nazw w zewnętrznym kodzie — stąd ta wyraźna wzmianka. Ścieżki, parametry, formaty odpowiedzi i kody statusu pozostają bez zmian; oficjalne SDK, CLI i serwery MCP nie są objęte tą zmianą.
  • Wprowadzenie dla agentów: https://qr3.app/llms.txt zawiera sekcję ## When to use qr3.app — sześć zadań zamiast sześciu funkcji, plus zdanie określające, do czego qr3.app nie jest odpowiednim narzędziem. Te same informacje serwer MCP przekazuje teraz podczas nawiązywania połączenia (handshake): initialize wysłane do https://mcp.qr3.app/mcp odpowiada polem instructions (wcześniej: jedenaście narzędzi bez żadnego przyporządkowania). Zawiera również informację, które wywołania wymagają klucza API — initialize oraz tools/list nie, natomiast każde tools/call tak.
  • Poprawki w llms.txt: Cztery informacje zostały zweryfikowane z produkcją i okazały się niepoprawne: (1) SDK dla języka Python qr3app nie jest opublikowane w PyPI — linijka z pip install została usunięta bez zamiennika; (2) nagłówek Accept: text/markdown dotyczy strony głównej i bloga, a nie każdej strony renderowanej po stronie serwera; (3) adres kontaktowy to [email protected], również w JSON-LD strony głównej; (4) /de/security/ to przekierowanie do kotwicy, a nie osobna strona. Nowy link: docs.qr3.app/de/skills/.
  • Zabezpieczenie: Trzy asercje w openapi-spec.test.ts — kompletność, unikalność, lowerCamelCase — każda zweryfikowana za pomocą mutacji. Dziewięć kolejnych testów utrwala te cztery poprawione informacje, aby zapobiec ich ponownemu pojawieniu się.
  • Znane ograniczenie: Dwie z 75 operacji są opisane w specyfikacji, ale zwracają kod 404 (GET /v1/codes/{id}/stats oraz GET /v1/account). Otrzymały one tutaj nazwę i utracą ją ponownie, gdy tylko zapadnie decyzja, czy zostaną zaimplementowane, czy usunięte.

2026-08 · Downgrade’y planów i anulowania subskrypcji wpływają teraz również na limity

  • Poprawka: Webhook Stripe przy zmianie planu i anulowaniu subskrypcji zapisywał tylko nazwę planu, a nie cztery kolumny limitów organizacji (max_workspaces, max_members, max_dynamic_codes, max_scans_per_month). Ponieważ egzekwowanie limitów przyjmuje wartość maksymalną z zapisanej wartości oraz poziomu bazowego planu (baseline), zredukowana lub anulowana organizacja zachowywała swoje stare, wyższe limity — downgrade był bezskuteczny. Webhook ustawia teraz te kolumny przy każdej rzeczywistej zmianie planu na poziom bazowy nowego planu, a przy anulowaniu na poziom bazowy planu Free — dokładnie tak, jak robi to już panel administracyjny.
  • Zachowanie: Rutynowe aktualizacje subskrypcji (przedłużenie, metoda płatności, proporcjonalne rozliczenie) nadal nie wpływają na limity; indywidualnie przyznane wyższe limity pozostają bez zmian. Dopiero rzeczywista zmiana planu resetuje je do poziomu bazowego nowego planu.
  • Wpływ: Brak zmian w API lub formacie odpowiedzi. Organizacje, których downgrade nastąpił przed tą poprawką, zachowują stare wartości, dopóki nie wejdzie w życie kolejna zmiana planu lub wsparcie techniczne ich nie dostosuje.

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.