Skip to content

История на промените

История на промените

Подбрани акценти от последните версии. За пълните версии на API и политиката за несъвместими промени (Breaking Changes) вижте Версиониране на API & LTS политика.

Подробни промени по отделните крайни точки: OpenAPI спецификация и интерактивна API справка.


2026-08 · Keyset-курсор вече на всички списъчни крайни точки

  • Корекция: Корекцията на курсора за GET /v1/codes и GET /v1/dpp (вижте по-долу) вече е внедрена за всички останали списъци с пагинация чрез курсор: GET /v1/qr-codes/:id/comments, /v1/workspaces, /v1/gs1/identifiers, /v1/members, /v1/audit-logs, /v1/admin/orgs, /v1/admin/users и /v1/webhooks/:id/deliveries. Всички те се прелистваха само по created_at; редове с идентично времево клеймо (одит записи от групова операция, повторни опити за webhook, импортиране на членове) можеха да бъдат изгубени на следващата страница. Ключът за сортиране навсякъде вече е кортежът (created_at, id).
  • Промяна в API: В тези списъци meta.pagination.next_cursor отсега нататък също е непрозрачна стойност (base64url) вместо чисто времево клеймо; нечетливите курсори връщат 400, а старите курсори с времево клеймо ще продължат да се приемат преходно. Изключение прави GET /v1/webhooks/:id/deliveries: там next_cursor остава идентификаторът на последната доставка (неизвестен ID → първа страница). Клиентите, които връщат next_cursor непроменен — Табло, CLI, SDKs, MCP —, не трябва да променят нищо.
  • Въздействие: Не е необходима миграция. Ако са ви липсвали записи при прелистване в някой от тези списъци (напр. одит лог или лог на доставките в Таблото): те никога не са изчезвали — списъците вече ги показват изцяло.

2026-08 · Времевите клейма след редактиране и изтриване отново съответстват на OpenAPI

  • Корекция: След PATCH /v1/codes/{id} updated_at се връщаше във формат на SQLite без часова зона (2026-08-17 09:00:00), въпреки че OpenAPI спецификацията обещава format: date-time и създаването (POST) предоставя ISO времево клеймо (2026-08-17T09:00:00.000Z). Същото важеше за deleted_at/updated_at при меко изтриване (soft-delete), както и за пътищата за редактиране/изтриване на API-Keys, организации, Workspaces, членове, коментари и webhooks, освен това и за last_used_at на API-Keys и last_triggered_at на webhooks. Всички пътища за запис сега записват времето по ISO 8601 (UTC, T и Z).
  • Въздействие: Клиентите, които анализират updated_at с new Date(...) (SDKs, CLI, Табло), разчитаха формата с интервал като местно време — CLI показваше времето, изместено с локалното отместване при веднъж редактирани кодове (Виена: −2 h). Това е коригирано. Освен това миграцията на данни нормализира вече записаните стойности в стария формат към ISO, за да бъдат правилни сортирането и сравненията в смесени масиви. Без промени в имената на полетата или структурата на отговора.
  • Контекст: Същият клас грешка като двете корекции по-долу (изтичане на API-Key, времеви лимит за повторно сканиране): datetime('now') на SQLite записва YYYY-MM-DD HH:MM:SS, докато всички останали записващи механизми използват ISO 8601. Тест за защита на изходния код ще предотвратява нови случаи в бъдеще.

2026-08 · Пагинацията на списъци вече не губи партидни кодове

  • Корекция: GET /v1/codes и GET /v1/dpp извършваха пагинация само по created_at. Кодовете от POST /v1/codes/batch, POST /v1/dpp/batch и CSV/XLSX импорта обаче споделят едно и също времево клеймо — веднага щом дадена партида беше по-голяма от limit (по подразбиране 20), втората страница вече не връщаше останалите редове със същото времево клеймо. Кодовете съществуваха и бяха достъпни чрез GET /v1/codes/:id, но никога не се появяваха в списъка (Табло, CLI qr3 list, SDKs, MCP). Курсорът вече е набор от ключове (keyset) върху (created_at, id).
  • Промяна в API: meta.pagination.next_cursor отсега нататък е непрозрачна стойност (base64url) вместо чисто времево клеймо. Всеки, който връща курсора непроменен като ?cursor= — както правят Таблото, CLI, всички SDKs и MCP сървърът — не трябва да променя нищо. Старите курсори с времеви клейма ще продължат да се приемат временно; нечетливите курсори вече връщат 400 вместо мълчаливо да зареждат първата страница.
  • Въздействие: За тези, които след партидно импортиране са виждали по-малко кодове в списъка, отколкото са били създадени: Кодовете никога не са изчезвали — отсега нататък списъкът ги показва изцяло. Не е необходима миграция.

2026-08 · Повторните сканирания за сигурност отново се изпълняват на всеки 24 часа

  • Корекция: Периодичното повторно сканиране на целевите URL адреси и на връзките на лендинг страницата (Google Web Risk) пропускаше кодове, чието последно сканиране е било в същия календарен ден като 24-часовия времеви лимит — в зависимост от часа, повторното сканиране се забавяше с до още един ден. Времевият лимит сега се изчислява в същия ISO формат, в който се съхраняват времевите клейма за сканиране.
  • Въздействие: Целеви URL адрес, който бъде класифициран като опасен след последното сканиране, отново води до автоматично спиране на кода на пауза в рамките на документирания 24-часов прозорец. Без промени в API или формата на отговора.

2026-08 · API-Keys изтичат точно в момента на изтичане

  • Корекция: API-Key, чийто expires_at беше на същия ден, се приемаше до полунощ UTC. Изтичането вече се сравнява като времево клеймо вместо като низ — изтекъл ключ незабавно връща 401.
  • Контекст: expires_at се съхранява като ISO времево клеймо (2026-08-14T09:00:00Z), а сравняваната страна предоставяше формат с интервал (2026-08-14 09:00:00). Поради това директното сравнение на низове беше коректно само когато датите вече се различаваха.
  • Въздействие: Не е необходима миграция, форматът на отговора на GET /v1/api-keys остава непроменен. Нечетливите стойности за изтичане вече се считат за изтекли вместо за валидни.

2026-08 · Справка за API: Документирано управление на Tenant

  • OpenAPI: Спецификацията — а с това и интерактивната справка — вече документира организации (вкл. GET /v1/organizations/usage), Workspaces, членове и роли и Audit-Logs.
  • Billing: Прегледът на плановете (GET /v1/billing/plans) е публичен; Checkout (POST /v1/billing/checkout) и клиентският портал на Stripe (GET /v1/billing/portal) са посочени като крайни точки за администратори на организации.
  • Експорт на сканирания: Статистиките за сканиранията (GET /v1/codes/{id}/scans) и експортът на сурови данни (…/scans.csv, …/scans.xlsx) са напълно документирани — включително бележка за GDPR: ip_hash никога не се съдържа в експорта.
  • Поведение при грешки: Новодокументиран е и отговорът 400 при валидиране на заявка: тялото е суровата грешка от Zod, а не RFC-7807 документ за проблем — въпреки това той се доставя с Content-Type application/problem+json.

2026-08 · Копиране на публични връзки към файлове

  • Dashboard: Публичните файлове на страницата с детайли на кода вече имат бутон, който копира публичната им връзка в клипборда – готова за директно използване като целеви URL на QR код, когато сканирането трябва веднага да отвори конкретен документ вместо лендинг страницата със списъка с файлове.
  • API: Крайните точки за файлове (/v1/files) връщат допълнително public_url. Полето е зададено само при файлове с visibility: public – частните файлове не получават публичен адрес.
  • Поведение: Връзката не изисква влизане в акаунт и отваря файла директно в браузъра. Действието Замени не променя връзката, така че отпечатаният с нея код остава валиден. Подробности: Файлове и информационни листове.

2026-07 · Екипни роли: Сътрудник без изтриване и администраторско таксуване

  • Ново: Роля за членове Сътрудник (без изтриване) — създава и редактира QR кодове, файлове и Digital Product Passports, но не може да изтрива съдържание и да генерира API ключове. Всички деструктивни API endpoints проверяват ролята на сървърно ниво (403).
  • Таксуване: Надграждането на планове и достъпът до клиентския портал на Stripe (POST /v1/billing/checkout, GET /v1/billing/portal) вече са разрешени само за Администратори на организацията — всички останали роли виждат преглед на абонамента само за четене.
  • Dashboard: Действията, които не са разрешени за съответната роля, се скриват автоматично: потребител с роля Наблюдател например не вижда бутони за създаване, редактиране или изтриване, докато списъците, изтеглянията и статистиките остават достъпни. Подробности: Екип и роли.

2026-06 · Външни връзки на лендинг страницата на кода

  • Лендинг страница: Хостваната от qr3 лендинг страница на код вече може да изброява външни, самостоятелно хоствани връзки ({ label, url }) в допълнение към или вместо качените файлове – например за технически данни на собствения ви сайт.
  • API: POST/PATCH /v1/codes приемат масив links (0–20 записа, http(s), ≤ 2048 знака). Всеки URL се проверява с Google Web Risk; незащитен URL връща 422. Празен масив изтрива всички връзки.
  • Dashboard: Добавяне, пренареждане и премахване на връзки на страницата с детайли на кода.
  • Сигурност: Рендираните връзки остават XSS-защитени (екранирани, само http(s)) и страницата запазва своя noindex хедър.

2026-04 · Анализи в таблото за управление (Dashboard) за всеки QR код

  • Dashboard: Бутонът за анализи в списъка с QR кодове вече отваря страницата със статистика за съответния QR код на адрес /dashboard/codes/{id}.
  • Routing: Псевдонимът (alias) /dashboard/codes продължава да пренасочва към /dashboard, но вече не прихваща детайлни маршрути като /dashboard/codes/{id}.
  • API: Страницата с детайли зарежда QR кода директно чрез GET /v1/codes/:id; по този начин тя вече не зависи от ограниченията за пагинация на списъка.
  • Tests: Регресионните тестове покриват пренасочването на псевдонима и директното зареждане на кода.

2026-04 · Диалогов прозорец за изтриване на QR кодове в таблото (Dashboard)

  • Dashboard: Иконата с кошче в списъка с QR кодове вече отваря собствен React диалогов прозорец вместо системно изскачащо съобщение на браузъра.
  • Feedback: След изтриване се появява изскачащо известие (toast) за успех или грешка.
  • Tests: packages/dashboard/tests/dashboard.test.ts предотвратява регресии при confirm() в процеса на изтриване на QR кодове.

2026-04 · Тест на кратки връзки в таблото (Dashboard) за динамични QR кодове

  • Dashboard: Кратките кодове (shortcodes) в списъка с QR кодове вече могат да се кликват директно като външни връзки за пренасочване. Иконата за външна връзка до напр. wu3qaa отваря https://qr3.app/{shortCode} в нов раздел.
  • i18n: Добавени са текстове за подсказки (tooltips) на немски и английски език.
  • Tests: packages/dashboard/tests/dashboard.test.ts защитава href на връзката, поведението за нов раздел, noopener noreferrer и иконата срещу регресии.

2026-04 · Маршрут на Redirect-Worker за динамични QR кодове

  • Корекция: Динамичните QR кодове на адрес https://qr3.app/{shortCode} отново се обработват от Redirect-Worker. Производственият маршрут (production route) вече използва qr3.app/*, тъй като маршрутите на Cloudflare Workers не поддържат параметри на пътя от типа :code.
  • Укрепване: Несъвпадащите пътища се препращат към оригиналния хост (landing origin), за да не се блокират нормални страници като /de/pricing от Redirect-Worker.
  • Tests: packages/redirect/tests/unit/redirect.test.ts проверява маршрута с маска (wildcard route), обработката на кратки кодове и преминаването към оригиналния хост (origin pass-through).

2026-04 · Общ преглед на сканиранията на DPP в работното пространство (Q3.4.2)

  • Ново: GET /v1/workspace/stats/dpp?days=30 — агрегира всички dpp_scans на работното пространство на API ключа (active_dpps, scans_by_day, top_dpps с име на продукт/категория).
  • Dashboard: Карта на началната страница (/dashboard) с 30-дневна хистограма + списъци с най-популярните — успоредно с картите за QR кодове.
  • Public: Маркетингова кратка връзка GET /dpp/dpp_<id> (един сегмент) за демонстрации на живо, успоредно с /dpp/{gtin}/{serial}.

2026-04 · Анализи на сканиранията на DPP (Q3.4.1)

  • Ново: GET /v1/dpp/:id/stats?days=30 — агрегирани сканирания от публичния GS1-Resolver за всяко DPP. Полета: total_scans, period_scans, scans_by_day, top_countries, top_devices, top_representations.
  • Ново: Таблица dpp_scans (миграция 0011) — отделно от scans (Redirect-Worker). IP адресите се хешират с ежедневно ротираща сол (salt), суровите IP адреси никога не достигат до D1.
  • Dashboard: Мини диаграма (SVG, без външна библиотека за графики) на страница /dashboard/dpp/:dppId с 30-дневни стълбове + разбивка на топ 3. Празно състояние (empty state), веднага щом даден DPP е активен, но все още няма сканирания.

2026-04 · Симулатор за съответствие с изискванията на ЕС в реално време (Q3.3.7)

  • Ново: POST /v1/dpp/:id/validate-update — симулира частични актуализации без състояние (stateless) (статус, списък с пазари, …) без персистентност. Отговорът съдържа eu_compliance + preview.changed_fields.
  • Dashboard: Карта на симулатора в детайлите на DPP (/dashboard/dpp/:dppId) — чипове за DE/AT/FR/IT/ES/NL + персонализирани, падащо меню за статус, Preview EU impact / Save changes / Reset. Неблокиращо чрез Remix useFetcher.
  • Укрепване: Изнесени помощни функции за симулатора (readUpdatePatchFromForm, marketCountriesKey) + 18 нови единични теста (unit tests); отстранена грешка: въвеждането на единичен не-ISO код вече не изтрива списъка с пазари.

2026-04 · Преглед на съответствието с изискванията на ЕС в реално време във формата за създаване (Q3.3.6)

  • Променено: POST /v1/dpp/validate допълнително връща eu_compliance — същият валидатор като GET /v1/dpp/:id/eu-compliance, без състояние (stateless) преди записване.
  • Dashboard: Преглед под съществуващия панел за валидация + нов банер за защита при запис (Save-Guard) преди бутоните за изпращане, ако има нерешени грешки/предупреждения (i18n плурализация за DE/EN).

2026-04 · Валидатор за ЕС + Текстилен потребителски интерфейс (Q3.3.4 + Q3.3.5)

  • Ново: Валидатор за съответствие с изискванията на ЕС с 5 текстилни правила (TEXTILE_AGEC_REQUIRED, TEXTILE_MICROPLASTICS_CONSISTENCY, TEXTILE_SVHC_THRESHOLD, TEXTILE_GREENWASHING, TEXTILE_ESPR_READY).
  • Ново: GET /v1/dpp/:id/eu-compliance с compliant / espr_ready / issues[] / summary.
  • Dashboard: Секция за съответствие с изискванията на ЕС в детайлите на DPP (обобщаващи плочки, групирани карти с проблеми, бадж ESPR-Ready в заглавната част).

2026-04 · Схема за текстилен DPP (Q3.3.1–Q3.3.3)

  • Ново: Категория textile със задължителна верига по AGEC (тъкане/плетене → боядисване/печат → конфекциониране), за всяко влакно origin_country + recycled_pct, svhc_substances[], ESPR-Opt-in (PEF, експлоатационен живот, Recyclability).
  • Ново: Основно поле market_countries: string[] (ISO 3166-1 alpha-2) за всички категории DPP — управлява специфичните за Франция правила по AGEC и френската задължителна бележка за потребителите.
  • Ново: Потребителски HTML шаблон с предупредително поле за микропластмаса по AGEC, 3-степенна верига на произход (хапчета с флагове), списък със SVHC, секция за Durability и Recyclability.
  • Migration: 0010_dpp_market_countries (D1).

2026-04 · Масов импорт на DPP (Q3.2.1–Q3.2.5)

  • Ново: POST /v1/dpp/import приема CSV и XLSX (съвместим с Workers чрез SheetJS xlsx, ~283 KB gzip пакет).
  • Мащабирано: лимит на базата на абонаментния план (Free 100 → Enterprise 10k) + разделяне на части (chunked) db.batch() по 100 + 5 MB лимит на тялото (body limit).
  • Ново: Отчет за грешки като CSV в полето errors_csv на отговор 201; GET /v1/dpp/import/templates/:category?format=csv|xlsx предоставя готови шаблони за батерии и текстил.
  • Dashboard: Качване чрез влачене и пускане (drag-and-drop) на адрес /dashboard/dpp/import с прокси за шаблони и директно изтегляне на CSV.

Съвместими промени (Non-Breaking) — разширения на LTS

Всички горепосочени промени са адитивни (добавъчни):

  • Съществуващите клиенти на POST /v1/dpp/validate игнорират новото поле eu_compliance без промяна.
  • Съществуващите процеси за battery остават непроменени.
  • Полето market_countries е незадължително и по подразбиране е [].

Вижте Версиониране на API за политиката относно несъвместимите промени (Breaking-Change-Policy).