# CLAUDE.md

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

## Overview

`songwhip-events` is an event ingestion service deployed to Vercel Edge Functions. It receives events from various Songwhip services and forwards them to multiple analytics endpoints (Google Analytics, Amplitude, Slack, songwhip-analytics).

The service runs on a limited JavaScript runtime provided by Vercel Edge Functions and uses streaming responses to avoid invocation timeouts.

## Development Commands

### Setup

- `yarn install` - Install dependencies
- Create `.env` file based on `.env.shadow` template

### Development

- `yarn dev` - Start Vercel dev server (requires Vercel CLI)
- `yarn ga4` - Run GA4 script to send test event

### Testing & Quality

- `yarn test` - Run all tests (format, lint, types, unit)
- `yarn test:format` - Check code formatting with Prettier
- `yarn test:lint` - Run ESLint
- `yarn test:types` - Run TypeScript type checking
- `yarn test:unit` - Run Jest unit tests
- `yarn format` - Auto-format code with Prettier

### Client Library

- `yarn build:client-lib` - Build the npm client package in `packages/songwhip-events`
- Publishing is done via [Publish version Github Action](https://github.com/theorchard/songwhip-events/actions/workflows/publishVersion.yml)

## Architecture

### Request Flow

1. **Entry Point**: `/api/send.ts` is the main endpoint (mapped to `/` via vercel.json)
   - Configured as a Vercel Edge Function (`runtime: 'edge'`)
   - Uses streaming responses via ReadableStream to avoid timeouts
   - Accepts POST requests with `SongwhipEventPayload` containing `context` and `event`

2. **Event Handling**: `/lib/endpoints/index.ts:handleEvent()`
   - Dispatches events to all endpoints in parallel using Promise.all
   - Active endpoints: GA3, GA4, Amplitude, Slack, songwhip-analytics
   - Segment endpoint is disabled due to quota concerns (see AD-950)

3. **Context Enrichment**: Events are enriched with base context from request headers
   - User IP from Cloudflare headers (`cf-connecting-ip`)
   - User country from Cloudflare (`cf-ipcountry`)
   - User agent and referrer from standard headers
   - Client can override these values in the payload

### Event Types

All event types are defined in `types.ts` as part of the `SongwhipEvent` union type. Key event categories:

- Page tracking: `page-view`, `click`, `search`
- User actions: `login`, `logout`, `create-account`, `claim-artist`
- Conversions: `create-subscription`, `purchase`, `checkout-complete`
- Content: `create-link`, `open-external-service`, `share`
- Features: `add-page-feature`, `remove-page-feature`, `edit-page-feature`
- Media: `video-start`, `video-progress`, `video-complete`, `story-play-heartbeat`
- Release tasks: `create-release-task`, `run-release-task`

### Client Library

The `packages/songwhip-events` directory contains a TypeScript client library published to GitHub Packages:

- Provides TypeScript types for all events
- Wraps `navigator.sendBeacon()` for browser usage
- Falls back to fetch when sendBeacon is unavailable
- Supports custom fetch implementations for server-side usage

### Error Handling

- `edgeHandler` utility (`lib/utils/edgeHandler.ts`) wraps all API routes
- Provides consistent error handling and JSON response formatting
- `ApiError` class for structured API errors with status codes
- Errors are sent to Sentry via `lib/sentry/index.ts`

### Environment Management

- Events include `context.env` field to distinguish `staging` vs `production`
- Endpoints use this to route to the correct destination instances

## Code Style

- **TypeScript**: Strict mode enabled, but `noImplicitAny: false`
- **Prettier**: Single quotes, 2-space tabs, trailing commas (ES5), semicolons
- **ESLint**: Based on recommended TypeScript rules
  - `@typescript-eslint/no-floating-promises` enforced (error)
  - `@typescript-eslint/no-explicit-any` is a warning only
  - Must use consistent casing in file names

## Important Patterns

### Adding New Events

1. Define event interface in `types.ts`
2. Add to `SongwhipEvent` union type
3. Update endpoint handlers in `lib/endpoints/*/` as needed
4. Client library types are automatically updated from root `types.ts`

### Adding New Endpoints

1. Create endpoint directory in `lib/endpoints/`
2. Export handler function matching `SongwhipEventEndpoint` signature
3. Register in `lib/endpoints/index.ts:handleEvent()`
4. Handler should be async and throw errors for the edgeHandler to catch

### Vercel Edge Functions Constraints

- Limited Node.js API surface (no fs, etc.)
- Use `@vercel/edge` package for Edge-compatible APIs
- Configure runtime in route files: `export const config = { runtime: 'edge' }`
