Project Structure

This document describes the layout of the solid-admin project and the responsibilities of each directory and key file.

Overview

solid-admin is a SolidJS 2.x application scaffolded from the with-tanstack-router template. It uses TanStack Router for routing, data loading, and navigation. The project compiles to a purely static site with zero server dependencies — vite build emits dist/client, which can be deployed to any static host.

Top-level layout

solid-admin/
├── .gitignore
├── AGENTS.md                # Agent guide: Solid conventions and diagnostics
├── .opencode/               # opencode config + agent skills (e.g. daisyUI)
├── bun.lock
├── node_modules/
├── oxlint.config.mjs        # Lint configuration
├── package.json
├── public/                  # Static assets served as-is
├── README.md
├── skills-lock.json
├── src/                     # Application source (see below)
├── tsconfig.json
├── vite.config.ts           # Vite + Solid plugin + TanStack router plugin
└── vitest-setup.ts          # Test environment setup

src/ layout

src/
├── App.tsx                  # App root: creates the TanStack router
├── App.css                  # App-level styles
├── Document.tsx             # HTML document shell (entry wrapper)
├── logo.svg
├── vite-env.d.ts           # Vite client type references
├── components/              # Reusable UI components
│   ├── Counter.tsx
│   └── Counter.test.tsx
├── routes/                  # TanStack route files (code-generated tree)
│   ├── __root.tsx           # Root layout + not-found boundary
│   ├── index.tsx            # Home route (dashboard)
│   ├── users.tsx            # Users list route
│   └── users.$id.tsx        # Dynamic /users/$id route with loader
└── routeTree.gen.ts         # Auto-generated typed route tree (do not edit)

Directory and file responsibilities

src/App.tsx

Creates the router with createRouter({ routeTree }) and registers its types library-wide via the Register interface augmentation, so every <Link>’s to and params are type-checked. The default export is the component the generated entries render, wrapped in src/Document.tsx.

src/Document.tsx

The document shell that wraps the app in the generated entries (provides the outer <html>/<head>/<body> structure for the client-mode build). Sets the daisyUI data-theme.

src/routes/

TanStack owns everything routing. Route files follow TanStack’s naming convention and are watched by @tanstack/router-plugin in vite.config.ts, which regenerates src/routeTree.gen.ts.

  • __root.tsx — the site-wide admin shell (drawer + navbar) every route renders inside, plus the notFoundComponent boundary. <HeadContent /> renders titles declared by matched routes’ head options.
  • index.tsx — the home route (/): the dashboard.
  • users.tsx — a users list page with a daisyUI table.
  • users.$id.tsx — a dynamic route (/users/$id) demonstrating loader-driven data: fetchUser(id) runs when navigation starts and is cached per params; Route.useLoaderData() returns typed, reactive data.

src/components/

Reusable, self-contained UI components. Counter.tsx is the demo component and ships with its Counter.test.tsx test.

src/routeTree.gen.ts

Auto-generated by @tanstack/router-plugin. It is the typed route tree that src/App.tsx feeds to createRouter. Do not edit by hand — it regenerates as route files change.

Ownership of concerns

  • @solidjs/vite-plugin owns the compile pipeline and app shell: the JSX transform, the turnkey entries around src/App.tsx, and src/Document.tsx. It does not know or care which router renders inside.
  • TanStack Router owns everything routing: route files under src/routes, loaders, navigation, and head management.

Routing idioms

  • Typesafe navigation<Link to="/users/$id" params=> is checked against the actual route tree at compile time.
  • Loader-driven data — routes declare loader, run on navigation start, and expose typed data via Route.useLoaderData().
  • Head management — routes declare head options; <HeadContent /> in the root renders the matched title.
  • Route-level code splittingautoCodeSplitting: true in vite.config.ts splits each route’s component out of the entry.

Tests

Components under src/components/ are tested with Vitest (see Counter.test.tsx). Run bun test to execute the suite.

Scripts

Script Purpose
bun dev Start the dev server at http://localhost:3000
bun build Build the static site to dist/client
bun serve Serve the production build locally
bun test Run the test suite