# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Core Commands ### Development ```bash npm run dev # Start Vite dev server at localhost:5173 npm run build # Build production bundle to dist/ npm run preview # Preview production build locally ``` ### Testing & Quality ```bash npm test # Run tests with Vitest npm run lint # Run ESLint ``` ### Docker Operations ```bash docker compose up -d # Start containerized app on port 3800 docker compose down # Stop containers docker compose build # Build Docker images ``` ## Architecture Overview ### Application Type React + TypeScript SPA for carbon offsetting calculations for yachts, built with Vite. Features both desktop and mobile-specific routes with Progressive Web App (PWA) support. ### Key Architectural Patterns **Component Structure**: The app uses a single-page architecture with client-side routing managed through state in `App.tsx`. Navigation changes `currentPage` state rather than using React Router. **Mobile App Route**: Special `/mobile-app` route renders `MobileCalculator` component exclusively, bypassing the standard layout. This is detected via `window.location.pathname` and managed through `isMobileApp` state. **Data Flow**: - Vessel data flows from `App.tsx` → Calculator components → `OffsetOrder` - Carbon calculations happen in `utils/carbonCalculator.ts` - API calls go through dedicated clients in `src/api/` ### API Integration **Wren Climate API** (`src/api/wrenClient.ts`): - Base URL: `https://www.wren.co/api` - Requires Bearer token authentication via `VITE_WREN_API_TOKEN` - Handles portfolio fetching and offset order creation - Implements retry logic and fallback to default portfolio **AIS Client** (`src/api/aisClient.ts`): - Fetches vessel data by IMO number - Currently uses mock data in development **Formspree Integration**: - Contact forms use `VITE_FORMSPREE_CONTACT_ID` and `VITE_FORMSPREE_OFFSET_ID` - Handled in `Contact.tsx` and offset order components ### State Management - Local component state via React hooks - No global state management library - Form state managed locally within components - Calculator results passed via props to OffsetOrder components ### Styling Approach - Tailwind CSS for utility-first styling - Custom glass morphism effects via `index.css` - Framer Motion for animations - Responsive design with mobile-first approach ### Component Responsibilities **Core Components**: - `TripCalculator.tsx`: Desktop carbon calculator with trip details form - `MobileCalculator.tsx`: Mobile-optimized calculator with step-by-step flow - `OffsetOrder.tsx` / `MobileOffsetOrder.tsx`: Handles offset purchase flow - `Home.tsx`: Landing page with hero section and navigation - `Contact.tsx`: Contact form integration **Calculation Logic** (`utils/carbonCalculator.ts`): - Implements DEFRA emission factors - Calculates based on distance, speed, engine power - Returns tons of CO2 and monetary amounts ### Environment Configuration Required environment variables in `.env`: ``` VITE_WREN_API_TOKEN= # Wren API authentication VITE_FORMSPREE_CONTACT_ID= # Contact form endpoint VITE_FORMSPREE_OFFSET_ID= # Offset order form endpoint ``` ### Testing Strategy - Unit tests using Vitest and React Testing Library - Test configuration in `vitest.config.ts` with jsdom environment - Setup file at `src/test/setup.ts` - Test files use pattern `*.test.ts` or `*.test.tsx` - Run all tests: `npm test` - Tests run with global test APIs enabled ### Build & Deployment - Production builds output to `dist/` directory - Vite build configuration includes: - Source maps enabled for debugging - Code splitting with vendor chunk (React/React-DOM) - Lucide-react excluded from optimizeDeps for compatibility - Docker deployment uses Nginx to serve static files on port 3800 - Host Nginx reverse proxy configuration available in `nginx-host.conf` - PWA manifest (`public/manifest.json`) and service worker (`public/sw.js`) for mobile app installation ### CI/CD Pipeline **Automated Builds**: - Gitea Actions workflow at `.gitea/workflows/build-deploy.yml` - Triggers on push to `main` branch - Builds multi-stage Docker image (Node build → Nginx serve) - Pushes to Gitea container registry at `code.puffinoffset.com/matt/puffin-app` **Image Tagging Strategy**: - `latest`: Always points to most recent main branch build - `main-`: Specific commit version for rollbacks **Container Registry**: - Gitea's built-in Docker registry - Authentication via Gitea credentials - Registry URL: `code.puffinoffset.com` **Deployment**: - Manual deployment via Portainer - Use `docker-compose.portainer.yml` for production stack configuration - Environment variables mounted via `.env` file volume - Detailed deployment instructions in `DEPLOYMENT.md` **Workflow Optimization**: - Docker buildx for multi-platform support - Layer caching to speed up builds - Separate build cache stored in registry ### Key Implementation Details **Routing without React Router**: App uses state-based routing via `currentPage` state and `window.history.pushState()`. The `/mobile-app` route is detected by checking `window.location.pathname` and renders only `MobileCalculator` without the standard layout. **Sample Vessel Data**: A hardcoded `sampleVessel` object is used as default vessel data in `App.tsx` (lines 17-24) since AIS client currently returns mock data. **Analytics Integration**: `utils/analytics.ts` tracks page views via Google Analytics. Called in `App.tsx` useEffect when route changes. **Currency Support**: `utils/currencies.ts` provides multi-currency conversion. Calculator components support USD, EUR, GBP selection. **Error Handling**: `ErrorBoundary.tsx` component wraps the app to catch React rendering errors gracefully.