# Persistent Runs + PostgreSQL + Authentication

This document describes the implementation of persistent runs with PostgreSQL and API key authentication for the 4Runr Gateway.

## Overview

The Gateway now supports two persistence modes:
- **Memory Mode** (`GATEWAY_PERSISTENCE=memory`): In-memory storage (no database)
- **PostgreSQL Mode** (`GATEWAY_PERSISTENCE=postgres` or `persistent`): Persistent storage via Prisma/PostgreSQL

All run endpoints are now protected by API key authentication (configurable via `AUTH_ENABLED`).

## Architecture

### Persistence Layer

The persistence layer uses an adapter pattern with two implementations:

1. **MemoryRunStore** (`apps/gateway/src/runs/memoryRunStore.ts`)
   - Stores runs in a Map
   - Data is lost on restart
   - No database required

2. **PostgresRunStore** (`apps/gateway/src/runs/postgresRunStore.ts`)
   - Stores runs in PostgreSQL via Prisma
   - Data persists across restarts
   - Requires DATABASE_URL environment variable

The store is selected automatically based on `GATEWAY_PERSISTENCE`:

```typescript
const runStore = getRunStore(); // Returns MemoryRunStore or PostgresRunStore
```

### Database Schema

New Prisma models:

- **Run**: Stores run data (id, name, status, input, output, logs, clientToken, tags, timestamps)
- **ApiKey**: Stores API keys for authentication (key, label, revoked, timestamps)
- **IdempotencyToken**: For idempotency token caching (future use)
- **CacheEntry**: For general caching (future use)

### Authentication

API key authentication is implemented via middleware (`apps/gateway/src/middleware/authApiKey.ts`):

- **Header**: `x-api-key: <token>`
- **Validation**: Checks against `api_keys` table (PostgreSQL) or `API_KEY` env var (memory mode)
- **Endpoints Protected**: All `/api/*` endpoints except `/health`, `/ready`, `/metrics`, and `/debug/*`

## Environment Variables

### Required (PostgreSQL Mode)

```bash
DATABASE_URL=postgresql://user:password@postgres:5432/dbname
GATEWAY_PERSISTENCE=postgres  # or 'persistent'
```

### Optional

```bash
AUTH_ENABLED=true              # Enable/disable API key auth (default: true)
API_KEY=your-key-here         # Single API key for memory mode or quick testing
API_KEYS=key1,key2,key3       # Comma-separated list for memory mode
```

### Memory Mode

```bash
GATEWAY_PERSISTENCE=memory
API_KEY=your-key-here         # Required if AUTH_ENABLED=true
```

## Setup

### 1. Update Prisma Schema

The schema has been updated to PostgreSQL. Run migrations:

```bash
cd apps/gateway
pnpm db:generate
pnpm db:migrate
```

### 2. Create API Keys

For PostgreSQL mode, seed an API key:

```bash
pnpm seed:api-key
# Or with custom key and label:
pnpm seed:api-key my-custom-key "Production Key"
```

For memory mode, set the `API_KEY` environment variable:

```bash
export API_KEY=my-secret-key
```

### 3. Start Gateway

```bash
# PostgreSQL mode (default)
export GATEWAY_PERSISTENCE=postgres
export DATABASE_URL=postgresql://4runr:4runr_password@postgres:5432/4runr_gateway
pnpm start

# Memory mode
export GATEWAY_PERSISTENCE=memory
export API_KEY=my-secret-key
pnpm start
```

## Usage

### Create a Run (with auth)

```bash
curl -X POST http://localhost:3000/api/runs \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{
    "name": "My Run",
    "input": {"foo": "bar"},
    "tags": ["test"]
  }'
```

### Get a Run

```bash
curl http://localhost:3000/api/runs/run-id \
  -H "x-api-key: your-api-key"
```

### Start a Run

```bash
curl -X POST http://localhost:3000/api/runs/run-id/start \
  -H "x-api-key: your-api-key"
```

## Testing

### Disable Authentication (Development Only)

```bash
export AUTH_ENABLED=false
```

⚠️ **Warning**: Never disable authentication in production!

### Test Memory Mode

```bash
export GATEWAY_PERSISTENCE=memory
export API_KEY=test-key
export AUTH_ENABLED=true
pnpm start
```

### Test PostgreSQL Mode

```bash
export GATEWAY_PERSISTENCE=postgres
export DATABASE_URL=postgresql://4runr:4runr_password@postgres:5432/4runr_gateway
export AUTH_ENABLED=true
# Seed an API key first
pnpm seed:api-key test-key "Test Key"
pnpm start
```

## Migration Guide

### From In-Memory to PostgreSQL

1. Set `GATEWAY_PERSISTENCE=postgres`
2. Provide `DATABASE_URL`
3. Run migrations: `pnpm db:migrate`
4. Seed API keys: `pnpm seed:api-key`
5. Restart gateway

### From PostgreSQL to Memory

1. Set `GATEWAY_PERSISTENCE=memory`
2. Set `API_KEY` environment variable
3. Restart gateway

⚠️ **Note**: Data in PostgreSQL will remain but won't be accessible in memory mode.

## File Structure

```
apps/gateway/
├── src/
│   ├── config/
│   │   └── persistence.ts          # Persistence mode resolver
│   ├── db/
│   │   └── prisma.ts                # Prisma client singleton
│   ├── runs/
│   │   ├── types.ts                 # Run type definitions
│   │   ├── runStore.ts              # RunStore interface
│   │   ├── memoryRunStore.ts        # In-memory implementation
│   │   ├── postgresRunStore.ts      # PostgreSQL implementation
│   │   └── index.ts                 # Factory function
│   ├── middleware/
│   │   └── authApiKey.ts            # API key authentication
│   └── index.ts                     # Main gateway server
├── scripts/
│   └── seed-api-key.ts              # API key seeding script
└── prisma/
    └── schema.prisma                # Database schema (PostgreSQL)
```

## Future Enhancements

- [ ] Idempotency token store implementation
- [ ] Cache entry store implementation
- [ ] Bearer token authentication (JWT)
- [ ] API key rotation
- [ ] Rate limiting per API key
- [ ] Audit logging for API key usage

