Onboarding
BioLoupe Forecasting - Onboarding Guide
Section titled “BioLoupe Forecasting - Onboarding Guide”Visual architecture guide for new developers.
1. High-Level Overview
Section titled “1. High-Level Overview”flowchart TB
subgraph External["External Services"]
API["Data-Gov API<br/>(Rails Backend)"]
BioLoupe["BioLoupe Platform<br/>(Login)"]
end
subgraph App["React App"]
Main["main.tsx"]
Auth["AuthProvider"]
Query["QueryClientProvider"]
AppComp["App.tsx"]
Forecast["Forecasting.tsx"]
subgraph Sections["Feature Sections"]
Config["Configuration"]
Model["Model"]
Sales["SalesChart"]
Monte["MonteCarlo"]
Tornado["Tornado"]
end
end
subgraph State["State Layer"]
RQ["React Query<br/>(Server State)"]
Jotai["Jotai Atoms<br/>(Client State)"]
end
Main --> Query --> Auth --> AppComp --> Forecast
Forecast --> Sections
API <--> RQ
BioLoupe <-.->|JWT Cookie| Auth
RQ -->|Sync Data| Jotai
Jotai <-->|Read/Write| Sections
Simple explanation:
- User visits app → Auth checks if logged in → Loads main Forecasting page
- React Query fetches data from API → Syncs to Jotai atoms → Sections read/write atoms
2. Authentication Flow
Section titled “2. Authentication Flow”sequenceDiagram
participant User
participant App
participant AuthProvider
participant API as Data-Gov API
participant BioLoupe as BioLoupe Login
User->>App: Opens app
App->>AuthProvider: Mount
AuthProvider->>API: GET /api/check_session<br/>(with JWT cookie)
alt Session Valid
API-->>AuthProvider: { logged_in: true, user: {...} }
AuthProvider->>App: isLoggedIn = true
App->>User: Show Forecasting
else Session Invalid
API-->>AuthProvider: { logged_in: false }
AuthProvider->>App: isLoggedIn = false
App->>BioLoupe: Redirect to /users/login
User->>BioLoupe: Enters credentials
BioLoupe->>BioLoupe: Sets JWT cookie
BioLoupe->>App: Redirect back
Note over App: Cycle repeats, session now valid
end
Simple explanation:
- App loads → checks if you’re logged in via API
- If yes → show the app
- If no → send you to BioLoupe login page
- After login → cookie is set → you come back authenticated
3. Data Fetching Flow
Section titled “3. Data Fetching Flow”flowchart LR
subgraph API["Backend"]
Endpoint["/api/statistics"]
end
subgraph ReactQuery["React Query Layer"]
Hook["useStatistics()"]
Cache["Query Cache"]
end
subgraph Jotai["Jotai Layer"]
RefRows["referenceRowsAtom<br/>(API data - read only)"]
InstRows["instanceRowsAtom<br/>(User edits)"]
Derived["Derived Atoms<br/>geographies, indications"]
end
subgraph Components["Components"]
Dropdown["Dropdowns"]
Sections["Sections"]
end
Endpoint -->|fetch| Hook
Hook -->|cache| Cache
Hook -->|setReferenceRows| RefRows
RefRows -->|auto-compute| Derived
Derived -->|useAtomValue| Dropdown
RefRows -->|useAtomValue| Sections
InstRows -->|useAtomValue| Sections
Simple explanation:
useStatistics()fetches data from API- Data syncs to
referenceRowsAtom(read-only reference data) - Derived atoms auto-compute lists (geographies, indications)
- Components read from atoms using
useAtomValue
4. State Management Architecture
Section titled “4. State Management Architecture”flowchart TB
subgraph Stores["Two Main Stores"]
Ref["Reference Store<br/>(referenceRowsAtom)<br/>━━━━━━━━━━━━━<br/>• From API<br/>• Read-only<br/>• Disease configs"]
Inst["Instance Store<br/>(instanceRowsAtom)<br/>━━━━━━━━━━━━━<br/>• User edits<br/>• Editable<br/>• Form values"]
end
subgraph Context["Context Atoms"]
Geo["geoAtom<br/>(active geography)"]
Ind["indicationAtom<br/>(active indication)"]
Year["selectedYearAtom"]
end
subgraph Sections["Section Atoms (via Factories)"]
ConfigAtoms["config.assumptions<br/>config.lines<br/>config.population"]
IncAtoms["incidence.evolution<br/>incidence.erosion"]
MonteAtoms["monteCarlo.variables"]
end
Ref --> Context
Inst --> Context
Context --> Sections
Simple explanation:
- Reference rows = Data from API (disease info, defaults) - never changes
- Instance rows = Your edits (form values) - you can change these
- Context atoms = What you currently have selected (geography, indication, year)
- Section atoms = Computed values for each section (derived from above)
5. How Data is Stored (Normalized Pattern)
Section titled “5. How Data is Stored (Normalized Pattern)”flowchart TB
subgraph Row["Each Row in Store"]
direction LR
G["geo: 'USA'"]
I["indication: 'Breast Cancer'"]
L["line: '1L'"]
Y["year: 2024"]
N["name: 'marketShare'"]
V["value: 0.25"]
end
subgraph Query["Query System"]
Q["getValue(rows, {<br/> geo: 'USA',<br/> indication: 'Breast Cancer',<br/> line: '1L'<br/>}, 'marketShare')"]
R["→ Returns: 0.25"]
end
Row --> Query
Simple explanation:
- All data stored as flat rows with keys:
geo + indication + line + year + name - To get a value: query with those keys + the field name
- Fast O(1) lookups instead of nested objects
6. Section Factory Pattern
Section titled “6. Section Factory Pattern”flowchart TB
subgraph Main["atoms.ts (Orchestrator)"]
Shared["Shared Atoms<br/>━━━━━━━━━━━━━<br/>geoAtom<br/>indicationAtom<br/>instanceRowsAtom"]
Factory["createForecastingAtoms()"]
end
subgraph Factories["Section Factories"]
CF["createConfigAtoms(deps)"]
IF["createIncidenceAtoms(deps)"]
MF["createModelAtoms(deps)"]
MCF["createMonteCarloAtoms(deps)"]
end
subgraph Returns["Returned Atoms"]
CA["config.assumptions<br/>config.lines<br/>config.updateLine"]
IA["incidence.evolution<br/>incidence.setEvolution"]
MA["model.yearLabels<br/>model.diseaseConfig"]
MCA["monteCarlo.variables"]
end
Shared -->|pass as deps| Factory
Factory -->|call| CF
Factory -->|call| IF
Factory -->|call| MF
Factory -->|call| MCF
CF --> CA
IF --> IA
MF --> MA
MCF --> MCA
Simple explanation:
- Main
atoms.tscreates shared atoms (geo, indication, rows) - Calls each section’s factory function, passing atoms as parameters
- Sections NEVER import from atoms.ts directly (prevents circular dependencies)
- Factories return section-specific atoms for components to use
7. User Interaction Flow
Section titled “7. User Interaction Flow”sequenceDiagram
participant User
participant Component
participant SetAtom as useSetAtom
participant Jotai as Jotai Store
participant Derived as Derived Atoms
participant OtherComp as Other Components
User->>Component: Changes input value
Component->>SetAtom: updateAssumptions({ treatmentRate: 80 })
SetAtom->>Jotai: set(instanceRowsAtom, newRow)
Note over Jotai: Row updated:<br/>{ geo: 'USA', indication: 'X',<br/>name: 'treatmentRate', value: 80 }
Jotai->>Derived: Triggers recomputation
Derived->>OtherComp: Components using this data re-render
OtherComp->>User: Updated UI
Simple explanation:
- User changes a value in a form
- Component calls a setter atom (e.g.,
updateAssumptions) - Setter atom updates the instance store
- Any derived atoms that depend on this data auto-recompute
- Components using those atoms re-render with new values
8. Component to Atom Relationship
Section titled “8. Component to Atom Relationship”flowchart LR
subgraph Components["Components"]
Config["Configuration.tsx"]
Model["Model.tsx"]
Monte["MonteCarlo.tsx"]
end
subgraph Atoms["forecastingAtoms"]
CA["config.assumptions"]
CL["config.lines"]
ML["model.yearLabels"]
MV["monteCarlo.variables"]
end
subgraph Hooks["Jotai Hooks"]
Read["useAtomValue<br/>(read only)"]
Write["useSetAtom<br/>(write only)"]
end
Config -->|useAtomValue| CA
Config -->|useAtomValue| CL
Config -->|useSetAtom| CA
Model -->|useAtomValue| CA
Model -->|useAtomValue| ML
Monte -->|useAtomValue| MV
Monte -->|useSetAtom| MV
Hook selection rules:
| Hook | When to Use | Re-renders? |
|---|---|---|
useAtomValue | Only reading data | Yes, when atom changes |
useSetAtom | Only writing data | Never |
useAtom | Both read & write | Yes, when atom changes |
9. Full Data Flow Example
Section titled “9. Full Data Flow Example”flowchart TB
subgraph Step1["1. App Loads"]
Load["Forecasting.tsx mounts"]
end
subgraph Step2["2. Fetch Data"]
RQ["useStatistics()<br/>fetches /api/statistics"]
Sync["setReferenceRows(data)"]
end
subgraph Step3["3. Derive Lists"]
Geos["geographiesAtom<br/>['USA', 'EU5', 'Japan']"]
Inds["indicationsAtom<br/>['Breast Cancer', 'Lung Cancer']"]
end
subgraph Step4["4. User Selects"]
Select["User picks:<br/>USA + Breast Cancer"]
Init["initIndicationAtom()<br/>creates 50+ instance rows"]
end
subgraph Step5["5. Sections Render"]
Sections["Configuration, Model, etc.<br/>read from instance + reference rows"]
end
subgraph Step6["6. User Edits"]
Edit["User changes treatment rate"]
Update["updateAssumptions({ treatmentRate: 80 })"]
Rerender["Dependent components re-render"]
end
Step1 --> Step2 --> Step3 --> Step4 --> Step5 --> Step6
10. Environment Configuration
Section titled “10. Environment Configuration”flowchart TB
subgraph EnvFiles[".env Files"]
ENV["VITE_API_URL<br/>VITE_BIOLOUPE_URL<br/>VITE_ENABLE_PRICING"]
end
subgraph Config["config.ts"]
GetAPI["getApiUrl()<br/>reads VITE_API_URL"]
GetAuth["getBioloupeUrl()<br/>reads VITE_BIOLOUPE_URL"]
end
subgraph Usage["Usage"]
API["API calls"]
Auth["Auth redirects"]
end
ENV --> GetAPI
ENV --> GetAuth
GetAPI --> API
GetAuth --> Auth
Variables:
| Variable | Purpose | Dev Default |
|---|---|---|
VITE_API_URL | Data-gov API endpoint | http://localhost:3010 |
VITE_BIOLOUPE_URL | BioLoupe auth redirects | http://localhost:8080 |
VITE_ENABLE_PRICING | Feature flag | false |
Copy .env.example to .env and customize as needed.
Quick Reference
Section titled “Quick Reference”Key Domain Terms
Section titled “Key Domain Terms”| Term | Definition |
|---|---|
| LoE | Loss of Exclusivity - when patent protection ends and generics/biosimilars enter market |
| 1L/2L/3L+ | Therapy lines (first-line, second-line, third-line and beyond) |
| Peak Share | Maximum market share within a therapy class (always computed, never stored) |
See ARCHITECTURE.md - Key Domain Concepts for full glossary.
Tech Stack
Section titled “Tech Stack”| Layer | Technology | Purpose |
|---|---|---|
| UI | React 19 + Radix UI | Components & accessibility |
| State | Jotai | Client-side reactive state |
| Server State | TanStack Query | API data fetching + caching |
| Styling | Tailwind CSS | Utility-first styling |
| Charts | Chart.js | Data visualization |
| Auth | JWT Cookies | Shared auth with BioLoupe |
| API | Rails Backend | Data persistence |
Key Files
Section titled “Key Files”| File | Purpose |
|---|---|
src/features/reports/forecasting/atoms.ts | Main Jotai state orchestrator |
src/features/reports/forecasting/Forecasting.tsx | Root component |
src/contexts/auth-context.tsx | Authentication |
src/hooks/useStatistics.ts | Data fetching |
src/lib/api.ts | API client |
src/lib/config.ts | Environment config |
Related Docs
Section titled “Related Docs”- ARCHITECTURE.md - Detailed technical architecture
- FORECASTING_MODEL.md - Domain model & calculations
- DESIGN_SYSTEM.md - UI patterns and component guidelines