# CLAUDE.md

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

## What This Is

Hot Updater is a backend bundle management and distribution service for mobile OTA (over-the-air) updates. It stores JS bundle metadata in PostgreSQL, serves bundle files via S3/CDN, and exposes REST APIs consumed by mobile clients (update checks, analytics) and Jenkins (releasing/promoting builds).

## Commands

```bash
# Setup
cp .env.shadow .env
npm install

# Development (runs migrations then starts with hot reload)
npm run api:dev

# Full Docker dev environment (rebuilds + restarts everything)
npm run docker:dev

# Run tests (requires Docker stack running, or direct DB access)
npm test

# Run tests in Docker
npm run docker:test

# Build TypeScript
npm run build

# CLI (after building)
npm run cli
npm run cli COMMAND help

# Prisma: create migration after schema change (dev only)
npx prisma migrate dev --name NAME

# Connect to local Postgres (find container name with: docker ps)
docker exec -it hot-updater-postgres-1 psql -U postgres -d hot_updater_server

# Inspect LocalStack S3
docker exec -it hot-updater-localstack-1 awslocal s3 ls s3://hot-updater-bundles
```

## Architecture

```
Mobile/Jenkins → API (Express, :4000)
                   ├── /hot-updater/*   → @hot-updater/server (update checks)
                   ├── /analytics/track → Datadog metrics
                   ├── /admin/*         → bundle CRUD + file uploads to S3
                   └── /api-keys/*      → API key management
                        ↓
                   PostgreSQL (bundles, api_keys, settings)
                   S3 / LocalStack (bundle .zip files)
                        ↓
Mobile              CDN (Nginx :5556) → S3
```

**Source layout:**
- `index.ts` — entry point, starts Express on `API_PORT`
- `src/api.ts` — all routes, auth middleware, router definitions
- `src/prisma.ts` — all database queries (repository layer)
- `src/s3.ts` — S3 upload/copy operations
- `src/hotUpdater.ts` — `@hot-updater/server` adapter setup with Prisma
- `src/cache.ts` — LRU cache for `bundleId → gitCommitHash` lookups (100 items, 24h TTL)
- `src/datadog.ts` — Datadog metric tracking (download/install/rollback events)
- `src/sentry.ts` — optional Sentry error tracking
- `src/factory.ts` — `generateApiKey()` using `crypto.randomBytes`
- `src/types.ts` — `Permission` type, `PERMISSIONS` and `PLATFORMS` constants
- `src/env.ts` — typed env var helpers (`getEnv`, `getOptionalEnv`, etc.)
- `src/cli/` — Commander.js CLI for managing API keys, bundles, and promotions

## Auth & Permissions

All routes (except `/health`) require a `Bearer <token>` header. The token is validated against the `api_keys` table. `API_MASTER_KEY` bypasses DB lookup and grants all permissions.

Permission strings are space-separated and stored in `api_keys.permission`:
- `hotupdater:read` / `hotupdater:write` — update check endpoints
- `analytics:write` — `/analytics/track`
- `admin:read` / `admin:write` — bundle management, file uploads
- `apikey:read` / `apikey:write` — API key CRUD

`requirePermission(readPerm, writePerm)` middleware is applied per router. GET/HEAD/OPTIONS requests accept either read or write permission; mutating methods require the write permission.

## Database

Prisma with PostgreSQL. Schema lives in `prisma/schema.prisma`. The three models are `api_keys`, `bundles`, and `private_hot_updater_settings`.

- Dev migrations: `npx prisma migrate dev` (interactive, creates migration files)
- Production migrations: `npx prisma migrate deploy` (called automatically by `npm run api`)
- After schema changes, always run `npm run prisma:generate` (or `npm run build`) to regenerate the Prisma client.

## Environment Variables

Copy `.env.shadow` to `.env`. Key variables:

| Variable | Purpose |
|---|---|
| `API_PORT` | Server listen port (default 4000) |
| `API_MASTER_KEY` | Dev bypass key — grants all permissions |
| `POSTGRES_URL` | PostgreSQL connection string |
| `AWS_ENDPOINT` | Set to LocalStack URL for local dev |
| `AWS_BUCKET` | S3 bucket name for bundles |
| `CDN_HOST` | Base URL prepended to bundle storage URIs |
| `USE_LOCALSTACK` | `true` to use path-style S3 addressing |
| `SENTRY_DSN` | Optional — omit to disable Sentry |
| `DD_API_KEY` | Optional — omit to disable Datadog |

Sentry and Datadog are fully optional; omitting their env vars disables them without any code changes.

## Testing

Tests use Jest + Supertest hitting the real Express app. The test file seeds API keys directly. Tests require a running PostgreSQL instance pointed to by `POSTGRES_URL` in `.env`. The easiest approach is `npm run docker:test` which spins up the full stack.

To run a single test file:
```bash
dotenv -e .env -- node --experimental-vm-modules node_modules/jest/bin/jest.js src/__tests__/api.test.ts
```

## TypeScript Notes

- Target: `ES2022`, module system: `ESM`. All imports must use `.js` extensions (even for `.ts` source files).
- Strict mode enabled. No linter configured — TypeScript type errors are the only automated style enforcement.
- `tsx` is used for dev hot-reload; compiled `dist/` is used in production and for the CLI.
