Frontend for QuantAMM product discovery, documentation/fact sheets, and simulation workflows.
The app is built with React + TypeScript + Vite and uses both:
- GraphQL (Apollo) for Balancer data
- REST (RTK Query) for app/backend operations such as simulations, docs, prices, and audit logging
- Node.js
20.x(matches CI) - npm
10+(or compatible with your Node install)
- Install dependencies
npm ci- Create local env file
cp env.local.template .env.local- Fill in required values in
.env.local(see variables below) - Run the app
npm run devDefault local URL: http://localhost:5173
Create .env.local from env.local.template.
| Variable | Required | Purpose |
|---|---|---|
VITE_BASE_URL |
Yes | Base URL for REST endpoints used by RTK Query services |
VITE_GRAPH_TARGET |
Yes | GraphQL endpoint used by Apollo + GraphQL codegen |
VITE_USE_STUBS_DATA |
Optional | Enables/disables stub product list flow in hooks |
VITE_AG_GRID_LICENSE_KEY |
Required for enterprise features | AG Grid/AG Charts enterprise license key |
Notes:
- Never commit
.env.local. npm run codegenreads.env.localviadotenv_config_path=.env.local.VITE_AG_GRID_LICENSE_KEYmust be set at build time for AG Grid/AG Charts enterprise features.
npm run dev: start Vite dev servernpm run start: same asdevnpm run build: type-check (tsc) + production Vite buildnpm run preview: preview production build locallynpm run lint: ESLint with strict warning policy (--max-warnings 0)npm run format: Prettier write onsrc/npm run test: run Vitest oncenpm run test:watch: run Vitest in watch modenpm run test:coverage: run tests with V8 coverage outputnpm run codegen: regenerate GraphQL types/hooks fromsrc/queries/*.graphql
Top-level frontend source is in src/, and the repo follows a mostly feature-first structure.
| Path | Responsibility |
|---|---|
src/index.tsx |
Runtime entry point; wires Apollo provider, Redux provider, and router |
src/App.tsx |
Main app shell; layout/menu, global bootstrapping, route outlet host |
src/routes.tsx |
Route graph (createBrowserRouter) and page-level composition |
src/routeComponents.ts |
Lazy imports for route-level code splitting |
src/app/ |
Store, typed hooks, app-level Redux plumbing |
src/features/ |
Domain features (UI, slice logic, feature-local utils/tests) |
src/services/ |
Shared RTK Query services and service helpers |
src/queries/ |
Apollo client + GraphQL operation documents |
src/__generated__/ |
GraphQL codegen output (generated types/hooks) |
src/hooks/ |
Cross-feature hooks for data fetch/transform orchestration |
src/utils/ |
Generic utilities not owned by a single feature |
src/test/setup.ts |
Global test setup for Vitest |
public/prerun_sims/ |
Static MessagePack files used for pre-run simulation data |
| Path | What it owns |
|---|---|
src/features/simulationRunner/ |
Simulation wizard orchestration, run controls, import/export, run-status flow |
src/features/simulationRunConfiguration/ |
Pool/token selection, update-rule parameters, pre-run configuration state |
src/features/simulationResults/ |
Result summaries, visualisations, breakdown tables, compare/save flows |
src/features/productExplorer/ |
Product listing, filtering, sorting, pagination, explorer state |
src/features/productDetail/ |
Product detail page, sidebar/content panels, product modal actions |
src/features/coinData/ |
Coin data page, current price polling, coin-level state |
src/features/documentation/ |
Documentation pages, fact sheets, landing/TOS/ineligible flows |
src/features/shared/ |
Shared graphs, tables, and explanatory content components |
src/features/themes/ |
Theme slice and AG Grid theme integration |
Common pattern in this repo:
FeaturePage.tsxstyle containers for major screensfeatureSlice.tsfor feature state and reducers*Service.tsfor feature-specific RTK Query APIs*.tsutilities for transforms/view-model logic*.test.ts/*.test.tsxcolocated near logic being tested
This keeps UI, state, and logic near their domain ownership while still allowing shared hooks/services across features.
Runtime boot sequence:
src/index.tsxmounts React root- Wraps app with
ApolloProvider - Wraps app with Redux
Provider - Mounts
RouterProviderwith route config fromsrc/routes.tsx
src/App.tsx then provides:
- App-level layout (
antdLayout, header/menu/content) - App bootstrap side effects (for example, price history load and simulation initialization when entering simulation routes)
- Route outlet rendering via
<Outlet />
- Routes are centralized in
src/routes.tsx. - Route components are lazy-loaded through
src/routeComponents.tsto keep initial bundle size smaller. - Route groups include:
- landing/company/research/contact/docs pages
- product explorer and product detail routes
- simulation runner and simulation result comparison routes
- fact-sheet and simulator-example routes
src/routeErrorBoundary.tsxhandles router-level errors.
Redux Toolkit store is in src/app/store.ts.
Core state slices:
simConfig: simulation pool/time/rule configuration statesimRunner: simulation wizard step/run status and active run breakdownssimResults: result-focused state (comparison, chart/breakdown selections)docs: documentation-related stateproductExplorer: explorer filters/search/sort/tab/page-level statecurrentPrices: current token pricing statetheme: UI theme state
In the same store, RTK Query API slices are registered for:
- simulation execution
- coin price retrieval
- documentation retrieval
- product and filter retrieval
- financial analysis
- audit logging
There are three primary data paths:
- GraphQL via Apollo
- Client:
src/queries/apolloClient.ts - Operations:
src/queries/*.graphql - Generated types/hooks:
src/__generated__/graphql-types.ts
- REST via RTK Query
- Feature-local example:
src/features/simulationRunner/simulationRunnerService.ts - Shared service examples:
src/services/productRetrievalService.ts,src/services/financialAnalysisService.ts,src/services/auditLogService.ts - Most requests include CSRF token propagation from cookie helpers
- Local static runtime assets
- Precomputed simulation data loaded from
public/prerun_sims/*.msgpack
The simulation product flow is split across:
simulationRunConfigurationfor building pool configsimulationRunnerfor run orchestration and step transitionssimulationResultsfor post-run analysis and visual output
Runner step model (managed by simRunner.simulationRunnerCurrentStepIndex):
0: options1: pool constituent selection2: time range3: hooks4: final review5: run progress/state view6: results summary7: save-to-compare view
Execution path:
- UI triggers
createRunSimulationsThunk(simulationRunButtonLogic.ts) - Thunk initializes ranges and pools in runner state
- Calls
runSimulationRTK Query mutation per pool/time range - Converts API response into snapshots + analysis payload
- Dispatches success/failure reducers (
addSimRunResults,completeRun,failRun) - Completes run and advances to results step
- UI components primarily use Ant Design primitives
- Data-heavy tables/charts use AG Grid and AG Charts enterprise modules
- Styling uses a mix of CSS modules (
*.module.css) and Sass modules (*.module.scss) - Feature folders generally keep style modules next to owning components
Current test stack:
- Vitest
- Testing Library (
@testing-library/*) - Coverage via
@vitest/coverage-v8
Configuration: vite.config.ts
Important current convention:
- Vitest environment is
nodeby default. - Most current tests focus on pure logic (reducers, utilities, view-model logic).
- If you add DOM-heavy component tests, prefer file-level jsdom override:
// @vitest-environment jsdomRun specific test file:
npx vitest run src/features/simulationRunner/simulationRunButton.test.ts- TypeScript is strict (
strict: trueand additional unused/fallthrough checks). - ESLint uses type-aware rules (
@typescript-eslint/*-type-checked). - Prettier config is in
.prettierrc.
Recommended pre-PR local check:
npm run lint
npm run test
npm run build- Update queries in
src/queries/*.graphql - Ensure
.env.localhas correctVITE_GRAPH_TARGET - Run:
npm run codegenGenerated output:
src/__generated__/graphql-types.ts
GitHub Actions workflow: .github/workflows/tests.yml
Current CI jobs on PRs to main and pushes to main:
- Lint
- Test
- Build
To enforce merge blocking on CI:
- Go to GitHub repo settings
Branches-> branch protection rule formain- Enable
Require status checks to pass before merging - Select required checks from this workflow (e.g.
Lint,Test,Build)
- Create feature/page component under
src/features/... - Add lazy export in
src/routeComponents.ts - Register route in
src/routes.tsx
- Add/extend an RTK Query service in
src/servicesor feature-local service - Register reducer + middleware in
src/app/store.ts(if new API slice) - Use generated hook in feature component/hook
- Create slice in relevant
src/features/... - Add reducer to
src/app/store.ts - Add selectors + tests near the slice
If files were moved during refactors, check relative imports first (especially CSS module imports).
- Re-run
npm cito align dependency tree with lockfile - Run
npm run lint && npm run test && npm run buildlocally - Confirm no generated or local-only files are accidentally required
- Validate
VITE_GRAPH_TARGETin.env.local - Ensure query files are valid under
src/queries/*.graphql
If you are new to this codebase, start with:
src/routes.tsxsrc/app/store.tssrc/features/simulationRunner/andsrc/features/simulationRunConfiguration/
Those files give the fastest understanding of routing, global state, and the main workflow engine in this app.