| 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.
@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)
nuqs: URL-based state for shareable UI state (filters, search, tabs, pagination)ahooks:useSetStatefor grouped ephemeral state,useLocalStorageStatefor persistence
zod: schema validation at boundaries (preferz.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 operationsnanoid: unique IDs when needed
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 contextuseWalletAuth(@/hooks/use-wallet-auth): wallet sign-in via SIWE/SIWSuseLinkWallet(@/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.
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
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
import { createQueryKeys } from "@lukemorales/query-key-factory"
export const users = createQueryKeys("users", {
detail: (id: string) => ({
queryKey: [id],
queryFn: () => fetchUser(id),
}),
})import { parseAsInteger, parseAsString, useQueryStates } from "nuqs"
const [filters, setFilters] = useQueryStates({
search: parseAsString.withDefault(""),
page: parseAsInteger.withDefault(1),
})