# Kaneo Web Application Monorepo Structure: A Complete Architecture Guide

> Explore the Kaneo web application monorepo structure at usekaneo/kaneo. Learn its feature-oriented architecture, file-based routing with TanStack Router, Zustand state management, and layered components with Tailwind CSS.

- Repository: [kaneo.app/kaneo](https://github.com/usekaneo/kaneo)
- Tags: architecture
- Published: 2026-08-09

---

**The Kaneo web application lives under `apps/web` and follows a feature-oriented architecture using TanStack Router for file-based routing, Zustand for state management, and a layered component hierarchy with Tailwind CSS v4.**

The **kaneo web application monorepo structure** organizes the React frontend as a discrete workspace within the larger repository, adhering to the architectural principles documented in the project's [`CLAUDE.md`](https://github.com/usekaneo/kaneo/blob/main/CLAUDE.md). Located at `apps/web`, the codebase separates concerns through a strict directory hierarchy that isolates routing, state, data fetching, and UI components into distinct layers.

## Entry Point and Application Bootstrap

Every request to the Kaneo web app begins at [`apps/web/src/main.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/main.tsx). This file initializes the three core systems that power the frontend: the **TanStack Router** instance, the **React Query** client for server-state management, and the **Zustand** store providers.

The bootstrap sequence creates a router using the generated [`routeTree.gen.ts`](https://github.com/usekaneo/kaneo/blob/main/routeTree.gen.ts) file, which contains the statically-typed route tree mapping every file in `src/routes/` to its corresponding URL path. After configuring the query client with default caching strategies, the application renders the `<RouterProvider>` into the DOM, handing control to the file-based routing system.

## File-Based Routing Architecture

Kaneo uses **TanStack Router** to eliminate manual route configuration. Instead of maintaining a central routes file, the directory structure inside `apps/web/src/routes/` defines the URL hierarchy.

The build process generates [`apps/web/src/routeTree.gen.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/routeTree.gen.ts), which imports every route component and constructs a type-safe tree. Route files use `createFileRoute` to declare their path segment:

```typescript
// apps/web/src/routes/auth/sign-in.tsx
import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/auth/sign-in")({
  component: SignInPage,
});

function SignInPage() {
  return <SignInForm />;
}

```

Nested directories create nested URLs. For example, `src/routes/_layout/_authenticated/dashboard/workspace/$workspaceId/project/$projectId/board.tsx` renders the Kanban board view at `/dashboard/workspace/123/project/456/board`.

## Nested Layout System

The routing layer implements a hierarchical layout pattern using **parent routes** that wrap child content via an `<Outlet />` component.

The root layout at [`apps/web/src/routes/_layout.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/routes/_layout.tsx) wraps every page in the application. It renders the global command palette (`CommandPalette`) and the searchable command menu (`SearchCommandMenu`), ensuring these UI elements persist across navigation.

For authenticated views, the [`apps/web/src/routes/_layout/_authenticated.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/routes/_layout/_authenticated.tsx) layout checks for an active session via Better Auth. When a user is logged in, this layout renders the main application scaffold: the sidebar navigation (`NavMain`), the top navigation bar, and the content area. All workspace-specific routes—such as project boards, backlogs, and settings—are children of this authenticated layout, inheriting its chrome automatically.

## Component Hierarchy and UI Primitives

Components are stratified into two categories: **primitives** and **feature components**.

UI primitives live in `apps/web/src/components/ui/*` and include low-level elements like `sidebar`, `tooltip`, `spinner`, and button variants. These are unstyled or minimally styled building blocks used throughout the application.

Feature components consume these primitives and implement business logic. The [`apps/web/src/components/nav-main.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/components/nav-main.tsx) file, for example, renders the primary sidebar navigation by consuming the active workspace data and pending invitations. Higher-level components like workspace switchers and project selectors reside alongside navigation components in `apps/web/src/components/`.

## State Management with Zustand

Global client-state lives in `apps/web/src/store/*.ts` files using **Zustand** stores. Unlike prop-drilling or context providers, these stores are imported directly into components that need them.

The [`apps/web/src/store/user-preferences.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/store/user-preferences.ts) file manages theme selection and other user settings:

```typescript
import { create } from "zustand";

interface UserPreferencesState {
  theme: "light" | "dark" | "system";
  setTheme: (theme: "light" | "dark" | "system") => void;
}

export const useUserPreferences = create<UserPreferencesState>((set) => ({
  theme: "system",
  setTheme: (theme) => set({ theme }),
}));

```

Additional stores handle complex UI state such as bulk task selection ([`project.ts`](https://github.com/usekaneo/kaneo/blob/main/project.ts)) and workspace context, ensuring that cross-cutting concerns remain accessible without prop threading.

## Data Fetching and API Integration

Server-state management follows a three-layer pattern: **fetchers**, **query hooks**, and **components**.

**Fetchers** in `apps/web/src/fetchers/**/*.ts` are thin, typed wrappers around REST endpoints. They reference the central `VITE_API_URL` environment variable and return promises for raw data. For example, [`apps/web/src/fetchers/workspace/get-workspaces.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/fetchers/workspace/get-workspaces.ts) handles the HTTP call to `GET /workspaces`.

**Query hooks** in `apps/web/src/hooks/queries/**/*.ts` wrap these fetchers with **TanStack Query**, providing caching, background refetching, and loading states:

```typescript
// apps/web/src/hooks/queries/workspace/use-get-workspaces.ts
import { useQuery } from "@tanstack/react-query";
import { getWorkspaces } from "@/fetchers/workspace/get-workspaces";

export function useGetWorkspaces() {
  return useQuery({
    queryKey: ["workspaces"],
    queryFn: getWorkspaces,
  });
}

```

**WebSocket hooks** like [`apps/web/src/hooks/use-user-websocket.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/hooks/use-user-websocket.ts) and [`use-project-websocket.ts`](https://github.com/usekaneo/kaneo/blob/main/use-project-websocket.ts) listen for real-time server events and invalidate query caches when data changes, ensuring the UI remains synchronized across clients.

## Utilities, Styling, and Testing

Helper functions are co-located in `apps/web/src/lib/`. This includes [`apps/web/src/lib/utils/create-workspace-slug.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/lib/utils/create-workspace-slug.ts) for URL-safe string generation, [`apps/web/src/lib/toast.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/lib/toast.ts) for notification management, and permission validation utilities.

Styling is handled by **Tailwind CSS v4**, configured in [`apps/web/src/index.css`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/index.css). This file imports Tailwind's base utilities and defines custom design tokens used by the component library.

Testing is co-located with source files using the `*.test.tsx` convention. Vitest runs these tests according to the configuration in [`apps/web/vitest.config.ts`](https://github.com/usekaneo/kaneo/blob/main/apps/web/vitest.config.ts), enabling unit tests for components like [`apps/web/src/components/list-view/task-row.test.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/components/list-view/task-row.test.tsx) and hooks like [`apps/web/src/hooks/use-board-sort.test.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/hooks/use-board-sort.test.tsx).

## Summary

- The Kaneo web application resides in `apps/web` and bootstraps from [`main.tsx`](https://github.com/usekaneo/kaneo/blob/main/main.tsx) using TanStack Router and React Query.
- **File-based routing** in `src/routes/` generates a type-safe route tree at [`routeTree.gen.ts`](https://github.com/usekaneo/kaneo/blob/main/routeTree.gen.ts), with nested layouts handling authentication and global UI chrome.
- **Zustand stores** in `src/store/` manage global client-state like themes and workspace selection without context providers.
- **Data fetching** follows a layered approach: fetchers wrap REST calls, query hooks provide caching via TanStack Query, and WebSocket hooks handle real-time updates.
- **Components** are split between UI primitives in `components/ui/` and feature-specific implementations in `components/`.
- **Tailwind CSS v4** powers styling, while **Vitest** handles testing for components and hooks co-located in the source tree.

## Frequently Asked Questions

### What routing system does the Kaneo web application use?

The application uses **TanStack Router** with a file-based convention. Routes are defined by creating files in `apps/web/src/routes/`, and the build process generates [`routeTree.gen.ts`](https://github.com/usekaneo/kaneo/blob/main/routeTree.gen.ts) to wire them together. This eliminates manual route configuration and provides full TypeScript safety for navigation.

### How does Kaneo manage global state across the application?

Global state is managed via **Zustand** stores located in `apps/web/src/store/`. Each store—such as [`user-preferences.ts`](https://github.com/usekaneo/kaneo/blob/main/user-preferences.ts) or [`project.ts`](https://github.com/usekaneo/kaneo/blob/main/project.ts)—exports a hook that components can use to read and write state directly, avoiding prop-drilling and context performance issues.

### Where are API calls defined in the Kaneo monorepo?

API calls are defined in two layers. The **fetchers** in `apps/web/src/fetchers/` contain the actual HTTP requests using the `VITE_API_URL` endpoint. The **query hooks** in `apps/web/src/hooks/queries/` wrap these fetchers with TanStack Query for caching, error handling, and background updates.

### How does Kaneo handle authentication in its layout structure?

Authentication is handled by a nested layout at [`apps/web/src/routes/_layout/_authenticated.tsx`](https://github.com/usekaneo/kaneo/blob/main/apps/web/src/routes/_layout/_authenticated.tsx). This layout checks for a valid session via Better Auth before rendering the sidebar and main content area. Unauthenticated users are redirected, while authenticated users inherit the layout's navigation scaffold automatically.