- Enable TCP keepalive on pg.Pool to detect dead connections
- Add connectionTimeoutMillis (5s) to prevent hanging on stale connections
- Add queryWithRetry() with exponential backoff for transient DB errors
- Add connectWithRetry() for transaction-based operations
- Detect PgBouncer "no available server" and other transient errors
- Health check has 3s timeout and returns 503 on DB failure
- All DB operations in keys, verification, usage use retry logic
Fixes BUG-075: PgBouncer failover causes permanent pod failures
- Replace JSON file storage with PostgreSQL (pg package)
- Add db.ts service for connection pool and schema init
- Rewrite keys.ts, verification.ts, usage.ts for async PostgreSQL
- Update all routes for async function signatures
- Add migration script (scripts/migrate-to-postgres.mjs)
- Update docker-compose.yml with DATABASE_* env vars
- Change SLA from 99.9% to 99.5% in landing page
- POST /v1/signup/free now returns verification code (temp in response)
- New POST /v1/signup/verify endpoint to verify code and get API key
- Codes expire after 15 minutes, max 3 attempts
- Frontend updated with 2-step signup modal (email → code → key)
- Legacy token verification kept for existing links
- Signup now requires email verification before API key is revealed
- Verification token sent via email (Resend) with console fallback
- GET /verify?token=xxx shows API key in styled HTML page
- Handles expired (24h), invalid, and already-verified tokens
- Frontend modal shows 'check your email' instead of key
- Keeps existing rate limiting