# Scale To 1m

> Step-by-step prompts to prepare free-crypto-news for 1M+ concurrent users. Covers database, job queues, WebSocket scaling, CDN caching, observability, load testing, DDoS protection, graceful degradation, API gateway, multi-region deployment, and disaster recovery.

- Skill: `jiayaoqijia/scale-to-1m` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add jiayaoqijia/scale-to-1m`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jiayaoqijia/scale-to-1m/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: jiayaoqijia (https://skillmd.com/u/jiayaoqijia)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/jiayaoqijia/scale-to-1m

---


# Scale to 1M+ Users — Prompt Playbook

> **Goal**: Transform free-crypto-news from a single-instance Vercel app into a horizontally-scaled, multi-region platform capable of serving 1M+ concurrent users — surpassing CoinGecko and DeFiLlama.

## Current State (Feb 2026)

- ~82% Edge Runtime routes on Vercel (226/351 API routes)
- Redis (Upstash) for distributed caching + rate limiting
- Nginx load balancer with 2+ app replicas in Docker
- WebSocket server with Redis pub/sub, leader election, 10K connection cap per instance
- SSE with 500 concurrent connection cap + auto-disconnect at 30min
- HTTP connection pool via undici Agent for upstream API calls
- No persistent database — static JSON archive + Redis cache
- Provider framework with circuit breakers, anomaly detection, health monitoring
- Only `market-price` category wired through ProviderChain (3 adapters: CoinGecko, CoinCap, Binance)
- 11 API client libs (CoinMarketCap, CryptoQuant, DeFiLlama, Glassnode, L2Beat, LunarCrush, Messari, NFT Markets, The Graph, CryptoPanic, NewsAPI) NOT wired through ProviderChain

## Prompt Sequence

Execute these prompts in order. Each builds on the previous.

---

### Prompt 1 — PostgreSQL + Drizzle ORM

```
Add a PostgreSQL database to free-crypto-news using Drizzle ORM.

Requirements:
1. Add drizzle-orm, drizzle-kit, @neondatabase/serverless as dependencies
2. Create src/lib/db/schema.ts:
   - articles (id, slug, title, summary, url, source, category, coin_tags text[],
     published_at, fetched_at, embedding vector(1536), language, sentiment_score, impact_score)
   - prices_snapshot (id, coin_id, symbol, price_usd, market_cap, volume_24h, change_24h, timestamp)
   - provider_health (id, provider_name, chain_name, success_rate, avg_latency_ms, circuit_state, recorded_at)
   - api_usage (id, api_key, endpoint, method, status_code, latency_ms, timestamp, ip_hash)
   - users (id, email, api_key, tier, created_at, last_active_at)
   - alerts (id, user_id, type, config jsonb, last_triggered_at, created_at)
3. src/lib/db/index.ts — drizzle client, @neondatabase/serverless HTTP mode for Edge Runtime
4. drizzle.config.ts, db:generate/migrate/push/studio scripts
5. src/lib/db/queries/ — reusable query functions
6. GIN indexes on coin_tags, full-text on title, btree on published_at DESC
7. Migration script: scripts/db/migrate-archive.ts (JSONL → PostgreSQL)
8. File-based fallback if DATABASE_URL not set

Target: <100ms queries for 1M+ articles.
```

---

### Prompt 2 — Background Job Queue with Inngest

```
Add Inngest for reliable background job processing.

Requirements:
1. Install inngest, create src/lib/inngest/client.ts (id: "free-crypto-news")
2. src/app/api/inngest/route.ts serve endpoint
3. Migrate crons: archive (5m), digest (daily), x-sentiment (15m),
   predictions (daily), tag-scores (1h), enrich-articles (10m)
4. New functions:
   - prices/snapshot.capture (30s) — snapshot top 100 prices to DB
   - providers/health.record (1m) — health metrics to DB
   - alerts/check.all (1m) — user alert evaluation
   - cache/warm.predictive (2m) — predictive cache warming
   - analytics/usage.aggregate (1h) — rollup stats
5. 3x retry with backoff, idempotency keys, error reporting
6. Fallback to Vercel cron when Inngest not configured

Target: 10K+ articles/hr, 100K+ price updates/hr.
```

---

### Prompt 3 — WebSocket TypeScript Rewrite + Scaling

```
Refactor ws-server.js to TypeScript with production hardening.

Current state: JavaScript with Redis pub/sub, leader election, 10K cap,
safeSend, maxPayload 64KB, graceful shutdown.

Requirements:
1. Refactor → src/lib/ws/server.ts (TypeScript)
2. Keep all existing: pub/sub, leader election, safeSend, caps, shutdown
3. Add ioredis for cluster support
4. Type-safe channels: "prices:{coinId}", "news:latest", "news:breaking",
   "alerts:{userId}", "market:global", "sentiment:live"
5. Per-client subscription tracking: Map<WebSocket, Set<string>>
6. Per-IP limit (100 conns) + per-instance limit (50K)
7. /ws/stats metrics endpoint
8. 4 replicas in docker-compose.yml

Target: 50K connections/instance, 200K total.
```

---

### Prompt 4 — CDN + Edge Caching Strategy

```
Comprehensive CDN caching with tag-based purging.

Requirements:
1. src/lib/cache/cdn-headers.ts — setCacheHeaders(res, preset):
   REALTIME (s-maxage=5), FAST (30), STANDARD (120), SLOW (3600), STATIC (86400)
2. Surrogate-Key headers for tag-based purging
3. src/lib/cache/purge.ts — purgeByTag/Path/All, support Vercel/Cloudflare/Fastly
4. Apply presets to ALL /api/* handlers:
   /api/prices/* → REALTIME, /api/news/* → FAST, /api/search → STANDARD,
   /api/archive/* → SLOW, /api/openapi.json → STATIC
5. Cache-Status: HIT/MISS/STALE/BYPASS header
6. ?force=1 bypass (admin only)
7. Vary: Accept-Encoding, Accept-Language, Accept

Target: 95% cache hit rate, <10ms edge responses.
```

---

### Prompt 5 — Observability Stack

```
Production observability for 1M+ scale.

Requirements:
1. src/lib/observability/metrics.ts — Prometheus-compatible:
   http_requests_total, http_request_duration_ms (histogram),
   cache_hits/misses, provider_requests, provider_latency,
   ws_connections, db_queries, job_executions
2. GET /api/metrics (METRICS_TOKEN protected)
3. src/lib/observability/tracing.ts — trace ID per request, structured JSON logs
4. src/lib/observability/alerts.ts — rules for p99, error rate, cache hit, circuit breakers, WS capacity → webhook alerts
5. Grafana dashboard JSON at infra/grafana/dashboard.json
6. /admin/dashboard with live metrics

Target: Identify bottlenecks within 60 seconds.
```

---

### Prompt 6 — Load Testing Suite

```
K6 load tests validating 1M user capacity.

Requirements:
1. scripts/load-tests/:
   smoke (10 VU, 1m), load (1K→10K VU, 10m), stress (10K→50K, 15m),
   spike (100→100K→100), soak (5K VU, 1h), websocket (10K conns)
2. Mix: 40% news, 25% prices, 15% market, 10% search, 10% other
3. SLOs: p95 <200ms, p99 <1s, error <0.1%, cache >90%
4. run.sh: start stack → health → smoke → load → stress → report
5. GitHub Action: smoke on PR, full on release

Target: Prove 10K req/sec, <200ms p95.
```

---

### Prompt 7 — DDoS Protection + Load Shedding

```
Survive abuse and overload without crashing.

Requirements:
1. src/lib/security/ip-reputation.ts — score 0-100, auto-block >80
2. src/lib/security/request-fingerprint.ts — detect distributed scraping
3. src/lib/security/adaptive-rate-limit.ts — tighten under load
4. src/lib/load-shedding.ts:
   GREEN → YELLOW (>70%: no AI, 2x cache) → ORANGE (>85%: stale only) → RED (>95%: 503 except news+prices)
5. X-Service-Level header
6. WS: ORANGE stop new, RED disconnect idle
7. Admin dashboards for security + load shedding

Target: Survive 100K req/sec DDoS. Never crash.
```

---

### Prompt 8 — API Gateway + Rate Limit Tiers

```
Production API gateway with paid tiers.

Requirements:
1. Tiers:
   Free (no key): 30/min, 1K/day
   Starter (free key): 300/min, 50K/day
   Pro ($29/mo): 3K/min, unlimited
   Enterprise ($199/mo): 30K/min, SLA
2. src/lib/gateway/api-key.ts — validation, issuance, rotation, tracking
3. src/lib/gateway/quota.ts — daily quotas, X-RateLimit-* headers
4. Update middleware.ts for tier-based limits
5. GET /api/v1/usage, GET /api/admin/keys
6. Backward compatible: free-tier IP limits still work

Target: Self-serve signup in <2 min.
```

---

### Prompt 9 — Multi-Region Deployment

```
Multi-region for <100ms global latency.

Requirements:
1. infra/terraform/ — Neon PG replicas (us-east, eu-west, ap-southeast),
   Upstash Redis Global, Cloudflare DNS
2. src/lib/db/read-replica.ts — route reads to nearest replica
3. X-Region response header
4. docker-compose.multi-region.yml — 3 regional clusters + Traefik
5. docs/MULTI-REGION.md with Mermaid diagram

Target: <100ms global, automatic failover.
```

---

### Prompt 10 — Disaster Recovery

```
Survive any infrastructure failure.

Requirements:
1. scripts/dr/snapshot.ts — nightly Redis + PG to R2/S3
2. scripts/dr/restore.ts — full restore + integrity check
3. docker-compose.dr.yml — warm standby
4. infra/runbook.md — 4 failure scenarios
5. RTO <5 min, RPO <1 hour
6. Monthly DR drill

Target: API stays up when everything goes down.
```

---

## Execution Order

| Phase | Prompts | Timeline | Impact |
|-------|---------|----------|--------|
| Foundation | 1 (Database), 2 (Jobs) | Week 1 | Persistent data, async processing |
| Scale | 3 (WebSocket), 4 (CDN) | Week 2 | 100K concurrent users |
| Observe | 5 (Observability), 6 (Load Test) | Week 3 | Know your limits |
| Protect | 7 (DDoS + Load Shedding) | Week 3 | Survive attacks |
| Monetize | 8 (API Gateway) | Week 4 | Revenue + abuse protection |
| Global | 9 (Multi-Region), 10 (DR) | Week 4 | <100ms worldwide |

## Success Metrics

| Metric | Target |
|--------|--------|
| p95 response time | < 100ms cached, < 500ms uncached |
| p99 response time | < 500ms cached, < 1,000ms uncached |
| CDN cache hit rate | > 95% |
| Error rate | < 0.05% |
| WebSocket connections | 100K+ per region |
| DB query time (p95) | < 50ms |
| TTFB (global) | < 100ms |
| Monthly requests | 1B+ |
| Uptime | 99.99% |
| RTO | < 5 minutes |
| Infra cost at 1M users | < $2,000/mo |

