VeztaVezta
Guides

Frontend Development

Next.js patterns, feature modules, and code generation

The Vezta frontend is a Next.js 16 App Router application built with React 19, Tailwind CSS v4, and TanStack Query v5. It runs on port 3000 and connects to the backend API at localhost:3001.

Project Structure

app/
├── (landing)/          # Public marketing pages (1440px max-width)
├── (dashboard)/        # Main app with AppLayout (Navbar + BottomStatusBar)
└── (auth)/             # Login, onboarding, access-key (no shell chrome)
features/
├── markets/            # Market browsing, search, terminal
├── portfolio/          # Positions, orders, analytics
├── trading/            # Order form, execution
├── social/             # Leaderboard, copy trade, wallet tracker
├── monitor/            # News feed, signal detection
├── rewards/            # Points, missions, challenges
└── ...                 # auth, events, overlays, settings
components/
├── ui/                 # shadcn/ui primitives (new-york style)
├── layout/             # AppLayout, Navbar, BottomStatusBar
└── states/             # Skeletons, empty states, error states
lib/
├── api/gen/            # Auto-generated (never hand-edit)
├── api/client.ts       # Fetch wrapper with auth + retry
├── api/auth.ts         # In-memory access token management
├── ws/                 # Socket.IO + Jotai atoms
├── trading/            # PnL helpers, price impact
├── types/              # TypeScript interfaces
├── utils.ts            # cn(), formatUsd, timeAgo, etc.
└── constants.ts        # Categories, filters, nav items
hooks/                  # Custom hooks (order form, media query, etc.)
providers/              # ThemeProvider, QueryProvider, AuthProvider, etc.

Key Patterns

Feature Modules

Business logic lives in features/{domain}/components/, not in flat component directories. Each feature domain contains its own components and hooks. Pages in app/ compose these feature components.

State Management

  • TanStack Query v5 -- server state, caching, and data fetching via auto-generated hooks
  • Zustand -- UI state (e.g., terminal sidebar panel order and visibility)
  • Jotai -- WebSocket atoms for real-time data (prices, orderbook, trades)
  • URL state -- route params for market slugs (/market/[slug])

TanStack Query is configured with refetchOnWindowFocus: false, which differs from the default. This is intentional for a trading terminal where stale data is refreshed via WebSocket, not tab focus.

API Integration

All API hooks are auto-generated by Kubb from the backend's OpenAPI spec. The generated code lives in lib/api/gen/ and must never be hand-edited. See API Client Generation for the full pipeline.

The custom fetch wrapper at lib/api/client.ts provides Bearer token injection, automatic 401 refresh-and-retry with a promise lock (preventing multiple simultaneous refreshes), and credentials: 'include' for cookies. All generated hooks use this wrapper via a Kubb fetch alias in next.config.ts.

Auth System

Wallet-based auth (Solana + EVM) plus Google OAuth, with a three-cookie system:

  1. Backend sets an httpOnly refresh_token cookie (7 days)
  2. Frontend sets a non-httpOnly logged_in=1 cookie for middleware route protection
  3. Frontend sets a non-httpOnly beta_access=1 cookie for the beta gate
  4. Access token is stored in-memory (not localStorage) to prevent XSS
  5. proxy.ts is the Next.js middleware (exported as proxy, picked up natively — never create middleware.ts alongside it, that breaks the build). Checks both logged_in AND beta_access for protected routes; AUTH_NO_BETA_ROUTES (e.g. /access-key) require logged_in only
  6. The middleware also blocks bot user-agents on non-API routes (returns 403)

Design System

  • Dark mode only (forced via ThemeProvider)
  • Accent color: lime-green #D4FF2B (bg-primary / text-primary)
  • Fonts: Space Grotesk for headings/UI, JetBrains Mono for prices/data
  • Green (#22C55E) = YES/Buy/Profit; Red (#EF4444) = NO/Sell/Loss
  • Tailwind v4 with CSS-first config via @theme block in app/globals.css
  • Icons from lucide-react

There is no tailwind.config.js. Tailwind v4 uses CSS variables defined in the @theme block in app/globals.css. Do not create a JS config file.

Dev Commands

pnpm dev              # Dev server on port 3000 (Turbopack)
pnpm build            # Production build (webpack, WASM compat)
pnpm test             # Vitest
pnpm exec vitest run navbar             # Run a single test file (or: pnpm test -- -t "name")
pnpm lint             # ESLint
pnpm generate         # Kubb: regenerate API client from OpenAPI spec

Environment Variables

VariableDefaultPurpose
NEXT_PUBLIC_API_URLhttp://localhost:3001/api/v1Backend API base
NEXT_PUBLIC_WS_URLws://localhost:3001WebSocket endpoint
BACKEND_URLhttps://backend.vezta.ioBackend URL for next.config.ts API proxy rewrite
OPENAPI_PATH./openapi.jsonKubb OpenAPI source (committed to repo)
NEXT_PUBLIC_GOOGLE_CLIENT_ID--Google OAuth client ID (required for GoogleAuthProvider)
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID--Reown WalletConnect ID
NEXT_PUBLIC_SOLANA_RPC_URLmainnet-betaSolana RPC endpoint
NEXT_PUBLIC_SOLANA_NETWORKmainnet-betaSolana network selection

Production overrides (in vezta-fe/.env.production / VM .env): NEXT_PUBLIC_API_URL=https://backend.vezta.io/api/v1, NEXT_PUBLIC_WS_URL=wss://backend.vezta.io. Staging points at staging.vezta.io instead.

On this page