[{"data":1,"prerenderedAt":487},["ShallowReactive",2],{"home-case-studies":3},[4,172,281,390],{"id":5,"title":6,"body":7,"businessProblem":134,"confidentiality":135,"description":136,"employer":137,"extension":138,"featured":139,"heroStat":140,"meta":143,"navigation":139,"ogImage":144,"order":145,"path":146,"publishedAt":147,"results":148,"seo":160,"stem":161,"summary":162,"technologies":163,"updatedAt":144,"__hash__":171},"caseStudies\u002Fwork\u002Fcase-studies\u002Fcatalogue-automation.md","High-Volume Ecommerce Catalogue Automation",{"type":8,"value":9,"toc":122},"minimark",[10,15,19,32,35,39,44,48,55,61,67,73,77,91,95,98,102,115,119],[11,12,14],"h2",{"id":13},"the-problem","The problem",[16,17,18],"p",{},"The business ran ecommerce on top of a supplier catalogue nobody fully controlled. More than 200,000\nSKUs came in through:",[20,21,22,26,29],"ul",{},[23,24,25],"li",{},"Nightly FTP drops in half a dozen different CSV\u002FExcel dialects",[23,27,28],{},"A handful of supplier REST and SOAP APIs, each with its own auth and pagination quirks",[23,30,31],{},"Scraped product pages for suppliers who published no feed at all",[16,33,34],{},"Every source had its own idea of a SKU, a category tree, and a unit of measure. Pricing and\ninventory changed daily. Before automation, updating the catalogue was a recurring manual chore —\nslow, error-prone, and a hard ceiling on how many suppliers the business could realistically carry.\nThe business problem wasn't \"we need a script,\" it was \"we can't grow the catalogue without this\nbecoming someone's full-time job.\"",[11,36,38],{"id":37},"architecture","Architecture",[40,41],"architecture-diagram",{":steps":42,"title":43},"[{\"label\":\"Ingest\",\"detail\":\"FTP, REST\u002FSOAP APIs, scrapers\"},{\"label\":\"Normalize\",\"detail\":\"Units, categories, attributes\"},{\"label\":\"Match & validate\",\"detail\":\"Dedup, price\u002Fstock sanity checks\"},{\"label\":\"Publish\",\"detail\":\"Shopify, Odoo, internal reporting\"}]","Catalogue pipeline — simplified",[11,45,47],{"id":46},"what-i-built","What I built",[16,49,50,54],{},[51,52,53],"strong",{},"Ingestion layer."," A set of Python jobs per supplier source — FTP pull, API client, or scraper —\neach normalizing into a common intermediate schema before anything touches the database. New\nsuppliers plug in as a new ingestion adapter, not a rewrite of the pipeline.",[16,56,57,60],{},[51,58,59],{},"Normalization and matching."," Supplier part numbers, UPCs, and free-text titles get reconciled\nagainst the existing catalogue using a mix of exact-key matching and fuzzy matching for the messy\ncases (title similarity, brand + attribute matching) with a manual review queue for anything under\na confidence threshold — so ambiguous matches get a human decision instead of a silent guess.",[16,62,63,66],{},[51,64,65],{},"Pricing and inventory sync."," Cost and quantity updates flow through margin rules before they hit\nthe storefront, with change thresholds that flag anything that moves further than expected (a price\ndrop of 90% is far more likely to be a bad feed row than a real discount).",[16,68,69,72],{},[51,70,71],{},"Publishing."," Validated records write to Odoo and Shopify through their APIs, with diffs logged so\nevery price or inventory change is traceable back to the source file or API call that caused it.",[11,74,76],{"id":75},"reliability-and-validation","Reliability and validation",[20,78,79,82,85,88],{},[23,80,81],{},"Every ingestion run produces a diff report before anything is published — new items, removed\nitems, and changed fields are all visible before they go live.",[23,83,84],{},"Sanity thresholds catch outlier price and quantity changes for manual review instead of\nauto-publishing them.",[23,86,87],{},"Failed or partial supplier feeds fail loudly (alerting) rather than silently publishing stale or\nincomplete data.",[23,89,90],{},"A confidence-scored matching queue means uncertain SKU matches never get merged automatically.",[11,92,94],{"id":93},"technologies-used","Technologies used",[16,96,97],{},"Python for ingestion and transformation, PostgreSQL as the system of record, pandas for bulk\ntransforms, and the Shopify Admin API and Odoo's API for publishing. Scheduled jobs run the pipeline\non a nightly and hourly cadence depending on the source.",[11,99,101],{"id":100},"business-impact","Business impact",[16,103,104,105,110,111,114],{},"The catalogue automation removed manual data entry as the ceiling on supplier growth — the business\nwent from a catalogue that required constant manual upkeep to one that scales by adding ingestion\nadapters. Combined with the marketplace and advertising work described in the\n",[106,107,109],"a",{"href":108},"\u002Fwork\u002Fcase-studies\u002Fshopify-amazon-sync","Shopify and Amazon marketplace synchronization"," case study,\nthis system was part of growing this employer's ecommerce revenue from roughly ",[51,112,113],{},"$60,000 to\n$400,000 per month",".",[11,116,118],{"id":117},"what-id-change-next","What I'd change next",[16,120,121],{},"The matching layer is the piece I'd keep investing in — better fuzzy-matching and a tighter feedback\nloop from the manual review queue back into the automated confidence scoring, so the system gets\nbetter at flagging its own uncertain calls over time.",{"title":123,"searchDepth":124,"depth":124,"links":125},"",3,[126,128,129,130,131,132,133],{"id":13,"depth":127,"text":14},2,{"id":37,"depth":127,"text":38},{"id":46,"depth":127,"text":47},{"id":75,"depth":127,"text":76},{"id":93,"depth":127,"text":94},{"id":100,"depth":127,"text":101},{"id":117,"depth":127,"text":118},"Product data for 200,000+ SKUs arrived from dozens of suppliers in inconsistent formats — FTP flat files, REST and SOAP APIs, and, for suppliers with no feed at all, scraped catalogue pages. None of it agreed on units, categories, or even what counted as the same product.\n","anonymized","How I built a Python-based pipeline that ingests, cleans, matches, and publishes 200,000+ supplier products across FTP feeds, APIs, and scraped sources — with validation built in.","a Canadian industrial distributor","md",true,{"label":141,"value":142},"SKUs under management","200,000+",{},null,1,"\u002Fwork\u002Fcase-studies\u002Fcatalogue-automation","2026-01-15",[149,152,154,157],{"label":150,"value":151},"Manual catalogue hours per week","-80%",{"label":153,"value":142},"SKUs under active automation",{"label":155,"value":156},"Pricing\u002Finventory refresh cycle","Daily → hourly",{"label":158,"value":159},"Duplicate\u002Fmismatched listings","Caught pre-publish",{"title":6,"description":136},"work\u002Fcase-studies\u002Fcatalogue-automation","Automating ingestion, cleanup, matching, and pricing for 200,000+ supplier SKUs.",[164,165,166,167,168,169,170],"Python","PostgreSQL","Pandas","Odoo","Shopify Admin API","Cron \u002F scheduled jobs","FTP\u002FSFTP","54mWLZEHR2EO6_FtvYCFbJ_-UOYmblyE3ijgq8hWufM",{"id":173,"title":174,"body":175,"businessProblem":256,"confidentiality":135,"description":257,"employer":137,"extension":138,"featured":139,"heroStat":144,"meta":258,"navigation":139,"ogImage":144,"order":127,"path":108,"publishedAt":259,"results":260,"seo":273,"stem":274,"summary":275,"technologies":276,"updatedAt":144,"__hash__":280},"caseStudies\u002Fwork\u002Fcase-studies\u002Fshopify-amazon-sync.md","Shopify and Amazon Marketplace Synchronization",{"type":8,"value":176,"toc":248},[177,179,182,184,188,190,200,206,212,218,220,234,236,243,245],[11,178,14],{"id":13},[16,180,181],{},"Selling the same products on Shopify and Amazon means keeping two independent systems honest with\neach other. Shopify handled the storefront and source-of-truth inventory; Amazon required its own\nlistings, its own pricing rules, and its own inventory feed through SP-API. Left unmanaged, that gap\nproduces the worst kind of ecommerce failure: an oversell on a marketplace, a listing that's\ntechnically live but effectively invisible because pricing or content issues knocked it out of buy\nbox contention, or inventory counts that just quietly drift apart over weeks.",[11,183,38],{"id":37},[40,185],{":steps":186,"title":187},"[{\"label\":\"Shopify (source of truth)\",\"detail\":\"Inventory, pricing, product data\"},{\"label\":\"Reconciliation engine\",\"detail\":\"Diff, match, policy checks\"},{\"label\":\"Amazon SP-API\",\"detail\":\"Listings, inventory feeds, pricing\"},{\"label\":\"Monitoring\",\"detail\":\"Mismatch + listing-health alerts\"}]","Marketplace sync — simplified",[11,189,47],{"id":46},[16,191,192,195,196,199],{},[51,193,194],{},"Product matching."," Amazon listings get matched back to Shopify SKUs using ASIN\u002FSKU mapping with\nfallback matching on UPC and title similarity for products without a clean existing mapping —\nsimilar in spirit to the matching logic in the\n",[106,197,198],{"href":146},"catalogue automation pipeline",", applied here across\nmarketplace boundaries instead of supplier boundaries.",[16,201,202,205],{},[51,203,204],{},"Inventory reconciliation."," A scheduled job compares Shopify's on-hand quantity against what\nAmazon believes it has, and pushes corrections through SP-API. Discrepancies beyond a normal sync\ndelay get flagged instead of silently corrected, since a persistent mismatch is usually a sign of a\ndeeper problem (a failed feed, a miscounted receiving, a return that didn't reconcile).",[16,207,208,211],{},[51,209,210],{},"Pricing sync with policy awareness."," Price updates flow to Amazon through SP-API respecting\nAmazon's pricing rules (minimum advertised price, fee-aware margin floors) so a Shopify-side sale\nprice can't accidentally violate marketplace policy or tank margin on a high-fee category.",[16,213,214,217],{},[51,215,216],{},"Listing health monitoring."," A recurring check watches for listings that dropped out of buy box\ncontention, got suppressed for content issues, or otherwise went quietly invisible — the kind of\nproblem that costs revenue for weeks before anyone notices it manually.",[11,219,76],{"id":75},[20,221,222,225,228,231],{},[23,223,224],{},"Reconciliation runs are diffed and logged before any corrective write, the same discipline used in\nthe catalogue pipeline.",[23,226,227],{},"Persistent mismatches (not explained by normal sync latency) escalate to a human instead of being\nauto-corrected indefinitely.",[23,229,230],{},"Pricing changes are checked against marketplace policy constraints before they're sent.",[23,232,233],{},"Listing-health checks run on a schedule independent of the sync jobs, so a healthy sync doesn't\nmask an unhealthy listing.",[11,235,101],{"id":100},[16,237,238,239,242],{},"Marketplace expansion is only worth doing if it doesn't create new operational risk. This system let\nthe business list and sell confidently on Amazon without inventory or pricing becoming a manual\nbabysitting job — a necessary piece of the same growth story covered in the\n",[106,240,241],{"href":146},"catalogue automation"," case study, where this employer's\necommerce revenue grew from roughly $60,000 to $400,000 per month.",[11,244,118],{"id":117},[16,246,247],{},"Buy-box and pricing dynamics on Amazon move faster than a scheduled job can always keep up with —\nthe next iteration I'd build is event-driven reconciliation triggered by Amazon notifications rather\nthan pure polling, to shrink the reaction window further.",{"title":123,"searchDepth":124,"depth":124,"links":249},[250,251,252,253,254,255],{"id":13,"depth":127,"text":14},{"id":37,"depth":127,"text":38},{"id":46,"depth":127,"text":47},{"id":75,"depth":127,"text":76},{"id":100,"depth":127,"text":101},{"id":117,"depth":127,"text":118},"Running the same catalogue on Shopify and Amazon meant two systems of record that disagreed — oversells when inventory drifted out of sync, pricing that violated marketplace policy, and listings that silently fell out of buy-box contention.\n","Architecture and lessons from building inventory reconciliation, pricing, and listing-health workflows across Shopify and Amazon SP-API for a multi-thousand-SKU catalogue.",{},"2026-02-10",[261,264,267,270],{"label":262,"value":263},"Marketplace oversells","Eliminated via reconciliation",{"label":265,"value":266},"Listing issues","Caught before customer impact",{"label":268,"value":269},"Price\u002Finventory sync","Automated, policy-aware",{"label":271,"value":272},"Marketplaces synchronized","2 (Shopify + Amazon)",{"title":174,"description":257},"work\u002Fcase-studies\u002Fshopify-amazon-sync","Keeping inventory, pricing, and listings consistent across Shopify and Amazon SP-API.",[168,277,164,165,278,279],"Amazon SP-API","Webhooks","Scheduled reconciliation jobs","VXLn4fG_S_7mzyThYgJ5UW8xRTtAU2H2_wlVKrs1ZgA",{"id":282,"title":283,"body":284,"businessProblem":362,"confidentiality":363,"description":364,"employer":365,"extension":138,"featured":139,"heroStat":144,"meta":366,"navigation":139,"ogImage":144,"order":124,"path":367,"publishedAt":368,"results":369,"seo":379,"stem":380,"summary":381,"technologies":382,"updatedAt":144,"__hash__":389},"caseStudies\u002Fwork\u002Fcase-studies\u002Fbig-box-outlet-growth.md","Ecommerce Growth and Marketplace Expansion at Big Box Outlet Store",{"type":8,"value":285,"toc":356},[286,288,291,295,301,307,313,319,328,334,336,344,348],[11,287,14],{"id":13},[16,289,290],{},"Big Box Outlet Store sells liquidation, closeout, and surplus inventory — the opposite of a stable\ncatalogue with predictable reorders. Product mix turns over constantly, quantities are often one-off\nor limited, and merchandising has to move fast enough to sell through inventory before it stops\nbeing relevant. Ecommerce for a business like this isn't just \"put products online\" — it's building\na channel and a set of workflows that can absorb constant change without falling apart.",[11,292,294],{"id":293},"what-i-did","What I did",[16,296,297,300],{},[51,298,299],{},"Platform management."," Owned the Shopify storefront end to end — merchandising, site structure,\nand the day-to-day decisions that keep a fast-changing catalogue usable for customers instead of\noverwhelming.",[16,302,303,306],{},[51,304,305],{},"Paid advertising."," Ran Google Ads and Meta Ads campaigns, tuning spend and targeting against a\ncatalogue that doesn't behave like a normal retailer's — creative and targeting had to keep pace\nwith inventory that could sell out or change entirely within days.",[16,308,309,312],{},[51,310,311],{},"Marketplace expansion."," Extended the sales channel beyond the core storefront into additional\nmarketplaces, adapting listings and operations to each platform's rules and audience.",[16,314,315,318],{},[51,316,317],{},"Auctions."," Built out auction-based selling as a channel for surplus and closeout inventory suited\nto that format — a different operating model from standard fixed-price ecommerce, run alongside it.",[16,320,321,324,325,114],{},[51,322,323],{},"Internal tools and workflow."," Where off-the-shelf tools didn't fit how the business actually\noperated, built internal tooling to close the gap — the same instinct that later became a core part\nof my ",[106,326,327],{"href":146},"ecommerce systems and automation work",[16,329,330,333],{},[51,331,332],{},"Team leadership."," Led the ecommerce function as it grew, balancing platform work, campaign\nmanagement, and day-to-day merchandising operations.",[11,335,101],{"id":100},[16,337,338,339,343],{},"This role is where I learned ecommerce as an ",[340,341,342],"em",{},"operation",", not just a technical system — merchandising\ndecisions, ad spend, marketplace rules, and fulfillment realities all interact, and the technical\nsystems only matter if they hold up against that operational messiness. That perspective now shapes\nhow I build software for ecommerce businesses: I design for the actual chaos of retail operations,\nnot an idealized version of it.",[11,345,347],{"id":346},"what-i-learned","What I learned",[16,349,350,351,355],{},"The biggest lesson from running ecommerce operations directly, rather than building systems for\nsomeone else's operation, is that the hardest problems are rarely purely technical. A perfectly\nengineered sync job doesn't help if the merchandising process feeding it is inconsistent. That's the\nlens I bring to the systems work described in my other ",[106,352,354],{"href":353},"\u002Fwork","case studies"," — I build for how the\nbusiness actually runs, not just for the API spec.",{"title":123,"searchDepth":124,"depth":124,"links":357},[358,359,360,361],{"id":13,"depth":127,"text":14},{"id":293,"depth":127,"text":294},{"id":100,"depth":127,"text":101},{"id":346,"depth":127,"text":347},"A liquidation and closeout retailer needed an ecommerce channel that could keep up with constantly changing, one-off, and surplus inventory — where the product catalogue itself is never stable.\n","public","The operator side of my experience — growing Big Box Outlet Store's ecommerce channel through platform management, paid advertising, marketplace expansion, auctions, and internal tooling.","Big Box Outlet Store",{},"\u002Fwork\u002Fcase-studies\u002Fbig-box-outlet-growth","2025-11-01",[370,373,376],{"label":371,"value":372},"Role","Ecommerce Manager",{"label":374,"value":375},"Scope","Platform, ads, marketplaces, ops",{"label":377,"value":378},"Tenure","2017–2023",{"title":283,"description":364},"work\u002Fcase-studies\u002Fbig-box-outlet-growth","Running ecommerce end-to-end — platform, advertising, marketplaces, merchandising, and internal tools.",[383,384,385,386,387,388],"Shopify","Google Ads","Meta Ads","Marketplace integrations","Internal tooling","Merchandising systems","S2pVpnby0FOfKBhMlSw0nZjDPlcQCwZgXyQ8kfJtuvc",{"id":391,"title":392,"body":393,"businessProblem":461,"confidentiality":363,"description":462,"employer":144,"extension":138,"featured":139,"heroStat":144,"meta":463,"navigation":139,"ogImage":144,"order":464,"path":465,"publishedAt":466,"results":467,"seo":477,"stem":478,"summary":479,"technologies":480,"updatedAt":144,"__hash__":486},"caseStudies\u002Fwork\u002Fcase-studies\u002Fai-assisted-automation.md","AI-Assisted Business Automation",{"type":8,"value":394,"toc":455},[395,397,400,404,408,414,420,426,432,438,442,448,452],[11,396,14],{"id":13},[16,398,399],{},"There's a wide gap between \"AI wrote some code\" and \"AI-assisted development that's actually\ntrustworthy in production.\" The first is a demo. The second requires a workflow — one where AI tools\nhandle the parts they're genuinely good at (drafting, boilerplate, exploring an unfamiliar API,\nfirst-pass tests) while a human still owns system design, correctness review, and the decision to\nship.",[11,401,403],{"id":402},"the-workflow","The workflow",[40,405],{":steps":406,"title":407},"[{\"label\":\"Business problem\",\"detail\":\"Defined by me, not the model\"},{\"label\":\"System design\",\"detail\":\"Architecture + constraints set upfront\"},{\"label\":\"AI-assisted implementation\",\"detail\":\"Claude Code, Codex, Cursor, Gemini\"},{\"label\":\"Tests + human review\",\"detail\":\"Nothing ships unread\"},{\"label\":\"Deploy + monitor\",\"detail\":\"Same ops discipline as any change\"}]","How AI fits into the process",[16,409,410,413],{},[51,411,412],{},"Business problem first."," Every task starts with the actual operational problem — a catalogue\nmismatch, a slow report, a manual process eating hours every week — not a prompt in search of a use\ncase.",[16,415,416,419],{},[51,417,418],{},"System design stays mine."," Architecture decisions, data models, and failure-mode thinking happen\nbefore AI tools touch the problem. This is the part that determines whether the resulting system is\nmaintainable six months later, and it's the part I don't delegate.",[16,421,422,425],{},[51,423,424],{},"AI-assisted implementation."," Different tools for different jobs: Claude Code and Codex for\nlarger, multi-file implementation work and refactors; Cursor for fast in-editor iteration; Gemini\nfor research and second opinions on approach. I treat model output as a strong first draft, not a\nfinished product.",[16,427,428,431],{},[51,429,430],{},"Tests and human review."," Nothing generated ships without tests and a real read-through — the same\nbar I'd hold a human collaborator's pull request to. AI-generated code gets the same scrutiny as\nanyone else's, arguably more, because it doesn't yet have a track record with this specific codebase.",[16,433,434,437],{},[51,435,436],{},"Deployment and monitoring."," Once something ships, it's watched the same way any production change\nwould be — logging, alerting, and a rollback plan, not \"the AI said it works.\"",[11,439,441],{"id":440},"why-this-matters","Why this matters",[16,443,444,445,447],{},"The honest pitch isn't \"AI writes my code.\" It's that AI tools meaningfully speed up the\nimplementation phase of systems I'd have designed and validated either way — the catalogue pipelines,\nmarketplace sync jobs, and internal tools described in my other ",[106,446,354],{"href":353}," get built\nfaster because of this workflow, not because judgment got outsourced to a model.",[11,449,451],{"id":450},"what-im-still-refining","What I'm still refining",[16,453,454],{},"The weakest link right now is turning implicit operational knowledge — the stuff I know about how a\nspecific supplier feed misbehaves, or how a marketplace's edge cases work — into context the AI tools\ncan actually use, instead of re-explaining it every session. That's the direction most of my current\ntooling investment is going.",{"title":123,"searchDepth":124,"depth":124,"links":456},[457,458,459,460],{"id":13,"depth":127,"text":14},{"id":402,"depth":127,"text":403},{"id":440,"depth":127,"text":441},{"id":450,"depth":127,"text":451},"AI coding tools are good at producing code fast. They're not automatically good at producing code that's correct, maintainable, and safe to run against real supplier data, real inventory, and real customer orders — that gap is where most \"AI-generated\" work quietly fails.\n","The workflow I use to fold AI tools into real ecommerce systems work, from problem framing through deployment and monitoring — with human review at every step that matters.",{},4,"\u002Fwork\u002Fcase-studies\u002Fai-assisted-automation","2026-03-01",[468,471,474],{"label":469,"value":470},"AI tools used daily","Claude Code, Codex, Cursor, Gemini",{"label":472,"value":473},"Human review","Every deploy",{"label":475,"value":476},"Judgment retained by","Me, not the model",{"title":392,"description":462},"work\u002Fcase-studies\u002Fai-assisted-automation","How Claude Code, Codex, Cursor, and Gemini fit into a real development process — not just code snippets.",[481,482,483,484,164,485],"Claude Code","Codex","Cursor","Gemini","CI\u002FCD","4e_ExX31zgQuu7opLtcYSbLIwiTkCTsvT9qGnt_TRP8",1785688078648]