Pular para o conteúdo

Changelog

Changelog

Destaques selecionados dos lançamentos mais recentes. Para versões completas da API e política de alterações incompatíveis (breaking changes), consulte a Versão da API e Política LTS.

Alterações detalhadas em endpoints individuais: Especificação OpenAPI e referência interativa da API.


2026-08 · Cursor keyset agora em todos os endpoints de lista

  • Fix: A correção do cursor para GET /v1/codes e GET /v1/dpp (veja abaixo) foi agora implementada em todas as demais listas paginadas por cursor: GET /v1/qr-codes/:id/comments, /v1/workspaces, /v1/gs1/identifiers, /v1/members, /v1/audit-logs, /v1/admin/orgs, /v1/admin/users e /v1/webhooks/:id/deliveries. Todas paginavam apenas por created_at; linhas com carimbo de data/hora idêntico (entradas de auditoria de uma operação em lote, novas tentativas de webhook, importações de membros) podiam se perder na página seguinte. A chave de ordenação agora é, em todas elas, a tupla (created_at, id).
  • Alteração na API: Nestas listas, meta.pagination.next_cursor passa a ser também um valor opaco (base64url) em vez de um carimbo de data/hora simples; cursores ilegíveis retornam 400, cursores antigos de carimbo de data/hora continuarão sendo aceitos temporariamente. Exceção GET /v1/webhooks/:id/deliveries: ali, next_cursor continua sendo o ID da última entrega (ID desconhecido → primeira página). Os clientes que retornam next_cursor sem alterações — Painel, CLI, SDKs, MCP — não precisam alterar nada.
  • Impacto: Nenhuma migração é necessária. Se sentiu falta de entradas ao paginar numa destas listas (por exemplo, log de auditoria ou log de entregas no Painel): elas nunca desapareceram — as listas passam a mostrá-las na totalidade a partir de agora.

2026-08 · Timestamps novamente em conformidade com a OpenAPI após edição e exclusão

  • Fix: Após PATCH /v1/codes/{id}, o updated_at retornava no formato SQLite sem fuso horário (2026-08-17 09:00:00), embora a especificação OpenAPI especifique format: date-time e a criação (POST) forneça o timestamp ISO (2026-08-17T09:00:00.000Z). O mesmo se aplicava a deleted_at/updated_at na exclusão lógica (soft-delete), bem como aos caminhos de edição e exclusão de API-Keys, organizações, workspaces, membros, comentários e webhooks, além de last_used_at de API-Keys e last_triggered_at de webhooks. Todos os caminhos de gravação agora registram em ISO 8601 (UTC, T e Z).
  • Impacto: Clientes que analisam updated_at com new Date(...) (SDKs, CLI, Painel) liam o formato com espaço como hora local — a CLI mostrava, para códigos que já haviam sido editados, a hora deslocada pelo offset local (Viena: −2 h). Isso foi corrigido. Além disso, uma migração de dados normaliza os valores já salvos no formato antigo para ISO, para que a ordenação e as comparações em registros mistos funcionem corretamente. Nenhuma alteração nos nomes dos campos ou na estrutura de resposta. Isso foi corrigido. Além disso, uma migração de dados normaliza os valores já salvos no formato antigo para ISO, para que a ordenação e as comparações em registros mistos funcionem corretamente. Nenhuma alteração nos nomes dos campos ou na estrutura de resposta.
  • Contexto: Mesma classe de erro que as duas correções abaixo (expiração de API-Key, limite de re-scan): o datetime('now') do SQLite grava YYYY-MM-DD HH:MM:SS, enquanto todos os outros gravadores usam ISO 8601. Um teste de proteção no código-fonte evitará novas ocorrências no futuro.

2026-08 · Paginação de listas não perde mais códigos em lote

  • Fix: GET /v1/codes e GET /v1/dpp paginavam apenas por created_at. No entanto, os códigos de POST /v1/codes/batch, POST /v1/dpp/batch e da importação de CSV/XLSX compartilham um único carimbo de data/hora — assim que um lote era maior que limit (padrão 20), a segunda página não retornava mais as linhas restantes do mesmo carimbo de data/hora. Os códigos existiam e estavam acessíveis via GET /v1/codes/:id, mas nunca apareciam na lista (Painel, CLI qr3 list, SDKs, MCP). O cursor agora é um keyset sobre (created_at, id).
  • Alteração na API: meta.pagination.next_cursor agora é um valor opaco (base64url) em vez de um carimbo de data/hora simples. Quem retorna o cursor inalterado como ?cursor= — como o Painel, CLI, todos os SDKs e o servidor MCP fazem — não precisa alterar nada. Cursores antigos de carimbo de data/hora continuarão sendo aceitos temporariamente; cursores ilegíveis agora retornam 400 em vez de entregar silenciosamente a primeira página.
  • Impacto: Se você viu menos códigos na lista após uma importação em lote do que os que foram criados: os códigos nunca sumiram — a lista agora os exibe por completo. Nenhuma migração é necessária.

2026-08 · Re-scans de segurança voltam a ser executados a cada 24 horas

  • Fix: O re-escaneamento periódico de URLs de destino e links de landing pages (Google Web Risk) ignorava códigos cujo último escaneamento ocorria no mesmo dia civil que o cutoff de 24 horas — dependendo do horário, o re-escaneamento era atrasado em até mais um dia. O cutoff agora é calculado no mesmo formato ISO em que os timestamps de escaneamento são armazenados.
  • Impacto: Uma URL de destino classificada como insegura após o último escaneamento resultará novamente na pausa automática do código dentro da janela documentada de 24 horas. Sem alterações na API ou no formato de resposta.

2026-08 · Chaves de API expiram no momento exato de expiração

  • Fix: Uma chave de API cujo expires_at ocorria no mesmo dia continuava sendo aceita até a meia-noite UTC. A expiração agora é comparada como um timestamp em vez de uma string — uma chave expirada retorna imediatamente 401.
  • Contexto: O expires_at é armazenado como um timestamp ISO (2026-08-14T09:00:00Z), mas o lado da comparação fornecia o formato com espaço (2026-08-14 09:00:00). Por isso, a comparação direta de strings só funcionava corretamente quando a data em si já era diferente.
  • Impacto: Nenhuma migração é necessária, o formato de resposta de GET /v1/api-keys permanece inalterado. Valores de expiração ilegíveis agora são considerados expirados em vez de válidos.

2026-08 · Referência da API: Gestão de Tenants documentada

  • OpenAPI: A especificação — e, portanto, a referência interativa — agora documenta Organizações (incl. GET /v1/organizations/usage), Workspaces, Membros e Funções e Logs de Auditoria.
  • Faturamento: A visão geral dos planos (GET /v1/billing/plans) é pública; o checkout (POST /v1/billing/checkout) e o portal do cliente Stripe (GET /v1/billing/portal) estão identificados como endpoints para administradores da organização.
  • Exportação de Scans: As estatísticas de scan (GET /v1/codes/{id}/scans) e a exportação de dados brutos (…/scans.csv, …/scans.xlsx) estão totalmente documentadas — incluindo o aviso de RGPD: o ip_hash nunca está incluído na exportação.
  • Comportamento de erro: Também está documentada a resposta 400 da validação de requisições: o corpo é o erro Zod bruto, não um documento de problema RFC-7807 — no entanto, é fornecido sob o Content-Type application/problem+json.
  • Dashboard: Os arquivos públicos na página de detalhes do código agora têm um botão que copia o seu link público para a área de transferência – utilizável diretamente como URL de destino de um QR Code, caso um escaneamento precise abrir imediatamente um documento específico em vez da landing page com la lista de arquivos.
  • API: Os endpoints de arquivos (/v1/files) agora também retornam public_url. Este campo é definido apenas para arquivos com visibility: public – arquivos privados não recebem um endereço público.
  • Comportamento: O link não requer login e abre o arquivo diretamente no navegador. A substituição do arquivo mantém o link inalterado, portanto, um código impresso com ele continua válido. Detalhes: Arquivos e Fichas Técnicas.

2026-07 · Funções de Equipe: Editor sem exclusão e Faturamento de Administrador

  • Novo: Nova função de membro Editor (sem exclusão) — cria e edita QR Codes, arquivos e Digital Product Passports, mas não pode excluir nada nem criar API-Keys. Todos os endpoints destrutivos verificam a função no lado do servidor (403).
  • Faturamento: Upgrades de plano e o portal do cliente Stripe (POST /v1/billing/checkout, GET /v1/billing/portal) agora são reservados para administradores da organização — todas as outras funções visualizam uma visão geral do plano em modo somente leitura.
  • Dashboard: As ações não permitidas pela função do usuário são ocultadas: um Visualizador, por exemplo, não vê botões para criar, editar ou excluir; listas, downloads e estatísticas continuam visíveis. Detalhes: Equipe e Funções.
  • Landing page: A landing page de um código hospedada pela qr3 agora pode listar links externos hospedados pelo próprio usuário ({ label, url }) – além de ou em vez de arquivos enviados, por exemplo, para fichas técnicas em seu próprio site.
  • API: POST/PATCH /v1/codes aceitam um array links (0–20 itens, http(s), ≤ 2048 caracteres). Cada URL é verificada com o Google Web Risk; uma URL insegura retorna 422. Um array vazio remove todos os links.
  • Dashboard: Adicionar, ordenar e remover links na página de detalhes do código.
  • Segurança: Os links renderizados permanecem protegidos contra XSS (escapados, apenas http(s)) e a página mantém seu cabeçalho noindex.

2026-04 · Análise do Dashboard por QR Code

  • Dashboard: O botão de análise na lista de QR Codes agora abre a página de estatísticas do respectivo QR Code em /dashboard/codes/{id}.
  • Roteamento: O alias /dashboard/codes continua redirecionando para /dashboard, mas não intercepta mais rotas de detalhes como /dashboard/codes/{id}.
  • API: A página de detalhes carrega o QR Code diretamente via GET /v1/codes/:id; com isso, ela não depende mais dos limites de paginação da lista.
  • Testes: Testes de regressão cobrem o redirecionamento do alias e o carregamento direto do código.

2026-04 · Diálogo de exclusão do Dashboard para QR Codes

  • Dashboard: O ícone de lixeira na lista de QR Codes agora abre um diálogo React próprio em vez de um pop-up nativo do navegador.
  • Feedback: Após a exclusão, uma notificação toast é exibida para indicar sucesso ou erro.
  • Testes: packages/dashboard/tests/dashboard.test.ts evita regressões no confirm() no fluxo de exclusão de QR Codes.
  • Dashboard: Os shortcodes na lista de QR Codes agora são clicáveis diretamente como links de redirecionamento externos. O ícone de link externo ao lado de, por exemplo, wu3qaa abre https://qr3.app/{shortCode} em uma nova aba.
  • i18n: Textos de dica de ferramenta (tooltips) adicionados para alemão e inglês.
  • Testes: packages/dashboard/tests/dashboard.test.ts protege o href do link, o comportamento de nova aba, noopener noreferrer e o ícone contra regressões.

2026-04 · Rota do Redirect-Worker para QR Codes dinâmicos

  • Fix: Correção: QR Codes dinâmicos em https://qr3.app/{shortCode} voltam a ser processados pelo Redirect-Worker. A rota de produção agora usa qr3.app/*, pois as rotas do Cloudflare Workers não suportam parâmetros de caminho :code.
  • Robustez: Caminhos que não correspondem são repassados para a origem da landing page, para que páginas normais como /de/pricing não sejam bloqueadas pelo Redirect-Worker.
  • Testes: packages/redirect/tests/unit/redirect.test.ts verifica a rota curinga (wildcard), o processamento de shortcodes e o redirecionamento para a origem (pass-through).

2026-04 · Visão geral de escaneamentos de DPP do Workspace (Q3.4.2)

  • Novo: GET /v1/workspace/stats/dpp?days=30 — agrega todos os dpp_scans do workspace da API-Key (active_dpps, scans_by_day, top_dpps com nome do produto/categoria).
  • Dashboard: Card na página inicial (/dashboard) com gráfico de barras de 30 dias + listas dos mais acessados — em paralelo com os cards de QR Codes.
  • Público: Link curto de marketing GET /dpp/dpp_<id> (um segmento) para demonstrações ao vivo, em paralelo com /dpp/{gtin}/{serial}.

2026-04 · Análise de escaneamentos de DPP (Q3.4.1)

  • Novo: GET /v1/dpp/:id/stats?days=30 — escaneamentos agregados do resolvedor GS1 público por DPP. Campos: total_scans, period_scans, scans_by_day, top_countries, top_devices, top_representations.
  • Novo: Tabela dpp_scans (migração 0011) — separada de scans (Redirect-Worker). Os endereços IP são hasheados com um salt rotativo diário, IPs brutos nunca chegam ao D1.
  • Dashboard: Card de mini-gráfico (SVG, sem biblioteca de gráficos) em /dashboard/dpp/:dppId com barras de 30 dias + detalhamento dos top 3. Estado vazio (empty state) assim que um DPP estiver ativo, mas ainda não tiver escaneamentos.

2026-04 · Simulador de conformidade da UE ao vivo (Q3.3.7)

  • Novo: POST /v1/dpp/:id/validate-update — simula atualizações parciais stateless (status, lista de mercados, …) sem persistência. A resposta contém eu_compliance + preview.changed_fields.
  • Dashboard: Card do simulador nos detalhes do DPP (/dashboard/dpp/:dppId) — chips para DE/AT/FR/IT/ES/NL + personalizado, menu suspenso de status, Preview EU impact / Save changes / Reset. Não bloqueante via Remix useFetcher.
  • Robustez: Helpers do simulador extraídos (readUpdatePatchFromForm, marketCountriesKey) + 18 novos testes unitários; correção de bug: entrada única não ISO não limpa mais a lista de mercados.

2026-04 · Visualização de conformidade da UE ao vivo no formulário de criação (Q3.3.6)

  • Alterado: POST /v1/dpp/validate agora também retorna eu_compliance — o mesmo validador de GET /v1/dpp/:id/eu-compliance, stateless antes de salvar.
  • Dashboard: Visualização abaixo do painel de validação existente + novo banner de proteção ao salvar (Save-Guard-Banner) antes dos botões de envio quando houver erros/avisos pendentes (pluralização i18n DE/EN).

2026-04 · Validador da UE + UI de Têxteis (Q3.3.4 + Q3.3.5)

  • Novo: Validador de conformidade da UE com 5 regras de têxteis (TEXTILE_AGEC_REQUIRED, TEXTILE_MICROPLASTICS_CONSISTENCY, TEXTILE_SVHC_THRESHOLD, TEXTILE_GREENWASHING, TEXTILE_ESPR_READY).
  • Novo: GET /v1/dpp/:id/eu-compliance com compliant / espr_ready / issues[] / summary.
  • Dashboard: Seção de conformidade da UE nos detalhes do DPP (blocos de resumo, cards de problemas agrupados, selo ESPR-Ready no cabeçalho).

2026-04 · Esquema de DPP para Têxteis (Q3.3.1–Q3.3.3)

  • Novo: Categoria textile com cadeia obrigatória AGEC (tecelagem/tricô → tingimento/impressão → confecção), por fibra origin_country + recycled_pct, svhc_substances[], opt-in ESPR (PEF, vida útil, reciclabilidade).
  • Novo: Campo básico market_countries: string[] (ISO 3166-1 alpha-2) em todas as categorias de DPP — controla as regras AGEC específicas da França e a nota obrigatória do consumidor francês.
  • Novo: Modelo HTML do consumidor com caixa de aviso de microplásticos AGEC, cadeia de origem de 3 etapas (pílulas com bandeiras), lista SVHC, seção de durabilidade e reciclabilidade.
  • Migração: 0010_dpp_market_countries (D1).

2026-04 · Importação em lote de DPP (Q3.2.1–Q3.2.5)

  • Novo: POST /v1/dpp/import aceita CSV e XLSX (compatível com Workers via SheetJS xlsx, pacote gzip de ~283 KB).
  • Escalável: limite baseado no plano (Free 100 → Enterprise 10k) + db.batch() em blocos (chunked) de 100 + limite de corpo de 5 MB.
  • Novo: Relatório de erros como CSV no campo errors_csv da resposta 201; GET /v1/dpp/import/templates/:category?format=csv|xlsx fornece modelos prontos para baterias e têxteis.
  • Dashboard: Upload por arrastar e soltar em /dashboard/dpp/import com proxy de modelo e download de CSV inline.

Extensões LTS sem alterações incompatíveis (Non-Breaking)

Todas as alterações mencionadas acima são aditivas:

  • Clientes existentes de POST /v1/dpp/validate ignoram o novo campo eu_compliance sem alterações.
  • Fluxos existentes de battery permanecem inalterados.
  • market_countries é opcional e tem como padrão [].

Consulte Versão da API para obter a política de alterações incompatíveis (breaking changes).