Skip to content

Frontend Architecture

The frontend is a React SPA built with Vite. It is served as static files and communicates with the backend through typed API classes.

State management

Server state is handled by TanStack Query. Local session state is stored in Zustand. Component-local form state is kept in React components and custom hooks unless it must be shared globally.

State typeToolExamples
Server cacheTanStack Queryfeeds, author profiles, access tiers, billing state, activity
MutationsTanStack Querysign in, create post, subscribe, upload file, archive post
Wallet/session stateZustand + wagmiJWT metadata, wallet address, connection state
Form stateReact hooks + validation schemasonboarding, access policy editor, post composer
Derived display statePure utilitiesprices, dates, file sizes, explorer links

API layer

The API layer wraps Axios and returns typed DTOs. Request params and response shapes are centralized to avoid inline object contracts inside pages.

The important rule is that pages do not know transport details. A page asks a domain hook for items, loadMore, isLoading, error and mutation actions. The hook decides which query key to use, which API class to call and which related queries must be invalidated after a mutation.

Web3 integration

wagmi and viem are used for:

  • wallet connection;
  • contract reads;
  • ERC-20 allowance checks;
  • approve transactions;
  • subscription transactions;
  • transaction status handling.

The UI never grants access immediately after writeContract. It waits for backend confirmation of the transaction receipt. This prevents a pending, reverted or unrelated transaction hash from becoming access state in the product.

Page composition

The frontend avoids turning pages into large UI components. Pages usually coordinate queries, route state and high-level layout. Domain folders then render the actual interface:

  • public author pages use access tier cards, tier drawers and post feed components;
  • author workspace pages reuse content manager, post composer and project tree components;
  • billing pages use storage/quota panels and checkout drawers;
  • feed pages reuse the same post card structure across home, subscription feed and author pages.

This structure makes it possible to change cards, fields or action buttons in one place instead of editing similar markup across many pages.

UI structure

Large pages are decomposed into page-specific component folders. Shared visual primitives live in components/common, while domain-specific components stay close to their domain folders.

See Frontend Data Flow for the detailed request/cache/mutation flow.

Error and validation model

The frontend separates three kinds of failure. Query failures render inline states, user-triggered mutation failures use toast notifications, and invalid form input is shown near the affected field. Validation schemas are written with Zod for important forms such as author onboarding, reports, comments and content forms.