Kaneo Web Application Monorepo Structure: A Complete Architecture Guide
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. 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. 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 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, which imports every route component and constructs a type-safe tree. Route files use createFileRoute to declare their path segment:
// 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 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 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 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 file manages theme selection and other user settings:
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) 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 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:
// 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 and 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 for URL-safe string generation, 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. 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, enabling unit tests for components like apps/web/src/components/list-view/task-row.test.tsx and hooks like apps/web/src/hooks/use-board-sort.test.tsx.
Summary
- The Kaneo web application resides in
apps/weband bootstraps frommain.tsxusing TanStack Router and React Query. - File-based routing in
src/routes/generates a type-safe route tree atrouteTree.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 incomponents/. - 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 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 or 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. 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →