Aller au contenu

Changelog

Changelog

Points forts sélectionnés des dernières versions. Pour les versions complètes de l’API et la politique de rupture de compatibilité, consultez la Politique de versioning de l’API & LTS.

Modifications détaillées des différents points de terminaison : Spécification OpenAPI et référence API interactive.


2026-08 · Curseur keyset désormais sur tous les endpoints de liste

  • Correctif : Le correctif de curseur pour GET /v1/codes et GET /v1/dpp (voir ci-dessous) est désormais déployé sur toutes les autres listes paginées par curseur : GET /v1/qr-codes/:id/comments, /v1/workspaces, /v1/gs1/identifiers, /v1/members, /v1/audit-logs, /v1/admin/orgs, /v1/admin/users et /v1/webhooks/:id/deliveries. Toutes paginaient uniquement via created_at ; les lignes ayant un horodatage identique (entrées d’audit d’une opération par lot, tentatives de webhook, importations de membres) pouvaient être perdues sur la page suivante. La clé de tri est désormais partout le tuple (created_at, id).
  • Modification de l’API : Sur ces listes, meta.pagination.next_cursor est désormais également une valeur opaque (base64url) au lieu d’un simple horodatage ; les curseurs illisibles renvoient 400, les anciens curseurs d’horodatage continuent d’être acceptés de manière transitoire. Exception pour GET /v1/webhooks/:id/deliveries : ici, next_cursor reste l’ID de la dernière livraison (ID inconnu → première page). Les clients qui renvoient next_cursor sans modification — Tableau de bord, CLI, SDKs, MCP — n’ont rien à changer.
  • Impact : Aucune migration requise. Si vous avez manqué des entrées lors de la navigation dans l’une de ces listes (par exemple, le journal d’audit ou le journal de livraison dans le Tableau de bord) : elles n’ont jamais disparu — les listes les affichent désormais de manière complète.

2026-08 · Les horodatages après modification et suppression sont à nouveau conformes à OpenAPI

  • Correctif : Après PATCH /v1/codes/{id}, updated_at était renvoyé au format SQLite sans fuseau horaire (2026-08-17 09:00:00), bien que la spécification OpenAPI promette format: date-time et que la création (POST) fournisse l’horodatage ISO (2026-08-17T09:00:00.000Z). Il en allait de même pour deleted_at/updated_at lors de la suppression logique (soft-delete) ainsi que pour les chemins de modification/suppression des clés API, organisations, workspaces, membres, commentaires et webhooks, ainsi que pour last_used_at des clés API et last_triggered_at des webhooks. Tous les chemins d’écriture horodatent désormais en ISO 8601 (UTC, T et Z).
  • Impact : Les clients qui analysent updated_at avec new Date(...) (SDKs, CLI, Tableau de bord) lisaient le format avec espace comme l’heure locale — la CLI affichait l’heure décalée de l’offset local pour les codes modifiés une fois (Vienne : −2 h). Ce problème est résolu. De plus, une migration de données normalise les valeurs déjà enregistrées dans l’ancien format vers le format ISO, afin que le tri et les comparaisons soient corrects dans les bases de données mixtes. Aucun changement au niveau des noms de champs ou de la structure des réponses.
  • Contexte : Même classe d’erreur que les deux corrections ci-dessous (expiration des clés API, limite de re-scan) : le datetime('now') de SQLite écrit YYYY-MM-DD HH:MM:SS, tandis que tous les autres chemins d’écriture utilisent l’ISO 8601. Un test de garde dans le code source empêchera de nouvelles occurrences à l’avenir.

2026-08 · La pagination des listes ne perd plus de codes batch

  • Correctif : GET /v1/codes et GET /v1/dpp paginaient uniquement via created_at. Cependant, les codes issus de POST /v1/codes/batch, POST /v1/dpp/batch et de l’importation CSV/XLSX partagent un seul horodatage — dès qu’un lot était plus grand que limit (par défaut 20), la deuxième page ne renvoyait plus les lignes restantes de ce même horodatage. Les codes existaient et étaient accessibles via GET /v1/codes/:id, mais n’apparaissaient jamais dans la liste (Tableau de bord, CLI qr3 list, SDKs, MCP). Le curseur est désormais un Keyset sur (created_at, id).
  • Modification de l’API : meta.pagination.next_cursor est désormais une valeur opaque (base64url) au lieu d’un simple horodatage. Ceux qui renvoient le curseur inchangé sous la forme ?cursor= — comme le font le Tableau de bord, la CLI, tous les SDKs et le serveur MCP — n’ont rien à modifier. Les anciens curseurs d’horodatage continueront d’être acceptés à titre transitoire ; les curseurs illisibles renvoient désormais 400 au lieu de renvoyer silencieusement la première page.
  • Impact : Si vous voyiez moins de codes dans la liste après un import par lot que ce qui avait été créé : les codes n’ont jamais disparu — la liste les affiche désormais en totalité. Aucune migration n’est nécessaire.

2026-08 · Les re-scans de sécurité sont à nouveau exécutés toutes les 24 heures

  • Correctif : Le re-scan périodique des URL cibles et des liens de pages de destination (Google Web Risk) ignorait les codes dont la dernière analyse avait eu lieu le même jour civil que le seuil de 24 heures — selon l’heure, le re-scan était retardé jusqu’à un jour supplémentaire. Le seuil est désormais calculé dans le même format ISO que celui dans lequel les horodatages d’analyse sont stockés.
  • Impact : Une URL cible classée comme non sécurisée après la dernière analyse entraîne à nouveau la mise en pause automatique du code dans la fenêtre documentée de 24 heures. Aucune modification de l’API ou du format de réponse.

2026-08 · Les clés API expirent à l’instant d’expiration

  • Correctif : Une clé API dont le expires_at tombait le même jour continuait d’être acceptée jusqu’à minuit UTC. L’expiration est désormais comparée sous forme d’horodatage plutôt que de chaîne de caractères — une clé expirée renvoie immédiatement 401.
  • Contexte : expires_at est stocké sous forme d’horodatage ISO (2026-08-14T09:00:00Z), tandis que le côté comparaison fournissait le format avec espace (2026-08-14 09:00:00). La comparaison brute de chaînes de caractères n’était donc correcte que tant que la date elle-même différait.
  • Impact : Aucune migration n’est nécessaire, le format de réponse de GET /v1/api-keys reste inchangé. Les valeurs d’expiration illisibles sont désormais considérées comme expirées plutôt que valides.

2026-08 · Référence API : Gestion des tenants documentée

  • OpenAPI : La spécification — et donc la référence interactive — documente désormais les organisations (y compris GET /v1/organizations/usage), les workspaces, les membres & rôles et les journaux d’audit.
  • Facturation : L’aperçu des tarifs (GET /v1/billing/plans) est public ; le paiement (POST /v1/billing/checkout) et le portail client Stripe (GET /v1/billing/portal) sont répertoriés comme des points de terminaison pour les administrateurs d’organisation.
  • Exportation des scans : Les statistiques de scan (GET /v1/codes/{id}/scans) et l’exportation des données brutes (…/scans.csv, …/scans.xlsx) sont entièrement documentées — y compris la mention RGPD : le ip_hash n’est jamais inclus dans l’exportation.
  • Gestion des erreurs : La réponse 400 de la validation de requête est également nouvellement documentée : le corps est l’erreur Zod brute, et non un document de problème RFC-7807 — elle est néanmoins fournie avec le Content-Type application/problem+json.

2026-08 · Copier les liens publics des fichiers

  • Tableau de bord : les fichiers publics sur la page de détails d’un code disposent désormais d’un bouton qui copie leur lien public dans le presse-papiers — directement utilisable comme URL cible d’un code QR lorsqu’un scan doit ouvrir un document précis plutôt que la page de destination et sa liste de fichiers.
  • API : les endpoints de fichiers (/v1/files) renvoient en plus public_url. Le champ n’est défini que pour les fichiers avec visibility: public — les fichiers privés n’ont pas d’adresse publique.
  • Comportement : le lien ne nécessite aucune connexion et ouvre le fichier directement dans le navigateur. Remplacer le fichier laisse le lien inchangé ; un code imprimé avec cette adresse reste donc valide. Détails : Fichiers & Fiches techniques.

2026-07 · Rôles d’équipe : Contributeur sans suppression & facturation admin

  • Nouveau : rôle de membre Contributeur (sans suppression) — crée et modifie les codes QR, les fichiers et les Digital Product Passports, mais ne peut rien supprimer ni créer de clés API. Tous les endpoints destructifs vérifient le rôle côté serveur (403).
  • Facturation : les mises à niveau de forfait et le portail client Stripe (POST /v1/billing/checkout, GET /v1/billing/portal) sont désormais réservés aux Administrateurs d’organisation — tous les autres rôles voient un aperçu du forfait en lecture seule.
  • Dashboard : les actions non autorisées par le rôle de l’utilisateur sont masquées : un Lecteur ne voit par exemple aucun bouton pour créer, modifier ou supprimer ; les listes, téléchargements et statistiques restent visibles. Détails : Équipe & Rôles.

2026-06 · Liens externes sur la page de destination du code

  • Page de destination : La page de destination hébergée par qr3 d’un code peut désormais lister des liens externes auto-hébergés ({ label, url }) en plus ou à la place des fichiers téléversés – par exemple pour des fiches techniques hébergées sur votre propre site.
  • API : POST/PATCH /v1/codes acceptent un tableau links (0–20 entrées, http(s), ≤ 2048 caractères). Chaque URL est vérifiée avec Google Web Risk ; une URL non sécurisée renvoie 422. Un tableau vide supprime tous les liens.
  • Tableau de bord : Ajoutez, réordonnez et supprimez des liens sur la page de détails du code.
  • Sécurité : Les liens rendus restent protégés contre les XSS (échappés, http(s) uniquement) et la page conserve son en-tête noindex.

2026-04 · Analyses du tableau de bord par code QR

  • Tableau de bord : Le bouton d’analyses dans la liste des codes QR ouvre désormais la page de statistiques du code QR correspondant sous /dashboard/codes/{id}.
  • Routage : L’alias /dashboard/codes redirige toujours vers /dashboard, mais n’intercepte plus les routes détaillées comme /dashboard/codes/{id}.
  • API : La page de détails charge le code QR directement via GET /v1/codes/:id ; elle ne dépend donc plus des limites de pagination de la liste.
  • Tests : Les tests de régression couvrent la redirection d’alias et le chargement direct du code.

2026-04 · Boîte de dialogue de suppression des codes QR sur le tableau de bord

  • Tableau de bord : L’icône de corbeille dans la liste des codes QR ouvre désormais une boîte de dialogue React dédiée au lieu d’une fenêtre contextuelle native du navigateur.
  • Retour d’information : Après la suppression, une notification toast apparaît pour indiquer le succès ou l’échec.
  • Tests : packages/dashboard/tests/dashboard.test.ts empêche les régressions sur confirm() dans le flux de suppression de code QR.

2026-04 · Test de lien court sur le tableau de bord pour les codes QR dynamiques

  • Tableau de bord : Les codes courts dans la liste des codes QR sont désormais directement cliquables en tant que liens de redirection externes. L’icône de lien externe à côté de par ex. wu3qaa ouvre https://qr3.app/{shortCode} dans un nouvel onglet.
  • i18n : Ajout des textes d’infobulle pour l’allemand et l’anglais.
  • Tests : packages/dashboard/tests/dashboard.test.ts protège le href du lien, le comportement du nouvel onglet, noopener noreferrer et l’icône contre les régressions.

2026-04 · Route du Worker de redirection pour les codes QR dynamiques

  • Correctif : Les codes QR dynamiques sous https://qr3.app/{shortCode} sont à nouveau traités par le Worker de redirection. La route de production utilise désormais qr3.app/* car les routes de Cloudflare Workers ne prennent pas en charge les paramètres de chemin :code.
  • Renforcement : Les chemins non correspondants sont transmis à l’origine de la page d’atterrissage afin que les pages normales comme /de/pricing ne soient pas bloquées par le Worker de redirection.
  • Tests : packages/redirect/tests/unit/redirect.test.ts vérifie la route générique, le traitement du code court et le passage à l’origine.

2026-04 · Aperçu des scans DPP de l’espace de travail (Q3.4.2)

  • Nouveau : GET /v1/workspace/stats/dpp?days=30 — agrège tous les dpp_scans de l’espace de travail de la clé API (active_dpps, scans_by_day, top_dpps avec nom de produit/catégorie).
  • Tableau de bord : Carte sur la page d’accueil (/dashboard) avec un graphique à barres sur 30 jours + listes des tops — en parallèle des cartes de codes QR.
  • Public : Lien court marketing GET /dpp/dpp_<id> (un segment) pour les démos en direct, en parallèle de /dpp/{gtin}/{serial}.

2026-04 · Analyses des scans DPP (Q3.4.1)

  • Nouveau : GET /v1/dpp/:id/stats?days=30 — scans agrégés du résolveur public GS1 par DPP. Champs : total_scans, period_scans, scans_by_day, top_countries, top_devices, top_representations.
  • Nouveau : Table dpp_scans (migration 0011) — séparée de scans (Worker de redirection). Les adresses IP sont hachées avec un sel rotatif quotidien, les IP brutes n’atteignent jamais D1.
  • Tableau de bord : Carte mini-graphique (SVG, sans bibliothèque de graphiques) sur /dashboard/dpp/:dppId avec barres sur 30 jours + ventilations du top 3. État vide dès qu’un DPP est en ligne mais n’a pas encore eu de scans.

2026-04 · Simulateur de conformité UE en direct (Q3.3.7)

  • Nouveau : POST /v1/dpp/:id/validate-update — simule des mises à jour partielles sans état (statut, liste de marchés, …) sans persistance. La réponse contient eu_compliance + preview.changed_fields.
  • Tableau de bord : Carte de simulateur dans les détails du DPP (/dashboard/dpp/:dppId) — puces pour DE/AT/FR/IT/ES/NL + personnalisé, menu déroulant de statut, Preview EU impact / Save changes / Reset. Non bloquant via Remix useFetcher.
  • Renforcement : Assistants de simulation externalisés (readUpdatePatchFromForm, marketCountriesKey) + 18 nouveaux tests unitaires ; correction de bug : une entrée non-ISO isolée ne supprime plus la liste des marchés.

2026-04 · Aperçu de la conformité UE en direct dans le formulaire de création (Q3.3.6)

  • Modifié : POST /v1/dpp/validate fournit en plus eu_compliance — le même validateur que GET /v1/dpp/:id/eu-compliance, sans état avant l’enregistrement.
  • Tableau de bord : Aperçu sous le panneau de validation existant + nouvelle bannière de protection de sauvegarde avant les boutons de soumission si des erreurs/avertissements sont en suspens (pluralisation i18n DE/EN).

2026-04 · Validateur UE + UI Textile (Q3.3.4 + Q3.3.5)

  • Nouveau : Validateur de conformité UE avec 5 règles textiles (TEXTILE_AGEC_REQUIRED, TEXTILE_MICROPLASTICS_CONSISTENCY, TEXTILE_SVHC_THRESHOLD, TEXTILE_GREENWASHING, TEXTILE_ESPR_READY).
  • Nouveau : GET /v1/dpp/:id/eu-compliance avec compliant / espr_ready / issues[] / summary.
  • Tableau de bord : Section de conformité UE dans les détails du DPP (tuiles de résumé, cartes de problèmes groupées, badge ESPR-Ready dans l’en-tête).

2026-04 · Schéma DPP Textile (Q3.3.1–Q3.3.3)

  • Nouveau : Catégorie textile avec chaîne d’obligation AGEC (tissage/tricotage → teinture/impression → confection), par fibre origin_country + recycled_pct, svhc_substances[], opt-in ESPR (PEF, durée de vie, recyclabilité).
  • Nouveau : Champ de base market_countries: string[] (ISO 3166-1 alpha-2) sur toutes les catégories de DPP — contrôle les règles AGEC spécifiques à la France et la notice obligatoire pour les consommateurs français.
  • Nouveau : Modèle HTML consommateur avec boîte d’avertissement sur les microplastiques AGEC, chaîne d’origine à 3 étapes (badges de drapeaux), liste SVHC, sections durabilité et recyclabilité.
  • Migration : 0010_dpp_market_countries (D1).

2026-04 · Importation en lot de DPP (Q3.2.1–Q3.2.5)

  • Nouveau : POST /v1/dpp/import accepte CSV et XLSX (compatible Worker via SheetJS xlsx, bundle gzip d’environ 283 Ko).
  • Mise à l’échelle : Limite basée sur le forfait (Free 100 → Enterprise 10k) + db.batch() fragmenté par 100 + limite de corps de 5 Mo.
  • Nouveau : Rapport d’erreurs au format CSV dans le champ errors_csv de la réponse 201 ; GET /v1/dpp/import/templates/:category?format=csv|xlsx fournit des modèles prêts à l’emploi pour les batteries et le textile.
  • Tableau de bord : Téléchargement par glisser-déposer sous /dashboard/dpp/import avec proxy de modèle et téléchargement CSV en ligne.

Sans rupture — Extensions LTS

Toutes les modifications mentionnées ci-dessus sont additives :

  • Les clients existants de POST /v1/dpp/validate ignorent le nouveau champ eu_compliance sans modification.
  • Les flux battery existants restent inchangés.
  • market_countries est facultatif et a pour valeur par défaut [].

Consultez le Versioning de l’API pour la politique de rupture de compatibilité.