Built by the creator of tx|Primitives for memory, tasks & orchestrationVisit tx docs
tx-agent-kit
Apps

Web App

Client-only Next.js SPA with strict constraints against server-side code, typed API clients, and centralized browser utilities.

Web App (apps/web)

The web application is a client-only Next.js SPA. It acts as a thin presentation layer that consumes the API server directly. No server-side rendering, no API proxying, no middleware.

Hard Constraints

These constraints are mechanically enforced by ESLint and structural checks:

ConstraintDetail
No server-side codeapp/api routes, proxy.ts, middleware.ts, next/server, and next/headers are all forbidden
Client-only componentsEvery .tsx file under app/ and components/ must start with 'use client'
No Effect or DrizzleThe web app must not import effect, effect/*, or drizzle-orm. Keep runtime complexity in the API/core/worker layers
No direct fetchAll API communication goes through typed client layers generated by Orval

Centralized Utilities

To prevent scattered usage of browser APIs and third-party libraries, the web app enforces single entry points for common concerns:

Storage (lib/auth-token.ts)

Only this module may read or write localStorage. All other modules access auth tokens through the exported functions.

URL State (lib/url-state.tsx)

Wraps the nuqs library. Direct nuqs imports are forbidden elsewhere. Direct window.location reads are also forbidden. Use the URL state wrappers instead.

// Correct: use the centralized wrapper
import { useQueryState } from '@/lib/url-state'

// Forbidden: direct nuqs import
import { useQueryState } from 'nuqs'

// Forbidden: direct browser API
const path = window.location.pathname

Notifications (lib/notify.tsx)

Wraps the sonner toast library. Direct sonner imports are forbidden outside this module.

Environment (lib/env.ts)

All runtime environment reads are centralized here. Direct process.env access is forbidden in web source modules.

API Client Generation

The web app uses Orval to generate typed API hooks from the OpenAPI spec:

# Regenerate after API changes
pnpm api:client:generate

This produces files under apps/web/lib/api/generated/. The generated client uses a custom Axios mutator defined in apps/web/lib/api/orval-mutator.ts that injects the auth token and points to API_BASE_URL.

The Axios client in apps/web/lib/axios.ts must use webEnv.API_BASE_URL as its base URL. Proxy paths like /api/* are forbidden.

Integration Testing

Web integration tests are colocated alongside the components and pages they test:

Test file
apps/web/components/AuthForm.integration.test.tsx
apps/web/components/CreateWorkspaceForm.integration.test.tsx
apps/web/components/CreateTaskForm.integration.test.tsx
apps/web/app/dashboard/page.integration.test.tsx
apps/web/app/workspaces/page.integration.test.tsx
apps/web/app/invitations/page.integration.test.tsx

Suite lifecycle is centralized in apps/web/vitest.integration.setup.ts. Individual test files must not call setupWebIntegrationSuite, resetWebIntegrationCase, or teardownWebIntegrationSuite directly.

Integration suites verify unauthenticated redirect behavior (e.g., /sign-in?next=%2Fdashboard), invalid-token handling (401 -> clear session -> redirect), and authenticated data-loading paths with seeded fixtures.

On this page