diff --git a/docs/phase6-deployment-checklist.md b/docs/phase6-deployment-checklist.md index 8502901..ef4f860 100644 --- a/docs/phase6-deployment-checklist.md +++ b/docs/phase6-deployment-checklist.md @@ -11,7 +11,7 @@ This document outlines the remaining steps to complete Phase 6. All code is writ ### ✅ Container Images - [x] `acb-matchmaker` - Match scheduling, health checks, reaper - [x] `acb-worker` - Match execution, B2 upload -- [x] `acb-index-builder` - PostgreSQL → JSON → Pages deploy, R2 management +- [x] `acb-index-builder` - PostgreSQL → JSON → Pages deploy - [x] `acb-evolver` - LLM evolution pipeline - [x] `acb-strategy-random` - Python RandomBot - [x] `acb-strategy-gatherer` - Go GathererBot @@ -46,7 +46,7 @@ All K8s manifests are in the `ardenone-cluster` repo at: ### ✅ Deployment Scripts All scripts in `scripts/` directory are ready: - [x] `cloudflare-setup.sh` - Full Cloudflare setup -- [x] `setup-r2.sh` - R2 bucket + custom domain +- [x] `setup-b2.sh` - B2 bucket configuration (obsolete — B2 credentials already in SealedSecrets) - [x] `deploy-pages.sh` - Deploy SPA to Pages - [x] `configure-dns.sh` - DNS configuration - [x] `verify-deployment.sh` - End-to-end verification @@ -85,25 +85,19 @@ All scripts in `scripts/` directory are ready: - Add domain: `aicodebattle.com` - DNS CNAME will be auto-configured -### ⏳ Cloudflare R2 Setup +### ⏳ Backblaze B2 Custom Domain -**Automated via script:** -```bash -export CLOUDFLARE_API_TOKEN=your_token -export CLOUDFLARE_ACCOUNT_ID=your_account_id # optional, auto-detected -./scripts/setup-r2.sh -``` +B2 credentials are already provisioned (SealedSecret in cluster). The remaining step is to +expose the bucket under a `b2.aicodebattle.com` subdomain so the SPA can fetch replays +via Cloudflare's Bandwidth Alliance (zero egress fees). -**Or manual steps:** -1. Create R2 bucket: - ```bash - wrangler r2 bucket create acb-data - ``` +**Manual steps:** +1. In Backblaze console, enable public access on the `acb-data` bucket. +2. Note the native B2 endpoint: `{bucket}.s3.{region}.backblazeb2.com` +3. Add a Cloudflare DNS CNAME (see DNS section below) — Cloudflare proxies the request, + activating the Bandwidth Alliance and serving files via CDN. -2. Add custom domain: - - Go to: R2 > acb-data > Settings > Custom Domains - - Add domain: `r2.aicodebattle.com` - - DNS CNAME will be auto-configured +No script required — no Cloudflare account credentials needed for this step (DNS-only change). ### ⏳ DNS Configuration @@ -121,13 +115,13 @@ export TRAEFIK_IP=$(kubectl --server=http://kubectl-apexalgo-iad:8001 get svc -n - Target: `aicodebattle.pages.dev` - Proxy: On (orange cloud) -2. R2 subdomain: +2. B2 subdomain (Bandwidth Alliance): - Type: CNAME - - Name: `r2` - - Target: `acb-data.r2.cloudflarestorage.com` - - Proxy: Off (gray cloud) - DNS only + - Name: `b2` + - Target: `acb-data.s3..backblazeb2.com` ← replace `` with actual B2 region + - Proxy: On (orange cloud) — required to activate Cloudflare Bandwidth Alliance (zero egress) -3. API subdomain: +3. API subdomain (deferred — not needed for v1 static-first launch): - Type: A - Name: `api` - Target: `` @@ -153,11 +147,11 @@ Or manually check: # SPA should be accessible curl -I https://aicodebattle.com -# R2 should be accessible -curl -I https://r2.aicodebattle.com +# B2 CDN should be accessible (a known replay file) +curl -I https://b2.aicodebattle.com/replays/latest.json.gz -# API health (once K8s is running) -curl https://api.aicodebattle.com/health +# API health (deferred — not required for v1) +# curl https://api.aicodebattle.com/health ``` --- @@ -168,85 +162,83 @@ curl https://api.aicodebattle.com/health |---------|-----| | SPA (Pages) | `https://aicodebattle.com` | | SPA (Pages default) | `https://aicodebattle.pages.dev` | -| Replays (R2) | `https://r2.aicodebattle.com/replays/{match_id}.json.gz` | -| Match metadata (R2) | `https://r2.aicodebattle.com/matches/{match_id}.json` | -| Evolution feed (R2) | `https://r2.aicodebattle.com/evolution/live.json` | -| API (K8s) | `https://api.aicodebattle.com/health` | +| Replays (B2 via CDN) | `https://b2.aicodebattle.com/replays/{match_id}.json.gz` | +| Match metadata (B2 via CDN) | `https://b2.aicodebattle.com/matches/{match_id}.json` | +| Evolution feed (B2 via CDN) | `https://b2.aicodebattle.com/evolution/live.json` | +| API (K8s, deferred) | `https://api.aicodebattle.com/health` | --- ## Data Flow ``` -┌─────────────────────────────────────────────────────────────────┐ -│ Public Internet │ -├─────────────────────────────────────────────────────────────────┤ -│ │ -│ ┌─────────────────────┐ ┌─────────────────────────────────┐ │ -│ │ Cloudflare Pages │ │ Cloudflare R2 │ │ -│ │ aicodebattle.com │ │ r2.aicodebattle.com │ │ -│ │ │ │ │ │ -│ │ SPA shell (HTML/ │ │ replays/*.json.gz │ │ -│ │ JS/CSS) │ │ matches/*.json │ │ -│ │ data/*.json │ │ evolution/live.json │ │ -│ │ │ │ │ │ -│ └─────────────────────┘ └─────────────────────────────────┘ │ -│ ▲ ▲ │ -└───────────┼────────────────────────────┼────────────────────────┘ - │ │ -┌───────────┼────────────────────────────┼────────────────────────┐ -│ │ apexalgo-iad cluster │ │ -│ │ │ │ -│ ┌────────▼─────────────────────────────┼────────────────────┐ │ -│ │ Index Builder Deployment │ │ │ -│ │ - Reads PostgreSQL │ │ │ -│ │ - Generates JSON indexes │ │ │ -│ │ - Deploys to Pages (wrangler) │ │ │ -│ │ - Promotes replays to R2 │ │ │ -│ │ - Prunes R2 warm cache │ │ │ -│ └────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Match Workers (Deployment) │ │ -│ │ - Execute matches │ │ -│ │ - Upload replays to B2 │ │ -│ │ - Write results to PostgreSQL │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Matchmaker Deployment │ │ -│ │ - Creates match jobs │ │ -│ │ - Enqueues to Valkey │ │ -│ │ - Health checks bots │ │ -│ │ - Reaps stale jobs │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Evolver Deployment │ │ -│ │ - LLM evolution pipeline │ │ -│ │ - Writes evolution/live.json to R2 │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Strategy Bot Deployments (x6) │ │ -│ │ - HTTP servers on cluster-internal Services │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ PostgreSQL (cnpg-apexalgo) │ │ -│ │ - Bots, matches, jobs, ratings, etc. │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Valkey StatefulSet │ │ -│ │ - Job queue (acb:jobs:pending) │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ Backblaze B2 (cold archive) │ │ -│ │ - ALL replays, permanently │ │ -│ └─────────────────────────────────────────────────────────────┘ │ -└───────────────────────────────────────────────────────────────────┘ +┌──────────────────────────────────────────────────────────────────────┐ +│ Public Internet │ +│ (No K8s services exposed here — cluster is write-only compute) │ +├──────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────┐ ┌────────────────────────────────────┐ │ +│ │ Cloudflare Pages │ │ Backblaze B2 (via Cloudflare CDN) │ │ +│ │ aicodebattle.com │ │ b2.aicodebattle.com │ │ +│ │ │ │ │ │ +│ │ SPA shell (HTML/ │ │ replays/*.json.gz │ │ +│ │ JS/CSS) │ │ matches/*.json │ │ +│ │ data/*.json │ │ evolution/live.json │ │ +│ │ │ │ (Bandwidth Alliance = free egress) │ │ +│ └──────────────────────┘ └────────────────────────────────────┘ │ +│ ▲ ▲ │ +└───────────┼───────────────────────────────┼──────────────────────────┘ + writes (wrangler) writes (S3-compatible API) + │ │ +┌───────────┼───────────────────────────────┼──────────────────────────┐ +│ │ apexalgo-iad cluster │ │ +│ │ (compute only — no │ │ +│ │ inbound user traffic) │ │ +│ │ │ │ +│ ┌────────▼───────────────────────────────┼────────────────────────┐ │ +│ │ Index Builder Deployment │ │ │ +│ │ - Reads PostgreSQL │ │ │ +│ │ - Generates JSON indexes │ │ │ +│ │ - Deploys data/*.json to Pages (wrangler pages deploy) │ │ +│ └────────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ Match Workers (Deployment) │ │ +│ │ - Execute matches (battles happen here) │ │ +│ │ - Build replay JSON │ │ +│ │ - Upload replays to B2 │ │ +│ │ - Write results to PostgreSQL │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ Matchmaker Deployment │ │ +│ │ - Creates match jobs │ │ +│ │ - Enqueues to Valkey │ │ +│ │ - Health checks bots │ │ +│ │ - Reaps stale jobs │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ Evolver Deployment │ │ +│ │ - LLM evolution pipeline │ │ +│ │ - Writes evolution/live.json to B2 │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ Strategy Bot Deployments (x6) │ │ +│ │ - HTTP servers on cluster-internal Services only │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ PostgreSQL (cnpg-apexalgo) │ │ +│ │ - Bots, matches, jobs, ratings, etc. │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ Valkey StatefulSet │ │ +│ │ - Job queue (acb:jobs:pending) │ │ +│ └──────────────────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────────────┘ ``` --- @@ -257,17 +249,16 @@ Once Cloudflare resources are created: 1. **Update environment variables in index builder:** - `CLOUDFLARE_API_TOKEN` - For Pages deployment - - `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_BUCKET`, `R2_ENDPOINT` - For R2 operations - - `B2_KEY_ID`, `B2_APPLICATION_KEY`, `B2_BUCKET`, `B2_ENDPOINT` - For B2 operations + - `B2_KEY_ID`, `B2_APPLICATION_KEY`, `B2_BUCKET`, `B2_ENDPOINT` - For B2 operations (workers and evolver) 2. **Deploy to Kubernetes:** - K8s manifests are already in `ardenone-cluster` repo - ArgoCD will sync them automatically 3. **Verify data flow:** - - Index builder should start deploying to Pages - - Match workers should upload replays to B2 - - R2 warm cache should populate with recent replays + - Index builder should start deploying JSON indexes to Pages + - Match workers should upload replay files to B2 + - Replays should be accessible at `b2.aicodebattle.com` via Cloudflare CDN 4. **Monitor:** - Check ArgoCD for sync status @@ -285,8 +276,8 @@ Phase 6 is complete when: - [x] CI/CD pipeline working - [x] Monitoring and alerting configured - [ ] Cloudflare Pages project created and deployed -- [ ] Cloudflare R2 bucket created with custom domain -- [ ] DNS configured (aicodebattle.com, r2.aicodebattle.com, api.aicodebattle.com) +- [ ] B2 bucket public access enabled and `b2.aicodebattle.com` CNAME added (Bandwidth Alliance) +- [ ] DNS configured (aicodebattle.com, b2.aicodebattle.com) - [ ] Platform publicly accessible -The final 3 items require Cloudflare account access and must be completed by someone with admin access to the Cloudflare account. +The Pages and DNS items require Cloudflare account access. The B2 item requires Backblaze console access. The `api.aicodebattle.com` DNS entry is deferred — the Go API is not required for v1. diff --git a/docs/spa-route-test-results.md b/docs/spa-route-test-results.md index 3d67f35..b886a62 100644 --- a/docs/spa-route-test-results.md +++ b/docs/spa-route-test-results.md @@ -14,7 +14,7 @@ | **Failed** | 0 | | **Total** | 43 | -**Result:** All SPA routes return valid HTML. The /r2/ data paths return 404 (data not yet deployed to R2/Pages Function). +**Result:** All SPA routes return valid HTML. The /b2/ data paths return 404 (data not yet deployed — B2 bucket not yet publicly accessible and index builder not yet running). ## Static Routes (All Passed) @@ -67,21 +67,21 @@ | `/blog/:slug` | Blog post | 200 OK | | `/watch/playlists/:slug` | Playlist detail | 200 OK | -Note: Parameterized routes tested with placeholder IDs. Routes return valid SPA shell; actual data loading depends on /r2/ data path. +Note: Parameterized routes tested with placeholder IDs. Routes return valid SPA shell; actual data loading depends on `/b2/` data paths served from Backblaze B2 via Cloudflare CDN. -## Data Paths (/r2/) - 404 Expected +## Data Paths (/b2/) - 404 Expected | Path | Description | Status | |------|-------------|--------| -| `/r2/` | R2 data root | 404 Not Found | -| `/r2/data/matches/index.json` | Matches index | 404 Not Found | -| `/r2/data/leaderboard.json` | Leaderboard data | 404 Not Found | -| `/r2/data/seasons/index.json` | Seasons index | 404 Not Found | -| `/r2/data/series/index.json` | Series index | 404 Not Found | -| `/r2/data/blog/index.json` | Blog index | 404 Not Found | -| `/r2/data/playlists/index.json` | Playlists index | 404 Not Found | +| `/b2/` | B2 data root | 404 Not Found | +| `/b2/data/matches/index.json` | Matches index | 404 Not Found | +| `/b2/data/leaderboard.json` | Leaderboard data | 404 Not Found | +| `/b2/data/seasons/index.json` | Seasons index | 404 Not Found | +| `/b2/data/series/index.json` | Series index | 404 Not Found | +| `/b2/data/blog/index.json` | Blog index | 404 Not Found | +| `/b2/data/playlists/index.json` | Playlists index | 404 Not Found | -**Note:** These 404s are expected - the data has not been uploaded to R2 or the Pages Function has not been configured yet. This is a data availability issue, not a routing issue. See related bead `bf-cmh1` for end-to-end replay viewer testing. +**Note:** These 404s are expected — the B2 bucket is not yet publicly accessible and the index builder is not yet running. Data paths are served from Backblaze B2 (not Cloudflare R2). This is a data availability issue, not a routing issue. See related bead `bf-cmh1` for end-to-end replay viewer testing. ## Test Script