npm run dev # Start development server
npm run build # Build for production (verifies production readiness)
npm run start # Start production server
npm run lint # Run ESLintnpx tsc --noEmit # Run TypeScript type checking- Framework: Next.js 14 (App Router)
- Language: TypeScript 5 (strict mode)
- UI Library: React 18, Shadcn UI & Radix UI
- Styling: Tailwind CSS 3.4+ with CSS variables
- Icons: Lucide React
- Database: Supabase (PostgreSQL)
- State: React hooks / URL search params
app/ # Next.js App Router pages and components
components/ # Page-specific components
globals.css # Global styles with CSS variables
components/
ui/ # Shadcn UI base components
lib/
supabase/ # Supabase client configuration
utils.ts # Utility functions (cn() for class merging)
types/
index.ts # TypeScript interfaces and types
- Write concise, technical TypeScript code
- Use functional and declarative patterns; avoid classes
- Prefer iteration and modularization over duplication
- Structure files: imports, types/interfaces, component, export
- Directories: lowercase-kebab-case (e.g.,
components/hero-section) - Files: kebab-case.tsx (e.g.,
prompt-card.tsx) - Components: PascalCase with named exports (e.g.,
export function PromptCard) - Variables/functions: camelCase
- Constants: UPPER_SNAKE_CASE
- Types/interfaces: PascalCase
- Use TypeScript for all code; prefer interfaces over types
- Avoid
any; useunknownwhen unsure - Enable strict type checking
- Use explicit return types for functions where helpful
- Use absolute imports with
@/alias (configured via tsconfig.json) - Organize: external deps first, then internal modules
- Group: React imports, third-party, internal imports
- Avoid default imports for components; use named exports
Example:
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"- Style exclusively with Tailwind utilities
- Mobile-first responsive design
- Use
cn()utility (@/lib/utils) for conditional classes
- Use Shadcn UI for core components (located in
components/ui/) - Customize via
cn()utility - Extend components rather than modifying source
- Components use CSS variables for theming (see
tailwind.config.ts)
Follow the Shadcn UI pattern for components:
import * as React from "react"
import { cn } from "@/lib/utils"
export interface ComponentProps {
className?: string
}
export function Component({ className, ...props }: ComponentProps) {
return (
<div className={cn("base-styles", className)} {...props} />
)
}- Add
'use client'at the top of files with:- React hooks (
useState,useEffect, etc.) - Event handlers
- Browser APIs
- Client-side interactivity
- React hooks (
Example from prompt-card.tsx:
'use client';
import { useState } from 'react';
// Component uses useState and event handlers- Implement error boundaries for data fetching
- Check client vs server component issues
- Validate environment variables
- Use try/catch for async operations
- Never commit
.envfiles - Required variables (document in
.env.example):NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEY
Located at lib/supabase/client.ts:
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);Defined in types/index.ts:
export interface Category {
id: string;
name: string;
slug: string;
created_at: string;
}
export interface Prompt {
id: string;
title: string;
content: string;
category_id: string | null;
image_url: string | null;
created_at: string;
category?: Category | null;
}Located at lib/utils.ts:
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}- Minimize 'use client'; favor Server Components by default
- Only add 'use client' for hooks, event handlers, browser APIs
- Wrap client components in Suspense with fallbacks
- Use
next/imagewith explicit width/height
- Follow conventional commits:
feat:,fix:,chore:,docs:,refactor: - Keep commits atomic and focused
- Next.js: https://nextjs.org/docs/app
- Shadcn UI: https://ui.shadcn.com
- Tailwind CSS: https://tailwindcss.com/docs
- Supabase: https://supabase.com/docs