Development Workflow and Tools 🛠️

Set up your development environment and master the CrittrHavens workflow. A comprehensive guide for productive reptile care software development.

Developer working on laptop with multiple screens showing code

Local Development Setup

Get up and running in minutes.

Prerequisites

Required Software:

# Node.js (v18 or higher)
node --version  # Should output v18.x.x or higher

# npm (comes with Node.js)
npm --version   # Should output 9.x.x or higher

# Git
git --version   # Should output 2.x.x or higher

# Supabase CLI (optional but recommended)
supabase --version

Initial Setup

Clone and Install:

# Clone the repository
git clone https://github.com/your-org/crittrhavens.git
cd crittrhavens

# Install dependencies
npm install

# Copy environment variables
cp .env.example .env.local

# Start local development
npm run dev

Environment Configuration

.env.local Setup:

# Supabase Configuration
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key

# Stripe Configuration (optional)
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxx

# Feature Flags
VITE_ENABLE_PWA=true
VITE_ENABLE_ANALYTICS=false

# Development Settings
VITE_DEV_TOOLS=true
VITE_LOG_LEVEL=debug

Database Setup

Local Supabase Instance:

# Install Supabase CLI
npm install -g supabase

# Start local Supabase
supabase start

# This will output:
# API URL: http://localhost:54321
# DB URL: postgresql://postgres:postgres@localhost:54322/postgres
# Studio URL: http://localhost:54323

# Run migrations
supabase db push

# Seed database (optional)
psql $DATABASE_URL < supabase/seed.sql

First Run Checklist

After setup:

  • Application loads at http://localhost:8080
  • Can create an account and log in
  • Database connection working
  • Hot reload functioning
  • No console errors

VS Code Configuration

Optimize your editor for CrittrHavens development.

Essential Extensions:

// .vscode/extensions.json
{
  "recommendations": [
    // Language Support
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "bradlc.vscode-tailwindcss",
    
    // React Development
    "dsznajder.es7-react-js-snippets",
    "burkeholland.simple-react-snippets",
    
    // TypeScript
    "ms-vscode.vscode-typescript-next",
    
    // Testing
    "vitest.explorer",
    "Orta.vscode-jest",
    
    // Git
    "eamodio.gitlens",
    "mhutchie.git-graph",
    
    // Database
    "mtxr.sqltools",
    "mtxr.sqltools-driver-pg",
    
    // Utilities
    "christian-kohler.path-intellisense",
    "formulahendry.auto-rename-tag",
    "naumovs.color-highlight"
  ]
}

Workspace Settings

VS Code Configuration:

// .vscode/settings.json
{
  // Editor
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.organizeImports": true
  },
  
  // TypeScript
  "typescript.preferences.importModuleSpecifier": "relative",
  "typescript.updateImportsOnFileMove.enabled": "always",
  
  // Tailwind CSS
  "tailwindCSS.experimental.classRegex": [
    ["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
  ],
  
  // Files
  "files.exclude": {
    "**/node_modules": true,
    "**/.git": true,
    "**/dist": true
  },
  
  // Search
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "package-lock.json": true
  }
}

Code Snippets

Custom React Snippets:

// .vscode/snippets/react.code-snippets
{
  "React Component": {
    "prefix": "rfc",
    "body": [
      "import { FC } from 'react';",
      "",
      "interface ${1:Component}Props {",
      "  $2",
      "}",
      "",
      "export const ${1:Component}: FC<${1:Component}Props> = ({$3}) => {",
      "  return (",
      "    <div>",
      "      $0",
      "    ",
      "  );",
      "};"
    ]
  },
  
  "Custom Hook": {
    "prefix": "hook",
    "body": [
      "import { useState, useEffect } from 'react';",
      "",
      "export function use${1:Hook}() {",
      "  const [state, setState] = useState($2);",
      "  ",
      "  useEffect(() => {",
      "    $3",
      "  }, []);",
      "  ",
      "  return state;",
      "}"
    ]
  }
}

Git Workflow and Branching

Collaborative development with Git.

Branch Strategy

Git Flow Model:

main
├── develop
│   ├── feature/add-crittr-notes
│   ├── feature/improve-feeding-tracker
│   └── feature/vet-report-generator
├── release/v1.2.0
└── hotfix/fix-login-issue

Branch Naming Conventions

Standard Prefixes:

  • feature/ - New features
  • bugfix/ - Bug fixes
  • hotfix/ - Urgent production fixes
  • refactor/ - Code refactoring
  • docs/ - Documentation updates
  • test/ - Test additions/fixes

Git Workflow

Feature Development:

# 1. Create feature branch from develop
git checkout develop
git pull origin develop
git checkout -b feature/add-temperature-tracking

# 2. Make changes and commit
git add .
git commit -m "feat: add temperature tracking to habitat details"

# 3. Keep branch updated
git fetch origin
git rebase origin/develop

# 4. Push to remote
git push origin feature/add-temperature-tracking

# 5. Create pull request
gh pr create --base develop --head feature/add-temperature-tracking

Commit Message Format

Conventional Commits:

# Format: <type>(<scope>): <subject>

# Examples:
git commit -m "feat(crittrs): add photo upload functionality"
git commit -m "fix(auth): resolve login timeout issue"
git commit -m "docs(readme): update installation instructions"
git commit -m "style(ui): improve button hover states"
git commit -m "refactor(api): simplify data fetching logic"
git commit -m "test(crittrs): add unit tests for CrittrCard"
git commit -m "chore(deps): update React Query to v5"

Pre-commit Hooks

Husky Configuration:

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md}": [
      "prettier --write"
    ]
  }
}

Code Review Process

Maintaining code quality through peer review.

Pull Request Template

PR Description:

<!-- .github/pull_request_template.md -->
## Description
Brief description of changes

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed

## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No console.log statements
- [ ] Performance impact considered

## Screenshots
If applicable, add screenshots

## Related Issues
Fixes #(issue number)

Review Guidelines

Code Review Checklist:

  • Functionality: Does it work as intended?
  • Design: Is the code well-structured?
  • Performance: Any performance concerns?
  • Security: Any security vulnerabilities?
  • Testing: Adequate test coverage?
  • Documentation: Code properly documented?
  • Style: Follows project conventions?

Review Commands

GitHub CLI Review:

# List PRs needing review
gh pr list --label "needs-review"

# Check out PR locally
gh pr checkout 123

# Approve PR
gh pr review --approve

# Request changes
gh pr review --request-changes --body "Please add tests"

# Comment on PR
gh pr comment 123 --body "Great work! Just one small suggestion..."

Debugging Techniques

Finding and fixing issues efficiently.

VS Code Debugging

Launch Configuration:

// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Launch Chrome",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}/src",
      "sourceMaps": true,
      "sourceMapPathOverrides": {
        "webpack:///src/*": "${webRoot}/*"
      }
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Tests",
      "runtimeExecutable": "npm",
      "runtimeArgs": ["test", "--", "--inspect-brk"],
      "port": 9229,
      "skipFiles": ["<node_internals>/**"]
    }
  ]
}

Console Debugging

Debugging Utilities:

// Debug helper functions
export const debug = {
  // Conditional logging
  log: (message: string, data?: any) => {
    if (import.meta.env.DEV) {
      console.log(`🐛 ${message}`, data);
    }
  },
  
  // Performance timing
  time: (label: string) => {
    if (import.meta.env.DEV) {
      console.time(label);
    }
  },
  
  timeEnd: (label: string) => {
    if (import.meta.env.DEV) {
      console.timeEnd(label);
    }
  },
  
  // Table display
  table: (data: any) => {
    if (import.meta.env.DEV) {
      console.table(data);
    }
  },
  
  // Stack trace
  trace: (message?: string) => {
    if (import.meta.env.DEV) {
      console.trace(message);
    }
  }
};

// Usage
debug.log('Fetching crittrs', { havenId });
debug.time('API Call');
// ... api call
debug.timeEnd('API Call');

Network Debugging

Intercepting Requests:

// Debug network requests
if (import.meta.env.DEV) {
  window.addEventListener('fetch', (event) => {
    console.group(`🌐 ${event.request.method} ${event.request.url}`);
    console.log('Headers:', event.request.headers);
    console.groupEnd();
  });
}

// Log Supabase queries
const { data, error } = await supabase
  .from('crittrs')
  .select('*')
  .eq('haven_id', havenId);

if (import.meta.env.DEV) {
  console.log('Query:', { table: 'crittrs', filter: { haven_id: havenId }, result: data });
}

Browser DevTools Usage

Mastering browser developer tools.

Performance Profiling

Chrome DevTools Performance:

// Mark performance events
performance.mark('crittr-list-start');

// ... render component

performance.mark('crittr-list-end');
performance.measure('crittr-list-render', 'crittr-list-start', 'crittr-list-end');

// View in Performance tab
const measures = performance.getEntriesByType('measure');
console.table(measures);

Memory Profiling

Finding Memory Leaks:

// Take heap snapshot before
// Perform action 5 times
// Take heap snapshot after
// Compare snapshots

// Memory leak detection helper
class MemoryMonitor {
  private initialMemory: number;
  
  start() {
    if (performance.memory) {
      this.initialMemory = performance.memory.usedJSHeapSize;
      console.log('Initial memory:', this.formatBytes(this.initialMemory));
    }
  }
  
  check(label: string) {
    if (performance.memory) {
      const current = performance.memory.usedJSHeapSize;
      const diff = current - this.initialMemory;
      console.log(`${label}: ${this.formatBytes(current)} (${diff > 0 ? '+' : ''}${this.formatBytes(diff)})`);
    }
  }
  
  private formatBytes(bytes: number): string {
    return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
  }
}

Network Tab Analysis

Optimizing Network Requests:

// Log slow requests
const slowRequestThreshold = 1000; // 1 second

const originalFetch = window.fetch;
window.fetch = async (...args) => {
  const start = performance.now();
  const response = await originalFetch(...args);
  const duration = performance.now() - start;
  
  if (duration > slowRequestThreshold) {
    console.warn(`Slow request (${duration.toFixed(0)}ms):`, args[0]);
  }
  
  return response;
};

React DevTools

Debugging React applications.

Component Profiling

React DevTools Profiler:

import { Profiler } from 'react';

function onRenderCallback(
  id: string,
  phase: 'mount' | 'update',
  actualDuration: number
) {
  // Send to analytics in production
  if (actualDuration > 16) { // Slower than 60fps
    console.warn(`Slow render: ${id} took ${actualDuration}ms`);
  }
}

export function ProfiledCrittrList() {
  return (
    <Profiler id="CrittrList" onRender={onRenderCallback}>
      <CrittrList />
    </Profiler>
  );
}

Component Inspector

Debugging Props and State:

// Add display names for better debugging
CrittrCard.displayName = 'CrittrCard';

// Debug hook for inspecting renders
export function useWhyDidYouUpdate(name: string, props: Record<string, any>) {
  const previousProps = useRef<Record<string, any>>();
  
  useEffect(() => {
    if (previousProps.current) {
      const allKeys = Object.keys({ ...previousProps.current, ...props });
      const changedProps: Record<string, any> = {};
      
      allKeys.forEach(key => {
        if (previousProps.current![key] !== props[key]) {
          changedProps[key] = {
            from: previousProps.current![key],
            to: props[key]
          };
        }
      });
      
      if (Object.keys(changedProps).length) {
        console.log('[why-did-you-update]', name, changedProps);
      }
    }
    
    previousProps.current = props;
  });
}

Database GUI Tools

Visual database management.

Supabase Studio

Local Studio Access:

# Start local Supabase
supabase start

# Open Studio in browser
open http://localhost:54323

# Features available:
# - Table editor
# - SQL editor
# - Database functions
# - RLS policies
# - Realtime logs

TablePlus Configuration

Database Connection:

{
  "name": "CrittrHavens Local",
  "host": "localhost",
  "port": 54322,
  "user": "postgres",
  "password": "postgres",
  "database": "postgres",
  "ssl": false
}

pgAdmin Setup

Docker pgAdmin:

# docker-compose.yml
services:
  pgadmin:
    image: dpage/pgadmin4
    ports:
      - "5050:80"
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@crittrhavens.com
      PGADMIN_DEFAULT_PASSWORD: admin
    volumes:
      - pgadmin:/var/lib/pgadmin

Performance Profiling

Measuring and optimizing performance.

Lighthouse CI

Automated Performance Testing:

// lighthouserc.js
module.exports = {
  ci: {
    collect: {
      url: ['http://localhost:8080'],
      numberOfRuns: 3,
      settings: {
        preset: 'desktop',
        throttling: {
          cpuSlowdownMultiplier: 1
        }
      }
    },
    assert: {
      assertions: {
        'categories:performance': ['warn', { minScore: 0.9 }],
        'categories:accessibility': ['error', { minScore: 0.95 }],
        'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
        'largest-contentful-paint': ['warn', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['warn', { maxNumericValue: 0.1 }]
      }
    }
  }
};

Bundle Analysis

Vite Bundle Visualizer:

# Install plugin
npm install -D rollup-plugin-visualizer

# Add to vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';

export default {
  plugins: [
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true
    })
  ]
};

# Build and analyze
npm run build

React Query DevTools

Query Performance:

import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Your app */}
      {import.meta.env.DEV && (
        <ReactQueryDevtools 
          initialIsOpen={false}
          position="bottom-right"
        />
      )}
    </QueryClientProvider>
  );
}

Deployment Process

Shipping code to production.

Build Process

Production Build:

# Install dependencies
npm ci

# Run tests
npm test

# Build for production
npm run build

# Preview build locally
npm run preview

# Check bundle size
npm run analyze

Environment-Specific Builds

Multi-Environment Configuration:

// vite.config.ts
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd());
  
  return {
    define: {
      __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
      __BUILD_TIME__: JSON.stringify(new Date().toISOString()),
      __COMMIT_SHA__: JSON.stringify(process.env.GITHUB_SHA || 'local')
    },
    build: {
      sourcemap: mode === 'development',
      minify: mode === 'production' ? 'terser' : false
    }
  };
});

CI/CD Pipeline

GitHub Actions Deployment:

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test
      
      - name: Build
        run: npm run build
        env:
          VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
          VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
      
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v20
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.ORG_ID }}
          vercel-project-id: ${{ secrets.PROJECT_ID }}
          vercel-args: '--prod'

Deployment Checklist

Before deploying:

  • All tests passing
  • Build succeeds without warnings
  • Environment variables configured
  • Database migrations run
  • Performance budget met
  • Security headers configured
  • Error tracking enabled
  • Analytics configured
  • Backup created
  • Rollback plan ready

Best Practices

Development workflow guidelines.

Code Quality

Maintaining Standards:

  • Write tests for new features
  • Document complex logic
  • Use TypeScript strictly
  • Follow naming conventions
  • Keep components small
  • Optimize for performance

Collaboration

Team Workflow:

  • Create draft PRs early
  • Request reviews promptly
  • Respond to feedback constructively
  • Update documentation
  • Communicate blockers
  • Share knowledge

Productivity Tips

Development Efficiency:

# Useful aliases
alias gc="git commit -m"
alias gp="git push"
alias gl="git pull"
alias gs="git status"
alias nr="npm run"

# Quick commands
nr dev         # Start development
nr build       # Build for production
nr test        # Run tests
nr lint        # Check code quality

Common Issues and Solutions

Troubleshooting guide.

Development Issues

Common Problems:

# Port already in use
lsof -i :8080
kill -9 <PID>

# Clear npm cache
npm cache clean --force
rm -rf node_modules package-lock.json
npm install

# Reset database
supabase db reset

# Clear build cache
rm -rf dist .vite

Git Issues

Recovery Commands:

# Undo last commit (keep changes)
git reset --soft HEAD~1

# Discard local changes
git checkout -- .

# Fix diverged branches
git fetch origin
git reset --hard origin/develop

# Cherry-pick specific commit
git cherry-pick <commit-hash>

Next Steps

Continue improving your workflow.


Developing reptile care software with the efficiency of a well-organized terrarium. 🦎