Skip to content

Commit e173ebb

Browse files
authored
chore: bootstrap agent files (JUM-870) (#2834)
1 parent 009d422 commit e173ebb

5 files changed

Lines changed: 243 additions & 22 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,7 @@ test-results.json
7070

7171
*storybook.log
7272
storybook-static
73+
74+
# Per-developer agent overrides
75+
AGENTS.local.md
76+
CLAUDE.local.md

AGENTS.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# AGENTS.md — jumper-exchange
2+
3+
## What this repo is
4+
5+
`jumper.exchange` — the Next.js frontend for [jumper.xyz](https://jumper.xyz). Talks primarily to `jumper-backend` over REST; some legacy paths still hit `strapi-cms` directly. See [ARCHITECTURE.md](./ARCHITECTURE.md) for the app shape, route map, and dependency rules.
6+
7+
## Run, build, test
8+
9+
See @README.md
10+
11+
## Coding conventions
12+
13+
### Stack and idioms
14+
15+
- **Next.js 16 App Router** with locale segment `src/app/[lng]/…`. New pages go under `src/app/[lng]/<segment>/`; never under `src/app/` directly except for non-localized infrastructure (`api/`, `lib/`, root `layout.tsx`, etc.).
16+
- **React 19** with the React Compiler enabled (see `babel-plugin-react-compiler`). Do not write manual `useMemo` / `useCallback` for cases the compiler handles; reach for them only when profiling shows it matters.
17+
- **MUI v9 + Emotion** for styling. Prefer the `sx` prop or `styled()` over ad-hoc CSS modules. Theme tokens live under `src/theme/`.
18+
- **State**: server state via `@tanstack/react-query`; client state via `zustand` stores under `src/stores/<feature>/`. Do not introduce a third state library.
19+
- **Forms**: `@tanstack/react-form`.
20+
- **i18n**: `next-i18n-router` + `i18next`. Translations under `src/i18n/translations/<lng>/`; regenerate the typed resources file with `pnpm i18next-resources-for-ts` after editing the `en` translation.
21+
- **Wallet stack**: LI.FI SDK + widget, Wagmi/Viem for EVM, plus per-chain providers (Solana, Sui, Bitcoin, Tron). Wire new connectors through `src/providers/WalletProvider/` so the existing widget config picks them up.
22+
- **API routes**: Next.js route handlers under `src/app/api/<name>/`. They proxy or wrap `jumper-backend`; do not put business logic here that belongs server-side.
23+
- **Observability**: Sentry is wired via `instrumentation.ts`, `instrumentation-client.ts`, and `sentry.*.config.ts`. Use the existing helpers; do not call `Sentry.init` from feature code.
24+
25+
### Style rules
26+
27+
- **No barrel files** (`index.ts` re-exports). Import directly from the source file.
28+
- **TypeScript path aliases**: `@/foo` and `src/foo` both resolve to `./src/foo` (see `tsconfig.json` and `vitest.config.ts`). Prefer `@/` in new code.
29+
- **Delete replaced code.** No backwards-compatibility shims inside this repo; this is a feature-branch codebase.
30+
31+
### Tests
32+
33+
- **Unit tests** colocate as `<file>.spec.ts(x)` under `src/`. Vitest picks them up via the `unit` project.
34+
- **Snapshot tests** colocate as `<file>.snapshot.spec.tsx`. Regenerate with `pnpm test:snapshots:generate` after intentional UI changes; review the diff before committing.
35+
- **Storybook tests** run the stories in `.storybook/` against a Playwright-driven Chromium browser via the `storybook` Vitest project.
36+
- **E2E tests** live in `tests/` (Playwright). One spec per top-level feature; helpers in `tests/utils/`. See [tests/README.md](./tests/README.md).
37+
- **Hot paths get benchmarks**, not just unit tests. Measure before claiming faster.
38+
39+
## Entry points
40+
41+
Read these first when picking up new work in this repo:
42+
43+
- `src/app/[lng]/layout.tsx` — top-level locale layout; wires providers.
44+
- `src/providers/` — provider tree (wallet, theme, query, i18n, intercom). Cross-cutting wiring lives here.
45+
- `src/components/` — feature components grouped by feature (e.g. `Earn*`, `Portfolio*`, `Quests*`). Reusable primitives in `core/`, `composite/`, `headless/`.
46+
- `src/stores/<feature>/` — zustand stores. One folder per feature; each owns its store, selectors, and types.
47+
- `src/hooks/<feature>/` — react-query hooks and feature-specific hooks. Mirror the `src/stores/` layout.
48+
- `src/app/api/` — Next.js route handlers (proxy + wrap `jumper-backend`).
49+
- `src/config/` — runtime config (`config.ts`, `env-config.ts`, wallet connector configs, widget config).
50+
- `next.config.mjs`, `instrumentation*.ts`, `sentry.*.config.ts` — framework + observability wiring.
51+
- `tests/` — Playwright E2E suite.
52+
53+
## Where new things go
54+
55+
| New thing | Goes in |
56+
| -------------------------------- | -------------------------------------------------------------------------------- |
57+
| New page | `src/app/[lng]/<segment>/page.tsx` (+ `layout.tsx` if it has children) |
58+
| New API route handler | `src/app/api/<name>/route.ts` |
59+
| New feature component | `src/components/<FeatureName>/` (subfolder; one component per file, no barrels) |
60+
| New zustand store | `src/stores/<feature>/` |
61+
| New react-query hook | `src/hooks/<feature>/use<Thing>.ts` |
62+
| New wallet connector | `src/providers/WalletProvider/` + relevant `src/config/<connector>.ts` |
63+
| New translation key | `src/i18n/translations/en/<namespace>.json` then `pnpm i18next-resources-for-ts` |
64+
| New unit test | `<file>.spec.ts(x)` next to the source |
65+
| New E2E test | `tests/<feature>.spec.ts` |
66+
| New theme token / palette change | `src/theme/` |
67+
| New env variable | `src/config/env-config.ts` + document in `.env.example` |
68+
69+
If a change does not fit any of the above, stop and ask — do not invent a new top-level folder.
70+
71+
## What NOT to do
72+
73+
- **Do not** add backwards-compatibility shims, deprecation wrappers, or dead-code "for safety". Delete and replace.
74+
- **Do not** add barrel `index.ts` files.
75+
- **Do not** put business logic in `src/app/api/` route handlers — they are thin proxies to `jumper-backend`.
76+
- **Do not** call `Sentry.init` outside the existing instrumentation files.
77+
- **Do not** import `strapi-cms` content directly when an equivalent endpoint exists on `jumper-backend`. New CMS access should go through the backend.
78+
79+
## Doc index
80+
81+
- [README.md](./README.md) — getting started, tools, lint, translations.
82+
- [ARCHITECTURE.md](./ARCHITECTURE.md) — app shape, route map, dependency rules.
83+
- [tests/README.md](./tests/README.md) — Playwright E2E setup and run commands.
84+
85+
<!-- local overrides (gitignored) -->
86+
87+
@AGENTS.local.md

ARCHITECTURE.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# ARCHITECTURE — jumper-exchange
2+
3+
Shape of this Next.js app. See [AGENTS.md](./AGENTS.md) for how to work in this repo (run, test, conventions, where new things go).
4+
5+
## What this app is
6+
7+
The B2C frontend for [jumper.xyz](https://jumper.xyz). Users land here to bridge and swap between any tokens across any chains (EVM, SVM, Sui, Bitcoin, Tron). Retention features (earn, portfolio, quests, campaigns, missions) are layered on top of the core swap flow.
8+
9+
The app embeds the `@lifi/widget` for the swap UX and wraps it with Jumper-specific surfaces (auth, profile, XP, content, partner themes, …).
10+
11+
## Stack
12+
13+
| Layer | Choice |
14+
| --------------- | --------------------------------------------------------------------------------------------------- |
15+
| Framework | Next.js 16 (App Router) on React 19 with the React Compiler |
16+
| Styling | MUI v9 + Emotion |
17+
| Server state | `@tanstack/react-query` |
18+
| Client state | `zustand` (one store per feature, under `src/stores/<feature>/`) |
19+
| Forms | `@tanstack/react-form` |
20+
| i18n | `next-i18n-router` + `i18next`, locale segment in the URL (`/[lng]/…`) |
21+
| Wallet | `@lifi/sdk` + `@lifi/widget` + per-chain providers (EVM via Wagmi/Viem, Solana, Sui, Bitcoin, Tron) |
22+
| Observability | Sentry (browser + server + edge) |
23+
| Tests | Playwright (E2E), Vitest (unit, snapshot, Storybook) |
24+
| Package manager | pnpm (`packageManager` field pins the version) |
25+
26+
## Directory layout
27+
28+
```
29+
jumper-exchange/
30+
├── src/
31+
│ ├── app/ # Next.js App Router
32+
│ │ ├── [lng]/ # all user-facing pages — locale-prefixed
33+
│ │ │ ├── (main)/ # route group: landing + main shell
34+
│ │ │ ├── (infos)/ # route group: legal / informational pages
35+
│ │ │ ├── bridge/, swap/ # core swap surfaces
36+
│ │ │ ├── earn/, portfolio/, quests/, missions/, campaign/, zap/, scan/, onboard/
37+
│ │ │ ├── error-preview/, meta/
38+
│ │ │ ├── error.tsx, layout.tsx
39+
│ │ ├── api/ # Next.js route handlers (thin proxies to jumper-backend)
40+
│ │ ├── lib/, ui/ # framework-level helpers
41+
│ │ ├── layout.tsx, global.css, global-error.tsx, not-found.tsx, robots.ts, sitemap.xml/
42+
│ ├── components/ # feature components (one folder per feature)
43+
│ │ ├── core/, composite/, headless/ # primitives by composition level
44+
│ │ ├── <FeatureName>/ # e.g. EarnDetails, ConnectButton, Cards, …
45+
│ ├── providers/ # provider tree: WalletProvider, ThemeProvider,
46+
│ │ # ReactQueryProvider, TranslationProvider, …
47+
│ ├── stores/<feature>/ # zustand stores (one folder per feature)
48+
│ ├── hooks/<feature>/ # react-query hooks + feature hooks
49+
│ ├── config/ # runtime config (env, wallet connectors, widget)
50+
│ ├── i18n/translations/<lng>/ # translation JSON; resources.d.ts is generated
51+
│ ├── theme/ # MUI theme + design tokens
52+
│ ├── const/, types/, utils/, fonts/, stories/
53+
│ ├── Layout.tsx, proxy.ts
54+
├── tests/ # Playwright E2E + page objects + test data
55+
├── public/ # static assets
56+
├── .storybook/ # Storybook config
57+
├── instrumentation.ts, instrumentation-client.ts, sentry.*.config.ts
58+
├── next.config.mjs, vitest.config.ts, playwright.config.ts, eslint.config.mjs
59+
├── gen-api.sh # regenerates the typed API client from jumper-backend's Swagger
60+
```
61+
62+
## Request and data flow
63+
64+
```
65+
┌─────────────────────────────────────────────────────────┐
66+
│ Browser (Next.js client) │
67+
│ ┌───────────────────────────────────────────────────┐ │
68+
│ │ React tree (App Router) │ │
69+
│ │ • providers/ wires query, wallet, theme, i18n │ │
70+
│ │ • components/ render features │ │
71+
│ │ • stores/ hold client state (zustand) │ │
72+
│ │ • hooks/ wrap react-query / wallet calls │ │
73+
│ └─────────────┬─────────────────────────────────────┘ │
74+
└────────────────┼────────────────────────────────────────┘
75+
76+
┌───────────────┼─────────────────┐
77+
│ │ │
78+
▼ ▼ ▼
79+
Next.js API jumper-backend LI.FI SDK
80+
routes (REST, (chains, quotes,
81+
(src/app/api/) primary) executions)
82+
83+
84+
jumper-backend (proxied)
85+
┌─────────────────┐
86+
│ strapi-cms │ ← legacy direct paths
87+
│ (REST) │ (content + campaigns)
88+
└─────────────────┘
89+
```
90+
91+
- **Server state** (chains, tokens, quotes, profile, campaigns, …) is fetched through react-query hooks under `src/hooks/`. Most go through `jumper-backend` either directly or via a Next.js route handler under `src/app/api/`. A few legacy hooks still call `strapi-cms` directly.
92+
- **Client state** (selected chain/token, route choice, settings, theme, modals, …) lives in zustand stores under `src/stores/<feature>/`. Stores never call APIs — they hold UI state and derived selectors.
93+
- **The swap engine** is `@lifi/widget`. We embed it inside our pages and configure it via `src/config/widgetConfig.ts`. Wallet connectors are wired in `src/providers/WalletProvider/` so the widget sees them.
94+
- **Sentry** is initialised once in `instrumentation*.ts` / `sentry.*.config.ts`. Feature code uses helpers — never `Sentry.init` directly.
95+
96+
## Internal dependency rules
97+
98+
| From → To | components | hooks | stores | providers | config | app/ | utils |
99+
| -------------- | ---------- | ----- | ------ | ------------------- | ------ | ---- | ----- |
100+
| **components** |||| ✓ (consume context) ||||
101+
| **hooks** |||| ✓ (consume context) ||||
102+
| **stores** ||||||||
103+
| **providers** | ✓ (render) |||||||
104+
| **config** ||||||||
105+
| **app/** ||||||||
106+
| **utils** ||||||||
107+
108+
Read as: a row module _may_ import from a column module where ✓; _must not_ where ✗.
109+
110+
Contribution Rules:
111+
112+
- **`utils/` is a leaf.** It must not import from anything else inside `src/`. Pure helpers only.
113+
- **`stores/` does not import from `components/`, `hooks/`, or `providers/`.** Stores must be renderable in isolation (and unit-testable) without pulling in the whole tree.
114+
- **`hooks/` does not import from `components/`.** Hooks describe data; components consume them.
115+
- **Nothing inside `src/` imports from `src/app/`.** App routes are leaves of the dependency graph — they compose everything else.
116+
- **No barrel `index.ts` files.** Import from source files directly. This keeps the dependency graph honest and tree-shakeable.
117+
118+
If a change requires reversing one of these directions, **stop**. The right shape is usually to move the shared code down a level (often into `utils/` or `config/`) rather than to invert the arrow.
119+
120+
## Invariants
121+
122+
| # | Invariant | Enforcement |
123+
| --- | ------------------------------------------------------------------------------ | ---------------------- |
124+
| 1 | All user-facing pages live under `src/app/[lng]/` | doc; obvious on review |
125+
| 2 | API route handlers in `src/app/api/` are thin proxies — no business logic | doc |
126+
| 3 | Server state goes through react-query; no direct `fetch` in components | doc |
127+
| 4 | One zustand store per feature folder under `src/stores/` | doc |
128+
| 5 | No barrel files (`index.ts` re-exports) | doc; ESLint candidate |
129+
| 6 | Sentry is initialised only in `instrumentation*.ts` / `sentry.*.config.ts` | doc |
130+
| 7 | Secrets never committed; new env vars documented in `src/config/env-config.ts` | per-repo CI (existing) |
131+
| 8 | Pre-commit hook (`tsc --noEmit` + ESLint + Prettier) must pass | Husky + lint-staged |
132+
133+
## Cross-repo position
134+
135+
- This app depends on `jumper-backend` (primary, via REST) and on `strapi-cms` (legacy direct paths, via REST).
136+
- The TypeScript types of the backend API are vendored here, regenerated from `jumper-backend`'s Swagger via `pnpm api` (which calls `gen-api.sh`). Never hand-edit the generated file — change the upstream Swagger and regenerate.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See @AGENTS.md

0 commit comments

Comments
 (0)