-
Notifications
You must be signed in to change notification settings - Fork 6
Project Structure Guide
This document is a companion to the Development Guide. It focuses exclusively on the codebase layout and how to work within each directory of the LangRoute monorepo.
This guide helps both new and existing contributors understand how the LangRoute project is structured. It aims to:
- Clarify the directory and file organization philosophy
- Explain where different types of logic (UI, API, DB, validation, etc.) should go
- Describe how to extend the system with new routes, services, or utilities
What this guide covers:
- Routing (UI and API) with Next.js App Router
- Cross-cutting utilities and shared runtime logic
- Suggested structure for backend business logic and future expansion
What this guide does not cover:
- Code formatting, linting, commit conventions
- GitHub workflows, branching, or PR standards
These remain in the Development Guide.
├── src
│ ├── app # Next.js routes (UI + API)
│ │ ├── (client)/ # Client routes, layouts, UI, providers
│ │ │ ├── (auth)/ # Auth routes (login, register, forgot-password)
│ │ │ ├── (dashboard)/ # Dashboard routes
│ │ │ ├── layout.tsx # Client layout (navbar, auth guards)
│ │ │ ├── page.tsx # Home page
│ │ │ └── providers/ # App-wide providers
│ │ └── (server) # Server routes, API endpoints, services
│ │ ├── api/ # API routes
│ │ └── services/ # Backend-only business logic
│ ├── db/ # Prisma client
│ ├── lib/ # Shared runtime helpers (config, middleware, validation, models, utils)
│ ├── shadcn-ui/ # UI primitives
│ ├── types/ # Global TS declarations
│ └── ...
Note: Some planned directories like
ws/andworkers/are not yet created. Others likeservices/are still evolving and may be restructured significantly. Treat the current layout as suggested, not final.
Each folder is explained in detail below.
This is the heart of the frontend routing system, powered by Next.js App Router. Pages and layouts are defined by the file system.
LangRoute uses named route groups like:
src/app/(client)/(auth)/...src/app/(client)/(dashboard)/...
These help logically separate routes (e.g. login/register vs dashboard) while keeping clean URLs like /login, /dashboard.
Inside each group:
-
layout.tsxdefines layout wrappers (navbar, auth guards, etc.) -
page.tsxdefines route content -
loading.tsxorerror.tsx(optional) handle async and error states
Example:
src/app/(client)/(auth)/login/page.tsx → /login
src/app/(client)/(dashboard)/dashboard/page.tsx → /dashboard
```src/app/(server)/api/{resource}/route.ts```
LangRoute follows these API conventions:
- RESTful structure (
/apikeys,/usage) - Zod validation inside handlers
- Keep handlers thin: delegate to services
src/app/(client)/providers/ contains individual React context providers, such as:
- AuthProvider
- QueryProvider
- ToastProvider
A single AppProviders component composes all individual providers.
src/app/(client)/providers/Providers.tsx wraps the app like this:
export default function Providers({ children }) {
return <AppProviders>{children}</AppProviders>
}- Create a file in
src/app/(client)/providers/{YourProvider}.tsx - Export the provider component
- Add it to
AppProvidersin the correct order
Located in: src/app/(client)/components/
- Use for reusable UI (buttons, tables, modals)
- Should follow PascalCase file naming
- Export from
components/index.tsfor shorter imports
Example:
import { Button } from '@/app/(client)/components'
UI specific to a page should live next to the page inside: src/app/(client)/(group)/feature/components/
Only promote components to global if they’re reused across multiple, unrelated routes.
- Tailwind CSS is preferred
- Use
cn()utility from@/lib/utilsfor conditional classes - For Shadcn UI variants, use
cva()via class-variance-authority (if/when added)
Current hook categories:
hooks/
├── data/ → React Query hooks (API calls)
├── forms/ → React Hook Form + Zod
└── ...
Future categories (optional):
-
ui/for Zustand-based UI state -
utils/for generic hooks likeuseDebounce
- Hooks should always begin with
useX - Do not use Zustand for server/remote data fetching
- Avoid duplication between hooks and services
This folder houses all utilities, validators, and singleton clients.
import { prisma } from '@/db/prisma'- Only import into backend files
- Avoid instantiating Prisma multiple times (handled internally)
import { redis } from '@/lib/redis/redis'- Used for rate limits, pub/sub, live logs
- More logic will be added here later
-
routesConfig.ts→ defines public routes & middleware matchers - More config files like
defaults.tsmay be added - Always export from
lib/config/index.ts
- For shared Zod schemas
- Keeps frontend and backend validation in sync
This folder contains core TypeScript types:
-
User.ts,ApiModels.ts, etc. - DTOs like
CreateKeyPayload.ts,UsageReport.ts - Enum-like types (
ProviderName,Role)
Usage:
import { User, ApiModels } from '@/lib/models'Rules:
- No runtime logic inside
- Export everything through
lib/models/index.ts - Keep in sync with Prisma schema and API contracts
⚠️ Disclaimer: The services structure is early and may change. This section reflects the current state only.
- Encapsulates backend business logic
- Should never be imported in frontend code
services/
├── adapters/ # Logic for external integrations
├── auth/ # Auth-related services (e.g., token validation)
├── proxy/ # Proxy-related services (e.g., API request forwarding)
├── usage/ # Usage tracking services
├── keys/ # API key management services (e.g., create, revoke, rotate)
├── logs/ # Log-related services (e.g., Redis pub/sub for live logs)
├── analytics/ # Analytics services (e.g., cost, tokens, latency tracking)
These may contain logic for:
- Token proxying
- API key validation
- Usage logging
Each service should be:
- Pure (no
req/resobjects) - Callable from routes or jobs
- Tested in isolation if possible
- Export from
services/index.ts
May eventually house:
- Background workers (usage alerts, key revocation)
- WebSocket log stream publisher
This file runs on every request and handles:
- Auth enforcement
- Rate-limiting (future)
- Skips public routes via matcher config
Shared functions (e.g., verifyApiKey, rateLimit) go here and are used by:
- Middleware
- API handlers
- Services
These directories don’t exist yet, but will be added soon.
-
ws/— WebSocket gateway (e.g. logs via Redis pub/sub) -
workers/— background jobs (usage alerts, email queue)
These will be wired via Docker Compose services.
-
src/types/next-auth.d.ts— NextAuth module augmentation (User/Session/JWT types). -
src/types/global.d.ts— project-wide ambient types (e.g., custom globals, env-safe helpers).
- Extend NextAuth types only in
next-auth.d.tsto keep auth concerns isolated. - Keep
global.d.tsminimal; use it for true ambient declarations that don’t fit a feature module. - Prefer colocated, exported interfaces/types in
src/lib/models/for domain types and import them where needed (avoid leaking runtime logic intomodels).
- Template lives at
env/.env.example. - The root
.envis generated/updated by project scripts:-
npm run dev→ prepares the root.env(viascripts/prepare-env.mjs) and starts the dev server. - You generally should not edit the root
.envdirectly; update your local values underenv/and re-run the dev script.
-
See
scripts/dev.mjsandscripts/prepare-env.mjsfor the exact flow.
Currently included:
sample-config-yaml-file-for-models
This will evolve into a proper config.yaml for:
- Provider metadata
- Rate/cost tables
- GitOps seeding (first boot → populate DB)
| Frontend | Backend |
|---|---|
Feature folders under src/app/(client)/(group)/{feature}/
|
API routes under src/app/(server)/api/{resource}/route.ts
|
Global UI components in src/app/(client)/components/
|
Business logic in src/app/(server)/services/
|
Typed fetch hooks in src/app/(client)/hooks/data/ (TanStack Query) |
Database access via Prisma (db/prisma.ts) |
Route-specific UI lives alongside the page in src/app/(client)/(group)/feature/components/
|
Root middleware in middleware.ts (auth, public-route matcher) |
Forms in src/app/(client)/hooks/forms/ using Zod + RHF |
Input validation via shared Zod schemas in lib/validation/
|
| Tailwind CSS via utility classes; custom classes via @apply in globals.css (if reusable) | Redis helpers and rate limiting logic in lib/redis/ (planned) |
Shared types/interfaces in lib/models/
|
Config and constants in lib/config/
|
App-wide providers in src/app/(client)/providers/ and composed in src/app/(client)/providers.tsx
|
Pure service functions — no req/res — callable from jobs or routes |
-
Pre-commit hook fails? Use
git commit --no-verify - Component tries to import a service? That’s a layering violation — move logic to a hook.
- WebSocket not connecting? Make sure Redis is running in dev mode.
This guide is a living document. As the LangRoute project evolves, so will the structure and conventions. Please contribute updates or suggestions to keep it relevant for all developers.