# CLAUDE.md

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

## Project Overview

songwhip-analytics is a serverless analytics service deployed on Vercel that ingests user analytics events (from songwhip-events) into BigQuery and serves aggregated query results to songwhip-api for dashboards.

## Commands

- `pnpm dev` — local dev server on port 5001 (requires Vercel CLI)
- `pnpm test:types` — TypeScript type checking (`tsc --noEmit`)
- `pnpm test:lint` — Biome formatting and linting checks
- `pnpm test:unit` — run unit tests with Vitest
- `pnpm test` — run all tests (lint, types, unit)
- `pnpm deploy` — deploy to staging (requires `.env` with credentials)
- `pnpm deploy --prod` — deploy to production

There are no unit tests or test runner — `pnpm test` only does type checking.

## Architecture

**Runtime:** Node.js 24, TypeScript, ES Modules (`"type": "module"`), pnpm

**Deployment:** Vercel serverless functions. All requests are rewritten from `/<path>` to `/api/<path>` via `vercel.json`. SQL files under `lib/` are bundled with functions via `includeFiles`.

### API Endpoints (under `api/`)

- `GET /health` — health check, no auth
- `POST /v3/event` — event ingestion, runs on **Vercel Edge runtime** for performance
- `GET /v3/items` — query aggregated analytics (page views, opens, presaves, unlocks, stories), requires Auth0 JWT, runs on **Node Lambda runtime**

### Handler Pattern (`lib/handler/`)

Two handler wrappers corresponding to the two runtimes:
- **`lambda.ts`** — wraps Node Lambda handlers with JWT verification, error handling, and Sentry reporting. Returns `{status: 'ok', data: {...}}`.
- **`edge.ts`** — wraps Edge handlers with method-based routing (`.get()`, `.post()`, etc.) and the same error/response conventions.

Auth is via Auth0 JWT Bearer tokens, verified through `@theorchard/songwhip-utils-auth`.

### BigQuery (`lib/bigQuery/`)

Two implementations for querying BigQuery:
- **`sdk/`** — official `@google-cloud/bigquery` SDK, used from Lambda functions
- **`rest/`** — custom REST API client, used from Edge functions (SDK doesn't work in Edge runtime)

SQL queries live as `.sql` files alongside the TypeScript code. Table references use string replacement (`$TABLE`). The dataset is `songwhip_analytics` with table `events_3` (prod) / `events_staging` (staging).

### Key Internals

- **`lib/env.ts`** — `assertEnvVar()` / `optionalEnvVar()` / `getSongwhipEnv()` for environment variable access
- **`lib/sentry/`** — separate Sentry setup for Node vs Edge runtimes
- **`lib/utils/`** — shared utilities (timezone handling, date formatting)
- **`@theorchard/songwhip-utils`** — provides `ApiError` class used for error responses
- **`@theorchard/songwhip-events`** — event type definitions (dev dependency)

## Coding Conventions

- Prettier: single quotes, trailing commas (ES5), semicolons, 2-space indent
- ESLint enforces: no floating promises, no misused promises, blank lines around multiline blocks/expressions, no multiple empty lines
- No explicit function return types required
- `@typescript-eslint/no-explicit-any` is a warning (not error)

## Environment

Credentials and config are passed as environment variables (see `.env.shadow` for the full list). Key vars: `BIG_QUERY_GOOGLE_*`, `AUTH0_DOMAIN`, `SONGWHIP_JWT_SECRET`, `SENTRY_DSN`, `SONGWHIP_ENV`.

## CI/CD

GitHub Actions on `master`: type-check, deploy to staging, then deploy to production. PRs run type-check only. Deployments dispatch a `new-deployment` event to songwhip-events.
