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-10 · Couleurs dans le Tableau de bord

  • Nouveau : la page de détails d’un code comporte la carte Couleurs : premier plan et arrière-plan en valeur hexadécimale, arrière-plan transparent, aperçu via la véritable route d’image. La vérification est celle de PATCH /v1/codes/{id} : les paires critiques nécessitent une confirmation, les paires inférieures à 1,5 : 1 ne peuvent pas être enregistrées.
  • La réinitialisation en noir sur blanc fournit de nouveau dans les quatre formats les mêmes octets que sans couleurs. Les codes sans couleurs ne changent pas.
  • Les codes transparents apparaissent sur un damier dans tous les aperçus du Tableau de bord. Détails : Couleurs dans le Tableau de bord.

2026-10 · Couleurs en PDF et EPS

  • Nouveau : qr.pdf et qr.eps dessinent fg et bg, en tant que paramètres et en tant que couleurs enregistrées. Le noir et chaque nuance de gris sont écrits en niveaux de gris (uniquement sur la plaque noire), toute autre couleur en CMJN en pourcentages entiers, par exemple 1F4E79 sous la forme C74 M36 Y0 K53.
  • Arrière-plan comme pour le SVG : Dès qu’une couleur est sélectionnée, une zone opaque se trouve derrière le code et sa zone de silence, en blanc ou en bg. bg=transparent n’en dessine aucune. Le titre reste noir, la plaque du logo blanche.
  • Aucune modification sans couleurs : Sans fg/bg et sans couleurs enregistrées, les deux formats fournissent les mêmes octets qu’auparavant. Le PDF d’un passeport produit reste non coloré.
  • Limites : pas de profil ICC, pas de PDF/X. Détails : Couleurs à l’impression.

2026-09 · Codes statiques sans cache de redirection, suppression simultanée

  • Modifié : Les codes statiques ne se trouvent plus dans le cache de redirection. Un appel de leur lien court (redirect_url) lit toujours l’état actuel. Après un DELETE /v1/account, un code statique ne redirige donc plus lors du prochain appel, alors qu’il pouvait le faire auparavant pendant jusqu’à 24 heures. Un changement de forfait prend également effet immédiatement pour les codes statiques. La suppression du compte nettoie les codes dynamiques comme auparavant. Les codes statiques imprimés contiennent directement leur destination et ne sont pas concernés.
  • Corrigé : Deux requêtes DELETE /v1/codes/:id simultanées sur le même code renvoient une fois 200 et une fois 404. Le webhook qr.deleted est envoyé exactement une fois, contre deux auparavant.
  • Nouveau : POST et DELETE /v1/codes/:id/logo répondent par 409 (errors/conflict) si une autre requête a modifié simultanément le logo du même code, et ne modifient rien dans ce cas. Auparavant, un logo téléversé pouvait rester stocké sans être utilisé. Deux requêtes DELETE /v1/codes/:id/logo simultanées renvoient toutes deux 200. Détails : Logo.

2026-09 · SDK TypeScript 1.2.0

  • Nouveau dans @qr3/sdk 1.2.0 : client.codes.update() accepte appearance et fournit les résultats de la vérification du contraste sous forme d’issues dans le résultat ; en l’absence d’anomalie, le champ est absent. client.codes.imageUrl() accepte fg, bg et ecc. Chaque code renvoyé par l’API (get, list, create, update, batchCreate) comporte title et appearance.
  • Mise à jour : npm install @qr3/sdk@latest. Python, Go et PHP suivront. Détails : SDK et CLI et Enregistrer les couleurs sur le code.

2026-09 · La nouvelle date d’expiration s’applique dans un délai d’environ une minute

  • Corrigé : Un PATCH sur expires_at vide désormais le cache de redirection du code. La nouvelle date d’expiration s’applique ainsi dans un délai d’environ une minute, au lieu de prendre jusqu’à 24 heures. Auparavant, une expiration supprimée ou reportée continuait à renvoyer un code 410 pendant jusqu’à 24 heures, et une expiration définie sur l’instant présent laissait la redirection active pendant jusqu’à 24 heures.
  • Corrigé : Un code créé avec expires_at expire également à l’heure prévue si l’expiration intervient dans les premières 24 heures.
  • Corrigé : Si un code est supprimé pendant que son logo est en cours de chargement ou de suppression, POST et DELETE /v1/codes/:id/logo répondent par un code 404 et ne modifient pas le code supprimé, tout comme le fait déjà PATCH.
  • Corrigé : Même un code statique dont le lien court (redirect_url) a été appelé est stocké dans le cache de redirection. La modification, la mise en pause et la suppression le vident désormais également, et pas seulement pour les codes dynamiques.

2026-09 · Enregistrer des couleurs sur le code

  • Nouveau : PATCH /v1/codes/:id accepte appearance avec foreground_color et background_color (#RRGGBB, l’arrière-plan acceptant également transparent). qr.svg et qr.png dessinent les couleurs enregistrées sans aucun paramètre ; un paramètre de requête tel que ?fg=000000 reste prioritaire. PDF et EPS ne dessineront les couleurs qu’avec une version ultérieure.
  • Vérification du contraste : Une paire inférieure à 1,5:1 renvoie 422. Les paires plus faibles sont enregistrées et signalées dans meta.issues comme warning ou critical ; un arrière-plan transparent est toujours critical, jamais bloqué.
  • Fusion : Les champs omis conservent leur valeur enregistrée, null réinitialise. Les modifications simultanées sur le même code ne s’écrasent plus mutuellement.
  • Dans chaque réponse de code : appearance figure dans chaque réponse de code et dans les webhooks qr.created et qr.updated. POST, le batch et l’importation le rejettent avec 422.
  • Aucun changement pour les codes existants : Sans couleurs enregistrées, chaque code fournit les mêmes octets qu’auparavant. Détails : Enregistrer des couleurs sur le code.

2026-09 · Couleurs et correction d’erreurs comme paramètres des routes d’images

  • Nouveau : Les quatre routes d’images acceptent fg (couleur de premier plan), bg (couleur d’arrière-plan ou transparent) et ecc (correction d’erreurs L, M, Q, H). SVG et PNG dessinent les couleurs ; PDF et EPS les acceptent, mais ne les dessineront que lors d’une version ultérieure. ecc fonctionne dans les quatre formats, un logo continue d’imposer H.
  • Transparence : bg=transparent fournit un SVG sans arrière-plan et un PNG avec un véritable canal alpha. Le fond doit être clair et laisser la zone de silence libre.
  • Jamais une erreur : Les valeurs invalides sont ignorées ; l’image s’affiche alors exactement comme sans paramètre.
  • Mise en cache : Chaque paramètre effectif fournit Cache-Control: public, max-age=300 au lieu des 24 heures de l’image par défaut.
  • Aucun changement de comportement sans paramètre : Tout code existant fournit les mêmes octets qu’auparavant dans les quatre formats.
  • Disponible dans tous les tarifs. Détails : Couleurs et correction d’erreurs.
  • Extension : qr.pdf et qr.eps intègrent désormais un logo configuré de la même manière que qr.svg et qr.png (voir ci-dessous) — sous forme d’image intégrée (PDF via un Image XObject, EPS via un dictionnaire d’images en PostScript, là uniquement avec %%LanguageLevel: 3), centré sur la même zone, avec la même augmentation de la correction d’erreurs à H. Jusqu’à présent, les deux formats ne fournissaient pas le logo ; cela est maintenant corrigé.
  • Mise en cache : Lorsqu’un logo est configuré, qr.pdf et qr.eps renvoient désormais également Cache-Control: public, max-age=300 au lieu des 24 heures habituelles — tout comme SVG/PNG.
  • Solution de repli : Si l’image du logo elle-même ne peut pas être traitée (par exemple, un objet enregistré corrompu), la correction d’erreurs reste à H, mais la zone réservée reste vide au lieu d’afficher une image — sans jamais générer d’erreur de serveur.
  • Aucun changement de comportement sans logo : Les codes sans logo continuent de fournir des fichiers qr.pdf/qr.eps identiques à l’octet près, avec un cache de 24 heures inchangé.
  • Détails et consignes d’impression : Logo dans le QR-Code.

2026-09 · Logo dans le code QR — Tableau de bord et API

  • Nouveau : Un code peut désormais comporter un logo au centre. Dans le Tableau de bord, la page de détails d’un code crée une carte de logo dédiée : Sélectionner un logo, confirmer un avertissement avec une case à cocher obligatoire lors du premier ajout ou de la suppression (les deux modifient le motif de points), puis Téléverser le logo/Supprimer le logo. Un remplacement ne nécessite aucune confirmation — seule l’image change, pas le motif. Le rôle viewer voit le statut et l’aperçu, mais n’a accès à aucune des trois actions.
  • API : POST /v1/codes/{id}/logo (champ multipart file ; PNG, JPEG ou WebP, maximum 1 Mo, SVG est refusé) crée un logo ou le remplace ; DELETE /v1/codes/{id}/logo le supprime à nouveau et est idempotent. Une image trop grande renvoie 413, un format non pris en charge 422, le rôle viewer 403.
  • Rendu : qr.svg et qr.png intègrent le logo sous forme de pixels réels (512 × 512, normalisés) et augmentent pour cela le niveau de correction d’erreurs à H. L’ajout et la suppression modifient ainsi le motif de points (M ↔ H), mais pas le remplacement. qr.pdf et qr.eps n’intègrent aucun logo et restent inchangés. Un code déjà imprimé continue de fonctionner dans tous les cas, car la cible encodée ne dépend pas du logo — seuls ceux qui souhaitent voir le (nouveau) rendu visuel du logo sur le support physique doivent réimprimer, en veillant à ne pas mélanger les anciens et les nouveaux fichiers d’impression.
  • Mise en cache : Lorsque le logo est défini, qr.svg et qr.png renvoient Cache-Control: public, max-age=300 au lieu des 24 heures habituelles. Détails, limites et conseils d’impression : Logo dans le code QR.

2026-08 · operationId pour l’ensemble des 75 opérations, et un guide d’utilisation pour les agents

  • Ajout : L’ensemble des 75 opérations de la spécification OpenAPI portent désormais une operationId — listCodes, createCode, getCodeStats, archiveWorkspace et ainsi de suite. Jusqu’à présent, ce champ manquait systématiquement, de sorte que chaque générateur devait déduire le nom de la méthode à partir de la méthode HTTP et du chemin (postV1Codes). De tels noms dépendent du chemin et changent à chaque modification de celui-ci. La forme du nom est identique aux 75 emplacements : list/get/create/update/replace/delete, sinon le verbe de l’action métier (validateDpp, registerGs1Identifier, pingWebhook). Le verbe suit la logique métier, non la méthode HTTP — archiveWorkspace est un DELETE, importDpps est un POST.
  • Impact sur les clients auto-générés : Si vous générez votre SDK à partir de la spécification, vous obtiendrez des méthodes renommées (postV1Codes → createCode) lors de la prochaine exécution. C’est le but de ce changement, mais il s’agit d’un renommage dans du code tiers — c’est pourquoi cela est explicitement mentionné ici. Les chemins, paramètres, formats de réponse et codes d’état restent inchangés ; les SDK officiels, la CLI et le serveur MCP ne sont pas concernés.
  • Introduction pour les agents : https://qr3.app/llms.txt contient une section ## When to use qr3.app — six tâches au lieu de six fonctions, plus la phrase indiquant ce pour quoi qr3.app n’est pas le bon outil. Le serveur MCP fournit désormais la même information lors de la phase d’initialisation : initialize sur https://mcp.qr3.app/mcp répond avec un champ instructions (auparavant : onze outils sans aucune classification). Il indique également quels appels nécessitent une clé API — initialize et tools/list non, mais chaque tools/call oui.
  • Corrections dans llms.txt : Quatre informations ont été vérifiées par rapport à la production et se sont révélées incorrectes : (1) le SDK Python qr3app n’est pas publié sur PyPI — la ligne pip install est supprimée sans remplacement ; (2) Accept: text/markdown s’applique à la page d’accueil et au blog, pas à toutes les pages générées côté serveur ; (3) l’adresse de contact est [email protected], y compris dans le JSON-LD de la page d’accueil ; (4) /de/security/ est une redirection vers un ancrage, pas une page distincte. Nouveau lien : docs.qr3.app/de/skills/.
  • Sécurisation : Trois assertions dans openapi-spec.test.ts — exhaustivité, unicité, lowerCamelCase —, chacune contre-vérifiée par une mutation. Neuf tests supplémentaires figent les quatre informations corrigées afin d’éviter toute régression.
  • Limitation connue : Deux des 75 opérations sont décrites dans la spécification mais répondent par un 404 (GET /v1/codes/{id}/stats et GET /v1/account). Elles ont reçu un nom ici et le perdront à nouveau dès qu’il aura été décidé si elles seront implémentées ou supprimées.

2026-08 · Les rétrogradations de forfait et les résiliations s’appliquent désormais aussi aux limites

  • Correctif : Lors d’un changement de forfait ou d’une résiliation, le webhook Stripe n’enregistrait que le nom du forfait, et non les quatre colonnes de limites de l’organisation (max_workspaces, max_members, max_dynamic_codes, max_scans_per_month). Comme l’application des limites prend le maximum entre la valeur enregistrée et la valeur de référence du forfait, une organisation rétrogradée ou résiliée conservait ses anciennes limites plus élevées — la rétrogradation était donc sans effet. Le webhook définit désormais ces colonnes sur la valeur de référence du nouveau forfait lors de chaque changement réel de forfait, et sur la valeur de référence Free en cas de résiliation — tout comme le fait déjà la gestion administrative.
  • Comportement : Les mises à jour de routine de l’abonnement (renouvellement, moyen de paiement, prorata) ne touchent toujours pas aux limites ; les limites plus élevées accordées individuellement restent inchangées. Seul un véritable changement de forfait les réinitialise à la valeur de référence du nouveau forfait.
  • Impact : Aucune modification de l’API ou du format de réponse. Les organisations dont la rétrogradation a eu lieu avant ce correctif conservent leurs anciennes valeurs jusqu’à ce que le prochain changement de forfait s’applique ou que le support les ajuste.

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.
  • Tableau de bord : 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é.