Removing the developer from a routine data request
Year
2026
Status
Internal production
Category
Internal Tools
Stack
Python 3.12 · FastAPI · Pydantic v2
01/Context
The business is made-to-order, but sometimes has matching finished stock sitting in spreadsheets maintained outside Shopify. Planners were manually cross-checking each order line against three separate Google Sheets.
The result was a developer-in-the-loop process for a routine request — the kind of dependency that looks small until you count how often it happens.
02/At a glance
Problem
Production planners needed one row per line item, each tagged with the warehouse that will actually ship it. Shopify's native export does not produce that shape, and Shopify exposes several non-equivalent 'location' values — so 'which warehouse' is a decision problem, not a field lookup.
Built
A stateless FastAPI service where the planning team picks a date range, previews the orders in-browser, and downloads Excel or CSV — behind company Google sign-in, with nothing customer-related written to disk.
Role
Sole developer: requirements analysis, Shopify schema investigation, architecture, implementation, tests, containerisation and the cloud deployment.
Changed
A non-technical team now self-serves data that previously required a developer to run local scripts on request.
03/Architecture
A stateless container behind Google sign-in. Identity is terminated at the proxy, the app holds no durable storage beyond a short-lived preview cache, and every external dependency is allowed to fail without taking the export with it.
04/The system
Two passes, because one query is too expensive
A single fully-nested query for orders, line items and fulfillment data exceeds Shopify's 1000-point per-query cost cap. So the fetch runs in two passes: orders plus line items, then per-order fulfillment.
The HTTP client reads the throttle status from the cost extension on every response and paces against the real bucket, rather than guessing at a safe delay.
Warehouse attribution with provenance
A dedicated resolver assigns each unit to a location using the actual fulfillment location first, then the assigned fulfillment-order location — never inventory levels, which answer a different question.
A split line item fans out into multiple rows, each tagged with how the warehouse was determined: fulfilled, assigned, or Unknown. Planners can see how much to trust each row instead of receiving a confident guess.
A conservative stock recommendation
A separate module reads three stock workbooks via a read-only service account and indexes them on normalized style, colour and size — deliberately never on style ID, because season prefixes differ between systems.
It emits Yes / Partial / No / Review per line, and fails soft: if the sheets are unreachable, the export still ships without the stock column rather than failing entirely.
Stateless by design
Exports are generated in memory. Nothing customer-related is written to disk or to a database; structured logs carry order references, counts and statuses only. The GraphQL documents deliberately select no customer name, email, address, phone or payment field.
05/What was hard
'Which warehouse' has three plausible answers
Shopify exposes the actual fulfillment location, the assigned fulfillment-order location, and inventory levels — and they disagree. Picking an order of preference and then shipping the provenance alongside the answer turned an ambiguous field lookup into information a planner can reason about.
Matching stock across two naming systems
The stock workbooks and Shopify do not agree on style IDs, because season prefixes differ. Indexing on normalized style, colour and size instead is less elegant and considerably more correct.
A stale build shipped once
The deployment runbook records the incident and the grep freshness check added to prevent it. Writing down the pitfall that actually happened, in the runbook, is worth more than a process document nobody reads.
06/Automation
Replaces a developer running local scripts on request, and the manual cross-check of each order line against three stock spreadsheets. Line-item fan-out, warehouse attribution, split-shipment expansion, timezone conversion and the stock recommendation are all computed rather than hand-assembled.
08/Direction & delivery
Eleven numbered deliverable documents covering requirements analysis, architecture, data mapping, warehouse logic, GraphQL cost math, security controls, deployment, a deployment checklist, a non-technical end-user guide, and a prioritized roadmap that names the infrastructure each idea would add. The README carries an explicit 'caveats to verify before production' list. The operational timezone was deliberately reversed at one point, and the reason is recorded.
09/Scale
25
Application modules
90
Test functions
11
Numbered docs
33
Export columns
2
GraphQL passes
Objective size signals taken from the repository. No impact metrics are claimed that the source does not prove.
10/What I would tell the next person
Ship provenance with an inferred value. 'Warehouse: X (assigned)' is more useful than 'Warehouse: X'.
Let non-critical dependencies fail soft. A missing stock column beats a failed export.
Record the incident that actually happened, next to the check that now prevents it.