Project Structure
A tour of the ContentAI codebase so you know where to make changes.
ContentAI follows a standard Next.js App Router layout. Here is what you'll find when you open the project:
ai-content-generator/
├── app/
│ ├── (dashboard)/ # Authenticated app routes
│ │ ├── dashboard/ # Overview & stats
│ │ ├── templates/ # Browse all AI templates
│ │ ├── generate/ # Template-based generation UI
│ │ ├── editor/ # Document editor with AI actions
│ │ ├── history/ # Past generations
│ │ ├── settings/ # API keys & model selection
│ │ └── layout.tsx # Sidebar layout
│ ├── api/
│ │ └── generate/
│ │ └── route.ts # The single AI endpoint
│ ├── globals.css # Tailwind + shadcn theme
│ ├── layout.tsx # Root layout + metadata
│ └── page.tsx # Marketing landing page
├── components/
│ ├── ui/ # shadcn/ui primitives
│ ├── app-sidebar.tsx # Main nav
│ └── page-header.tsx # Reusable page title
├── lib/
│ ├── store.ts # Zustand store (api keys, generations, docs)
│ ├── templates.ts # All 35+ templates + categories
│ └── utils.ts # cn() and helpers
├── public/ # Static assets
├── package.json
├── tsconfig.json
├── next.config.ts
└── components.json # shadcn registry configKey files to know
lib/templates.ts
The heart of the product. Every template is defined here as a plain object with:
id,name,description,category,iconprompt— the system prompt sent to the AI with{field}placeholdersfields— the inputs shown to the user on the Generate page
Adding a new template is as simple as appending to the templates array. See Customizing Templates.
lib/store.ts
Centralized Zustand store, persisted to localStorage under the key contentai-store. Holds:
apiKeys— one per provideractiveProvider— which provider is currently activeselectedModels— the chosen model per providergenerations— history of AI outputsdocuments— saved documents for the editortotalWords,totalGenerations— lifetime counters
The store is versioned. If you change its shape, bump version and add a migrate function so existing users don't lose data.
app/api/generate/route.ts
The only server-side code in the app. This route:
- Reads the API key for the chosen provider from the request body
- Instantiates the matching AI SDK client via
createModel() - Calls
generateText()with the prompt - Returns either the content or a parsed error message
Because keys are sent from the client with each request, no API keys ever touch your server's disk or environment variables. See Security for more.
components/app-sidebar.tsx
Left navigation shown on every dashboard route. Edit this to change the navigation structure or branding.
app/globals.css
Contains the Tailwind v4 @theme block with CSS custom properties for colors, radii, fonts. This is where you customize the theme — see Theming.
What's stored where
| Data | Location | Notes |
|---|---|---|
| API keys | localStorage (browser) | Never sent to your server except on generate calls |
| Generations | localStorage (browser) | Per-browser, per-device |
| Documents | localStorage (browser) | Per-browser, per-device |
| User/auth | NextAuth session + optional DB | See Auth & Supabase |
| AI responses | Provider API (Groq/Google/etc.) | Subject to that provider's privacy policy |
Where to add features
| If you want to... | Edit |
|---|---|
| Add a new template | lib/templates.ts |
| Add a new AI provider | app/api/generate/route.ts + lib/store.ts |
| Change colors / theme | app/globals.css |
| Change navigation / branding | components/app-sidebar.tsx |
| Add a new dashboard page | Create app/(dashboard)/<name>/page.tsx |
| Add user accounts | Wrap (dashboard) layout with auth |
| Add billing | Add a Stripe route + gating in layout |
Next: Architecture Overview →