История на промените
История на промените
Подбрани акценти от последните версии. За пълните версии на 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, но никога не се появяваха в списъка (Табло, CLIqr3 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-Typeapplication/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. Неблокиращо чрез RemixuseFetcher. - Укрепване: Изнесени помощни функции за симулатора (
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 чрез SheetJSxlsx, ~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).