Skip to main content
The web app follows a clean, feature-based architecture with clear separation of concerns.

Directory Overview

web/
├── app/                    # Next.js App Router
│   ├── layout.tsx         # Root layout with providers
│   ├── page.tsx           # Home page route
│   ├── globals.css        # Global styles & design tokens
│   └── favicon.ico        # App favicon
├── components/            # Reusable components
│   ├── ui/               # shadcn/ui components
│   ├── blocks/           # Composite components
│   └── lib/              # Utilities
├── features/              # Feature modules
│   └── home/             # Home feature
├── public/                # Static assets
├── package.json           # Dependencies & scripts
├── tsconfig.json          # TypeScript config
├── components.json        # shadcn/ui config
└── next.config.ts         # Next.js config

Core Directories

app/ - App Router

Next.js App Router with file-based routing.
import { ThemeProvider } from "@/components/blocks/theme/theme-provider";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });

export const metadata: Metadata = {
  title: "Agent Toolkit TS",
  description: "An opinionated starter template for building with GitHub Copilot",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={`${inter.variable} antialiased`}>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}
Key Pattern: Route handlers (page.tsx) are thin wrappers that delegate to feature components.

components/ - Reusable Components

Three-tier component organization:
Primitive UI components from shadcn/ui
  • Built on Base UI primitives
  • Styled with Tailwind CSS
  • Fully accessible (ARIA)
  • Typed with TypeScript
Examples:
  • button.tsx - Button component with variants
  • card.tsx - Card layout components
  • heading.tsx - Heading with semantic levels
  • dropdown-menu.tsx - Accessible menus

features/ - Feature Modules

Feature-based organization for scalability:
features/
└── home/
    └── home-page.tsx
Each feature can contain:
  • Page components
  • Feature-specific components
  • Hooks
  • State management (Zustand stores)
  • API utilities
  • Types
As your app grows, add features like features/auth/, features/dashboard/, etc. Each feature is self-contained.

File Naming Conventions

TypeConventionExample
Componentskebab-case.tsxtheme-toggle.tsx
Pagespage.tsxapp/about/page.tsx
Layoutslayout.tsxapp/layout.tsx
Utilitieskebab-case.tsutils.ts
Typeskebab-case.tsuser-types.ts
Hooksuse-*.tsuse-theme.ts
Do not mix naming conventions. Stick to kebab-case for all files except Next.js special files (page.tsx, layout.tsx).

Import Aliases

Use the @/ alias for clean imports:
// ✅ Good - with alias
import { Button } from "@/components/ui/button";
import { HomePage } from "@/features/home/home-page";

// ❌ Bad - relative paths
import { Button } from "../../../components/ui/button";
import { HomePage } from "./features/home/home-page";
Configured in tsconfig.json:
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./*"]
    }
  }
}

Adding New Features

1

Create feature directory

mkdir -p features/dashboard
2

Add feature components

touch features/dashboard/dashboard-page.tsx
touch features/dashboard/dashboard-stats.tsx
3

Create route in app/

mkdir -p app/dashboard
touch app/dashboard/page.tsx
4

Wire up the route

app/dashboard/page.tsx
import { DashboardPage } from "@/features/dashboard/dashboard-page";

export default function Dashboard() {
  return <DashboardPage />;
}

Static Assets

public/ Directory

Static files served from the root:
public/
└── copilot-cli.svg
Reference in components:
import Image from "next/image";

<Image src="/copilot-cli.svg" alt="Logo" width={60} height={60} />
Files in public/ are served at the root path. /copilot-cli.svg maps to public/copilot-cli.svg

Design Tokens

Global styles and CSS variables live in app/globals.css:
app/globals.css
:root {
  --background: light-dark(oklch(1 0 0), oklch(0.145 0 0));
  --foreground: light-dark(oklch(0.145 0 0), oklch(0.985 0 0));
  --primary: light-dark(oklch(0.6 0.13 163), oklch(0.7 0.15 162));
  --radius: 0.625rem;
  /* ... more tokens */
}
Modern CSS light-dark() function automatically switches colors based on color-scheme. Works with the ThemeProvider.

Best Practices

Co-location

Keep related files together in feature directories

Import Aliases

Always use @/ prefix for absolute imports

Thin Routes

Keep app/ routes minimal, delegate to features

Single Source

UI components only in components/ui/

Next Steps

Components

Explore the component patterns

Features

Learn feature-based architecture

Build docs developers (and LLMs) love