Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- Create Gitea Actions workflow for automated Docker builds on push to main - Add docker-compose.portainer.yml for production Portainer deployment - Create comprehensive DEPLOYMENT.md guide with step-by-step instructions - Update CLAUDE.md with CI/CD pipeline documentation Images are built and pushed to Gitea registry at: code.puffinoffset.com/matt/puffin-app:latest code.puffinoffset.com/matt/puffin-app:main-<sha> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
149 lines
5.8 KiB
Markdown
149 lines
5.8 KiB
Markdown
# 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-<commit-sha>`: 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. |