This file contains essential context about the project structure, technologies, and conventions to help Claude understand and work effectively within this codebase.
CodeGuide Starter Kit is a modern Next.js starter template featuring authentication, database integration, AI capabilities, and a comprehensive UI component system.
- Framework: Next.js 15 with App Router (
/src/appdirectory structure) - Language: TypeScript with strict mode enabled
- Styling: TailwindCSS v4 with CSS custom properties
- UI Components: shadcn/ui (New York style) with Lucide icons
- Authentication: Clerk with middleware protection
- Database: Supabase with third-party auth integration
- AI Integration: Vercel AI SDK with support for Anthropic Claude and OpenAI
- Theme System: next-themes with dark mode support
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ │ └── chat/ # AI chat endpoint
│ ├── globals.css # Global styles with dark mode
│ ├── layout.tsx # Root layout with providers
│ └── page.tsx # Home page with status dashboard
├── components/
│ ├── ui/ # shadcn/ui components (40+ components)
│ ├── chat.tsx # AI chat interface
│ ├── setup-guide.tsx # Configuration guide
│ ├── theme-provider.tsx # Theme context provider
│ └── theme-toggle.tsx # Dark mode toggle components
├── lib/
│ ├── utils.ts # Utility functions (cn, etc.)
│ ├── supabase.ts # Supabase client configurations
│ ├── user.ts # User utilities using Clerk
│ └── env-check.ts # Environment validation
└── middleware.ts # Clerk authentication middleware
- package.json: Dependencies and scripts
- components.json: shadcn/ui configuration (New York style, neutral colors)
- tsconfig.json: TypeScript configuration with path aliases (
@/) - .env.example: Environment variables template
- SUPABASE_CLERK_SETUP.md: Integration setup guide
- Middleware protects
/dashboard(.*)and/profile(.*)routes - Components:
SignInButton,SignedIn,SignedOut,UserButton - User utilities in
src/lib/user.tsusecurrentUser()from Clerk
- Client:
createSupabaseServerClient()for server-side with Clerk tokens - RLS: Row Level Security uses
auth.jwt() ->> 'sub'for Clerk user IDs - Example Migration:
supabase/migrations/001_example_tables_with_rls.sql
Server-side (Recommended for data fetching):
import { createSupabaseServerClient } from "@/lib/supabase"
export async function getServerData() {
const supabase = await createSupabaseServerClient()
const { data, error } = await supabase
.from('posts')
.select('*')
.order('created_at', { ascending: false })
if (error) {
console.error('Database error:', error)
return null
}
return data
}Client-side (For interactive operations):
"use client"
import { supabase } from "@/lib/supabase"
import { useAuth } from "@clerk/nextjs"
function ClientComponent() {
const { getToken } = useAuth()
const fetchData = async () => {
const token = await getToken()
// Pass token manually for client-side operations
const { data, error } = await supabase
.from('posts')
.select('*')
.auth(token)
return data
}
}- Version: TailwindCSS v4 with PostCSS
- Custom Properties: CSS variables for theming
- Dark Mode: Class-based with
next-themes - Animations:
tw-animate-csspackage included
- Style: New York variant
- Theme: Neutral base color with CSS variables
- Icons: Lucide React
- Components Available: 40+ UI components (Button, Card, Dialog, etc.)
- Provider:
ThemeProviderin layout with system detection - Toggle Components:
ThemeToggle(dropdown) andSimpleThemeToggle(button) - Persistence: Automatic theme persistence across sessions
- Endpoint:
/api/chat/route.ts - Providers: Anthropic Claude and OpenAI support
- Chat Component: Real-time streaming chat interface
- Authentication: Requires Clerk authentication
- Components: Use PascalCase, place in appropriate directories
- Utilities: Place reusable functions in
src/lib/ - Types: Define alongside components or in dedicated files
- API Routes: Follow Next.js App Router conventions
// Path aliases (configured in tsconfig.json)
import { Button } from "@/components/ui/button"
import { getCurrentUser } from "@/lib/user"
import { supabase } from "@/lib/supabase"
// External libraries
import { useTheme } from "next-themes"
import { SignedIn, useAuth } from "@clerk/nextjs"// Client components (when using hooks/state)
"use client"
// Server components (default, for data fetching)
export default async function ServerComponent() {
const user = await getCurrentUser()
// ...
}Required for full functionality:
# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
# Supabase Database
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
# AI Integration (optional)
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...All database tables should use RLS policies that reference Clerk user IDs via auth.jwt() ->> 'sub'.
Basic User-Owned Data Pattern:
-- Enable RLS on table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Users can read all posts (public)
CREATE POLICY "Anyone can read posts" ON posts
FOR SELECT USING (true);
-- Users can only insert posts as themselves
CREATE POLICY "Users can insert own posts" ON posts
FOR INSERT WITH CHECK (auth.jwt() ->> 'sub' = user_id);
-- Users can only update their own posts
CREATE POLICY "Users can update own posts" ON posts
FOR UPDATE USING (auth.jwt() ->> 'sub' = user_id);
-- Users can only delete their own posts
CREATE POLICY "Users can delete own posts" ON posts
FOR DELETE USING (auth.jwt() ->> 'sub' = user_id);Private Data Pattern:
-- Completely private to each user
CREATE POLICY "Users can only access own data" ON private_notes
FOR ALL USING (auth.jwt() ->> 'sub' = user_id);Conditional Visibility Pattern:
-- Public profiles or own profile
CREATE POLICY "Users can read public profiles or own profile" ON profiles
FOR SELECT USING (
is_public = true OR auth.jwt() ->> 'sub' = user_id
);Collaboration Pattern:
-- Owner and collaborators can access
CREATE POLICY "Owners and collaborators can read" ON collaborations
FOR SELECT USING (
auth.jwt() ->> 'sub' = owner_id OR
auth.jwt() ->> 'sub' = ANY(collaborators)
);Complete CRUD Example:
import { createSupabaseServerClient } from "@/lib/supabase"
import { getCurrentUser } from "@/lib/user"
// CREATE - Insert new record
export async function createPost(title: string, content: string) {
const user = await getCurrentUser()
if (!user) return null
const supabase = await createSupabaseServerClient()
const { data, error } = await supabase
.from('posts')
.insert({
title,
content,
user_id: user.id, // Clerk user ID
})
.select()
.single()
if (error) {
console.error('Error creating post:', error)
return null
}
return data
}
// READ - Fetch user's posts
export async function getUserPosts() {
const supabase = await createSupabaseServerClient()
const { data, error } = await supabase
.from('posts')
.select(`
id,
title,
content,
created_at,
user_id
`)
.order('created_at', { ascending: false })
if (error) {
console.error('Error fetching posts:', error)
return []
}
return data
}
// UPDATE - Modify existing record
export async function updatePost(postId: string, updates: { title?: string; content?: string }) {
const supabase = await createSupabaseServerClient()
const { data, error } = await supabase
.from('posts')
.update(updates)
.eq('id', postId)
.select()
.single()
if (error) {
console.error('Error updating post:', error)
return null
}
return data
}
// DELETE - Remove record
export async function deletePost(postId: string) {
const supabase = await createSupabaseServerClient()
const { error } = await supabase
.from('posts')
.delete()
.eq('id', postId)
if (error) {
console.error('Error deleting post:', error)
return false
}
return true
}Real-time Subscriptions:
"use client"
import { useEffect, useState } from "react"
import { supabase } from "@/lib/supabase"
import { useAuth } from "@clerk/nextjs"
function useRealtimePosts() {
const [posts, setPosts] = useState([])
const { getToken } = useAuth()
useEffect(() => {
const fetchPosts = async () => {
const token = await getToken()
const { data } = await supabase
.from('posts')
.select('*')
.auth(token)
setPosts(data || [])
}
fetchPosts()
// Subscribe to changes
const subscription = supabase
.channel('posts-channel')
.on('postgres_changes',
{ event: '*', schema: 'public', table: 'posts' },
(payload) => {
fetchPosts() // Refetch on any change
}
)
.subscribe()
return () => {
subscription.unsubscribe()
}
}, [getToken])
return posts
}Routes matching /dashboard(.*) and /profile(.*) are automatically protected by Clerk middleware.
// Automatic dark mode support via CSS custom properties
<div className="bg-background text-foreground border-border">
<Button variant="outline">Themed Button</Button>
</div>npm run dev # Start development server with Turbopack
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLint- Authentication: Always check user state with Clerk hooks/utilities
- Database: Use RLS policies with Clerk user IDs for security
- UI: Leverage existing shadcn/ui components before creating custom ones
- Styling: Use TailwindCSS classes and CSS custom properties for theming
- Types: Maintain strong TypeScript typing throughout
- Performance: Use server components by default, client components only when needed
- Clerk + Supabase: Uses modern third-party auth (not deprecated JWT templates)
- AI Chat: Requires authentication and environment variables
- Dark Mode: Automatically applied to all shadcn components
- Mobile: Responsive design with TailwindCSS breakpoints
This starter kit provides a solid foundation for building modern web applications with authentication, database integration, AI capabilities, and polished UI components.