# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Standard Worflow

Use this workflow when working on a new task:

### Workflow when working on a new task:

1. First, think through the problem, read the codebase for relevant files, and
   write a plan to tasks/todo.md.
2. The plan should have a list of todo items that you can check off as you complete them.
3. Before you begin to work, check in with me and I verify the plan.
4. Then, begin working on the todo items, marking them as complete as you go.
5. Finally, add a review section to the todo.md file with a summary of the changes
   you made and any other relevant information.

Periodically make sure to commit when it makes sense to do so.

## Development Commands

**Important: This project uses yarn, not npm. Always use yarn commands.**

**Node.js Version**: This project uses Node.js version 20.12.2 (see .nvmrc). Always ensure you're using the correct Node.js version before running any commands, especially linting and code quality tools.

**To activate the correct Node.js version, run these commands first:**
```bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm use
```

**Note**: These commands load nvm and switch to the project's Node.js version. You need to run them in each new terminal session.

### Core Development

- `yarn dev` - Start development server
- `yarn build` - Build for production
- `yarn lint` - Run ESLint
- `yarn type-check` - TypeScript type checking

### Code Quality

- `yarn clean` - Fix linting and format code (recommended after changes)
- `yarn lint:fix` - Auto-fix linting issues
- `yarn format:write` - Format code with Prettier

### Database Operations

- `yarn db:push` - Push schema changes to database
- `yarn db:generate` - Generate new migrations
- `yarn db:migrate` - Run pending migrations

## Architecture Overview

This is a full-stack Next.js application template with the following architecture:

### Tech Stack

- **Frontend**: Next.js 15 with App Router, React 19, TypeScript, Tailwind CSS, Shadcn/UI
- **Backend**: PostgreSQL with Supabase, Drizzle ORM, Next.js Server Actions
- **Auth**: Clerk authentication
- **Payments**: Stripe integration
- **Analytics**: PostHog
- **AI**: OpenAI integration

### Key Architectural Patterns

#### Route Organization

- **Route Groups**: `(auth)` for authentication pages, `(marketing)` for public pages
- **Route-specific Components**: Use `_components` folder within routes for one-off components
- **Layouts**: Separate layouts for different route groups

#### Data Layer

- **Server Actions**: Located in `/actions/` directory, organized by functionality
- **Services**: Located in `/lib/services/` directory for complex business logic
- **Database Schema**: Drizzle ORM schemas in `/db/schema/`
- **Type Safety**: Use schema-generated types like InsertProfile and SelectProfile from your database schemas

#### Data Flow Architecture

Follow this layered architecture pattern:

- **React Components** → **Server Actions** → **Services** (when complex logic is needed)
- Services handle domain-specific logic, external API integrations, and complex business rules
- Keep Server Actions lightweight and focused on data validation and orchestration

#### Component Architecture

- **UI Components**: Shadcn/UI components in `/components/ui/` (don't modify unless specified)
- **Shared Components**: Reusable components in `/components/`
- **Route-specific**: Components in `app/route/_components/`

## Important Development Rules

### Environment Variables

- Always use centralized config: `serverConfig` and `publicEnv` from `@/lib/config`
- Never use `process.env` directly in application code
- Update `.env.example` when adding new environment variables

### Import Conventions

- Use `@/` for all imports from the app root
- Import types from `@/types`
- Import database types from `@/db/schema`
- Import services from `@/lib/services`

### File Naming

- Use kebab-case for all files and folders
- Type files: `example-types.ts` in `/types/` directory
- Export all types in `types/index.ts`

### Code Quality Requirements

- **Always use the correct Node.js version (20.12.2)** before running any code quality commands
- **Load nvm first**: Run the nvm commands above if you're in a new terminal session
- Run `yarn clean` after making changes to ensure code quality
- Use TypeScript interfaces over type aliases when possible
- Follow the existing patterns in the codebase

## Coding Standards

All code must adhere to these strict formatting and quality guidelines:

### Syntax & Structure

- File names must be dash-case (word-cloud.service.ts) unless an existing pattern differs
- Group imports: node/standard → npm packages → internal paths. No unused imports
- Use arrow functions everywhere except inside class bodies, where concise method syntax is allowed
- Prefer early returns; nested if/else blocks deeper than two levels are disallowed
- Early returns must use block format with braces (e.g., `if (!value) { return }`) for readability
- Extract function call results as scope variables before using in conditions (e.g., `const trimmedText = text.trim(); if (!trimmedText) {...}` instead of `if (!text.trim()) {...}`)
- Use async/await—never chain .then()
- No .forEach for side effects; use for (const x of arr) instead
- Array combinators (map, reduce, filter) are allowed only when you return their result
- Identifiers must be English
- No commented code allowed

### Functional Programming Rules

Each function must:

- Be ≤ 50 lines (preferably; extract helpers if longer)
- Take ≤ 4 parameters (optional ones last)
- Have a single responsibility
- Be pure unless it is an intentional I/O wrapper (e.g. DB write); such wrappers must be ≤ 15 lines
- Name functions with camelCase imperative verbs (calculateTotals, getUserById)

### Type Safety & Error Handling

- Explicitly type all function parameters, return types, and exported constants
- Type all local variables inside a function
- **Special attention for async operations**: Variables from awaited functions (e.g., `const { userId } = await auth()`) must be explicitly typed, especially in Next.js components where auth results should use proper domain types
- No any; if an external library forces it, wrap and narrow
- Error handling in catch blocks:
  - If the error variable is not used, use `catch {}` (no parameter)
  - If the error is used, type it as `unknown` and handle it safely within the catch block

### React Component Standards

- Always define props with interfaces, never inline types
- Place interfaces directly above component definitions
- Use const arrow functions for component definitions
- Use implicit return syntax when components only return JSX (no logic before return)
- Export components using export default pattern (required for Next.js pages/layouts)
- Handler functions inside components must be ≤ 20 lines and have a single, clear responsibility. Extract helper functions for complex logic.

  **Wrong (~50 lines in one handler):**

  ```tsx
  const handleFormSubmit = async (): Promise<void> => {
    const trimmedName: string = formData.name.trim()
    const trimmedEmail: string = formData.email.trim()
    const trimmedMessage: string = formData.message.trim()

    if (!trimmedName) {
      setErrors({ ...errors, name: "Name is required" })
      toast({
        title: "Error",
        description: "Name is required",
        variant: "destructive"
      })
      return
    }

    if (!trimmedEmail || !trimmedEmail.includes("@")) {
      setErrors({ ...errors, email: "Valid email is required" })
      toast({
        title: "Error",
        description: "Valid email is required",
        variant: "destructive"
      })
      return
    }

    if (!trimmedMessage || trimmedMessage.length < 10) {
      setErrors({
        ...errors,
        message: "Message must be at least 10 characters"
      })
      toast({
        title: "Error",
        description: "Message too short",
        variant: "destructive"
      })
      return
    }

    setIsSubmitting(true)
    setErrors({})

    try {
      const payload: FormPayload = {
        name: trimmedName,
        email: trimmedEmail,
        message: trimmedMessage,
        timestamp: new Date().toISOString()
      }

      const response: Response = await fetch("/api/contact", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload)
      })

      if (!response.ok) {
        throw new Error("Failed to submit")
      }

      const result: SubmissionResult = await response.json()

      setFormData({ name: "", email: "", message: "" })
      setSubmissionCount((prev) => prev + 1)

      toast({ title: "Success", description: "Message sent successfully!" })

      if (onSuccess) {
        onSuccess(result)
      }
    } catch (error: unknown) {
      const errorMessage: string =
        error instanceof Error ? error.message : "Unknown error"
      console.error("Submission error:", errorMessage)
      setErrors({ submit: "Failed to send message" })
      toast({
        title: "Error",
        description: "Failed to send message",
        variant: "destructive"
      })
    } finally {
      setIsSubmitting(false)
    }
  }
  ```

  **Good (broken into focused helpers ≤ 20 lines each):**

  ```tsx
  const validateForm = (): boolean => {
    const trimmedName: string = formData.name.trim()
    const trimmedEmail: string = formData.email.trim()
    const trimmedMessage: string = formData.message.trim()

    if (!trimmedName) {
      setErrors({ ...errors, name: "Name is required" })
      toast({
        title: "Error",
        description: "Name is required",
        variant: "destructive"
      })
      return false
    }

    if (!trimmedEmail || !trimmedEmail.includes("@")) {
      setErrors({ ...errors, email: "Valid email is required" })
      toast({
        title: "Error",
        description: "Valid email is required",
        variant: "destructive"
      })
      return false
    }

    if (!trimmedMessage || trimmedMessage.length < 10) {
      setErrors({
        ...errors,
        message: "Message must be at least 10 characters"
      })
      toast({
        title: "Error",
        description: "Message too short",
        variant: "destructive"
      })
      return false
    }

    return true
  }

  const submitForm = async (): Promise<SubmissionResult> => {
    const payload: FormPayload = {
      name: formData.name.trim(),
      email: formData.email.trim(),
      message: formData.message.trim(),
      timestamp: new Date().toISOString()
    }

    const response: Response = await fetch("/api/contact", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload)
    })

    if (!response.ok) {
      throw new Error("Failed to submit")
    }

    return response.json()
  }

  const handleSuccess = (result: SubmissionResult): void => {
    setFormData({ name: "", email: "", message: "" })
    setSubmissionCount((prev: number) => prev + 1)
    toast({ title: "Success", description: "Message sent successfully!" })

    if (onSuccess) {
      onSuccess(result)
    }
  }

  const handleError = (error: unknown): void => {
    const errorMessage: string =
      error instanceof Error ? error.message : "Unknown error"
    console.error("Submission error:", errorMessage)
    setErrors({ submit: "Failed to send message" })
    toast({
      title: "Error",
      description: "Failed to send message",
      variant: "destructive"
    })
  }

  const handleFormSubmit = async (): Promise<void> => {
    const isValid: boolean = validateForm()

    if (!isValid) {
      return
    }

    setIsSubmitting(true)
    setErrors({})

    try {
      const result: SubmissionResult = await submitForm()
      handleSuccess(result)
    } catch (error: unknown) {
      handleError(error)
    } finally {
      setIsSubmitting(false)
    }
  }
  ```

- Example with implicit return:

  ```tsx
  interface MyComponentProps {
    title: string
    children: React.ReactNode
  }

  const MyComponent = ({ title, children }: MyComponentProps) => (
    <div>
      {title}
      {children}
    </div>
  )

  export default MyComponent
  ```

- Example with explicit return (when logic is present):

  ```tsx
  interface MyComponentProps {
    title: string
    children: React.ReactNode
  }

  const MyComponent = ({ title, children }: MyComponentProps) => {
    const processedTitle = title.toUpperCase()

    return (
      <div>
        {processedTitle}
        {children}
      </div>
    )
  }

  export default MyComponent
  ```

- Normal components that are not Next.js pages/layouts should be exported
  using export const pattern
- Example with implicit return:

  ```tsx
  interface NotAPageOrLayoutComponentProps {
    title: string
    children: React.ReactNode
  }

  export const NotAPageOrLayoutComponent = ({
    title,
    children
  }: NotAPageOrLayoutComponentProps) => (
    <div>
      {title}
      {children}
    </div>
  )
  ```

### Component Granularity & Organization

- Break down large components into smaller, focused components for better maintainability
- When a component contains multiple logical sections (e.g., Card with CardHeader + CardContent), extract each section into separate components
- Create dedicated folders for related component groups:
  - Use kebab-case folder names matching the main component concept
  - Place related sub-components within the same folder using kebab-case file names
  - Example structure: `component-name/component-name-header.tsx`, `component-name/component-name-content.tsx`
- Each sub-component should have a single, clear responsibility
- Maintain the parent component as a composition wrapper that orchestrates child components
- Follow this pattern when refactoring existing components or creating new feature components

### Advanced Component Architecture Patterns

#### Pure Functions and Constants Organization

- **Pure functions** (no side effects, deterministic output) must be extracted outside components:
  - Place above the component definition
  - Examples: `getGreeting()`, `getMembershipBadgeColor()`, `formatDate()`
- **Constants and static data** must be moved outside components:
  - Place after imports and interfaces, before pure functions
  - Use SCREAMING_SNAKE_CASE for naming (e.g., `TEMPLATE_FEATURES`, `TECH_STACK`) constants
  - **Always explicitly type constants** with appropriate type annotations
  - Examples: `const API_URL: string = "..."`, `const MAX_RETRIES: number = 3`
  - Use `as const` for immutable values when type inference is sufficient
  - Group related constants together

#### Custom Hooks Organization

- **Custom hooks** must be extracted to separate files in the `/hooks/` directory:
  - Use kebab-case file naming: `use-scroll-detection.ts`, `use-local-storage.ts`
  - Start hook names with `use` prefix following React conventions
  - Place hooks in `/hooks/` folder at project root level
  - Export hooks using named exports: `export const useScrollDetection = () => {}`
  - **Always explicitly type hook return values** and parameters
  - Examples: `useScrollDetection(): boolean`, `useLocalStorage<T>(key: string): [T, (value: T) => void]`
  - Group related hooks in the same file only if they're tightly coupled

#### Whitespace and Formatting Rules

- **Component variable organization**: Maintain consistent whitespace between different types of declarations:
  - Add a blank line between React state declarations and custom hook calls
  - Add a blank line between custom hook calls and other variable declarations
  - Example:

    ```tsx
    const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false)
    const [isVisible, setIsVisible] = useState<boolean>(true)

    const isScrolled: boolean = useScrollDetection()
    const userData: UserData = useUserData()

    const processedData: ProcessedData = processUserData(userData)
    ```

#### Nested Component Structure for Complex Components

When a component has multiple distinct sections, create nested folder structure:

```
dashboard-welcome/
├── dashboard-welcome.tsx           // Main orchestrator component
├── greeting.tsx                    // Self-contained greeting section
├── whats-included/                 // Folder for multi-part section
│   ├── whats-included.tsx         // Section orchestrator
│   ├── whats-included-title.tsx   // Title sub-component
│   └── whats-included-features.tsx // Features list sub-component
├── core-technologies/              // Folder for multi-part section
│   ├── core-technologies.tsx      // Section orchestrator
│   ├── core-technologies-title.tsx // Title sub-component
│   └── core-technologies-list.tsx  // Tech list sub-component
└── get-started/                    // Folder for multi-part section
    ├── get-started.tsx             // Section orchestrator
    ├── get-started-title.tsx       // Title sub-component
    ├── get-started-features.tsx    // Features grid sub-component
    └── get-started-feature-2.tsx   // Individual feature card
```

#### Component Organization Rules

1. **Main orchestrator**: Composition only, minimal logic, imports and renders sub-components
2. **Section orchestrators**: Handle section-specific logic, render related sub-components
3. **Leaf components**: Single responsibility, pure presentation, accept props only
4. **Shared constants**: Extract to file level, use proper naming conventions
5. **Pure functions**: Extract above component definitions, properly typed
6. **File structure**: Mirror logical component hierarchy in folder structure

### Application Guidelines

1. Apply these standards to all new code and when refactoring existing code
2. When making any code changes, ensure they conform to these guidelines
3. If existing code doesn't follow these standards, update it to comply when modifying those files
4. Use these standards as a checklist when reviewing code changes
5. Prefer extracting helper functions over writing long, complex functions
6. Always prioritize code readability and maintainability

## Database Schema

### Current Tables

- **Profiles**: User profiles with Stripe integration and membership tiers

### Schema Location

- Schemas: `/db/schema/`
- Migrations: `/db/migrations/`
- Database connection: `/db/db.ts`

## Testing and Deployment

- The project uses Vercel for deployment
- No specific test framework is configured - check with user if testing is needed
- Always run `yarn build` and `yarn type-check` before considering work complete
