Outils Shopify à encapsuler (couche de connaissance @Atlas)
Archive de conception. Cette page raconte ce qui etait vise le jour ou elle a ete ecrite, pas l'etat du code aujourd'hui. Ce qui a ete livre depuis est recense dans le README.
Archive de conception. Cette page raconte ce qui etait vise le jour ou elle a ete ecrite, pas l'etat du code aujourd'hui. Ce qui a ete livre depuis est recense dans le README.
← retour au README
6. Outils Shopify à encapsuler (couche de connaissance @Atlas)
Cible : @Atlas ne dit jamais « je ne sais pas ». Utiliser exclusivement la GraphQL Admin API 2025-10.
Philosophie de permissions : non-négociable
Aucune limite interne côté BoostEcom. La frontière d'@Atlas = les scopes accordés par l'utilisateur via sa custom app Shopify, et rien d'autre.
Concrètement :
- BoostEcom n'ajoute aucun filtrage au-dessus de Shopify. Si l'utilisateur
a accordé
read_customers, @Atlas lit les clients. Si l'utilisateur a accordé les 68+ scopes d'une custom app, @Atlas exploite les 68+. - Pas de feature flag interne « agents.canReadOrders = false » : la réponse à « puis-je faire X ? » est toujours « oui, si Shopify accepte le token ».
- Côté outils : chaque outil doit tenter l'appel GraphQL et
propager l'erreur Shopify telle quelle si le scope est insuffisant
(ses
userErrors, ou un 403 : il n'existe pas de type d'erreur maison). L'erreur sert de signal à @Atlas, qui peut alors guider l'utilisateur vers le skillshopify-app-custompour étendre les scopes : pas un blocage silencieux. - Pour les boutiques connectées par OAuth via une app publique (≠ custom app), le même principe s'applique avec les scopes négociés à l'installation ; si un scope manque, @Atlas propose d'élargir, ne ferme jamais la porte.
Référence interne : skill shopify-app-custom (catalogue exhaustif des
scopes et reproduction de l'accès admin/partner). La couche de connaissance
d'@Atlas est un relais transparent vers ce que la custom app permet.
Implémentation :
- Pas d'encapsulation conditionnelle
if (hasScope(...)) { ... }dans nos outils : on appelle Shopify, on gère l'erreur dans le repli. - Schémas zod des outils = stricts sur les entrées/sorties, jamais sur les permissions.
- Documentation : chaque outil note les scopes Shopify nécessaires comme information (pour le débogage), pas comme barrière.
Lot d'encapsulation (Lot 1 du plan d'exécution)
| Domaine | Endpoints GraphQL | Scope |
|---|---|---|
| Catalogue | products, product(id), productVariants, inventoryLevels, collections, collection(id) | read_products, read_inventory |
| Pages de contenu | pages, page(id) | read_content |
| Blogs / Articles | blogs, blog(id), articles, article(id) | read_content |
| Navigation | menus, menu(id) (linkLists via REST s'il manque) | read_content |
| Thème | themes, theme(id), themeFiles(themeId), mutations CRUD | read_themes, write_themes |
| Apps | currentAppInstallation, abonnements d'app | scope automatique |
| Réglages | shop, shopLocales, shopBillingPreferences, shippingZones | read_locales, read_shipping |
| Clients (soumis à scope) | customers, customer(id), customerSegments | read_customers |
| Commandes (soumis à scope) | orders, order(id), draftOrders | read_orders, read_draft_orders |
| Marketing | discountCodes, priceRules, marketingActivities, abandonedCheckouts | read_discounts, read_marketing_events |
| Analytics (limité) | shopifyAnalytics (basique) : préférer la Storefront API ou un rapport Shopify CLI | read_reports |
| Storefront | pixels de tracking, données structurées, robots, sitemap (lecture du HTML via fetch) | aucun (public) |
Pattern d'encapsulation
server.tool(
"shopify_list_pages",
"List all CMS pages of the store, with title, handle, body summary.",
{ first: z.number().min(1).max(50).optional() },
async ({ first = 50 }, ctx) => {
const data = await ctx.shopify.graphql(LIST_PAGES_QUERY, { first })
return text(formatPagesList(data.pages))
},
)
→ ~30 nouveaux outils à encapsuler. Bloc 1 = 1 lot dédié.
Suivant : execution-plan.md