- API /api/creation/collections liste toutes les collections Shopify
- Détection automatique depuis la colonne ID FAMILLE du Sheets
- Sélecteur avec recherche si absente ou pour modifier
- Collection affichée dans l'écran de confirmation
- collectionOverride passé à l'exécution comme fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Priorité à Stock conditionné (boîtes) sur Stock (en pièce) si renseigné.
Colonne exclue des métachamps spécifiques.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Les associations colonne→métachamp sont sauvegardées dans data/metafield-resolutions.json
et rechargées automatiquement à la prochaine création de produits.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- inventory_management: shopify + inventory_levels/set.json pour le stock
- weight/weight_unit sur le variant pour l'expédition
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sans le type, on envoyait toujours 'single_line_text_field' à Shopify,
causant une erreur quand le métachamp existant est de type number_decimal.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remplace le <select> par un input filtrant en temps réel sur le nom,
la clé et le namespace — utile quand il y a beaucoup de métachamps.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Utilise un compte de service Google avec JWT pour authentifier les écritures
dans le Sheets — sans dépendance npm supplémentaire (crypto natif Node.js).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
L'API variants.json ne filtre pas correctement par sku= quand le SKU contient
des tirets — elle retourne des variants aléatoires. On vérifie maintenant que
le variant retourné a bien le SKU demandé.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Un fichier nommé 26618-D-1.jpg trouvait le SKU 26618-D-1 (céramique) avant
de chercher 26618-D (la porte). On essaie maintenant d'abord le ref sans
suffixe purement numérique (-1, -2…).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ajoute alphaThreshold (défaut 30) — les pixels dont l'alpha dépasse ce seuil
sont rendus opaques avant la composition sur fond blanc, évitant que le verre
ou les surfaces translucides soient supprimés par le modèle IA.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Évite que "26618" matche avant "26618-D" car le tiret est un séparateur
de mot dans la regex — on collecte tous les matches et on garde le plus long.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Chargement du catalogue Shopify au début de l'exécution (fetchAllShopifyProducts)
- Vérification par SKU (ref) : si déjà présent dans Shopify → skipped, pas de création
- Nouveau type d'événement 'skipped' dans CreationStreamEvent
- CreationProgress affiche les produits ignorés en amber avec le SKU concerné
- Résumé final inclut le compte de produits ignorés
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- deleteShopifyProduct() dans shopifySync (DELETE REST API)
- GET /api/products/duplicates : groupe par ref/SKU, trie par ID (ancien en premier)
- DELETE /api/products/[id] : suppression unitaire avec auth
- Page /produits/doublons : liste des groupes, radio pour choisir lequel garder,
confirmation avant suppression, état par groupe (idle/confirm/deleting/done)
- Lien 'Vérifier les doublons' dans l'en-tête de la page Produits
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Quand un onglet est sélectionné, les produits Shopify absents du tab
peuvent appartenir à d'autres familles — ne pas les marquer 'deactivate'.
Les désactivations ne s'appliquent qu'en mode catalogue complet (sans filtre).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /api/sheets/tabs : liste les onglets Google Sheets disponibles
- readSheetProducts(tab?) et fetchPendingProducts(set, tab?) acceptent un filtre
- /api/sync/preview?tab=xxx et /api/creation/preview?tab=xxx filtrent sur un onglet
- Composant FamilySelector : grille de boutons chargeant les onglets dynamiquement
- Page Sync : étape 0 de sélection famille avant l'analyse
- Page Création : étape famille avant analyse, badge de famille sélectionnée
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- /api/dashboard/stats appelle Google Drive API pour récupérer modifiedTime du Sheets
- Compare avec createdAt de la dernière SyncRun → sheetDrift: boolean
- Dashboard affiche un bandeau amber cliquable si Sheets plus récent que la dernière sync
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- table-fixed avec colgroup pour éviter que la colonne Ref écrase les autres
- overflow-x-auto pour permettre le scroll si nécessaire
- parseSheetRows : ignore les refs invalides (< 2 chars, caractères spéciaux, mots réservés)
- parseSheetRows : ignore les lignes sans prix valide (séparateurs, notes)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Nouvel endpoint /api/dashboard/stats : comptes produits Shopify (actifs/brouillons/sans image) + dernière sync depuis Prisma
- Nouvel endpoint /api/dashboard/pending : nombre de produits en attente depuis Google Sheets (lazy)
- Page dashboard remplace le stub avec 4 KPIs, bloc dernière sync, et raccourcis vers les sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>