Internal Tools
Order Export for Production Planning
Removing the developer from a routine data request
2026Internal production
At a glance
Credit
- Built by
- Denandro YusufDesign · Directing Claude Code from specs · The warehouse-attribution rule and the conservative stock verdict · Requirements with the planning team · Deployment and the handover to planners
Run the demo synthetic data
- Problem
- Planners needed one row per order line, tagged to the warehouse that ships it.
- What I did
- I ruled that a warehouse is named by where units ship, and kept the stock verdict conservative.
- Outcome
- Planners self-serve an export that used to need a developer.
Explore
The component graph, from the source repository. Follow the arrows: left to right, and down where two steps share a column. The burgundy bars are where decisions are made; the numbers on the lines are the key flows, written out under the graph.
Key flows
- Planning team browser to TLS + Google sign-in: HTTPS + sign-in
- TLS + Google sign-in to FastAPI export service: verified identity
- FastAPI export service to Preview cache: preview → export reuse
- FastAPI export service to Warehouse resolver: date range
- Warehouse resolver to Shopify Admin GraphQL: two-pass fetch
- Warehouse resolver to Stock matcher: line item + qty
- Stock matcher to Stock workbooks ×3: read-only, cached
- Warehouse resolver to Excel / CSV builders: rows + summary
- Excel / CSV builders to Planning team browser: .xlsx / .csv
Go deeper
The full account
- 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.
- What was 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
- Designed and built it, with Claude Code writing to my design documents. Took the requirements from the production-planning team, ruled that a warehouse is named from where units ship rather than from where stock sits, kept the stock verdict conservative and carrying its provenance, and ran the deployment and the handover to planners. My engineers now develop it further, as the credits show.
- What changed
- A non-technical team now self-serves data that previously required a developer to run local scripts on request.
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.
Architecture and the system
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.
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.
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.
AI and automation
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.
Direction and delivery
The build is mine, made with Claude Code against my own written specification — the export's requirements, the implementation, its QA and the rollout. So are the documents: 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. Prada Dipa and Luthfi Aditya now develop it further.
Size signals
- Application modules
- 25
- Test functions
- 90
- Numbered docs
- 11
- Export columns
- 33
- GraphQL passes
- 2
Counted from the source repository. No impact metric is claimed that the source does not prove.
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.
Technologies and access
- Python 3.12
- FastAPI
- Pydantic v2
- httpx
- tenacity
- Jinja2
- XlsxWriter
- gspread
- Docker
- Cloud Run
- Cloud Build
- IAP
- oauth2-proxy
- Caddy
- pytest
- ruff
Integrations
- Shopify Admin GraphQL (orders, fulfillment orders, fulfillments)
- Google Sheets API (three stock workbooks, read-only)
- Google Cloud Secret Manager
- Google Identity-Aware Proxy
Internal service behind company Google sign-in.

