Thanks for contributing to Fluxora. This guide covers everything you need to go from zero to a mergeable PR: local setup, branch naming, commit conventions, and the full test/coverage workflow.
For first-time contributors:
- Fork the repo and clone your fork
- Run
npm installto install dependencies - Copy
.env.exampleto.env.localand fill in required values - Run
npm run devto start the local dev server - Create a branch:
feat/<issue>-short-descriptionorfix/<issue>-short-description - Make your change and write/update tests
- Run
npm testandnpm run lintbefore pushing - Open a PR targeting
mainand fill out the template
- Prerequisites
- Local Setup
- Environment Variables
- Branch Naming
- Commit Conventions
- Development Workflow
- Testing
- Lint and Format
- Design Specs and Docs
- Pull Request Expectations
- Security Notes
- Node.js 18 or later
- npm (bundled with Node) or pnpm
- Git
For end-to-end tests you also need Playwright browsers installed (see E2E Tests).
# 1. Clone and enter the repo
git clone https://github.com/Fluxora-Org/Fluxora-Frontend.git
cd Fluxora-Frontend
# 2. Install dependencies
npm install
# or: pnpm install
# 3. Copy the environment file
cp .env.example .env
# 4. Start the dev server
npm run dev
# or: pnpm run devThe app runs at http://localhost:5173.
All runtime config lives in .env (gitignored). Copy .env.example as shown above, then set the values you need.
| Variable | Required at runtime | Purpose |
|---|---|---|
VITE_API_URL |
For live API calls | Backend base URL |
VITE_NETWORK |
For wallet validation | TESTNET (default) or PUBLIC |
VITE_RPC_URL |
For on-chain transactions | Soroban RPC endpoint |
VITE_STREAM_CONTRACT_ID |
For on-chain streaming | Deployed contract address (C…) |
VITE_USE_MOCKS |
No | true enables mock data paths |
VITE_DEMO_MODE |
No | true renders static fixture data |
VITE_TX_POLL_INTERVAL_MS |
No | Transaction polling interval (ms, default 750) |
VITE_TX_POLL_MAX_ATTEMPTS |
No | Max polling attempts (default 6) |
VITE_TX_POLL_BACKOFF_FACTOR |
No | Exponential backoff multiplier (default 1.25) |
VITE_TX_DEMO_CONFIRMATION_ATTEMPTS |
No | Mock confirmation cycles (default 2) |
For full documentation of each variable, see docs/environment.md.
Tip for local development: Set
VITE_USE_MOCKS=truein your.envto run the full UI without a live backend or wallet.
Use this pattern:
<type>/<short-kebab-description>
Common types mirror the commit types below:
| Type | When to use |
|---|---|
feat |
New feature or UI component |
fix |
Bug fix |
docs |
Documentation only |
refactor |
Code restructure with no behaviour change |
test |
Adding or updating tests |
chore |
Tooling, deps, config changes |
ci |
CI/CD workflow changes |
Examples:
feat/stream-cancel-button
fix/wallet-disconnect-race
docs/contributing-guide
test/metric-card-coverage
This repo follows Conventional Commits.
<type>(<optional scope>): <short summary>
<optional body — what and why, not how>
<optional footer — e.g. Closes #123>
Rules:
- Use the imperative mood in the summary: "add X", not "added X".
- Keep the summary line under 72 characters.
- Reference the relevant GitHub issue in the footer when applicable:
Closes #390. - Do not mix unrelated changes in a single commit.
Examples:
feat(streams): add cancel stream confirmation modal
Closes #201
fix(wallet): clear stale address on Freighter disconnect
Prevents the app shell from showing a connected state after
the extension removes the session.
Closes #312
docs: add contributing guide
Covers setup, branch naming, commit conventions, and the
test/coverage workflow for new contributors.
Closes #390
# Run the dev server
npm run dev
# Production build (type-check + bundle)
npm run build
# Preview the production build locally
npm run preview
# Bundle size report (runs build first)
npm run build:reportVitest runs all *.test.tsx / *.test.ts files under src/, excluding e2e/.
# Single run (used in CI)
npm run test
# Watch mode (local development)
npm run test:watchThe CI coverage job enforces 95% thresholds across statements, branches, functions, and lines. Run this locally before opening a PR:
npm run test:coverageThe report is written to coverage/ (HTML) and printed to the terminal. If your branch adds a new production module, append it to the include list in vitest.config.ts and add tests to cover it — otherwise the coverage job will fail.
Playwright drives the browser-level tests in e2e/. Install browsers once:
npx playwright install --with-depsThen run:
# Full e2e suite (starts the dev server automatically)
npm run test:e2e
# Accessibility-only suite
npm run test:a11yPlaywright auto-starts npm run dev on port 5173 before the suite and tears it down after. Set PLAYWRIGHT_BASE_URL to point at a different server if needed.
# Check for lint errors
npm run lint
# Auto-fix lint errors where possible
npm run lint:fix
# Format source files
npm run format
# Check formatting without writing
npm run format:checkThe repo uses ESLint flat config with TypeScript, React Hooks, and React Refresh rules. Prettier handles formatting for src/**/*.{ts,tsx,css} and top-level config files.
Both lint and format:check run in CI. Fix all warnings before pushing — the build fails on lint errors.
Several design and accessibility specs live at the repo root and in docs/. Refer to them when working on UI components:
| File | Topic |
|---|---|
| DESIGN_SPEC.md | Visual design system |
| DESIGN_TOKENS_QUICK_REFERENCE.md | Token reference |
| DARK_THEME_SPEC.md | Dark mode behaviour |
| FOCUS_RING_SPEC.md | Focus ring standards |
| WALLET_FLOWS_DESIGN_SPEC.md | Wallet UX flows |
| STREAM_CARD_INTERACTION_SPEC.md | Stream card interactions |
| EMPTY_STATES_DESIGN_SPEC.md | Empty state patterns |
| LOADING_SKELETON_DESIGN_SPEC.md | Loading skeleton patterns |
| MODAL_FOCUS_MANAGEMENT_DESIGN_SPEC.md | Modal focus management |
| docs/environment.md | All VITE_* variables |
| docs/security.md | Contract security model |
| docs/soroban-contract-abi.md | Contract ABI reference |
- Fill in the PR template completely.
- Every PR must pass the full CI matrix before merge:
npm run build— TypeScript type check + production bundlenpm run test— all unit tests greennpm run test:coverage— all coverage thresholds ≥ 95%npm run lint— no lint errors
- Link the related issue in the PR description and in the commit footer (
Closes #<number>). - Keep PRs focused. One concern per PR makes review faster.
- Add or update tests for every behaviour change. See Coverage.
VITE_*variables are public. Vite statically inlines them into the client bundle at build time. Anyone can read them by inspecting the page source or network traffic. Never put secrets, private keys, seed phrases, wallet credentials, or sensitive API tokens in.envor.env.local.- Private secrets belong on the backend (
fluxora-backend). The frontend only holds public metadata: RPC endpoints, contract IDs, network identifiers, and feature flags. - Address inputs are sanitized through
sanitizeStellarAddressbefore reaching explorer links, the clipboard, or query strings. - The
/approute subtree is protected byRequireWallet. This is a client-side UX guard only — backend services must still enforce authorization independently.
For the full contract security model see docs/security.md.
Vite is configured with a chunk size warning limit of 650 kB (chunkSizeWarningLimit in vite.config.ts). A CI job enforces this as a hard gate:
# Run locally before opening a PR:
npm run size-checkThis runs npm run build followed by node scripts/bundle-size-report.mjs --fail, which exits with code 1 if any JS chunk exceeds 650 kB, blocking the merge.
If you need to merge while a chunk is over-limit (e.g. a large vendored library with no tree-shaking support), pass --allow <chunkName> in the CI step and add a comment explaining the reason and a follow-up ticket:
# .github/workflows/bundle-size-check.yml
run: npm run build && node scripts/bundle-size-report.mjs --fail --allow vendor-heavy
# TEMP: vendor-heavy does not support ESM tree-shaking. Tracked in #999.Remove the exemption once the underlying issue is resolved.