How a customs declaration becomes an opportunity
Two halves that meet only through files on disk: a Python pipeline that turns raw extracts into typed, flagged rows, and a Next.js app that reads its committed output. The app never runs the pipeline and never reads its working files — only the payloads in public/. That is why Vercel can build this without Python, pandas, or the 540 MB intermediate CSV.
Every number on these pages is measured from the artifacts, not typed into them. Sizes are read from disk on the server; counts come from a payload the page already loads. This exists because the numbers that were typed — all of them, in README.md — had drifted by two to three times.
Raw spreadsheet to rendered page
What produces what, and in which order?
Dotted edges are side inputs and side outputs. The chain through dashboard-data.json is an ordering constraint, not a convenience: scripts.prospect.index reads that file to decide which companies count as accounts.
The payloads
| Payload | Built by | Size |
|---|---|---|
Opportunity contractpublic/dashboard-data.json | python3 -m scripts.opportunity.build | 4.65 MB |
Per-account evidencepublic/evidence/arkema.json | python3 -m scripts.opportunity.build | 0.45 MB |
Analytics cubepublic/analytics-cube.json | python3 -m scripts.analytics.cube | 4.86 MB |
Entity cubepublic/entity-cube.json | python3 -m scripts.analytics.entities | 3.43 MB |
Prospect indexpublic/prospect-index.json | python3 -m scripts.prospect.index | 2.22 MB |
Lanxess catalogpublic/lanxess-catalog.json | python3 -m scripts.lanxess.catalog | 1.56 MB |
The evidence/ row is one representative file. There are 40 of them, one per covered account, totalling 19.12 MB — fetched one account at a time, never as a set, which is why the directory can be larger than everything else combined without costing a page load. See what each payload holds and what breaks when it is stale →
Where to go next
| Pipeline | Normalization, entity resolution, and the review queues where a human decides. |
| Runbook | What to type, in order, from a fresh data drop to a deployed site. |
| Contracts | Each payload: builder, readers, live size, and the failure it causes. |
| Engine | Buckets, plays, coverage, and the defects found the hard way. |
| App map | Every route, walked from the filesystem, plus the portfolio state model. |