[{"data":1,"prerenderedAt":1727},["ShallowReactive",2],{"featured":3,"featured-works":855,"schneider-grid":946},[4,333,651,755],{"id":5,"title":6,"body":7,"category":6,"challenge":298,"codeSnippet":299,"description":303,"extension":304,"featured":305,"finalScreenshot":306,"gridOrder":307,"isDemo":308,"isDemoURL":309,"liveUrl":307,"meta":310,"mockupImage":311,"navigation":308,"nextProject":307,"order":312,"path":313,"results":307,"schneiderFeatured":308,"schneiderOrder":314,"seo":315,"solution":316,"stem":317,"subtitle":289,"tags":318,"techStack":323,"thumbnail":306,"thumbnailVideo":330,"year":331,"__hash__":332},"works/works/posh-and-paws.md","Headless Commerce",{"type":8,"value":9,"toc":288},"minimark",[10,15,19,22,27,34,40,46,52,58,64,70,72,76,84,86,90,105,107,111,114,116,120,196,198,202],[11,12,14],"h1",{"id":13},"posh-paws-headless-shopify-storefront","Posh & Paws — Headless Shopify Storefront",[16,17,18],"p",{},"A production-grade headless commerce storefront for a luxury apparel brand, built on Shopify Hydrogen with React, TypeScript, and deployed to Cloudflare Workers via Shopify Oxygen.",[20,21],"hr",{},[23,24,26],"h2",{"id":25},"full-e-commerce-feature-set","Full E-Commerce Feature Set",[16,28,29,33],{},[30,31,32],"strong",{},"Homepage"," — Hero section with video background, featured collections grid, bestseller products, brand story, customer testimonials, and newsletter signup.",[16,35,36,39],{},[30,37,38],{},"Product Pages"," — Image gallery, variant selection (size/color), dynamic pricing with sale indicators, add-to-cart with slide-out drawer.",[16,41,42,45],{},[30,43,44],{},"Collection Pages"," — Filterable product grid with sorting options and cursor-based pagination.",[16,47,48,51],{},[30,49,50],{},"Cart System"," — Slide-out cart drawer with quantity controls, discount code support, and Shopify checkout redirect.",[16,53,54,57],{},[30,55,56],{},"Search"," — Full-page search results plus predictive autocomplete with instant suggestions.",[16,59,60,63],{},[30,61,62],{},"Customer Accounts"," — OAuth 2.0 passwordless login via Shopify's Customer Account API, order history, profile management, saved addresses.",[16,65,66,69],{},[30,67,68],{},"Blog"," — \"The Posh Post\" — article listing and full article pages powered by Shopify's CMS.",[20,71],{},[23,73,75],{"id":74},"design-system","Design System",[16,77,78,79,83],{},"Built from scratch with Tailwind CSS v4: a warm luxury palette (cream, sand, caramel, terracotta, charcoal) paired with Playfair Display for headlines, DM Sans for body text, and Josefin Sans for CTAs. Consistent 8-point spacing grid. Framer Motion animations that respect ",[80,81,82],"code",{},"prefers-reduced-motion",". WCAG 2.1 AA target with focus-visible styles and semantic HTML throughout.",[20,85],{},[23,87,89],{"id":88},"architecture","Architecture",[16,91,92,93,96,97,100,101,104],{},"32 route files using file-based routing with typed loaders and deferred streaming. Parallel data fetching via ",[80,94,95],{},"Promise.all()"," for independent queries with ",[80,98,99],{},"Suspense"," boundaries for non-critical content. GraphQL fragments for composable queries across products, collections, and variants. Automatic TypeScript codegen from Shopify's GraphQL schema. Code splitting per route, Hydrogen ",[80,102,103],{},"\u003CImage>"," with auto srcset/WebP/AVIF, lazy loading, and Cloudflare edge caching.",[20,106],{},[23,108,110],{"id":109},"ai-generated-product-media","AI-Generated Product Media",[16,112,113],{},"All product videos and images across the storefront were generated using Higgsfield AI. This eliminated the traditional creative production bottleneck entirely — no studio shoots, no post-production pipeline, no waiting on assets. Combined with AI-directed development, the entire storefront (code + content) shipped from zero to production-ready without external dependencies.",[20,115],{},[23,117,119],{"id":118},"project-stats","Project Stats",[121,122,123,136],"table",{},[124,125,126],"thead",{},[127,128,129,133],"tr",{},[130,131,132],"th",{},"Metric",[130,134,135],{},"Value",[137,138,139,148,156,164,172,180,188],"tbody",{},[127,140,141,145],{},[142,143,144],"td",{},"Components",[142,146,147],{},"58 TSX files",[127,149,150,153],{},[142,151,152],{},"Routes",[142,154,155],{},"32 pages",[127,157,158,161],{},[142,159,160],{},"Utility modules",[142,162,163],{},"21 files",[127,165,166,169],{},[142,167,168],{},"Total TS/TSX files",[142,170,171],{},"~100",[127,173,174,177],{},[142,175,176],{},"Custom CSS",[142,178,179],{},"~670 lines",[127,181,182,185],{},[142,183,184],{},"Design tokens",[142,186,187],{},"30+ CSS custom properties",[127,189,190,193],{},[142,191,192],{},"GraphQL queries",[142,194,195],{},"Storefront + Customer Account APIs",[20,197],{},[23,199,201],{"id":200},"tech-stack","Tech Stack",[121,203,204,214],{},[124,205,206],{},[127,207,208,211],{},[130,209,210],{},"Layer",[130,212,213],{},"Technology",[137,215,216,224,232,240,248,256,264,272,280],{},[127,217,218,221],{},[142,219,220],{},"Framework",[142,222,223],{},"Shopify Hydrogen 2 (React Router / Remix)",[127,225,226,229],{},[142,227,228],{},"Language",[142,230,231],{},"TypeScript (strict mode)",[127,233,234,237],{},[142,235,236],{},"UI",[142,238,239],{},"React 18, Framer Motion",[127,241,242,245],{},[142,243,244],{},"Styling",[142,246,247],{},"Tailwind CSS v4 with custom design tokens",[127,249,250,253],{},[142,251,252],{},"API",[142,254,255],{},"Shopify Storefront GraphQL API",[127,257,258,261],{},[142,259,260],{},"Auth",[142,262,263],{},"Shopify Customer Account API (OAuth 2.0 passwordless)",[127,265,266,269],{},[142,267,268],{},"Build",[142,270,271],{},"Vite 6, GraphQL Codegen",[127,273,274,277],{},[142,275,276],{},"Hosting",[142,278,279],{},"Shopify Oxygen (Cloudflare Workers)",[127,281,282,285],{},[142,283,284],{},"AI Media",[142,286,287],{},"Higgsfield AI (all product videos and images)",{"title":289,"searchDepth":290,"depth":290,"links":291},"",2,[292,293,294,295,296,297],{"id":25,"depth":290,"text":26},{"id":74,"depth":290,"text":75},{"id":88,"depth":290,"text":89},{"id":109,"depth":290,"text":110},{"id":118,"depth":290,"text":119},{"id":200,"depth":290,"text":201},"Theme-based Shopify stores constrain the experience to Liquid's rendering model — limited animation control, rigid layout systems, and performance ceilings imposed by the theme architecture. For a luxury brand where the shopping experience needs to feel as polished as the product, headless commerce removes those constraints entirely.",{"language":300,"filename":301,"code":302},"typescript","app/routes/products.$handle.tsx","export async function loader({ params, context }: LoaderFunctionArgs) {\n  const { product } = await context.storefront.query(\n    PRODUCT_QUERY,\n    { variables: { handle: params.handle } }\n  )\n\n  if (!product) throw new Response(null, { status: 404 })\n\n  const selectedVariant = product.selectedOrFirstAvailableVariant\n  const relatedProducts = context.storefront.query(\n    RECOMMENDED_PRODUCTS_QUERY,\n    { variables: { productId: product.id } }\n  )\n\n  return defer({\n    product,\n    selectedVariant,\n    relatedProducts,\n  })\n}\n","A luxury apparel storefront built as a fully headless Shopify implementation on Hydrogen — 100+ TypeScript files, OAuth customer accounts, full cart-to-checkout flow, and all product media generated with AI.","md",false,"/images/projects/posh-and-paws.jpg",null,true,"https://poshandpaws.com",{},"/images/projects/posh-and-paws-mockup.jpg",13,"/works/posh-and-paws",1,{"title":6,"description":303},"A complete headless Shopify storefront using Hydrogen 2 (built on React Router/Remix). 58 components, 32 routes, full OAuth customer accounts, cart-to-checkout flow, blog, search with predictive autocomplete, and a custom design system. Every product image and video generated with Higgsfield AI — zero dependency on traditional creative production.","works/posh-and-paws",[319,6,320,321,322],"Shopify Hydrogen","React","TypeScript","Cloudflare Workers",[324,325,321,326,327,255,328,329],"Shopify Hydrogen 2","React 18","Tailwind CSS v4","Framer Motion","Shopify Oxygen","Higgsfield AI","/videos/posh-and-paws.mp4","2026","mskbZh7vqlU9-uj-aiMyuTupGchvgAww5zLXIFWCkdk",{"id":334,"title":335,"body":336,"category":621,"challenge":622,"codeSnippet":623,"description":626,"extension":304,"featured":305,"finalScreenshot":627,"gridOrder":307,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":628,"mockupImage":629,"navigation":308,"nextProject":307,"order":630,"path":631,"results":307,"schneiderFeatured":308,"schneiderOrder":290,"seo":632,"solution":633,"stem":634,"subtitle":635,"tags":636,"techStack":642,"thumbnail":648,"thumbnailVideo":649,"year":331,"__hash__":650},"works/works/shopagent.md","ShopAgent",{"type":8,"value":337,"toc":604},[338,342,345,348,350,352,361,366,395,398,400,404,408,415,419,422,426,433,437,443,445,449,453,492,496,534,536,538],[11,339,341],{"id":340},"shopagent-ucp-compliant-ai-shopping-assistant","ShopAgent — UCP-Compliant AI Shopping Assistant",[16,343,344],{},"A production-grade agentic commerce application that replaces traditional browse-and-click shopping with natural language commerce. Users describe what they want, and the AI agent discovers products across the entire Shopify ecosystem, compares prices across merchants, manages checkout, and handles payment — all in a single conversational interface.",[16,346,347],{},"This isn't a chatbot bolted onto a storefront. It's a UCP-native agent that implements the full buyer journey: discovery → refinement → checkout → order confirmation.",[20,349],{},[23,351,89],{"id":88},[353,354,359],"pre",{"className":355,"code":357,"language":358},[356],"language-text","┌───────────────────────────────────────────────────────────┐\n│                    Nuxt 3 Frontend                         │\n│   Chat UI  ←→  Product Carousels  ←→  ECP Checkout        │\n│          (SSE streaming + Pinia stores)                    │\n└─────────────────────┬─────────────────────────────────────┘\n                      │ SSE\n┌─────────────────────┴─────────────────────────────────────┐\n│              Nitro API Layer                                │\n│   Agent Orchestrator (Claude API + Tool Definitions)       │\n│   JWT Token Manager  │  Session Store  │  UCP Negotiation  │\n└──────┬────────────────────┬────────────────────┬──────────┘\n       │                    │                    │\n  Catalog MCP         Checkout MCP        Storefront MCP\n  (Global Discovery)  (Per-Merchant)      (Per-Store)\n","text",[80,360,357],{"__ignoreMap":289},[362,363,365],"h3",{"id":364},"how-the-agent-works","How the Agent Works",[367,368,369,373,376,383,386,389,392],"ol",{},[370,371,372],"li",{},"User sends a message (\"Find sustainable running shoes under $150\")",[370,374,375],{},"Nitro API passes it to the Agent Orchestrator",[370,377,378,379,382],{},"Claude analyzes intent and calls tools (e.g., ",[80,380,381],{},"search_global_products",")",[370,384,385],{},"Orchestrator executes tool calls against Shopify MCP servers via JSON-RPC 2.0",[370,387,388],{},"Results feed back to Claude, which may call more tools or generate a response",[370,390,391],{},"Text and tool results stream to the frontend via SSE in real time",[370,393,394],{},"Frontend extracts product data into Pinia stores and renders rich product cards",[16,396,397],{},"The agentic loop runs up to 10 tool rounds per request — enough for complex multi-step flows like \"find shoes, compare prices across merchants, then start checkout with the cheapest one.\"",[20,399],{},[23,401,403],{"id":402},"key-engineering-decisions","Key Engineering Decisions",[362,405,407],{"id":406},"full-replacement-checkout-updates","Full-Replacement Checkout Updates",[16,409,410,411,414],{},"Shopify's ",[80,412,413],{},"update_checkout"," is not a PATCH — it's a full replacement. Every call must include ALL fields (line items, buyer info, shipping) or they get dropped. The agent maintains complete checkout state and replays it on every update.",[362,416,418],{"id":417},"multi-merchant-checkout","Multi-Merchant Checkout",[16,420,421],{},"A single search returns products from multiple Shopify stores. Each merchant requires its own checkout session. The agent manages parallel checkout flows, each with independent state machines.",[362,423,425],{"id":424},"embedded-checkout-protocol-ecp","Embedded Checkout Protocol (ECP)",[16,427,428,429,432],{},"When checkout requires payment credentials the agent can't handle (card numbers, 3D Secure), it escalates to a sandboxed iframe with bidirectional JSON-RPC 2.0 communication via ",[80,430,431],{},"postMessage",", delegation handlers for payment instruments and credentials, and auto-response with cached buyer data where possible.",[362,434,436],{"id":435},"streaming-ux","Streaming UX",[16,438,439,440,442],{},"SSE interleaves text chunks and tool execution status. The frontend shows real-time typing with a streaming cursor, human-readable tool names (\"Searching products...\" not ",[80,441,381],{},"), and inline product carousels that appear as results arrive.",[20,444],{},[23,446,448],{"id":447},"what-i-built","What I Built",[362,450,452],{"id":451},"server-layer-16-files","Server Layer (16 files)",[454,455,456,462,468,474,480,486],"ul",{},[370,457,458,461],{},[30,459,460],{},"Agent orchestrator"," — Agentic loop managing Claude API ↔ tool execution ↔ response streaming",[370,463,464,467],{},[30,465,466],{},"3 MCP wrappers"," — Type-safe clients for Catalog, Checkout, and Storefront servers",[370,469,470,473],{},[30,471,472],{},"JSON-RPC 2.0 client"," — Exponential backoff retries, transport/RPC/business error classification",[370,475,476,479],{},[30,477,478],{},"JWT token manager"," — Auto-refresh with 5-minute buffer before 60-min expiry",[370,481,482,485],{},[30,483,484],{},"11 tool definitions"," across 3 MCP servers matching Shopify's API schemas",[370,487,488,491],{},[30,489,490],{},"UCP profile + negotiation"," — Capability declaration and intersection computation",[362,493,495],{"id":494},"frontend-layer-15-components-5-composables-2-stores","Frontend Layer (15 components + 5 composables + 2 stores)",[454,497,498,504,510,516,522,528],{},[370,499,500,503],{},[30,501,502],{},"Chat interface"," — Message list, streaming input, typing indicator",[370,505,506,509],{},[30,507,508],{},"Product carousels"," — Horizontal scroll cards with images, pricing, merchant info",[370,511,512,515],{},[30,513,514],{},"Cart sidebar"," — Per-shop grouping, quantity controls, slide-in animation",[370,517,518,521],{},[30,519,520],{},"Checkout status"," — Step-based progress with status colors and recovery hints",[370,523,524,527],{},[30,525,526],{},"ECP iframe"," — Sandboxed embedded checkout with delegation bridge",[370,529,530,533],{},[30,531,532],{},"Demo mode"," — 3 pre-configured scenarios that run without API keys",[20,535],{},[23,537,201],{"id":200},[121,539,540,548],{},[124,541,542],{},[127,543,544,546],{},[130,545,210],{},[130,547,213],{},[137,549,550,558,566,574,582,589,597],{},[127,551,552,555],{},[142,553,554],{},"Frontend",[142,556,557],{},"Nuxt 3, Vue 3 Composition API, Tailwind CSS v4",[127,559,560,563],{},[142,561,562],{},"Agent",[142,564,565],{},"Claude API with custom tool definitions",[127,567,568,571],{},[142,569,570],{},"Protocol",[142,572,573],{},"JSON-RPC 2.0 over HTTPS to Shopify MCP servers",[127,575,576,579],{},[142,577,578],{},"State",[142,580,581],{},"Pinia stores (conversation, cart, checkouts, orders)",[127,583,584,586],{},[142,585,260],{},[142,587,588],{},"JWT tokens (OAuth client credentials, 60-min TTL, auto-refresh)",[127,590,591,594],{},[142,592,593],{},"Streaming",[142,595,596],{},"Server-Sent Events from Nitro to frontend",[127,598,599,601],{},[142,600,228],{},[142,602,603],{},"TypeScript (strict mode) throughout",{"title":289,"searchDepth":290,"depth":290,"links":605},[606,610,616,620],{"id":88,"depth":290,"text":89,"children":607},[608],{"id":364,"depth":609,"text":365},3,{"id":402,"depth":290,"text":403,"children":611},[612,613,614,615],{"id":406,"depth":609,"text":407},{"id":417,"depth":609,"text":418},{"id":424,"depth":609,"text":425},{"id":435,"depth":609,"text":436},{"id":447,"depth":290,"text":448,"children":617},[618,619],{"id":451,"depth":609,"text":452},{"id":494,"depth":609,"text":495},{"id":200,"depth":290,"text":201},"Agentic Commerce","Shopify's Universal Commerce Protocol launched with backing from Walmart, Target, Visa, Mastercard, and Stripe — yet almost no independent developers have built production-grade UCP agents. The protocol is complex, the reference implementations are minimal, and building a full buyer journey requires coordinating three MCP servers, multi-merchant checkout state, and payment escalation.",{"language":300,"filename":624,"code":625},"server/api/agent/orchestrator.ts","async function runAgentLoop(\n  messages: Message[],\n  tools: ToolDefinition[]\n): Promise\u003CStreamableResponse> {\n  let toolRound = 0\n  const MAX_ROUNDS = 10\n\n  while (toolRound \u003C MAX_ROUNDS) {\n    const response = await anthropic.messages.create({\n      model: 'claude-sonnet-4-20250514',\n      messages,\n      tools,\n      stream: true,\n    })\n\n    const toolCalls = extractToolCalls(response)\n    if (toolCalls.length === 0) break\n\n    const results = await Promise.all(\n      toolCalls.map(tc => executeMcpTool(tc))\n    )\n    messages.push(...formatToolResults(results))\n    toolRound++\n  }\n\n  return streamResponse(messages)\n}\n","Full-stack agentic commerce app — conversational product discovery across the entire Shopify ecosystem, multi-merchant checkout, Embedded Checkout Protocol, and streaming UI.","/images/projects/shopagent-final.jpg",{},"/images/projects/shopagent-mockup.jpg",10,"/works/shopagent",{"title":335,"description":626},"A UCP-native agent implementing the complete buyer journey: discovery, refinement, checkout, and order confirmation. Three MCP server integrations (Catalog, Checkout, Storefront), agentic orchestration via Claude API with up to 10 tool rounds per request, full-replacement checkout state management, Embedded Checkout Protocol for payment escalation, and a streaming Nuxt 3 frontend with real-time product carousels.","works/shopagent","UCP Shopping Assistant",[637,638,639,640,641,621],"Shopify UCP","Catalog MCP","Checkout MCP","Nuxt 3","Claude API",[640,643,321,641,644,639,645,646,326,647],"Vue 3","Shopify Catalog MCP","Storefront MCP","Pinia","SSE","/images/projects/shopify-agent.jpg","/videos/shopagent.mp4","wLnkOmmdpjdsRwPLZ5JvcM8j73Qh3T8CUeSl0sYmWW4",{"id":652,"title":653,"body":654,"category":724,"challenge":725,"codeSnippet":726,"description":729,"extension":304,"featured":305,"finalScreenshot":730,"gridOrder":307,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":731,"mockupImage":732,"navigation":308,"nextProject":733,"order":314,"path":736,"results":307,"schneiderFeatured":308,"schneiderOrder":737,"seo":738,"solution":739,"stem":740,"subtitle":741,"tags":742,"techStack":748,"thumbnail":752,"thumbnailVideo":753,"year":331,"__hash__":754},"works/works/shopify-shopping-agent.md","Cart Whisperer",{"type":8,"value":655,"toc":718},[656,660,663,665,671,677,683,689,693,699,705,711,715],[23,657,659],{"id":658},"the-problem","The Problem",[16,661,662],{},"Traditional e-commerce search is keyword-based. A customer looking for \"something for my wife's birthday under $50 that ships fast\" has to mentally translate that into filter combinations and keyword searches. Faceted navigation helps but still requires customers to understand the catalog taxonomy. For stores with large catalogs, this friction leads to abandonment.",[23,664,89],{"id":88},[16,666,667,670],{},[30,668,669],{},"MCP Server"," — A TypeScript server exposing Shopify Storefront API operations as MCP tools: product search, collection browsing, variant selection, cart management, and store policies lookup. The AI agent calls these tools naturally during conversation.",[16,672,673,676],{},[30,674,675],{},"Agent Loop"," — Claude receives the customer's message along with conversation history and available MCP tools. It decides whether to search, ask clarifying questions, compare options, or proceed to cart. The agent maintains context about stated preferences across the conversation.",[16,678,679,682],{},[30,680,681],{},"Cart Builder"," — When the customer is ready, the agent uses the Cart Permalink API to generate a pre-filled checkout URL. This avoids the complexity of managing Storefront API cart mutations while still providing a seamless path to purchase.",[16,684,685,688],{},[30,686,687],{},"Frontend Widget"," — A lightweight React component that embeds on any Shopify storefront via a script tag. Handles the chat UI, message streaming, and cart link rendering.",[23,690,692],{"id":691},"key-technical-decisions","Key Technical Decisions",[16,694,695,698],{},[30,696,697],{},"Why MCP over function calling?"," MCP provides a standardized tool interface that's model-agnostic. If the underlying LLM changes, the tool definitions don't. MCP also enables the catalog tools to be reused in other AI contexts (merchant copilot, customer service bot).",[16,700,701,704],{},[30,702,703],{},"Why Cart Permalink over Storefront API carts?"," Cart permalinks are simpler and more reliable for the checkout handoff. They work across all Shopify themes without requiring any theme modifications. The tradeoff is less cart customization, but for the primary use case of \"find products and buy them,\" permalinks are sufficient.",[16,706,707,710],{},[30,708,709],{},"Why streaming over batch responses?"," Shopping conversations need to feel interactive. Streaming Claude's responses token-by-token keeps the experience feeling natural, especially when the agent is thinking through product comparisons.",[23,712,714],{"id":713},"outcome","Outcome",[16,716,717],{},"The shopping agent handles an average of 4 tool calls per conversation, with customers reaching a cart-ready state in under 2 minutes. Product discovery success rate (customer adds recommended item to cart) is 68%, compared to 23% for traditional site search on the same catalog.",{"title":289,"searchDepth":290,"depth":290,"links":719},[720,721,722,723],{"id":658,"depth":290,"text":659},{"id":88,"depth":290,"text":89},{"id":691,"depth":290,"text":692},{"id":713,"depth":290,"text":714},"AI Agent","Product discovery on Shopify stores relies on traditional search and filter UIs that break down when customers don't know exact product names or when catalogs exceed hundreds of products. Customers abandon stores when they can't quickly find what matches their needs.",{"language":300,"filename":727,"code":728},"mcp/tools/search-products.ts","export const searchProducts = defineMcpTool({\n  name: 'search_products',\n  description: 'Search the Shopify catalog by query, filters, and price range',\n  parameters: z.object({\n    query: z.string(),\n    productType: z.string().optional(),\n    minPrice: z.number().optional(),\n    maxPrice: z.number().optional(),\n    sortBy: z.enum(['RELEVANCE', 'PRICE', 'BEST_SELLING']).optional(),\n  }),\n  execute: async ({ query, productType, minPrice, maxPrice, sortBy }) => {\n    const filters: string[] = []\n    if (productType) filters.push(`product_type:${productType}`)\n    if (minPrice) filters.push(`variants.price:>=${minPrice}`)\n    if (maxPrice) filters.push(`variants.price:\u003C=${maxPrice}`)\n\n    const { products } = await storefront.query(SEARCH_QUERY, {\n      variables: {\n        query: [query, ...filters].join(' '),\n        sortKey: sortBy ?? 'RELEVANCE',\n        first: 10,\n      },\n    })\n\n    return products.nodes.map(formatProductForAgent)\n  },\n})\n","A conversational AI shopping assistant that browses Shopify catalogs via MCP, understands customer intent, and builds carts — turning natural language into checkout-ready orders.","/images/projects/shopify-shopping-agent-final.jpg",{},"/images/projects/shopify-shopping-agent-mockup.jpg",{"title":734,"slug":735},"Headless Kit","shopify-storefront-kit","/works/shopify-shopping-agent",4,{"title":653,"description":729},"Built a conversational agent using Claude with Model Context Protocol (MCP) tools that gives the AI direct access to a Shopify store's catalog. Customers describe what they want in natural language, and the agent searches, compares, recommends, and adds items to cart.","works/shopify-shopping-agent","Conversational Commerce for Shopify",[743,744,745,746,747],"AI","MCP","Claude","Storefront API","Conversational Commerce",[641,669,749,750,321,320,751],"Shopify Storefront API","Cart Permalink API","Vercel","/images/projects/shopify-shopping-agent.jpg","/videos/shopify-shopping-agent.mp4","-r79H9DNgga7v8_Uw2OnmoS4rSzco0OsNvU71QfDVvQ",{"id":756,"title":757,"body":758,"category":724,"challenge":825,"codeSnippet":826,"description":829,"extension":304,"featured":305,"finalScreenshot":830,"gridOrder":307,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":831,"mockupImage":832,"navigation":308,"nextProject":833,"order":314,"path":836,"results":837,"schneiderFeatured":308,"schneiderOrder":838,"seo":839,"solution":840,"stem":841,"subtitle":842,"tags":843,"techStack":847,"thumbnail":648,"thumbnailVideo":853,"year":331,"__hash__":854},"works/works/shopify-agent.md","StockPilot",{"type":8,"value":759,"toc":819},[760,762,765,767,770,776,782,788,794,796,802,808,814,816],[23,761,659],{"id":658},[16,763,764],{},"Multi-store Shopify merchants face a compounding inventory challenge: as SKU counts grow and sales patterns shift seasonally, manual inventory management becomes a bottleneck. Spreadsheet-based reorder points can't adapt to real-time demand changes, and by the time a human notices a trending product is running low, the sales window has already passed.",[23,766,89],{"id":88},[16,768,769],{},"The system follows an event-driven architecture built entirely on AWS CDK infrastructure-as-code:",[16,771,772,775],{},[30,773,774],{},"Data Ingestion Layer"," — Shopify webhooks (orders/create, inventory_levels/update) flow through API Gateway into SQS queues, ensuring no events are lost during traffic spikes. Each event is enriched with historical context from DynamoDB before processing.",[16,777,778,781],{},[30,779,780],{},"Analysis Pipeline"," — Lambda functions calculate rolling sales velocity, seasonal adjustment factors, and supplier reliability scores. These metrics feed into a decision context that the AI agent evaluates.",[16,783,784,787],{},[30,785,786],{},"Decision Engine"," — Claude evaluates each potential restock against multiple factors: current velocity, upcoming seasonal trends, supplier lead times, and cash flow constraints. The agent doesn't just calculate — it reasons about whether a restock makes strategic sense.",[16,789,790,793],{},[30,791,792],{},"Execution Layer"," — Approved restock decisions automatically generate purchase orders via supplier APIs and update Shopify inventory expectations. Every decision is logged with full reasoning for merchant review.",[23,795,692],{"id":691},[16,797,798,801],{},[30,799,800],{},"Why multi-agent over single-agent?"," Each store has different suppliers, margins, and seasonal patterns. Dedicated agents per store maintain focused context windows while a coordinator agent handles cross-store optimization (e.g., transferring stock between locations).",[16,803,804,807],{},[30,805,806],{},"Why DynamoDB over RDS?"," The access patterns are almost entirely key-value lookups (SKU → velocity, SKU → supplier context). DynamoDB's single-digit millisecond reads keep the decision pipeline under the 15-minute Lambda timeout even for bulk evaluations.",[16,809,810,813],{},[30,811,812],{},"Why Claude over rule-based?"," Pure threshold-based systems can't handle edge cases: a sudden TikTok viral moment, a supplier delay announcement, or a seasonal shift that historical data hasn't seen. The LLM layer adds judgment to the data.",[23,815,714],{"id":713},[16,817,818],{},"The system processes approximately 2,000 inventory evaluations daily across 15,000+ SKUs. The merchant's stockout rate dropped from ~8% to under 1%, and the time saved on manual inventory review freed up 20+ hours per week for strategic work.",{"title":289,"searchDepth":290,"depth":290,"links":820},[821,822,823,824],{"id":658,"depth":290,"text":659},{"id":88,"depth":290,"text":89},{"id":691,"depth":290,"text":692},{"id":713,"depth":290,"text":714},"Managing inventory across multiple Shopify stores meant constant manual monitoring, delayed restock decisions, and missed sales opportunities during peak periods. Merchants needed a system that could think and act on its own.",{"language":300,"filename":827,"code":828},"agent/restock-decision.ts","export async function evaluateRestockDecision(\n  sku: string,\n  context: InventoryContext\n): Promise\u003CRestockDecision> {\n  const salesVelocity = await calculateVelocity(sku, 30)\n  const currentStock = context.availableQuantity\n  const leadTime = context.supplier.avgLeadTimeDays\n\n  const daysOfStock = currentStock / salesVelocity.unitsPerDay\n  const reorderPoint = salesVelocity.unitsPerDay * leadTime * 1.3\n\n  if (currentStock \u003C= reorderPoint) {\n    const orderQty = Math.ceil(\n      salesVelocity.unitsPerDay * leadTime * 2 - currentStock\n    )\n\n    const decision = await claude.messages.create({\n      model: 'claude-sonnet-4-20250514',\n      messages: [{\n        role: 'user',\n        content: buildRestockPrompt(sku, {\n          salesVelocity,\n          currentStock,\n          orderQty,\n          seasonalTrends: context.trends,\n        }),\n      }],\n    })\n\n    return parseRestockDecision(decision, orderQty)\n  }\n\n  return { action: 'hold', reason: `${daysOfStock.toFixed(0)}d remaining` }\n}\n","An autonomous AI agent that monitors inventory, analyzes sales trends, and executes restocking decisions across multiple Shopify stores without human intervention.","/images/projects/shopify-agent-final.jpg",{},"/images/projects/shopify-agent-mockup.jpg",{"title":834,"slug":835},"Shopify AI Copilot","shopify-ai-copilot","/works/shopify-agent","92% reduction in stockout events. Average restock decision time dropped from 48 hours to 12 minutes. System manages 15,000+ SKUs across 3 stores autonomously.",5,{"title":757,"description":829},"Built a multi-agent system powered by Claude that ingests real-time Shopify webhooks, processes sales velocity data through AWS Lambda pipelines, and autonomously creates purchase orders when inventory drops below dynamically calculated thresholds.","works/shopify-agent","AI-powered inventory management that thinks and acts autonomously",[743,844,745,845,846],"AWS CDK","Data Pipeline","Shopify",[641,844,848,849,850,851,852,321],"Lambda","DynamoDB","SQS","EventBridge","Shopify Admin API","/videos/shopify-agent.mp4","DbuSjHTGX9j1ymb5TRzaGhgM344qIYoJnQcMK03V6ck",[856],{"id":857,"title":858,"body":859,"category":917,"challenge":918,"codeSnippet":919,"description":922,"extension":304,"featured":308,"finalScreenshot":923,"gridOrder":314,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":924,"mockupImage":925,"navigation":308,"nextProject":307,"order":312,"path":926,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":927,"solution":928,"stem":929,"subtitle":930,"tags":931,"techStack":938,"thumbnail":944,"thumbnailVideo":307,"year":331,"__hash__":945},"works/works/multi-channel-fulfillment.md","Full Route IQ",{"type":8,"value":860,"toc":913},[861,865,868,870,874,880,886,892,898,904,906,910],[11,862,864],{"id":863},"fulfill-mesh","Fulfill Mesh",[16,866,867],{},"A unified order ingestion and intelligent fulfillment routing system for Shopify Plus merchants operating across five sales channels (Shopify D2C, Shopify B2B, Amazon SP-API, Walmart Marketplace, Best Buy/Mirakl) and five fulfillment providers (ShipBob, ShipHero, Amazon MCF, and internal warehouses).",[20,869],{},[23,871,873],{"id":872},"what-it-does","What It Does",[16,875,876,879],{},[30,877,878],{},"Order ingestion"," — Channel connectors normalize orders from every source into a unified order format. Shopify orders arrive via webhooks; marketplace orders via polling with configurable intervals.",[16,881,882,885],{},[30,883,884],{},"Routing engine"," — A rules-based decision engine evaluates each order against inventory availability, geographic proximity, SLA deadlines, and fulfillment cost. Handles B2B bulk orders, BOPIS, Amazon Prime SLA enforcement, EU shipping, and out-of-stock flagging.",[16,887,888,891],{},[30,889,890],{},"Split shipment logic"," — When no single warehouse can fulfill an order, the engine calculates minimum location coverage, compares split-shipment cost vs. inventory-transfer-then-ship cost, and selects the option that meets the SLA at lowest total cost.",[16,893,894,897],{},[30,895,896],{},"Tracking push-back"," — Once a 3PL provides tracking, the system pushes it back to the originating channel (Shopify fulfillment API, Amazon SP-API feed, Walmart shipOrder, Mirakl updateShipment), each with its own format and carrier code requirements.",[16,899,900,903],{},[30,901,902],{},"Operations dashboard"," — Real-time view of orders by channel, fulfillment provider status, SLA-at-risk alerts, inventory health, and routing analytics.",[20,905],{},[23,907,909],{"id":908},"key-decisions","Key Decisions",[16,911,912],{},"The unified order type is the core abstraction — all channel-specific logic lives in connectors, everything downstream operates on a single interface. BullMQ workers decouple API response times from external latency with retry and dead-letter handling. The rules engine uses priority ordering so new routing rules can be added without modifying existing logic.",{"title":289,"searchDepth":290,"depth":290,"links":914},[915,916],{"id":872,"depth":290,"text":873},{"id":908,"depth":290,"text":909},"E-Commerce Operations","Multi-channel Shopify Plus merchants operating across D2C, B2B, Amazon, Walmart, and marketplace channels face fragmented order flows, disconnected fulfillment providers, and no unified routing logic. Each channel has different SLA requirements, tracking formats, and carrier code conventions.",{"language":300,"filename":920,"code":921},"engine/route-order.ts","async function routeOrder(order: UnifiedOrder): Promise\u003CRoutingDecision> {\n  const warehouses = await getWarehousesWithInventory(order.lineItems)\n\n  // Check single-warehouse fulfillment first\n  const singleFulfill = warehouses.find(w =>\n    canFulfillComplete(w, order.lineItems)\n  )\n\n  if (singleFulfill) {\n    return { type: 'single', warehouse: singleFulfill }\n  }\n\n  // Calculate split shipment vs inventory transfer\n  const splitCost = calculateSplitShipment(warehouses, order)\n  const transferCost = calculateTransferThenShip(warehouses, order)\n\n  return splitCost.total \u003C transferCost.total && splitCost.meetsSlA\n    ? { type: 'split', plan: splitCost }\n    : { type: 'transfer', plan: transferCost }\n}\n","Unified order ingestion and intelligent routing across 5 sales channels and 5 fulfillment providers — with cost-aware split shipment logic, SLA enforcement, and tracking push-back to originating channels.","/images/projects/multi-channel-fulfillment-final.jpg",{},"/images/projects/multi-channel-fulfillment-mockup.jpg","/works/multi-channel-fulfillment",{"title":858,"description":922},"A unified order ingestion system with channel connectors that normalize orders from every source into a single format. A rules-based routing engine evaluates each order against inventory availability, geographic proximity, SLA deadlines, and fulfillment cost. Split shipment logic calculates minimum location coverage and compares costs. Tracking pushes back to each originating channel in its required format.","works/multi-channel-fulfillment","Multi-Channel Order Routing for Shopify Plus",[932,933,934,935,936,937],"Shopify Plus","Amazon SP-API","Walmart","BullMQ","PostgreSQL","Fulfillment",[321,939,935,940,936,941,320,942,943],"Hono","Redis","Drizzle ORM","Recharts","Docker","/images/projects/multi-channel-fulfillment.jpg","ISD-i605dzvfc7o9M_PgkRVkfW0Mw74mzS8ZAO__FPU",[947,993,1092,1205,1314,1382,1446,1571,1675],{"id":857,"title":858,"body":948,"category":917,"challenge":918,"codeSnippet":988,"description":922,"extension":304,"featured":308,"finalScreenshot":923,"gridOrder":314,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":989,"mockupImage":925,"navigation":308,"nextProject":307,"order":312,"path":926,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":990,"solution":928,"stem":929,"subtitle":930,"tags":991,"techStack":992,"thumbnail":944,"thumbnailVideo":307,"year":331,"__hash__":945},{"type":8,"value":949,"toc":984},[950,952,954,956,958,962,966,970,974,978,980,982],[11,951,864],{"id":863},[16,953,867],{},[20,955],{},[23,957,873],{"id":872},[16,959,960,879],{},[30,961,878],{},[16,963,964,885],{},[30,965,884],{},[16,967,968,891],{},[30,969,890],{},[16,971,972,897],{},[30,973,896],{},[16,975,976,903],{},[30,977,902],{},[20,979],{},[23,981,909],{"id":908},[16,983,912],{},{"title":289,"searchDepth":290,"depth":290,"links":985},[986,987],{"id":872,"depth":290,"text":873},{"id":908,"depth":290,"text":909},{"language":300,"filename":920,"code":921},{},{"title":858,"description":922},[932,933,934,935,936,937],[321,939,935,940,936,941,320,942,943],{"id":994,"title":995,"body":996,"category":1063,"challenge":1064,"codeSnippet":1065,"description":1068,"extension":304,"featured":305,"finalScreenshot":1069,"gridOrder":838,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1070,"mockupImage":1071,"navigation":308,"nextProject":307,"order":1072,"path":1073,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":1074,"solution":1075,"stem":1076,"subtitle":1077,"tags":1078,"techStack":1084,"thumbnail":1090,"thumbnailVideo":307,"year":331,"__hash__":1091},"works/works/pixelguard.md","Pixel Guard",{"type":8,"value":997,"toc":1060},[998,1002,1005,1007,1009,1018,1024,1034,1051,1057],[11,999,1001],{"id":1000},"pixelguard-server-side-tracking-for-shopify","PixelGuard — Server-Side Tracking for Shopify",[16,1003,1004],{},"Replaces $200-500/month SaaS tools (Elevar, Analyzify, Littledata) with a self-hosted, open-source solution. Three components: a Shopify Web Pixel Extension capturing client-side events with SHA-256 hashed PII, a Cloudflare Workers edge server firing server-side CAPI to four ad platforms simultaneously, and a Remix + Polaris admin app that diagnoses tracking loss.",[20,1006],{},[23,1008,692],{"id":691},[16,1010,1011,1017],{},[30,1012,1013,1014],{},"Event deduplication via shared ",[80,1015,1016],{},"event_id"," — Both client pixel and server webhook use the same UUID per purchase. Ad platforms auto-deduplicate without manual coordination.",[16,1019,1020,1023],{},[30,1021,1022],{},"GDPR-safe consent defaults"," — All tracking permissions default to denied. Only explicit consent grants access. Every state change logged with timestamp and region for audit compliance. Maps to Google Consent Mode v2's four signals.",[16,1025,1026,1029,1030,1033],{},[30,1027,1028],{},"Resilient multi-platform dispatch"," — ",[80,1031,1032],{},"Promise.allSettled"," ensures one platform's API failure doesn't block the others. Events logged to D1 regardless of platform response.",[16,1035,1036,1039,1040,1043,1044,1043,1047,1050],{},[30,1037,1038],{},"Session bridging"," — Client-side attribution cookies (",[80,1041,1042],{},"_fbp",", ",[80,1045,1046],{},"_fbc",[80,1048,1049],{},"gclid",") captured by the pixel and stored in D1 keyed by hashed email. Server-side webhooks (which have email but no cookies) pull the missing attribution data for CAPI enrichment.",[16,1052,1053,1056],{},[30,1054,1055],{},"Validation engine"," — The dashboard doesn't just track — it diagnoses. Compares client vs server event counts to calculate per-platform capture rates and classify every missed event by root cause: ad blocker, iOS ITP, consent denied, or redirect.",[16,1058,1059],{},"Saves merchants $2,400-6,000/year in SaaS fees while providing better diagnostic visibility than the paid alternatives.",{"title":289,"searchDepth":290,"depth":290,"links":1061},[1062],{"id":691,"depth":290,"text":692},"Analytics & Tracking","E-commerce stores lose 30-50% of purchase tracking data to ad blockers, iOS ITP, consent denials, and external payment redirects. Ad platform bidding algorithms trained on incomplete data make profitable campaigns look unprofitable. Existing SaaS solutions cost $200-500/month and offer limited diagnostic visibility.",{"language":300,"filename":1066,"code":1067},"worker/dispatch.ts","async function dispatchServerEvents(\n  event: NormalizedEvent,\n  platforms: PlatformConfig[]\n) {\n  const results = await Promise.allSettled(\n    platforms.map(async (platform) => {\n      const payload = platform.transform(event)\n      const response = await fetch(platform.endpoint, {\n        method: 'POST',\n        headers: platform.headers,\n        body: JSON.stringify(payload),\n      })\n      return { platform: platform.name, status: response.status }\n    })\n  )\n\n  await env.DB.prepare(\n    'INSERT INTO dispatch_log VALUES (?, ?, ?, ?)'\n  ).bind(event.id, event.type, JSON.stringify(results), Date.now()).run()\n}\n","Open-source server-side tracking that replaces $200-500/month SaaS tools. Captures purchase events via Shopify Web Pixel and webhooks, fires server-side CAPI to Meta, GA4, Google Ads, and TikTok, and diagnoses exactly why tracking was lost.","/images/projects/pixelguard-final.jpg",{},"/images/projects/pixelguard-mockup.jpg",12,"/works/pixelguard",{"title":995,"description":1068},"Three components: a Shopify Web Pixel Extension capturing client-side events with SHA-256 hashed PII, a Cloudflare Workers edge server firing server-side CAPI to four ad platforms simultaneously from a first-party subdomain, and a Remix + Polaris admin app that diagnoses tracking loss by root cause — ad blocker, iOS ITP, consent denied, or redirect.","works/pixelguard","Server-Side Tracking",[1079,1080,322,1081,1082,1083],"Shopify Web Pixel","CAPI","Meta Ads","GA4","Privacy",[321,1085,1086,322,939,1087,1088,1089],"Remix","Polaris","D1","Shopify Web Pixel Extension","Prisma","/images/projects/pixelguard.jpg","oGxmZl4y6hjCmSrjfg3HnBxskpGUpJNG6kHf7luZ69E",{"id":1093,"title":1094,"body":1095,"category":1173,"challenge":1174,"codeSnippet":1175,"description":1179,"extension":304,"featured":305,"finalScreenshot":1180,"gridOrder":1181,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1182,"mockupImage":1183,"navigation":308,"nextProject":1184,"order":1187,"path":1188,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":1189,"solution":1190,"stem":1191,"subtitle":1192,"tags":1193,"techStack":1199,"thumbnail":1203,"thumbnailVideo":307,"year":331,"__hash__":1204},"works/works/shopify-deploy-pipeline.md","Theme Launch",{"type":8,"value":1096,"toc":1167},[1097,1099,1106,1109,1111,1117,1123,1129,1135,1137,1143,1149,1162,1164],[23,1098,659],{"id":658},[16,1100,1101,1102,1105],{},"Shopify theme development is stuck in a pre-DevOps era. The typical workflow: developer edits files locally, runs ",[80,1103,1104],{},"shopify theme push"," to a development theme, manually checks the preview, then pushes to the live theme hoping nothing breaks. There's no automated testing, no preview environments for PR review, no performance gates, and no rollback plan.",[16,1107,1108],{},"For agencies managing multiple client stores, this multiplies into a significant risk surface. One bad push to a live theme during a sale event can cost thousands in lost revenue.",[23,1110,89],{"id":88},[16,1112,1113,1116],{},[30,1114,1115],{},"Reusable Workflow"," — The pipeline is distributed as a reusable GitHub Actions workflow. Teams reference it from their theme repository with minimal configuration (store URL, CLI credentials).",[16,1118,1119,1122],{},[30,1120,1121],{},"PR Preview Flow"," — Every pull request automatically pushes to an unpublished preview theme named after the PR number. A bot comments with the preview URL. Reviewers can see changes on a real Shopify store before approving.",[16,1124,1125,1128],{},[30,1126,1127],{},"Quality Gates"," — The pipeline runs Theme Check (Shopify's official linter) and Lighthouse CI against the preview theme. Both must pass before merge is allowed. Theme Check catches Liquid anti-patterns; Lighthouse catches performance regressions.",[16,1130,1131,1134],{},[30,1132,1133],{},"Production Deploy"," — On merge to main, the pipeline pushes to the live theme. It captures a snapshot of the current live theme first, enabling instant rollback if issues are discovered post-deploy.",[23,1136,692],{"id":691},[16,1138,1139,1142],{},[30,1140,1141],{},"Why unpublished themes for preview?"," Shopify doesn't have a native \"preview environment\" concept. Unpublished themes are the closest equivalent — they're fully functional stores accessible via a preview URL but not visible to customers. Each PR gets its own isolated preview.",[16,1144,1145,1148],{},[30,1146,1147],{},"Why Theme Check over custom linting?"," Theme Check is maintained by Shopify and updated with each platform change. Custom linting rules would require constant maintenance to keep up with Liquid API changes. Theme Check handles this upstream.",[16,1150,1151,1154,1155,1158,1159,1161],{},[30,1152,1153],{},"Why snapshot-based rollback over git-based?"," ",[80,1156,1157],{},"git revert"," + ",[80,1160,1104],{}," takes minutes. Capturing a theme snapshot before deploy and swapping back via the Theme API takes seconds. For a live store, those minutes matter.",[23,1163,714],{"id":713},[16,1165,1166],{},"The pipeline has been adopted by 3 Shopify agencies managing a combined 20+ stores. Average time from PR merge to live deployment: 4 minutes. Zero production incidents from theme deployments since adoption, compared to an average of 2 per month before.",{"title":289,"searchDepth":290,"depth":290,"links":1168},[1169,1170,1171,1172],{"id":658,"depth":290,"text":659},{"id":88,"depth":290,"text":89},{"id":691,"depth":290,"text":692},{"id":713,"depth":290,"text":714},"DevOps Template","Shopify theme development lacks standardized CI/CD practices. Most teams push directly to live themes via Shopify CLI, skip linting, have no preview environment workflow, and risk breaking production with every deployment. There's no 'Vercel for Shopify themes.'",{"language":1176,"filename":1177,"code":1178},"yaml",".github/workflows/theme-deploy.yml","deploy-preview:\n  if: github.event_name == 'pull_request'\n  runs-on: ubuntu-latest\n  steps:\n    - uses: actions/checkout@v4\n\n    - name: Setup Shopify CLI\n      uses: shopify/cli-action@v1\n      with:\n        store: ${{ secrets.SHOPIFY_STORE }}\n        password: ${{ secrets.SHOPIFY_CLI_TOKEN }}\n\n    - name: Push to preview theme\n      id: preview\n      run: |\n        THEME_NAME=\"PR-${{ github.event.number }}\"\n        THEME_ID=$(shopify theme list --json | \\\n          jq -r \".[] | select(.name==\\\"$THEME_NAME\\\") | .id\")\n\n        if [ -z \"$THEME_ID\" ]; then\n          shopify theme push --unpublished --theme \"$THEME_NAME\" --json\n        else\n          shopify theme push --theme \"$THEME_ID\" --json\n        fi\n\n        PREVIEW_URL=$(shopify theme info --theme \"$THEME_NAME\" --json | \\\n          jq -r '.preview_url')\n        echo \"url=$PREVIEW_URL\" >> \"$GITHUB_OUTPUT\"\n\n    - name: Comment PR with preview link\n      uses: actions/github-script@v7\n      with:\n        script: |\n          github.rest.issues.createComment({\n            issue_number: context.issue.number,\n            owner: context.repo.owner,\n            repo: context.repo.repo,\n            body: `🔍 Preview: ${{ steps.preview.outputs.url }}`\n          })\n","A production-ready GitHub Actions pipeline template for Shopify theme development — automated linting, theme check, preview deployments, and zero-downtime production pushes.","/images/projects/shopify-deploy-pipeline-final.jpg",7,{},"/images/projects/shopify-deploy-pipeline-mockup.jpg",{"title":1185,"slug":1186},"Shopify OTel Kit","shopify-otel-kit",8,"/works/shopify-deploy-pipeline",{"title":1094,"description":1179},"Created a reusable GitHub Actions workflow that automates the full Shopify theme lifecycle: PR previews on unpublished themes, automated Theme Check linting, Lighthouse performance gates, and atomic production deployments with instant rollback capability.","works/shopify-deploy-pipeline","CI/CD Pipeline for Shopify Themes",[1194,1195,1196,1197,1198],"GitHub Actions","Shopify CLI","CI/CD","Theme Check","Automation",[1194,1195,1197,1200,1201,1202],"Lighthouse CI","Bash","YAML","/images/projects/shopify-deploy-pipeline.jpg","Xs3L-_4hIV3Abe0keqZfZvy5Xd5DhScyR0XKhgQaV4A",{"id":1206,"title":1207,"body":1208,"category":1288,"challenge":1289,"codeSnippet":1290,"description":1293,"extension":304,"featured":305,"finalScreenshot":1294,"gridOrder":1295,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1296,"mockupImage":1297,"navigation":308,"nextProject":1298,"order":1181,"path":1300,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":1301,"solution":1302,"stem":1303,"subtitle":1304,"tags":1305,"techStack":1310,"thumbnail":1312,"thumbnailVideo":307,"year":331,"__hash__":1313},"works/works/shopify-bff.md","Store Bridge",{"type":8,"value":1209,"toc":1282},[1210,1212,1215,1218,1220,1239,1245,1251,1257,1259,1265,1271,1277,1279],[23,1211,659],{"id":658},[16,1213,1214],{},"Shopify's API surface is fragmented by design: the Storefront API is public and optimized for customer-facing reads, the Admin API requires private authentication and provides full CRUD, and custom apps add their own endpoints. A headless frontend that needs product data with real-time inventory, custom pricing, and metafields must juggle 2-3 different API clients with different auth mechanisms.",[16,1216,1217],{},"This complexity bleeds into the frontend: multiple API clients, inconsistent error handling, no shared caching strategy, and TypeScript types that don't compose well across APIs.",[23,1219,89],{"id":88},[16,1221,1222,1225,1226,1043,1229,1043,1232,1043,1235,1238],{},[30,1223,1224],{},"tRPC Router"," — The BFF exposes a tRPC router with procedures organized by domain: ",[80,1227,1228],{},"product",[80,1230,1231],{},"collection",[80,1233,1234],{},"cart",[80,1236,1237],{},"customer",". Each procedure fetches from whichever Shopify APIs it needs and returns a unified shape.",[16,1240,1241,1244],{},[30,1242,1243],{},"Dual API Client"," — The server maintains authenticated clients for both Storefront and Admin APIs. Storefront API handles the bulk of read operations; Admin API fills in gaps (inventory levels, metafield writes, custom data).",[16,1246,1247,1250],{},[30,1248,1249],{},"Edge Deployment"," — Runs on Cloudflare Workers via Hono. Product data caches at the edge with stale-while-revalidate strategy. Cache invalidation triggers from Shopify webhooks (product/update, inventory_levels/update).",[16,1252,1253,1256],{},[30,1254,1255],{},"Type Safety End-to-End"," — tRPC generates client types automatically. The frontend imports the router type and gets full autocomplete for every procedure, input, and response shape. No API documentation needed.",[23,1258,692],{"id":691},[16,1260,1261,1264],{},[30,1262,1263],{},"Why tRPC over GraphQL federation?"," The frontend doesn't need a generic query language — it needs specific data shapes for specific pages. tRPC's procedure-based approach maps cleanly to page data requirements and avoids the complexity of schema stitching.",[16,1266,1267,1270],{},[30,1268,1269],{},"Why Cloudflare Workers over a traditional server?"," Edge deployment puts the BFF physically closer to customers. For Shopify storefronts where the Storefront API is already globally distributed, the BFF at the edge means the aggregation overhead is minimal.",[16,1272,1273,1276],{},[30,1274,1275],{},"Why merge APIs on the server?"," Client-side API orchestration means multiple round trips and exposing Admin API credentials. Server-side merging does one round trip to the BFF and keeps all Shopify credentials server-side.",[23,1278,714],{"id":713},[16,1280,1281],{},"Frontend API code was reduced by 60% across the projects using the BFF. Response times improved by an average of 200ms due to edge caching and parallel API fetches. The type-safe interface eliminated an entire category of integration bugs.",{"title":289,"searchDepth":290,"depth":290,"links":1283},[1284,1285,1286,1287],{"id":658,"depth":290,"text":659},{"id":88,"depth":290,"text":89},{"id":691,"depth":290,"text":692},{"id":713,"depth":290,"text":714},"Backend Architecture","Headless Shopify storefronts need data from multiple Shopify APIs: product data from Storefront API, inventory from Admin API, metafields from both, and custom logic for pricing rules. Frontend code becomes a tangled web of different API clients, authentication schemes, and error handling patterns.",{"language":300,"filename":1291,"code":1292},"src/routers/product.ts","export const productRouter = router({\n  getByHandle: publicProcedure\n    .input(z.object({ handle: z.string() }))\n    .query(async ({ input, ctx }) => {\n      // Parallel fetch from both APIs\n      const [storefrontData, adminData] = await Promise.all([\n        ctx.storefront.query(PRODUCT_QUERY, {\n          variables: { handle: input.handle },\n        }),\n        ctx.admin.query(INVENTORY_QUERY, {\n          variables: { handle: input.handle },\n        }),\n      ])\n\n      const product = storefrontData.product\n      const inventory = adminData.productByHandle\n\n      return {\n        ...product,\n        variants: product.variants.nodes.map(variant => ({\n          ...variant,\n          inventoryQuantity: inventory?.variants.nodes\n            .find(v => v.id === variant.id)\n            ?.inventoryQuantity ?? null,\n          // Custom pricing logic\n          finalPrice: applyPricingRules(variant, ctx.customerTags),\n        })),\n      }\n    }),\n})\n","A Backend-for-Frontend layer that unifies Shopify's Storefront and Admin APIs behind a single, type-safe tRPC interface — reducing client complexity and enabling edge caching.","/images/projects/shopify-bff-final.jpg",9,{},"/images/projects/shopify-bff-mockup.jpg",{"title":1094,"slug":1299},"shopify-deploy-pipeline","/works/shopify-bff",{"title":1207,"description":1293},"Built a tRPC-based BFF that sits between the frontend and Shopify. It merges data from multiple Shopify APIs into unified response shapes, handles all authentication, implements edge caching strategies, and exposes a single type-safe interface that frontends consume.","works/shopify-bff","Unified API Layer for Headless Shopify",[1306,1307,746,1308,1309],"tRPC","Node.js","Admin API","Edge",[1306,1307,939,322,749,852,321,1311],"Zod","/images/projects/shopify-bff.jpg","d4CDX1U6-nLMjE2TSZVhKtlN4CDXk7L9CmJ31_xiosY",{"id":1315,"title":1316,"body":1317,"category":1356,"challenge":1357,"codeSnippet":1358,"description":1361,"extension":304,"featured":305,"finalScreenshot":1362,"gridOrder":630,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1363,"mockupImage":1364,"navigation":308,"nextProject":307,"order":1365,"path":1366,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":1367,"solution":1368,"stem":1369,"subtitle":1370,"tags":1371,"techStack":1376,"thumbnail":1380,"thumbnailVideo":307,"year":331,"__hash__":1381},"works/works/shopify-e2e-testing.md","Shopify E2E",{"type":8,"value":1318,"toc":1351},[1319,1323,1326,1328,1332,1335,1339,1342,1344],[11,1320,1322],{"id":1321},"shopify-e2e-testing-framework","Shopify E2E Testing Framework",[16,1324,1325],{},"A store-agnostic testing framework that treats store configuration as data, not code. Add a new Shopify store by dropping in a config file — the entire test suite runs against it automatically. Covers critical path flows, third-party integration validation, visual regression, accessibility compliance, and performance budgets across 40+ browser/device combinations via BrowserStack.",[20,1327],{},[23,1329,1331],{"id":1330},"store-agnostic-design","Store-Agnostic Design",[16,1333,1334],{},"Each store is a TypeScript config object: URLs, selectors (with fallback chains for dynamic themes), test data, accessibility exceptions, and per-device performance budgets. Adding a new store means copying the template and filling in selectors. No test code changes required.",[23,1336,1338],{"id":1337},"what-gets-tested","What Gets Tested",[16,1340,1341],{},"13 critical path tests (cart, checkout, subscriptions, navigation), 7 integration tests (Appstle widget loading, Klaviyo forms, GoAffPro referral persistence), 9 visual regression tests, 6 WCAG 2.1 AA accessibility tests via axe-core, and 12+ performance tests with separate desktop/mobile budgets for LCP, FCP, CLS, TBT, and Lighthouse scores.",[23,1343,89],{"id":88},[16,1345,1346,1347,1350],{},"Composable Playwright fixtures (base → shopify → a11y → performance) give every test automatic screenshot capture, store config injection, and clean cart state without boilerplate. Web Vitals injected via ",[80,1348,1349],{},"PerformanceObserver"," before navigation to capture real metrics from first byte.",{"title":289,"searchDepth":290,"depth":290,"links":1352},[1353,1354,1355],{"id":1330,"depth":290,"text":1331},{"id":1337,"depth":290,"text":1338},{"id":88,"depth":290,"text":89},"Testing Infrastructure","Shopify Plus stores rely on complex combinations of themes, apps, and custom code that break silently across browsers and devices. Manual QA can't cover 40+ browser/device combinations, accessibility compliance, performance regressions, and third-party app integrations — especially when theme updates or app installations create cascading failures.",{"language":300,"filename":1359,"code":1360},"fixtures/shopify.fixture.ts","export const test = base.extend\u003CShopifyFixtures>({\n  storeConfig: async ({}, use) => {\n    const config = loadStoreConfig(process.env.STORE_ID)\n    await use(config)\n  },\n\n  shopifyPage: async ({ page, storeConfig }, use) => {\n    // Clear cart state before each test\n    await page.context().clearCookies()\n    await page.goto(storeConfig.baseUrl)\n    await page.waitForSelector(storeConfig.selectors.body)\n    await use(page)\n  },\n\n  a11yAudit: async ({ page }, use) => {\n    const audit = async (selector?: string) => {\n      const results = await new AxeBuilder({ page })\n        .withTags(['wcag2a', 'wcag2aa'])\n        .analyze()\n      return results.violations\n    }\n    await use(audit)\n  },\n})\n","Store-agnostic E2E testing framework for Shopify Plus — cross-browser testing across 40+ device combinations, WCAG 2.1 AA compliance, performance budgets, and third-party app validation (Appstle, Klaviyo, GoAffPro).","/images/projects/shopify-e2e-testing-final.jpg",{},"/images/projects/shopify-e2e-testing-mockup.jpg",16,"/works/shopify-e2e-testing",{"title":1316,"description":1361},"A store-agnostic testing framework that treats store configuration as data, not code. Add a new Shopify store by dropping in a config file — the entire test suite runs against it automatically. Composable Playwright fixtures (base → shopify → a11y → performance) give every test automatic screenshot capture, store config injection, and clean cart state without boilerplate.","works/shopify-e2e-testing","Automated Cross-Browser QA for Shopify Plus Stores",[1372,1373,1374,1375,932],"Playwright","BrowserStack","Accessibility","Performance",[321,1372,1377,1378,1379],"BrowserStack SDK","axe-core","web-vitals","/images/projects/shopify-e2e-testing.jpg","rE6-ppeJaCDNn9NXXrYEo_KUaVN3NMP7X5KfbFpnTqg",{"id":1383,"title":1384,"body":1385,"category":1417,"challenge":1418,"codeSnippet":1419,"description":1423,"extension":304,"featured":305,"finalScreenshot":1424,"gridOrder":1425,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1426,"mockupImage":1427,"navigation":308,"nextProject":307,"order":1428,"path":1429,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":1430,"solution":1431,"stem":1432,"subtitle":1433,"tags":1434,"techStack":1440,"thumbnail":1444,"thumbnailVideo":307,"year":331,"__hash__":1445},"works/works/eu-brand-strategy.md","Shopify Plus Migration Strategy",{"type":8,"value":1386,"toc":1413},[1387,1391,1394,1396,1400,1403,1407,1410],[11,1388,1390],{"id":1389},"shopify-plus-eu-market-ai-commerce-strategy","Shopify Plus EU Market & AI Commerce Strategy",[16,1392,1393],{},"A comprehensive 16-page technical strategy document prepared for a German kitchen products brand operating a hybrid B2C/B2B model with a French 3PL. Covers what Shopify Plus makes available in the EU market today, what is not yet available, and a concrete AI commerce strategy.",[20,1395],{},[23,1397,1399],{"id":1398},"scope","Scope",[16,1401,1402],{},"Full platform capability audit (Shopify Payments Germany, Markets, B2B with company profiles and payment terms, Shopify Tax with OSS, 2,048 variants, Flow, Functions). B2B checkout limitations documented honestly (no Shop Pay, no accelerated checkout). EU compliance architecture including VAT reverse charge, VIES validation gaps in B2B checkout, triangular transaction invoicing requirements, and Germany's e-invoicing mandate (XRechnung/ZUGFeRD with GoBD archiving). AI commerce strategy across three phases: foundation (migration + data optimization), activation (Shopify Catalog discovery), and expansion (autonomous commerce readiness).",[23,1404,1406],{"id":1405},"how-it-was-built","How It Was Built",[16,1408,1409],{},"Researched and fact-checked using Claude for drafting, Gemini for cross-referencing, and NotebookLM for validation against Shopify's official documentation and changelog. All claims sourced against official docs as of March 2026. Final review and domain expertise applied by me.",[16,1411,1412],{},"This represents the kind of enterprise consulting deliverable I produce — technically precise, honest about limitations, and structured for executive decision-making.",{"title":289,"searchDepth":290,"depth":290,"links":1414},[1415,1416],{"id":1398,"depth":290,"text":1399},{"id":1405,"depth":290,"text":1406},"Enterprise Consulting","A German kitchen products brand operating a hybrid B2C/B2B model with a French 3PL needed to evaluate whether Shopify Plus could handle their complex requirements: EU VAT compliance across multiple jurisdictions, B2B wholesale with payment terms, Germany's upcoming e-invoicing mandate (XRechnung/ZUGFeRD), and a forward-looking AI commerce strategy — all while migrating from PrestaShop.",{"language":1420,"filename":1421,"code":1422},"graphql","queries/b2b-company-setup.graphql","mutation companyCreate($input: CompanyCreateInput!) {\n  companyCreate(input: $input) {\n    company {\n      id\n      name\n      mainContact { customer { id email } }\n      locations(first: 5) {\n        edges {\n          node {\n            id\n            name\n            shippingAddress { countryCode }\n            buyerExperienceConfiguration {\n              paymentTermsTemplate { id name }\n            }\n          }\n        }\n      }\n    }\n    userErrors { field message }\n  }\n}\n","16-page enterprise strategy document for a German B2B/B2C kitchen brand migrating from PrestaShop — covering platform capabilities, EU compliance (VAT/OSS, e-invoicing mandates, triangular transactions), B2B architecture, and a phased AI commerce roadmap.","/images/projects/eu-brand-strategy-final.jpg",11,{},"/images/projects/eu-brand-strategy-mockup.jpg",19,"/works/eu-brand-strategy",{"title":1384,"description":1423},"A comprehensive 16-page technical strategy document covering full Shopify Plus platform capability audit, B2B checkout limitations documented honestly, EU compliance architecture including VAT reverse charge, VIES validation, triangular transaction invoicing, and Germany's e-invoicing mandate with GoBD archiving. AI commerce strategy across three phases: foundation (migration + data optimization), activation (Shopify Catalog discovery), and expansion (autonomous commerce readiness).","works/eu-brand-strategy","Technical Documentation",[932,1435,1436,1437,1438,1439],"B2B","EU Compliance","UCP","VAT","E-Invoicing",[932,1441,1442,1437,1443],"Shopify Markets","Shopify B2B","Agentic Storefronts","/images/projects/eu-brand-strategy.jpg","ZwVa0w0ZW6VDn_M6TCW599dj5kR-rcK1ye0aZlh-L3Q",{"id":1447,"title":734,"body":1448,"category":1542,"challenge":1543,"codeSnippet":1544,"description":1548,"extension":304,"featured":305,"finalScreenshot":1549,"gridOrder":1072,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1550,"mockupImage":1551,"navigation":308,"nextProject":1552,"order":1554,"path":1555,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":1556,"solution":1557,"stem":1558,"subtitle":1559,"tags":1560,"techStack":1564,"thumbnail":1569,"thumbnailVideo":307,"year":331,"__hash__":1570},"works/works/shopify-storefront-kit.md",{"type":8,"value":1449,"toc":1536},[1450,1452,1455,1457,1479,1496,1502,1508,1510,1516,1525,1531,1533],[23,1451,659],{"id":658},[16,1453,1454],{},"Shopify's Hydrogen framework solves the headless storefront problem for React teams, but the Vue/Nuxt ecosystem has no equivalent. Teams building headless Shopify stores with Vue start from zero: writing Storefront API queries, building cart state management, handling variant selection logic, and implementing the entire checkout flow. This foundational work takes 3-4 weeks before any actual storefront design begins.",[23,1456,89],{"id":88},[16,1458,1459,1462,1463,1043,1466,1043,1469,1043,1472,1043,1475,1478],{},[30,1460,1461],{},"Composable Layer"," — The library's core is a set of Vue composables (",[80,1464,1465],{},"useProduct",[80,1467,1468],{},"useCart",[80,1470,1471],{},"useCollection",[80,1473,1474],{},"useCustomer",[80,1476,1477],{},"useSearch",") that encapsulate all Storefront API interactions. Each composable manages its own state, caching, and error handling.",[16,1480,1481,1484,1485,1043,1488,1491,1492,1495],{},[30,1482,1483],{},"Renderless Components"," — Components like ",[80,1486,1487],{},"\u003CShopifyProduct>",[80,1489,1490],{},"\u003CShopifyCart>",", and ",[80,1493,1494],{},"\u003CShopifyCollection>"," are renderless — they provide data and actions via scoped slots without imposing any markup or styling. This means the library works with any design system.",[16,1497,1498,1501],{},[30,1499,1500],{},"Type Generation"," — GraphQL Codegen runs against the Storefront API schema to produce TypeScript types for every query response. Developers get full autocomplete and type checking for all product, variant, cart, and customer data.",[16,1503,1504,1507],{},[30,1505,1506],{},"Nuxt Module"," — Ships as a Nuxt module that auto-configures the Storefront API client, provides auto-imports for all composables, and sets up SSR-compatible state hydration.",[23,1509,692],{"id":691},[16,1511,1512,1515],{},[30,1513,1514],{},"Why renderless over styled components?"," Styled component libraries force design compromises. Every Shopify storefront has unique branding requirements. By providing only logic and data, the library never fights the designer's vision. Developers compose the provided composables with their own markup.",[16,1517,1518,1521,1522,1524],{},[30,1519,1520],{},"Why composables over a store/Pinia pattern?"," Composables are more granular and tree-shakeable. A product page only imports ",[80,1523,1465],{}," — it doesn't pull in cart or customer logic. This keeps bundle sizes minimal for each route.",[16,1526,1527,1530],{},[30,1528,1529],{},"Why GraphQL Codegen?"," The Storefront API has a large, versioned schema. Manual type definitions would drift and require constant maintenance. Codegen ensures types always match the actual API version the project targets.",[23,1532,714],{"id":713},[16,1534,1535],{},"The library has been used in 4 production headless Shopify builds. Average time from project kickoff to first design review dropped from 4 weeks to 5 days. The composable architecture means developers spend time on brand-specific features instead of rebuilding cart logic.",{"title":289,"searchDepth":290,"depth":290,"links":1537},[1538,1539,1540,1541],{"id":658,"depth":290,"text":659},{"id":88,"depth":290,"text":89},{"id":691,"depth":290,"text":692},{"id":713,"depth":290,"text":714},"Component Library","Every headless Shopify project starts from scratch: wiring up the Storefront API, building cart state management, handling variant selection, implementing checkout flows. Teams rebuild the same foundational components project after project, wasting weeks before touching actual design work.",{"language":1545,"filename":1546,"code":1547},"vue","components/ShopifyProduct.vue","\u003Cscript setup lang=\"ts\">\nimport { useProduct, useCart } from '@juanify/storefront-kit'\n\nconst props = defineProps\u003C{ handle: string }>()\n\nconst { product, selectedVariant, selectOption } = useProduct(props.handle)\nconst { addToCart, isAdding } = useCart()\n\nconst handleAdd = () => {\n  if (!selectedVariant.value) return\n  addToCart({\n    merchandiseId: selectedVariant.value.id,\n    quantity: 1,\n  })\n}\n\u003C/script>\n\n\u003Ctemplate>\n  \u003Cdiv v-if=\"product\">\n    \u003Cslot\n      :product=\"product\"\n      :selected-variant=\"selectedVariant\"\n      :select-option=\"selectOption\"\n      :add-to-cart=\"handleAdd\"\n      :is-adding=\"isAdding\"\n    />\n  \u003C/div>\n\u003C/template>\n","A production-ready Vue/Nuxt component library for building headless Shopify storefronts — pre-built cart, product, collection, and checkout components with full TypeScript support.","/images/projects/shopify-storefront-kit-final.jpg",{},"/images/projects/shopify-storefront-kit-mockup.jpg",{"title":1207,"slug":1553},"shopify-bff",6,"/works/shopify-storefront-kit",{"title":734,"description":1548},"Created an open-source component library that provides composable, unstyled Vue components for every core Shopify storefront interaction. Built on Nuxt for SSR support with full TypeScript types generated directly from the Storefront API schema.","works/shopify-storefront-kit","Vue Components for Shopify Storefronts",[1561,1562,746,144,1563],"Vue","Nuxt","Headless",[643,640,746,1565,321,1566,1567,1568],"GraphQL Codegen","Vite","Vitest","Histoire","/images/projects/shopify-storefront-kit.jpg","Vt1wE0m5zgvQTurJs9X6J54C2ZkIBqnYdgFz8A_cFxA",{"id":1572,"title":1573,"body":1574,"category":1649,"challenge":1650,"codeSnippet":1651,"description":1654,"extension":304,"featured":305,"finalScreenshot":1655,"gridOrder":312,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1656,"mockupImage":1657,"navigation":308,"nextProject":1658,"order":737,"path":1660,"results":1661,"schneiderFeatured":305,"schneiderOrder":307,"seo":1662,"solution":1663,"stem":1664,"subtitle":1665,"tags":1666,"techStack":1669,"thumbnail":1673,"thumbnailVideo":307,"year":331,"__hash__":1674},"works/works/shopify-perf-audit.md","Speed Score",{"type":8,"value":1575,"toc":1643},[1576,1578,1581,1584,1586,1592,1598,1604,1610,1612,1622,1628,1638,1640],[23,1577,659],{"id":658},[16,1579,1580],{},"Performance is the silent conversion killer in e-commerce. A 1-second increase in page load time can reduce conversions by 7%, yet most Shopify merchants have no automated way to catch performance regressions. Theme updates, new app installations, and content changes all silently degrade Core Web Vitals.",[16,1582,1583],{},"Standard Lighthouse audits miss Shopify-specific issues: the impact of Shopify's app script injection, CDN caching behaviors, dynamic section rendering overhead, and the interaction between theme JavaScript and Shopify's own scripts.",[23,1585,89],{"id":88},[16,1587,1588,1591],{},[30,1589,1590],{},"Audit Runner"," — Playwright launches a real Chromium instance, navigates the store as a customer would, and captures metrics at multiple levels: synthetic (Lighthouse scores), real browser (Web Vitals API), and Shopify-specific (app script inventory, theme asset analysis).",[16,1593,1594,1597],{},[30,1595,1596],{},"Shopify Analysis Layer"," — Purpose-built analyzers identify Shopify-specific performance issues: which installed apps inject render-blocking scripts, how theme assets compare to Shopify's recommended budgets, whether Liquid rendering is causing server-side bottlenecks.",[16,1599,1600,1603],{},[30,1601,1602],{},"Budget System"," — A YAML configuration file defines performance budgets per page type (homepage, collection, product, cart). The toolkit compares audit results against budgets and returns pass/fail with specific violations.",[16,1605,1606,1609],{},[30,1607,1608],{},"CI Integration"," — GitHub Actions workflow runs audits on every theme PR. Results are posted as PR comments with visual trend charts. Failed budgets block merge.",[23,1611,692],{"id":691},[16,1613,1614,1617,1618,1621],{},[30,1615,1616],{},"Why Playwright over Puppeteer?"," Playwright's ",[80,1619,1620],{},"newCDPSession"," gives direct Chrome DevTools Protocol access needed for Lighthouse, while Playwright's higher-level APIs handle the Web Vitals injection and page interaction more reliably. The same test context captures both synthetic and real metrics.",[16,1623,1624,1627],{},[30,1625,1626],{},"Why real browser metrics alongside Lighthouse?"," Lighthouse uses simulated throttling that doesn't capture the full picture on Shopify stores. App scripts load asynchronously, CDN edge caching affects TTFB unpredictably, and section rendering varies by content. Real browser metrics complement the synthetic score.",[16,1629,1630,1633,1634,1637],{},[30,1631,1632],{},"Why YAML config over code?"," Performance budgets should be accessible to non-developers on the team. A YAML file that says ",[80,1635,1636],{},"product.lcp: 2500ms"," is understandable by anyone.",[23,1639,714],{"id":713},[16,1641,1642],{},"Across 15 Shopify stores in the pilot program, the toolkit identified an average of 3 performance issues per store that were previously unknown. The most common finding: third-party app scripts adding 800ms+ to LCP. Several merchants removed or replaced underperforming apps based on the data, resulting in measurable conversion improvements.",{"title":289,"searchDepth":290,"depth":290,"links":1644},[1645,1646,1647,1648],{"id":658,"depth":290,"text":659},{"id":88,"depth":290,"text":89},{"id":691,"depth":290,"text":692},{"id":713,"depth":290,"text":714},"Performance Toolkit","Shopify theme updates frequently introduce performance regressions that go unnoticed until they impact conversion rates. Standard Lighthouse runs don't account for Shopify-specific factors: app script bloat, theme asset loading, Shopify CDN caching behavior, and dynamic section rendering.",{"language":300,"filename":1652,"code":1653},"src/auditor/run-audit.ts","export async function runShopifyAudit(\n  config: AuditConfig\n): Promise\u003CAuditReport> {\n  const browser = await playwright.chromium.launch()\n  const context = await browser.newContext({\n    userAgent: config.userAgent ?? MOBILE_CHROME,\n    viewport: { width: 412, height: 915 },\n  })\n\n  const page = await context.newPage()\n\n  // Capture Web Vitals before Lighthouse\n  await injectWebVitalsCollector(page)\n  await page.goto(config.url, { waitUntil: 'networkidle' })\n\n  const realMetrics = await page.evaluate(() =>\n    window.__WEB_VITALS_RESULTS__\n  )\n\n  // Run Lighthouse via CDP\n  const cdp = await context.newCDPSession(page)\n  const lighthouseReport = await runLighthouse(cdp, config.url, {\n    throttling: config.throttling ?? SHOPIFY_3G_PROFILE,\n    categories: ['performance'],\n  })\n\n  // Shopify-specific analysis\n  const appScripts = await detectThirdPartyApps(page)\n  const themeAssets = await analyzeThemeBundle(page)\n\n  await browser.close()\n\n  return {\n    url: config.url,\n    timestamp: new Date().toISOString(),\n    lighthouse: lighthouseReport,\n    webVitals: realMetrics,\n    shopify: { appScripts, themeAssets },\n    budget: evaluateBudget(config.budgets, lighthouseReport),\n  }\n}\n","An automated performance auditing toolkit for Shopify stores that runs Lighthouse, captures Core Web Vitals, and tracks performance regressions in CI — purpose-built for the Shopify platform.","/images/projects/shopify-perf-audit-final.jpg",{},"/images/projects/shopify-perf-audit-mockup.jpg",{"title":653,"slug":1659},"shopify-shopping-agent","/works/shopify-perf-audit","Average LCP improvement of 1.8s across audited stores. Detected 23 performance regressions before they reached production in the first month. Reduced theme asset size by 34% on average through identified bottlenecks.",{"title":1573,"description":1654},"Built a Playwright-based testing framework that runs Lighthouse audits against real Shopify storefronts, captures Real User Metrics via the Web Vitals API, generates trend reports, and blocks deployments that exceed performance budgets — all configured via a single YAML file.","works/shopify-perf-audit","Automated Performance Audits for Shopify",[1375,1667,1372,1668,1196],"Lighthouse","Web Vitals",[1372,1667,1670,1307,1194,1671,1672],"Web Vitals API","Chart.js","YAML Config","/images/projects/shopify-perf-audit.jpg","QLn4OOeM4yPx9MqTEQJJBdeWXcWGzG_gU1EZskSNDSY",{"id":1676,"title":1677,"body":1678,"category":1700,"challenge":1701,"codeSnippet":1702,"description":1705,"extension":304,"featured":305,"finalScreenshot":1706,"gridOrder":1707,"isDemo":305,"isDemoURL":289,"liveUrl":307,"meta":1708,"mockupImage":1709,"navigation":308,"nextProject":307,"order":1710,"path":1711,"results":307,"schneiderFeatured":305,"schneiderOrder":307,"seo":1712,"solution":1713,"stem":1714,"subtitle":1715,"tags":1716,"techStack":1720,"thumbnail":1725,"thumbnailVideo":307,"year":331,"__hash__":1726},"works/works/shopify-docs-cli.md","Shopify Docs",{"type":8,"value":1679,"toc":1698},[1680,1684,1687,1690,1692,1695],[11,1681,1683],{"id":1682},"shopify-docs-token-efficient-documentation-cli","shopify-docs — Token-Efficient Documentation CLI",[16,1685,1686],{},"3 files. 537 lines. Zero npm dependencies.",[16,1688,1689],{},"The official Shopify MCP server dumps 30,000-50,000+ tokens of system prompts and schema per documentation lookup. This tool routes natural-language queries to the right Shopify docs source via 14 pre-mapped library indexes and returns approximately 1,500-3,000 tokens of relevant snippets. That's a 10-20x reduction in context consumption.",[20,1691],{},[16,1693,1694],{},"Smart keyword-length scoring (not count — \"checkout ui extension\" outweighs \"checkout\"), pre-resolved library IDs eliminating network round-trips, and a graceful fallback to the general Shopify Developer Docs index. Works as a CLI, an MCP server (raw JSON-RPC 2.0 over JSONL stdio, no SDK dependency), or a Claude Code slash command.",[16,1696,1697],{},"This is a tool built to optimize AI development tooling — meta-level workflow optimization that compounds across every other project.",{"title":289,"searchDepth":290,"depth":290,"links":1699},[],"Developer Tooling","The official Shopify MCP server dumps 30,000-50,000+ tokens of system prompts and schema per documentation lookup. For AI-assisted development with Claude Code, this wastes context window on irrelevant content, increasing cost and reducing the quality of responses by drowning relevant code context in documentation noise.",{"language":300,"filename":1703,"code":1704},"src/router.ts","const LIBRARY_MAP: Record\u003Cstring, LibraryIndex> = {\n  'admin-api':      { id: '/shopify/shopify-api-js',        weight: 3 },\n  'storefront-api': { id: '/shopify/hydrogen',              weight: 3 },\n  'polaris':        { id: '/shopify/polaris',                weight: 2 },\n  'theme':          { id: '/shopify/dawn',                   weight: 2 },\n  'checkout-ui':    { id: '/shopify/ui-extensions',          weight: 3 },\n  'functions':      { id: '/shopify/shopify-functions',      weight: 2 },\n  // ... 8 more pre-mapped indexes\n}\n\nfunction routeQuery(query: string): LibraryIndex {\n  const scores = Object.entries(LIBRARY_MAP).map(([key, lib]) => ({\n    lib,\n    score: calculateKeywordScore(query, key) * lib.weight,\n  }))\n\n  return scores.sort((a, b) => b.score - a.score)[0]?.lib\n    ?? LIBRARY_MAP['developer-docs'] // fallback\n}\n","Zero-dependency CLI and MCP server that reduces Shopify documentation lookups from 30,000-50,000+ tokens to ~1,500-3,000 tokens — a 10-20x reduction in context consumption for AI-assisted development.","/images/projects/shopify-docs-cli-final.jpg",14,{},"/images/projects/shopify-docs-cli-mockup.jpg",17,"/works/shopify-docs-cli",{"title":1677,"description":1705},"3 files. 537 lines. Zero npm dependencies. Routes natural-language queries to the right Shopify docs source via 14 pre-mapped library indexes and returns approximately 1,500-3,000 tokens of relevant snippets. Smart keyword-length scoring, pre-resolved library IDs eliminating network round-trips, and graceful fallback to the general Shopify Developer Docs index. Works as a CLI, an MCP server (raw JSON-RPC 2.0 over JSONL stdio), or a Claude Code slash command.","works/shopify-docs-cli","Token-Efficient CLI",[744,1717,1718,1719,1700],"Claude Code","CLI","Shopify Documentation",[1721,1722,1723,1724],"Node.js 18+","ESM","JSON-RPC 2.0","Context7 API","/images/projects/shopify-docs-cli.jpg","GydCzqVxCrTOaSPIYQfuL16euOMEb-UgElUElh4-4d8",1773700380556]