Genesis AI — Complete File Trigger Map

Every file triggered from the moment the Excel is uploaded to the moment the dashboard renders. In exact execution order.

1
Phase 1 — Frontend: User Uploads File React
Browser → UploadModal → POST /api/upload
File PathFunctions CalledWhat it does
1
react-dashboard/src/components/Header.jsx
FE
Header()
setUploadOpen(true)
User clicks Upload button → sets uploadOpen=true → UploadModal mounts
2
react-dashboard/src/components/UploadModal.jsx
FE
UploadModal()
POST /api/upload/reset
onDrop(e) or browse
handleFile(file)
On open → POST /api/upload/reset (clears previous job)
User picks file → handleFile() runs:
① Validates extension (.xlsx/.xlsm/.xls)
② Builds FormData({ file })
POST /api/upload
④ Starts startPolling() — polls every 1.5 s
2
Phase 2 — Backend: Receive File & Start Pipeline FastAPI
upload_server.py handles the POST, saves file, spawns thread
File PathFunctions CalledWhat it does
3
Modular app/upload_server.py
BE FastAPI server
upload_excel()
POST /api/upload
_find_pipeline_python()
Thread(_run_pipeline).start()
① Validates extension (server-side guard)
② Checks no job already running (HTTP 409 if busy)
③ Saves xlsx → _uploads/filename.xlsx
_find_pipeline_python() — finds Python with pandas
⑤ Spawns background thread → _run_pipeline(xlsx_path)
⑥ Returns HTTP 200 immediately
4
Modular app/upload_server.py
BE background thread
_run_pipeline(xlsx_path)
_reset_steps()
subprocess.Popen([python,
  "-m", "pipeline.run", ...])
_annotate(line) per line
Streams subprocess stdout live to terminal
_annotate() prints step banners at key lines
After completion → copies output/*.jsonreact-dashboard/public/data/
Sets _job["status"] = "done"
▼ subprocess.Popen launches Python pipeline
3
Phase 3 — Python Pipeline Execution Python
python -m pipeline.run --input file.xlsx --output output/
File PathFunctions CalledWhat it does
5
Modular app/pipeline/run.py
PY Entry point — python -m pipeline.run
main()
Parses CLI args (--input, --output)
Orchestrates all pipeline steps in sequence
Calls every function below and writes all JSON outputs
6
Modular app/pipeline/config.py
CFG imported by run.py, modelling.py, proxies.py, recommendations.py
DEFAULT_PACK_ORDER
GUARDRAIL_MIN_OBS = 6
MAX_COMP_COMBO_SIZE = 3
ELASTICITY_ABS_CAP = 6.0
SEASONAL_R2_THRESHOLD = 0.05
ANCHOR_DOMINANCE_RATIO = 1.20
REC_DELTA_PCT = 5.0
Single source of truth for all thresholds.
Imported (not called) — all constants read at import time.
No magic numbers anywhere else in the pipeline.
7
Modular app/pipeline/loader.py
PY Step 0 — Data loading
load_source_data(path)
read_brand_config(path)
load_source_data():
 → Opens xlsx, finds 1_Source_Data sheet header row
 → Reads Brand, Date, Channel, Region, Pack Size Group, Value, Volume, Distribution
 → Computes Price = Value / Volume
 → Parses dates, drops null rows

read_brand_config():
 → Reads 2_Brand_Config sheet
 → Returns focal brand(s) + competitors list
8
Modular app/pipeline/modelling.py
PY Step 1 & 2 — Pivot + OLS models
build_wide_pivot(df, focal,
  comps, ch, rg, pack_order)

run_elasticity_models(all_data,
  comps, pack_order)

ols(y, X) — internal
build_wide_pivot():
 → Called once per Channel × Region combination
 → Creates wide monthly table with focal brand + competitor columns
 → Adds: Vol_F, Price_F, Dist_F, Cat_Vol, Vol_Up, Vol_Down

run_elasticity_models():
 → Tests all OLS spec combinations per grain
 → Base + competitors + seasonal dummies
 → Selects best Adj-R² with own-price coef < 0
 → Clamps elasticity to [−6, 0]

ols(y, X):
 → numpy.linalg.lstsq solver
 → Returns betas, t-stats, p-values, R², Adj-R²
9
Modular app/pipeline/diagnostics.py
PY Step 1 — Pre-modelling quality checks
run_diagnostics(all_data, comps)
safe_corr(a, b) — internal
safe_trend(s) — internal
Produces 5-sheet diagnostics Excel:
 → descriptive: mean, std, CV, trend per grain
 → correlation: Pearson |r|, collinearity flags (>0.70)
 → rpi_dist: relative price index vs competitors
 → cannibalization: cross-pack volume correlations
 → summary: model-readiness pass/warn/fail per grain
Writes: output/{focal}_Step1_Diagnostics.xlsx
10
Modular app/pipeline/proxies.py
PY Step 3 — Proxy assignment & anchors
assign_proxies(best_df, pack_order)
compute_freq_anchors(df, focal)
assign_proxies():
 → Grains with wrong sign get borrowed elasticity
 → Priority 1: interpolate adjacent packs
 → Priority 2: borrow from nearest pack same CH/Region
 → Priority 3: borrow from nearest pack any region
 → Adds Final_OwnE, IsProxy, ProxyMethod columns

compute_freq_anchors():
 → Finds dominant pack per Channel × Region by vol %
 → Returns {CH|Region: {anchor, vol_sal}}
11
Modular app/pipeline/exporters/stats.py
PY Exporter — Elasticity results & brand KPIs
build_grain_metrics(df, focal, comps)
build_model_export(final_df, metrics)
build_stats_json(df, focal,
  final_df, anchors)
print_summary(final_df, anchors)
build_grain_metrics(): vol sal, val share, MS yr25/yr24, price/ml per grain
build_model_export(): flat list of grain elasticities + metrics → models.json
build_stats_json(): brand KPIs (vol growth, avg ε, anchors, Cr value) → stats.json
print_summary(): prints grain/proxy/Adj-R² summary to terminal
12
Modular app/pipeline/exporters/market.py
PY Exporter — Market dynamics
build_trend_json(df, focal, comps)
build_ms_json(df, focal)
build_vol_salience_json(df, focal)
build_val_share_json(df, focal)
build_comp_ms_json(df, focal, comps)
build_vtm_json(df, focal, comps)
trend.json: monthly time-series for all brands (volume, value, price, dist)
ms.json: focal brand market share yr25 vs yr24 per grain
vol_salience.json: pack vol % of focal brand total
val_share.json: pack value % of focal brand total
comp_ms.json: all brands market share yr25 vs yr24
vtm.json: category + per-brand volumes with MS and vol change
13
Modular app/pipeline/exporters/ppa.py
PY Exporter — Price Pack Architecture
build_ppa_json(df, focal, comps,
  channel, pack_order,
  excel_path, excel_sheet)
_parse_ppa_sheet(path, sheet) — internal
Called twice:
channel="MT", sheet 3_PPA_MTppa_mt.json
channel="TT", sheet 4_PPA_TTppa_tt.json
Per-brand PPA matrix: SKU count, MRP, price/ml, relative gradient, gross contribution %, RPI
14
Modular app/pipeline/exporters/analytics.py
PY Exporter — Growth & interaction analytics
build_interaction_json(df, focal, comps)
build_growth_decomp_json(df, focal)
build_pgi_json(df, focal, pack_order)
interaction.json: cross-brand Pearson r of monthly volumes per CH×Region
growth_decomp.json: %-point contribution per grain to brand vol growth yr24→yr25
pgi.json: Price Gradient Index per channel yr24 vs yr25
15
Modular app/pipeline/exporters/recommendations.py
PY Exporter — Pricing recommendations
build_recs_json(df, focal, comps,
  final_df, pack_order, excel_path)
recs_full.json: pricing rec cards per Channel × Pack
±5% scenarios: score, feasibility, vol/val/GC impact for each
Uses elasticity from final_df + GC% from PPA sheet
JSON files written to Modular app/output/
models.json
stats.json
freq_anchors.json
trend.json
ms.json
vol_salience.json
val_share.json
comp_ms.json
vtm.json
ppa_mt.json
ppa_tt.json
interaction.json
growth_decomp.json
pgi.json
recs_full.json
4
Phase 4 — Backend: Copy JSONs & Mark Done FastAPI
upload_server.py copies output/*.json → public/data/
File PathFunctions CalledWhat it does
16
Modular app/upload_server.py
BE post-pipeline copy step
shutil.copy2(src, REACT_DATA/fname)
for each of 15 JSON files

_job["status"] = "done"
Copies all output/*.jsonreact-dashboard/public/data/
Also copies recs_full.jsonrecs.json (alias)
Sets job status to "done" so frontend poll loop stops
React now has two sources: live API + static fallback
5
Phase 5 — Frontend: Data Reload & Dashboard Renders React
Poll detects "done" → reload() → all 16 keys fetched → tabs render
File PathFunctions CalledWhat it does
17
react-dashboard/src/components/UploadModal.jsx
FE
startPolling()
GET /api/upload/status
GET /api/upload/logs
handleReload()
onSuccess(filename)
Polls status every 1.5 s until status="done"
On done: handleReload() → calls onSuccess(filename)
Closes modal
18
react-dashboard/src/components/Header.jsx
FE
handleSuccess(filename)
setActiveFile(filename)
localStorage.setItem(LS_KEY, filename)
reload()
Updates header badge to show filename
Persists filename in localStorage
Calls reload() from DataContext → triggers full data refresh
19
react-dashboard/src/DataContext.jsx
FE shared data provider
loadAll()
fetchKey(key) × 16
GET /api/data/{key} (primary)
GET /data/{key}.json (fallback)
setData(results)
setLoading(false)
Fetches all 16 keys sequentially
Each key: tries FastAPI first → falls back to Vite static if server down
setProgress() updated per key (progress bar)
Once all done: setData(results) → all tabs re-render with fresh data
20
react-dashboard/src/App.jsx
FE root layout
Dashboard()
tabComponents[activeTab]
Loading screen clears once loading=false
Active tab component mounts with fresh data from context
Complete File List — All Files Triggered
In execution order, with full paths
# Full File Path Layer Triggered by Purpose
1 react-dashboard/src/components/Header.jsx FE User click Opens upload modal
2 react-dashboard/src/components/UploadModal.jsx FE Header.jsx File validation, POST /api/upload, polling
3 Modular app/upload_server.py BE POST /api/upload Saves xlsx, spawns pipeline thread
4 Modular app/pipeline/run.py PY subprocess.Popen Pipeline entry point — orchestrates all steps
5 Modular app/pipeline/config.py CFG import by run.py All thresholds and constants (pack order, caps, ratios)
6 Modular app/pipeline/loader.py PY run.py line 65 Read 1_Source_Data + 2_Brand_Config sheets from xlsx
7 Modular app/pipeline/modelling.py PY run.py line 111, 134 Wide pivot per grain + OLS elasticity model search
8 Modular app/pipeline/diagnostics.py PY run.py line 125 Correlation, CV, RPI checks → writes Diagnostics.xlsx
9 Modular app/pipeline/proxies.py PY run.py line 140, 145 Proxy elasticity for wrong-sign grains + frequency anchors
10 Modular app/pipeline/exporters/stats.py PY run.py line 153 → models.json, stats.json, freq_anchors.json
11 Modular app/pipeline/exporters/market.py PY run.py line 178 → trend.json, ms.json, vol_salience.json, val_share.json, comp_ms.json, vtm.json
12 Modular app/pipeline/exporters/ppa.py PY run.py line 198, 206 → ppa_mt.json, ppa_tt.json (reads 3_PPA_MT, 4_PPA_TT sheets)
13 Modular app/pipeline/exporters/analytics.py PY run.py line 217 → interaction.json, growth_decomp.json, pgi.json
14 Modular app/pipeline/exporters/recommendations.py PY run.py line 220 → recs_full.json (pricing rec cards ±5% scenarios)
15 Modular app/upload_server.py BE After pipeline exits 0 Copies output/*.json → react-dashboard/public/data/, sets job done
16 react-dashboard/src/DataContext.jsx FE Header.handleSuccess() → reload() Fetches all 16 keys via GET /api/data/{key}, updates React state
17 react-dashboard/src/App.jsx FE DataContext loading=false Clears loading screen, renders active tab with fresh data
Files NOT triggered on upload (only triggered on tab click, if pre-loaded): tabs/ElasticityResults.jsx tabs/Trends.jsx tabs/PPA.jsx tabs/Recommendations.jsx tabs/Simulation.jsx tabs/BrandInteraction.jsx tabs/GrowthDecomposition.jsx tabs/PriceGradient.jsx tabs/Methodology.jsx — these mount after tab click, not on upload.