Genesis AI — Detailed Interaction Flowchart

Exact functions, APIs, validations and data keys for every user action

PART A — File Upload: Complete Flow

From the moment the user clicks "Upload" to the moment JSON data is in React state — every function, API call, validation and Python function.

flowchart TD U([" 👤 User clicks\n Upload button "]) --> H1 subgraph FE1 [" FRONTEND — Header.jsx "] H1["Header()\nstate: uploadOpen=false → true\nonClick: setUploadOpen(true)"] H2["UploadModal opens\nPOST /api/upload/reset\n→ clears previous job state"] H1 --> H2 end subgraph FE2 [" FRONTEND — UploadModal.jsx "] V1{"User picks file\n(drag-drop or browse)"} V2["onDrop(e)\ne.dataTransfer.files[0]"] V3["handleFile(file)\n── VALIDATION ──\n① file.name.endsWith('.xlsx'/'.xlsm'/'.xls')\n② if invalid → setError('Please upload .xlsx')\n return early"] V4["phase = 'uploading'\nsetStatus(null), setError(null)"] V5["POST /api/upload\nfetch('/api/upload', {\n method: 'POST',\n body: FormData({ file })\n})"] V6{"res.ok?"} V7["setError(detail from JSON)\nphase = null"] V8["phase = 'running'\nstartPolling()"] V1 -- drag --> V2 V1 -- browse --> V3 V2 --> V3 V3 -- valid --> V4 --> V5 V3 -- invalid --> V7 V5 --> V6 V6 -- No --> V7 V6 -- Yes --> V8 end subgraph FE3 [" FRONTEND — UploadModal.jsx (polling) "] P1["startPolling()\nsetInterval every 1500 ms"] P2["GET /api/upload/status\n→ { status, message, elapsed_s }"] P3["GET /api/upload/logs\n→ { logs }"] P4["setStatus(message)\nsetLogs(logs)"] P5{"status == 'done'\nor 'error'?"} P6["clearInterval\nphase = 'done' or 'error'"] P7["handleReload()\nonSuccess(filename)\n→ Header.handleSuccess()"] P1 --> P2 --> P3 --> P4 --> P5 P5 -- No, keep polling --> P2 P5 -- Yes --> P6 --> P7 V8 --> P1 end subgraph FE4 [" FRONTEND — Header.jsx (on success) "] S1["handleSuccess(filename)\nsetActiveFile(filename)\nlocalStorage.setItem('genesis_active_file', filename)\nreload() ← from DataContext"] S2["Header badge updates:\n'Simulating / filename.xlsx'"] S1 --> S2 end subgraph FE5 [" FRONTEND — DataContext.jsx (reload) "] DC1["loadAll()\nsetLoading(true), setProgress(0)"] DC2["for each key in KEYS[16]\n fetchKey(key)"] DC3["fetchKey(key)\n① fetch('/api/data/{key}')\n if res.ok → return res.json()\n② catch → fetch('/data/{key}.json')\n if res.ok → return res.json()\n③ else → null"] DC4["setProgress(i+1 / 16 × 100)"] DC5["setData(results)\nsetLoading(false)"] DC1 --> DC2 --> DC3 --> DC4 --> DC5 end subgraph BE [" BACKEND — upload_server.py "] B1["POST /api/upload\n① validate extension\n② save to _uploads/file.xlsx\n③ _job['filename'] = filename\n④ Thread(_run_pipeline).start()"] B2["GET /api/upload/status\nreturns _job dict snapshot"] B3["GET /api/data/{key}\n① check DATA_KEY_MAP\n② read output/{key}.json\n③ return JSONResponse"] B4["_run_pipeline(xlsx_path)\nStreams subprocess stdout live\nUpdates _job['logs'] per line\nCopies output/*.json → public/data/\n_job['status'] = 'done'"] end subgraph PY [" PYTHON PIPELINE — pipeline/run.py "] PY1["load_source_data(xlsx)\npipeline/loader.py\nReads sheet: 1_Source_Data\nPrice = Value / Volume\nDrops null rows"] PY2["read_brand_config(xlsx)\npipeline/run.py\nReads sheet: 2_Brand_Config\nFocal brand, competitors"] PY3["build_wide_pivot()\npipeline/modelling.py\nOne table per CH × Region\nFocal + competitor columns"] PY4["run_diagnostics()\npipeline/diagnostics.py\nCorrelation, CV, RPI flags\nWrites *_Diagnostics.xlsx"] PY5["run_elasticity_models()\npipeline/modelling.py\nOLS all spec combos\nSelects best Adj-R²"] PY6["assign_proxies()\npipeline/proxies.py\nBorrow elasticity for\nwrong-sign grains"] PY7["compute_freq_anchors()\npipeline/proxies.py\nDominant pack per\nCH × Region"] PY8["build_grain_metrics()\npipeline/exporters/stats.py\nVol sal, val share,\nmarket share per grain"] EXPORT["5 exporter functions\n(see Part B diagram)"] PY1-->PY2-->PY3-->PY4-->PY5-->PY6-->PY7-->PY8-->EXPORT end H2 --> FE2 V5 --> B1 B1 --> B4 B4 --> PY1 P2 --> B2 DC3 --> B3 P7 --> FE4 S1 --> DC1 style FE1 fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b style FE2 fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b style FE3 fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b style FE4 fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b style FE5 fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b style BE fill:#fff3e0,stroke:#c84b00,color:#3e2000 style PY fill:#e8f5e9,stroke:#2e7d32,color:#1b2e1b
React Frontend
FastAPI Backend
Python Pipeline
Part A — Frontend Validations on Upload
CheckWhereFunctionConditionOn Fail
File type FE handleFile(file) — UploadModal.jsx filename ends with .xlsx, .xlsm, or .xls setError("Please upload an .xlsx / .xlsm / .xls file"); returns early, no API call
Server extension check BE upload_excel() — upload_server.py Same extension check server-side (double guard) HTTP 400 — detail shown in modal error state
Concurrent run guard BE upload_excel() — upload_server.py _job['status'] != 'running' HTTP 409 — "A pipeline run is already in progress"
HTTP response check FE handleFile() — UploadModal.jsx res.ok === true after POST Reads res.json().detail and shows as error; stops polling
Pipeline error check FE startPolling() — UploadModal.jsx status != 'error' clearInterval; phase = 'error'; shows logs panel with failure detail
Data key unknown BE get_data(key) — upload_server.py key in DATA_KEY_MAP HTTP 404 — DataContext catches, key value = null; tab shows empty state
JSON file missing BE get_data(key) — upload_server.py output/{key}.json exists on disk HTTP 404 — DataContext falls back to /data/{key}.json static file
Part A — Python Functions Invoked (Pipeline)
#FileFunctionInputOutputWhat it does
1pipeline/loader.pyload_source_data(path)xlsx pathDataFrameReads 1_Source_Data sheet; computes Price = Value/Volume; parses dates; drops nulls in Brand/Month/Value/Volume
2pipeline/run.pyread_brand_config(path)xlsx pathconfig dictReads 2_Brand_Config sheet; extracts focal brand name + competitor list
3pipeline/modelling.pybuild_wide_pivot(df, focal, comps, ch, rg, pack_order)DataFramewide DataFrameOne wide monthly table per CH×Region grain. Adds Vol_F, Price_F, Dist_F, Price_<comp>, Cat_Vol, Vol_Up, Vol_Down columns
4pipeline/diagnostics.pyrun_diagnostics(all_data, competitors)wide DataFrameExcel file5-sheet diagnostics: descriptive stats, correlation/collinearity, RPI trends, cannibalization, summary flags
4apipeline/diagnostics.pysafe_corr(a, b)two Series(r, p)Pearson r with ≥5 non-null pairs guard
4bpipeline/diagnostics.pysafe_trend(s)Series(slope, r², p)OLS trend over time index
5pipeline/modelling.pyrun_elasticity_models(all_data, comps, pack_order)wide DataFrame(all_results_df, best_df)Exhaustive OLS spec search per grain; selects best Adj-R² with own-price coef < 0; clamps elasticity to [−6, 0]
5apipeline/modelling.pyols(y, X)arrayscoef dictnumpy.linalg.lstsq OLS; returns betas, t-stats, p-values, R², Adj-R²
6pipeline/proxies.pyassign_proxies(best_df, pack_order)best_dffinal_dfWrong-sign grains: interpolate adjacent packs → borrow same CH/RG → borrow any region. Adds Final_OwnE, IsProxy, ProxyMethod
7pipeline/proxies.pycompute_freq_anchors(df, focal, ppa_pml)DataFrameanchors dictDominant pack per CH×Region by vol %; tie-break by lowest price/ml if PPA supplied
8pipeline/exporters/stats.pybuild_grain_metrics(df, focal, comps)DataFramemetrics dictVol sal, val share, MS yr25/yr24, price/ml, base vol/val — enrichment for model export
9pipeline/exporters/stats.pybuild_model_export(final_df, grain_metrics)final_dfmodels.jsonFlat list of grain elasticities + market metrics
10pipeline/exporters/stats.pybuild_stats_json(df, focal, final_df, anchors, growth_decomp)DataFramestats.jsonBrand-level KPIs: vol growth, avg elasticity, market share, anchor count
11pipeline/exporters/market.pybuild_trend_json(df, focal, comps)DataFrametrend.jsonMonthly time-series rows for all brands
12pipeline/exporters/market.pybuild_ms_json(df, focal)DataFramems.jsonFocal brand market share yr25 vs yr24 per grain
13pipeline/exporters/market.pybuild_vol_salience_json(df, focal)DataFramevol_salience.jsonPack volume % of focal brand total
14pipeline/exporters/market.pybuild_val_share_json(df, focal)DataFrameval_share.jsonPack value % of focal brand total
15pipeline/exporters/market.pybuild_comp_ms_json(df, focal, comps)DataFramecomp_ms.jsonAll brands' market share yr25 vs yr24
16pipeline/exporters/market.pybuild_vtm_json(df, focal, comps)DataFramevtm.jsonCategory + per-brand volumes with MS and vol change
17pipeline/exporters/ppa.pybuild_ppa_json(df, focal, comps, channel, ...)DataFrame + xlsxppa_mt.json / ppa_tt.jsonPer-brand PPA matrix (SKU, MRP, price/ml, RPI, gross contribution)
18pipeline/exporters/analytics.pybuild_interaction_json(df, focal, comps)DataFrameinteraction.jsonCross-brand Pearson r of monthly volumes per CH×Region
19pipeline/exporters/analytics.pybuild_growth_decomp_json(df, focal)DataFramegrowth_decomp.json%-point contribution per grain to brand volume growth yr24→yr25
20pipeline/exporters/analytics.pybuild_pgi_json(df, focal, pack_order)DataFramepgi.jsonPrice Gradient Index per channel yr24 vs yr25
21pipeline/exporters/recommendations.pybuild_recs_json(df, focal, comps, final_df, pack_order, xlsx)DataFramerecs_full.json±5% pricing recommendation cards with score, feasibility, impact (vol, val, GC)
PART B — Tab Button Click: Complete Flow

What happens in the frontend when a tab is clicked. Data is already loaded in DataContext at this point — no new backend calls are made on tab switch.

flowchart TD T([" 👤 User clicks\n a Tab button "]) --> TN subgraph FE_NAV [" FRONTEND — TabNav.jsx "] TN["TabNav()\nonClick: onTabChange(t.id)\nprop callback -> App.jsx"] TN2["App.jsx\nsetActiveTab(t.id)\nstate: activeTab = 'results' | 'trends' | 'ppa'\n | 'recs' | 'sim' | 'interaction'\n | 'growth' | 'gi' | 'methodology'"] TN --> TN2 end subgraph FE_APP [" FRONTEND — App.jsx "] APP["tabComponents[activeTab]\nMounted tab component renders\n(previously loaded data from DataContext)\nNo new API calls triggered"] TN2 --> APP end subgraph CTX [" FRONTEND — DataContext (already loaded) "] CTX1["useData() hook\nAll 16 keys already in memory:\nmodels, recs, ms, vol_salience,\nval_share, freq_anchors, ppa_mt,\nppa_tt, comp_ms, vtm, interaction,\ngrowth_decomp, pgi, stats,\ntrend, recs_full"] APP --> CTX1 end subgraph TABS [" TAB COMPONENTS "] T1["ElasticityResults.jsx\nTab: Results\nuseData(): models, stats, freq_anchors\nLocal state: channel filter, region filter,\npack filter, sort column"] T2["Trends.jsx\nTab: Trends\nuseData(): trend\nLocal state: brand filter, channel,\nmetric (volume/value/price/dist)"] T3["PPA.jsx\nTab: PPA\nuseData(): ppa_mt, ppa_tt, freq_anchors, trend\nLocal state: channel (MT/TT), pack filter"] T4["Recommendations.jsx\nTab: Recommendations\nuseData(): recs, freq_anchors\nLocal state: type filter (inc/dec/both),\nchannel filter"] T5["Simulation.jsx\nTab: Simulation\nuseData(): models\nLocal state: selected grain,\nprice delta input, computed impact"] T6["BrandInteraction.jsx\nTab: Interaction\nuseData(): vtm, interaction, freq_anchors\nLocal state: channel, region filters"] T7["GrowthDecomposition.jsx\nTab: Growth\nuseData(): growth_decomp, stats\nLocal state: sort, filter state"] T8["PriceGradient.jsx\nTab: Price Gradient\nuseData(): pgi\nLocal state: channel filter"] T9["Methodology.jsx\nTab: Methodology\nNo DataContext dependency\nStatic explanatory content"] CTX1 --> T1 & T2 & T3 & T4 & T5 & T6 & T7 & T8 & T9 end style FE_NAV fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b style FE_APP fill:#e3f2fd,stroke:#1565c0,color:#0d1b4b style CTX fill:#e8f5e9,stroke:#2e7d32,color:#1b2e1b style TABS fill:#f3e5f5,stroke:#7b1fa2,color:#2e0040
React Frontend
DataContext (in-memory)
Tab Components
Part B — How Each Tab Gets Its Data

Data flows from pipeline → JSON files → FastAPI → DataContext → tab component. Once loaded, tab switches are instant (no API calls).

Tab (id) Component Data keys used Python function that created each JSON What is displayed
results ElasticityResults.jsx models, stats, freq_anchors build_model_export() → models.json
build_stats_json() → stats.json
compute_freq_anchors() → freq_anchors.json
Elasticity table per CH×Region×Pack; own-price E, Adj-R², dist E, comp coefs; anchor tags
trends Trends.jsx trend build_trend_json() → trend.json Monthly time-series chart; brand/channel/metric filter; volume, value, price, distribution lines
ppa PPA.jsx ppa_mt, ppa_tt, freq_anchors, trend build_ppa_json(ch='MT') → ppa_mt.json
build_ppa_json(ch='TT') → ppa_tt.json
Price-pack architecture matrix; MRP, price/ml, RPI, gross contribution per brand/pack; MT or TT toggle
recs Recommendations.jsx recs, freq_anchors build_recs_json() → recs_full.json (served as "recs") Pricing recommendation cards per CH×Pack; ±5% scenarios; score, feasibility, vol/val/GC impact
sim Simulation.jsx models build_model_export() → models.json Interactive price simulator; user enters % price change; computes vol/val impact using own-price elasticity
interaction BrandInteraction.jsx vtm, interaction, freq_anchors build_vtm_json() → vtm.json
build_interaction_json() → interaction.json
Cross-brand correlation heatmap; volume-to-market by brand; channel/region filters
growth GrowthDecomposition.jsx growth_decomp, stats build_growth_decomp_json() → growth_decomp.json
build_stats_json() → stats.json
%-point contribution bars per grain to brand volume growth yr24→yr25; sorted by contribution
gi PriceGradient.jsx pgi build_pgi_json() → pgi.json Price Gradient Index table per channel; MRP, price/ml, relative gradient yr24 vs yr25
methodology Methodology.jsx none Static methodology explanation; no data dependency
Part B — DataContext Loading Sequence (on page load or reload)

This runs once on page load and again after every successful upload. All 16 keys are fetched sequentially; progress bar reflects completion.

sequenceDiagram participant DC as DataContext.jsx participant API as FastAPI :8000 participant FS as public/data/ (Vite static) Note over DC: loadAll() called on mount or reload() loop for each of 16 keys DC->>API: GET /api/data/{key} alt Server running & output file exists API-->>DC: 200 JSON (from output/{key}.json) else Server down or file missing DC->>FS: GET /data/{key}.json alt Static file exists FS-->>DC: 200 JSON (from public/data/{key}.json) else FS-->>DC: 404 DC-->>DC: key = null (tab shows empty state) end end Note over DC: setProgress((i+1)/16 × 100) end Note over DC: setData(all 16 keys)
setLoading(false)
All tabs can now render
API Endpoint Reference
MethodEndpointCalled byFunction in upload_server.pyPurpose
POST /api/upload handleFile() — UploadModal.jsx upload_excel() Saves xlsx, starts background pipeline thread
POST /api/upload/reset UploadModal on open reset_job() Clears previous job state so fresh run can start
GET /api/upload/status startPolling() — every 1.5 s get_status() Returns { status, message, elapsed_s, filename }
GET /api/upload/logs startPolling() — every 1.5 s get_logs() Returns full pipeline stdout log accumulated so far
GET /api/data/{key} fetchKey(key) — DataContext.jsx get_data(key) Reads output/{key}.json written by pipeline; returns as JSON
GET /api/data Debug / manual use list_data_keys() Lists all 16 keys with availability and file size
Complete Map: API Key → JSON File → Python Function → Tab
API keyJSON fileExporter filePython functionUsed in tab
modelsmodels.jsonexporters/stats.pybuild_model_export()results, sim
statsstats.jsonexporters/stats.pybuild_stats_json()results, growth, header KPIs
freq_anchorsfreq_anchors.jsonpipeline/proxies.pycompute_freq_anchors()results, ppa, recs, interaction
trendtrend.jsonexporters/market.pybuild_trend_json()trends, ppa
msms.jsonexporters/market.pybuild_ms_json()(available for market share views)
vol_saliencevol_salience.jsonexporters/market.pybuild_vol_salience_json()(available for pack salience charts)
val_shareval_share.jsonexporters/market.pybuild_val_share_json()(available for value share charts)
comp_mscomp_ms.jsonexporters/market.pybuild_comp_ms_json()(available for competitor views)
vtmvtm.jsonexporters/market.pybuild_vtm_json()interaction
ppa_mtppa_mt.jsonexporters/ppa.pybuild_ppa_json(channel='MT')ppa
ppa_ttppa_tt.jsonexporters/ppa.pybuild_ppa_json(channel='TT')ppa
interactioninteraction.jsonexporters/analytics.pybuild_interaction_json()interaction
growth_decompgrowth_decomp.jsonexporters/analytics.pybuild_growth_decomp_json()growth
pgipgi.jsonexporters/analytics.pybuild_pgi_json()gi
recs / recs_fullrecs_full.jsonexporters/recommendations.pybuild_recs_json()recs