• Skip to main content
  • Skip to navigation
  • Skip to search
    Petunia™
    FeaturesPricingIntegrationsAboutContact
    Log inStart free trialSign up
    Loading
    Petunia™

    Reimagining customer communication for the modern business.

    Product

    • Features
    • Pricing
    • Integrations
    • Roadmap
    • What's New

    Resources

    • Help Center
    • Documentation
    • Guides
    • API Reference
    • Community
    • Support

    Company

    • About Us
    • Careers
    • Blog
    • Press
    • Contact

    © 2026 Gray Group International LLC. All rights reserved.·
    Made by gardenpatch 🌱

    Privacy PolicyTerms of ServiceCookie Policy

    Petunia™ is a trademark of Gray Group International LLC. The Petunia name, brand, product design, and content are proprietary. Unauthorized use, imitation, or copying is prohibited.

    Documentation

    DEVELOPER_GUIDE

    docs/DEVELOPER_GUIDE.md
    Docs homeGuidesSupport
    Quick links
    Start here
    How the docs are organized.
    Environment setup
    Configure env + run locally.
    Unified Inbox
    Inbox concepts & behavior.
    Voice AI setup
    Providers, Twilio, testing.
    Pricing model
    Source-of-truth pricing.
    Operations runbook
    How to operate safely.

    Petunia Developer Guide

    Version: 1.0.0 Last Updated: 2025-12-13 Status: Complete Onboarding Guide

    Welcome to Petunia! This guide will help you set up your development environment, understand the project structure, and become productive quickly.


    Table of Contents

    1. Quick Start
    2. Development Environment Setup
    3. Project Structure
    4. Key Architectural Patterns
    5. Common Development Workflows
    6. Testing Guidelines
    7. Code Style and Conventions
    8. Troubleshooting
    9. Additional Resources

    Quick Start

    Get up and running in 5 minutes:

    # 1. Clone the repository
    git clone https://github.com/gardenpatch-xyz/petunia.git
    cd petunia
    
    # 2. Install dependencies (pnpm is required)
    pnpm install
    
    # 3. Set up environment variables
    cp .env.example .env.local
    # Edit .env.local with your configuration (see Environment Setup below)
    
    # 4. Validate environment
    pnpm prestart
    
    # 5. Generate Prisma client and start dev server
    pnpm dev
    
    # 6. Open http://localhost:3000
    

    Prerequisites

    • Node.js: 22.x (check with node --version)
    • pnpm: 10.12.1+ (install with npm install -g pnpm)
    • PostgreSQL: Access to a Supabase project or local PostgreSQL instance
    • Git: For version control

    Development Environment Setup

    1. Node.js and pnpm

    # Install Node.js 22.x via nvm (recommended)
    nvm install 22
    nvm use 22
    
    # Install pnpm globally
    npm install -g pnpm@10.12.1
    

    2. Environment Variables

    Petunia uses environment variables for configuration. Follow these steps:

    # Copy the example file
    cp .env.example .env.local
    

    Required Variables (minimum for local development):

    # Supabase Configuration
    NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
    SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
    
    # Database
    DATABASE_URL=postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres?pgbouncer=true
    DIRECT_DATABASE_URL=postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres
    
    # Application
    NEXT_PUBLIC_SITE_URL=http://localhost:3000
    
    # Security Keys (generate with: openssl rand -base64 32)
    SESSION_SECRET=your-session-secret
    CSRF_SECRET=your-csrf-secret
    CREDENTIALS_ENCRYPTION_KEY=your-encryption-key
    ADMIN_API_KEY=your-admin-api-key
    INTERNAL_API_KEY=your-internal-api-key
    CRON_SECRET=your-cron-secret
    

    Where to Get Keys:

    • Supabase Keys: Supabase Dashboard → Settings → API
    • Database URLs: Supabase Dashboard → Settings → Database → Connection String
    • Security Keys: Generate with openssl rand -base64 32

    For a complete list of environment variables, see docs/env/ENV_GUIDE.md.

    IMPORTANT: NEVER commit .env.local or .env.production to git. Only .env.example should be committed.

    3. Database Setup

    # Run database migrations (creates tables)
    pnpm prisma migrate dev
    
    # Generate Prisma client (required after schema changes)
    pnpm prisma generate
    
    # Seed demo data (optional, takes ~4 minutes)
    pnpm prisma db seed
    

    4. Verify Installation

    # Run type checking
    pnpm typecheck
    
    # Run tests
    pnpm test
    
    # Build the application
    pnpm build:prod
    

    If all commands succeed, you're ready to develop!


    Project Structure

    Petunia follows a strict directory structure for maintainability. Here's the layout:

    /Users/tiago/Documents/Projects/petunia/
    ├── app/                    # Next.js App Router
    │   ├── api/               # ALL API routes (single source of truth)
    │   │   ├── auth/          # Authentication endpoints
    │   │   ├── onboarding/    # User onboarding
    │   │   ├── inbox/         # Unified inbox
    │   │   ├── voice/         # Voice AI
    │   │   └── webhooks/      # Third-party webhooks
    │   ├── (client)/          # Client-facing pages (dashboard, inbox, etc.)
    │   ├── (public)/          # Public pages (landing, pricing, etc.)
    │   ├── (admin)/           # Admin pages
    │   ├── (system)/          # System pages (onboarding, settings)
    │   └── layout.tsx         # Root layout
    │
    ├── components/            # React components
    │   ├── ui/               # shadcn/ui components
    │   └── [feature]/        # Feature-specific components
    │
    ├── lib/                   # Core application logic
    │   ├── hooks/            # Custom React hooks (FLAT structure preferred)
    │   ├── providers/        # React Context providers
    │   ├── utils/            # Utility functions
    │   ├── types/            # TypeScript type definitions
    │   ├── services/         # Business logic services
    │   ├── auth/             # Authentication utilities
    │   ├── database/         # Database utilities
    │   └── [domain]/         # Domain-specific code
    │
    ├── tests/                 # ALL test files (mirrors source structure)
    │   ├── lib/              # Tests for /lib code
    │   ├── components/       # Tests for /components code
    │   ├── app/              # Tests for /app routes
    │   ├── utils/            # Test utilities
    │   └── mocks/            # Test mocks
    │
    ├── prisma/                # Database schema and migrations
    │   ├── schema.prisma     # Database schema (133+ models)
    │   ├── migrations/       # Database migrations
    │   └── seed.ts           # Database seeding script
    │
    ├── docs/                  # Documentation
    │   ├── features/         # Feature-specific docs
    │   ├── env/              # Environment variable docs
    │   ├── security/         # Security docs
    │   └── [topic]/          # Topic-specific docs
    │
    ├── scripts/               # Utility scripts
    │   ├── verify-env.ts     # Environment validation
    │   ├── auth-init.mjs     # Auth initialization
    │   └── [script].ts       # Other scripts
    │
    ├── public/                # Static assets
    ├── cypress/               # E2E tests (Cypress)
    ├── e2e/                   # E2E tests (Playwright)
    └── realtime-server/       # WebSocket server
    

    Key Directories Explained

    DirectoryPurposeRules
    /app/api/ALL API routesNEVER create API routes elsewhere (no route groups)
    /tests/ALL test filesMirror source paths (e.g., /lib/auth/ → /tests/lib/auth/)
    /lib/hooks/Custom React hooksKeep FLAT unless part of feature module
    /lib/providers/React Context providersALL providers go here (no /contexts/)
    /lib/utils/Utility functionsSingle source of truth for utilities
    /lib/types/TypeScript typesSingle source of truth for types
    /docs/DocumentationPersistent docs only (use .tmp/ for work-in-progress)

    Path Aliases (tsconfig.json)

    // Use these aliases in imports
    import { Button } from '@/components/ui/button';
    import { logger } from '@/lib/utils/logging';
    import { createClient } from '@/lib/utils/supabase/server';
    import type { AuthUser } from '@/lib/types/auth';
    import { useAuth } from '@/hooks/auth/useAuth';
    import { AuthProvider } from '@/lib/providers/AuthContext';
    

    Key Architectural Patterns

    1. Multi-Tenant Architecture (Portal-First)

    Petunia is a multi-tenant platform where Portal is the primary tenant boundary.

    Entity Hierarchy:

    User → Company → Client → Portal
                               ├── Conversations
                               ├── Leads
                               ├── Contacts
                               └── Reviews
    

    Key Concepts:

    • Portal: Workspace container (identified by petuniaID)
    • Company: Business organization (persists across portals)
    • Client: Organization representation (legacy, 1:1 with Company)
    • User: Authenticated identity with role-based access

    Row-Level Security (RLS): All database queries are protected by 4 layers:

    1. Middleware (session verification)
    2. Service layer (authorization checks)
    3. Query layer (portal filtering)
    4. RLS policies (database-level enforcement)

    See docs/ARCHITECTURE.md for complete details.

    2. Next.js App Router

    Petunia uses Next.js 15 with the App Router:

    Route Groups:

    • (client) - Client-facing pages (dashboard, inbox)
    • (public) - Public pages (landing, pricing)
    • (admin) - Admin pages (user management)
    • (system) - System pages (onboarding, settings)

    Important: Route groups are for PAGES ONLY. API routes MUST be in /app/api/.

    Navigation:

    // ✅ CORRECT - Client-side navigation
    import { useRouter } from 'next/navigation';
    const router = useRouter();
    router.push('/dashboard');
    
    // ❌ WRONG - Full page reload
    window.location.href = '/dashboard';
    

    Exceptions (when to use window.location.href):

    • Logout (intentional full reload)
    • OAuth flows (preserves user gesture chain)
    • Post-auth redirects (ensures clean React tree)

    3. Authentication & Security

    Stack:

    • Supabase Auth: Email/password, OAuth (Google, Facebook)
    • TOTP 2FA: Two-factor authentication via otplib
    • Session Management: Encrypted sessions with rotation

    Auth Patterns:

    // Server Components
    import { createClient } from '@/lib/utils/supabase/server';
    
    export default async function Page() {
      const supabase = await createClient();
      const { data: { user } } = await supabase.auth.getUser();
      if (!user) redirect('/auth/signin');
      // ...
    }
    
    // Client Components
    'use client';
    import { useAuth } from '@/hooks/auth/useAuth';
    
    export function Component() {
      const { user, isLoading } = useAuth();
      if (isLoading) return <Spinner />;
      if (!user) return <SignInPrompt />;
      // ...
    }
    

    See docs/features/AUTHENTICATION.md.

    4. Database Access (Prisma)

    Prisma Client:

    import { db } from '@/lib/database';
    
    // Always filter by portal for tenant isolation
    const conversations = await db.conversation.findMany({
      where: { portalId: userPortal.id },
      orderBy: { updatedAt: 'desc' }
    });
    

    Service Layer Pattern:

    // lib/services/conversation.ts
    export async function getConversations(portalId: string) {
      // Authorization checks
      if (!portalId) throw new Error('Portal ID required');
    
      // Query with RLS
      return db.conversation.findMany({
        where: { portalId },
        include: { messages: true }
      });
    }
    

    5. API Routes

    Standard Pattern:

    // app/api/example/route.ts
    import { NextRequest, NextResponse } from 'next/server';
    import { createClient } from '@/lib/utils/supabase/server';
    
    export async function GET(request: NextRequest) {
      try {
        // 1. Authenticate
        const supabase = await createClient();
        const { data: { user } } = await supabase.auth.getUser();
        if (!user) {
          return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
        }
    
        // 2. Get portal context
        const portalId = request.headers.get('x-portal-id');
        if (!portalId) {
          return NextResponse.json({ error: 'Portal ID required' }, { status: 400 });
        }
    
        // 3. Authorize access
        // ... authorization logic
    
        // 4. Query data
        const data = await getDataForPortal(portalId);
    
        // 5. Return response
        return NextResponse.json({ data });
      } catch (error) {
        console.error('API error:', error);
        return NextResponse.json(
          { error: 'Internal server error' },
          { status: 500 }
        );
      }
    }
    

    6. Real-Time Updates

    WebSocket Server:

    // Realtime server runs separately
    pnpm realtime:dev
    
    // Client usage
    import { useRealtimeConnection } from '@/hooks/useRealtimeConnection';
    
    export function InboxPage() {
      const { isConnected, subscribe } = useRealtimeConnection();
    
      useEffect(() => {
        const unsubscribe = subscribe('conversations', (message) => {
          // Handle real-time message
        });
        return unsubscribe;
      }, [subscribe]);
    }
    

    See docs/features/REAL_TIME_WEBSOCKET.md.


    Common Development Workflows

    Creating a New Feature

    1. Check for existing implementations first:

      # Search for similar files
      find . -name "*keyword*"
      
      # Search for similar functionality
      grep -r "keyword" lib/
      
    2. Create files in correct locations:

      # Component
      touch components/feature/MyComponent.tsx
      
      # Hook (FLAT preferred)
      touch lib/hooks/useMyFeature.ts
      
      # Service
      touch lib/services/myFeature.ts
      
      # API route
      touch app/api/my-feature/route.ts
      
      # Test (mirrors source)
      touch tests/components/feature/MyComponent.test.tsx
      
    3. Follow existing patterns:

      • Look at similar features in the codebase
      • Maintain consistency with existing code
      • Use TypeScript strictly
    4. Write tests:

      # Run tests in watch mode
      pnpm test -- --watch
      
    5. Verify before committing:

      # Type check
      pnpm typecheck
      
      # Run tests
      pnpm test
      
      # Build
      pnpm build:prod
      

    Making API Changes

    1. Update Prisma schema (if needed):

      # Edit prisma/schema.prisma
      
      # Create migration
      pnpm prisma migrate dev --name add_my_field
      
      # Generate client
      pnpm prisma generate
      
    2. Create/update API route:

      // app/api/my-endpoint/route.ts
      export async function POST(request: NextRequest) {
        // Implementation
      }
      
    3. Write API tests:

      // tests/app/api/my-endpoint/route.test.ts
      import { POST } from '@/app/api/my-endpoint/route';
      
      describe('POST /api/my-endpoint', () => {
        it('should create resource', async () => {
          // Test implementation
        });
      });
      
    4. Test manually:

      # Start dev server
      pnpm dev
      
      # Test with curl
      curl -X POST http://localhost:3000/api/my-endpoint \
        -H "Content-Type: application/json" \
        -d '{"data": "value"}'
      

    Running the Application

    # Development mode (Next.js + Prisma generation)
    pnpm dev
    
    # Development mode with real-time server
    pnpm dev:all
    
    # Production build
    pnpm build:prod
    
    # Start production server
    pnpm start
    

    Database Operations

    # Run migrations
    pnpm prisma migrate dev
    
    # Reset database (CAUTION: deletes all data)
    pnpm prisma migrate reset
    
    # Open Prisma Studio (database GUI)
    pnpm prisma:studio
    
    # Seed demo data
    pnpm prisma db seed
    
    # Check database health
    pnpm db:health
    

    Git Workflow

    # Create feature branch
    git checkout -b feature/my-feature
    
    # Make changes and commit
    git add .
    git commit -m "feat: Add my feature"
    
    # Pre-push hooks automatically run:
    # - pnpm typecheck:strict (must pass with 0 errors)
    # - pnpm build:prod (must succeed)
    
    # Push to remote
    git push origin feature/my-feature
    
    # Create pull request on GitHub
    

    Commit Message Conventions:

    feat: Add new feature
    fix: Fix bug in authentication
    chore: Update dependencies
    docs: Update developer guide
    test: Add tests for inbox
    refactor: Improve database queries
    

    Testing Guidelines

    Petunia has comprehensive testing infrastructure. See /TESTING.md for complete details.

    Test Structure

    ALL tests go in /tests/ directory (mirrors source structure):

    /lib/services/conversation.ts
      → /tests/lib/services/conversation.test.ts
    
    /components/ui/button.tsx
      → /tests/components/ui/button.test.tsx
    
    /app/api/inbox/route.ts
      → /tests/app/api/inbox/route.test.ts
    

    Running Tests

    # Run all tests
    pnpm test
    
    # Run tests in watch mode
    pnpm test -- --watch
    
    # Run specific test file
    pnpm test -- tests/lib/auth/useAuth.test.ts
    
    # Run tests with coverage
    pnpm test:coverage
    
    # Run E2E tests (Cypress)
    pnpm cypress:open
    
    # Run E2E tests (Playwright)
    pnpm playwright:test
    

    Writing Unit Tests

    // tests/lib/services/myService.test.ts
    import { myFunction } from '@/lib/services/myService';
    
    describe('myFunction', () => {
      it('should return expected result', () => {
        const result = myFunction('input');
        expect(result).toBe('expected');
      });
    
      it('should handle errors', () => {
        expect(() => myFunction(null)).toThrow();
      });
    });
    

    Writing API Tests

    // tests/app/api/my-endpoint/route.test.ts
    import { POST } from '@/app/api/my-endpoint/route';
    import { NextRequest } from 'next/server';
    
    describe('POST /api/my-endpoint', () => {
      it('should require authentication', async () => {
        const request = new NextRequest('http://localhost:3000/api/my-endpoint');
        const response = await POST(request);
        expect(response.status).toBe(401);
      });
    });
    

    Writing E2E Tests

    // cypress/e2e/my-feature/flow.cy.ts
    describe('My Feature Flow', () => {
      it('should complete user journey', () => {
        cy.visit('/my-feature');
        cy.get('[data-testid="submit-button"]').click();
        cy.url().should('include', '/success');
      });
    });
    

    Test Coverage Goals

    ComponentTarget Coverage
    Critical paths (auth, billing)95%+
    Business logic (services)90%+
    API routes85%+
    UI components80%+
    Utilities95%+

    Code Style and Conventions

    Petunia follows strict coding standards. See /CLAUDE.md for complete guidelines.

    Directory Structure Rules

    MANDATORY Rules (enforced by ESLint and pre-commit hooks):

    1. API Routes: ALL in /app/api/ (no route groups)
    2. Tests: ALL in /tests/ (mirrors source paths)
    3. Hooks: ALL in /lib/hooks/ (FLAT preferred)
    4. Providers: ALL in /lib/providers/
    5. Utils: ALL in /lib/utils/
    6. Types: ALL in /lib/types/

    FORBIDDEN Patterns:

    ❌ /app/(system)/api/          # API routes in route groups
    ❌ /contexts/                  # Use /lib/providers/
    ❌ /utils/                     # Use /lib/utils/
    ❌ /types/                     # Use /lib/types/
    ❌ /hooks/                     # Use /lib/hooks/
    ❌ /components/*/hooks/        # Use /lib/hooks/
    ❌ *.backup.ts                 # No backup files
    ❌ *-v2.ts                     # No version suffixes
    ❌ enhanced-*.ts               # No "improved" variants
    

    File Naming Conventions

    # Components (PascalCase)
    Button.tsx
    ConversationList.tsx
    
    # Hooks (camelCase, start with "use")
    useAuth.ts
    useConversation.ts
    
    # Providers (PascalCase, end with "Context" or "Provider")
    AuthContext.tsx
    ThemeProvider.tsx
    
    # Utils (camelCase or kebab-case)
    logging.ts
    api-client.ts
    
    # Types (camelCase or PascalCase)
    auth.ts
    ApiResponse.ts
    
    # Tests (match source + .test)
    Button.test.tsx
    useAuth.test.ts
    route.test.ts
    

    TypeScript Standards

    // ✅ Use strict types
    interface User {
      id: string;
      email: string;
      name: string | null;
    }
    
    // ✅ Avoid "any" (use "unknown" if needed)
    function parse(data: unknown): User {
      // Type guard
      if (!isUser(data)) throw new Error('Invalid user');
      return data;
    }
    
    // ✅ Use optional chaining and nullish coalescing
    const userName = user?.profile?.name ?? 'Anonymous';
    
    // ✅ Define return types explicitly
    function getUser(id: string): Promise<User | null> {
      return db.user.findUnique({ where: { id } });
    }
    

    Import Organization

    // 1. External dependencies
    import React from 'react';
    import { NextRequest, NextResponse } from 'next/server';
    
    // 2. Internal imports (grouped by alias)
    import { Button } from '@/components/ui/button';
    import { useAuth } from '@/hooks/auth/useAuth';
    import { logger } from '@/lib/utils/logging';
    import type { User } from '@/lib/types/auth';
    
    // 3. Relative imports (if needed)
    import { helper } from './helper';
    

    Error Handling

    // ✅ Structured error handling
    try {
      const result = await riskyOperation();
      return NextResponse.json({ data: result });
    } catch (error) {
      // Log with context
      console.error('Operation failed:', {
        error: error instanceof Error ? error.message : 'Unknown error',
        stack: error instanceof Error ? error.stack : undefined,
        context: { userId, portalId }
      });
    
      // Return user-friendly error
      return NextResponse.json(
        { error: 'Operation failed', details: 'Please try again' },
        { status: 500 }
      );
    }
    

    Logging

    import { logger } from '@/lib/utils/logging';
    
    // ✅ Structured logging with context
    logger.info('User action', {
      action: 'create_conversation',
      userId: user.id,
      portalId: portal.id,
      conversationId: conversation.id
    });
    
    // ✅ Error logging with stack traces
    logger.error('Database error', {
      error: error.message,
      stack: error.stack,
      query: 'findMany',
      model: 'Conversation'
    });
    

    Pre-commit and Pre-push Hooks

    Petunia uses Git hooks to prevent common issues:

    Pre-commit Hook:

    • Blocks forbidden files (backups, enhanced-*, -v2, etc.)
    • Blocks tests outside /tests/ directory
    • Runs pnpm typecheck:strict (must pass with 0 errors)

    Pre-push Hook:

    • Runs pnpm typecheck:strict
    • Runs pnpm build:prod (catches syntax/build errors)

    To bypass (for urgent fixes only):

    git push --no-verify
    

    Troubleshooting

    Common Issues and Solutions

    "Module not found" errors

    # Regenerate Prisma client
    pnpm prisma generate
    
    # Clear Next.js cache
    rm -rf .next
    
    # Reinstall dependencies
    rm -rf node_modules pnpm-lock.yaml
    pnpm install
    

    TypeScript errors

    # Run type check to see all errors
    pnpm typecheck
    
    # Check specific file
    pnpm exec tsc --noEmit path/to/file.ts
    
    # Update TypeScript (if needed)
    pnpm update typescript
    

    Database connection issues

    # Verify DATABASE_URL is correct
    echo $DATABASE_URL
    
    # Test database connection
    pnpm db:health
    
    # Check Prisma can connect
    pnpm prisma db pull
    

    Build failures

    # Clear all caches
    pnpm clean
    
    # Run production build
    pnpm build:prod
    
    # Check for syntax errors
    pnpm typecheck
    

    Tests failing

    # Run tests in watch mode to debug
    pnpm test -- --watch
    
    # Run specific test file
    pnpm test -- tests/path/to/test.test.ts
    
    # Check test environment
    NODE_ENV=test pnpm test
    

    Hydration errors (React)

    Petunia has comprehensive hydration error prevention using the ClientOnly component.

    Quick debugging:

    // Wrap client-only code
    import { ClientOnly } from '@/components/ClientOnly';
    
    export function MyComponent() {
      return (
        <ClientOnly>
          {/* Client-only content */}
        </ClientOnly>
      );
    }
    

    WebSocket connection issues

    # Start realtime server separately
    pnpm realtime:dev
    
    # Check WebSocket URL in .env.local
    NEXT_PUBLIC_REALTIME_URL=ws://localhost:3001
    NEXT_PUBLIC_WEBSOCKET_URL=ws://localhost:3001
    

    Pre-push hook failures

    # Run checks manually
    pnpm typecheck:strict
    pnpm build:prod
    
    # Fix errors before pushing
    # Or bypass for urgent fixes (not recommended)
    git push --no-verify
    

    Getting Help

    1. Check existing documentation:

      • README.md - Project overview
      • TESTING.md - Testing guide
      • CONTRIBUTING.md - Contributing guidelines
      • docs/ARCHITECTURE.md - Architecture details
      • docs/features/ - Feature-specific docs
    2. Search the codebase:

      # Find similar implementations
      grep -r "pattern" lib/
      
      # Find files by name
      find . -name "*keyword*"
      
    3. Ask the team:

      • Open an issue on GitHub
      • Check team communication channels

    Additional Resources

    Documentation

    • README.md - Project overview and quick start
    • TESTING.md - Comprehensive testing guide
    • CONTRIBUTING.md - Contributing guidelines
    • CLAUDE.md - Code organization and standards
    • docs/ARCHITECTURE.md - System architecture
    • docs/env/ENV_GUIDE.md - Environment variables
    • docs/features/ - Feature documentation
    • docs/security/ - Security documentation

    Key Features Documentation

    • Authentication - Auth system and patterns
    • Unified Inbox - Inbox architecture
    • Real-Time WebSocket - WebSocket server
    • Voice Providers - Voice AI integration
    • Billing System - Stripe integration
    • Demo Mode - Demo portal configuration

    External Resources

    • Next.js Documentation
    • Prisma Documentation
    • Supabase Documentation
    • React Documentation
    • TypeScript Handbook
    • Tailwind CSS Documentation

    Development Tools

    # Code quality
    pnpm lint                    # Run ESLint
    pnpm format                  # Format with Prettier
    pnpm typecheck              # TypeScript type checking
    
    # Testing
    pnpm test                    # Run unit tests
    pnpm test:coverage          # Run tests with coverage
    pnpm cypress:open           # Open Cypress E2E tests
    pnpm playwright:test        # Run Playwright tests
    
    # Database
    pnpm prisma:studio          # Open database GUI
    pnpm prisma migrate dev     # Run migrations
    pnpm db:health              # Check database health
    
    # Analysis
    pnpm analyze:bundle         # Analyze bundle size
    pnpm analyze:deps           # Find unused dependencies
    

    Next Steps

    Now that you've set up your development environment:

    1. Explore the codebase:

      • Browse /app/api/ to understand API structure
      • Look at /lib/services/ for business logic
      • Check /components/ for UI patterns
    2. Run the demo:

      pnpm prisma db seed
      pnpm dev
      # Visit http://localhost:3000
      
    3. Pick a task:

      • Check open issues on GitHub
      • Look for // TODO comments in code
      • Improve test coverage
    4. Make your first contribution:

      • Follow the Contributing Guide
      • Write tests for your changes
      • Open a pull request

    Welcome to the team! We're excited to have you contribute to Petunia.


    Maintained by: Petunia Engineering Team Last Review: 2025-12-13 Next Review: 2026-01-13

    On this page
    Table of ContentsQuick StartPrerequisitesDevelopment Environment Setup1. Node.js and pnpm2. Environment Variables3. Database Setup4. Verify InstallationProject StructureKey Directories ExplainedPath Aliases (tsconfig.json)Key Architectural Patterns1. Multi-Tenant Architecture (Portal-First)2. Next.js App Router3. Authentication & Security4. Database Access (Prisma)5. API Routes6. Real-Time UpdatesCommon Development WorkflowsCreating a New FeatureMaking API ChangesRunning the ApplicationDatabase OperationsGit WorkflowTesting GuidelinesTest StructureRunning TestsWriting Unit TestsWriting API TestsWriting E2E TestsTest Coverage GoalsCode Style and Conventions