Skip to content

Latest commit

 

History

History
112 lines (85 loc) · 4.02 KB

File metadata and controls

112 lines (85 loc) · 4.02 KB
title Frontend Stack
description Core libraries, patterns, and Web3 wallet integration for Next.js apps.

Core technology choices and patterns for frontend apps. See Frontend Architecture for overview and ownership.

Data fetching & async state

  • @tanstack/react-query: default choice for async data and server state (caching, dedupe, retries)
  • @repo/react: React Query hooks and helpers only (no UI components). Route-specific UI (e.g. login form) lives in apps, collocated by route
  • @repo/core: generated, runtime-agnostic API client and types
  • @lukemorales/query-key-factory: centralized query key factories (for hand-written queries)

URL and local state

  • nuqs: URL-based state for shareable UI state (filters, search, tabs, pagination)
  • ahooks: useSetState for grouped ephemeral state, useLocalStorageState for persistence

Validation, errors, utilities

  • zod: schema validation at boundaries (prefer z.infer<typeof schema>)
  • react-error-boundary: component subtree failure isolation (see Error Handling)
  • @repo/utils: shared utilities (prefer subpath imports)
  • lodash-es: per-function imports for common operations
  • nanoid: unique IDs when needed

Web3 & wallet auth

Wallet hooks live in apps/next (@/hooks/, @/wallet/). @repo/react exposes only verify hooks (useVerifyWeb3Auth, useVerifyLinkWallet).

  • useWallet (@/hooks/use-wallet): returns adapter for a chain from WalletProvider context
  • useWalletAuth (@/hooks/use-wallet-auth): wallet sign-in via SIWE/SIWS
  • useLinkWallet (@/hooks/use-link-wallet): link connected wallet to account (Bearer required)
  • useLinkEmail (@repo/react): request link email + verify from token

WalletProvider and adapters: In apps/next, WalletAdaptersInjector bridges wagmi + Solana into adapters, enforces single-wallet mode, and triggers sign-out on wallet disconnect when session was created by wallet.

Post-login home: After auth (magic link or wallet), users are redirected to /. The home page renders merged dashboard content including Link wallet, Link email (formerly on /dashboard).

See Authentication for auth flows, SIWE/SIWS, and account linking.

Web3 stack hierarchy

flowchart TB
  subgraph AppLayer [App layer]
    Dashboard[Dashboard]
    Login[Login page]
  end

  subgraph AppHooks [apps/next @/hooks @/wallet]
    useWalletAuth[useWalletAuth]
    useLinkWallet[useLinkWallet]
    useWallet[useWallet]
    WalletProvider[WalletProvider]
    WalletAdaptersInjector[WalletAdaptersInjector]
  end

  subgraph RepoReact [@repo/react]
    useVerifyWeb3Auth[useVerifyWeb3Auth]
    useVerifyLinkWallet[useVerifyLinkWallet]
    useLinkEmail[useLinkEmail]
  end

  subgraph ChainLibs [Chain libraries]
    Wagmi[wagmi]
    SolanaAdapter[Solana wallet-adapter]
  end

  Dashboard --> useLinkWallet
  Dashboard --> useLinkEmail
  Login --> useWalletAuth
  useWalletAuth --> useWallet
  useLinkWallet --> useWallet
  useWalletAuth --> useVerifyWeb3Auth
  useLinkWallet --> useVerifyLinkWallet
  useWallet --> WalletProvider
  WalletProvider --> WalletAdaptersInjector
  WalletAdaptersInjector --> Wagmi
  WalletAdaptersInjector --> SolanaAdapter
Loading

Chain libraries

  • viem: low-level Ethereum interactions (address validation, transactions)
  • wagmi: React hooks for Ethereum (built on viem + TanStack Query)
  • @solana/wallet-adapter-react: Solana wallet connection

Query key factory (example)

import { createQueryKeys } from "@lukemorales/query-key-factory"

export const users = createQueryKeys("users", {
  detail: (id: string) => ({
    queryKey: [id],
    queryFn: () => fetchUser(id),
  }),
})

nuqs URL state (example)

import { parseAsInteger, parseAsString, useQueryStates } from "nuqs"

const [filters, setFilters] = useQueryStates({
  search: parseAsString.withDefault(""),
  page: parseAsInteger.withDefault(1),
})