# Climperor Cloudflare player data layer Production multi-user storage for Steam-login player pages: | Resource | Name | Role | |----------|------|------| | D1 | `climperor-users` | users, stats, heroes, match index, sync jobs | | R2 | `climperor-player-data` | private full match JSON (`matches/{id}.json`) | | Queue | `climperor-player-sync` | async OpenDota/Steam refresh | | DLQ | `climperor-player-sync-dlq` | failed sync messages | | Worker | `climperor-player-sync` | queue consumer | ## Provision ```powershell # via keyzoo refining/cloudflare asset python web/cloudflare/provision.py ``` Then deploy the worker: ```powershell cd web/cloudflare/player-sync npx wrangler@3 deploy npx wrangler@3 secret put STEAM_API_KEY # optional: npx wrangler@3 secret put OPENDOTA_API_KEY ``` Pages project `climperor-relations` needs bindings `DB`, `MATCHES`, `SYNC_QUEUE` (see `web/frontend/wrangler.toml`). `provision.py` binds production **and** preview with matching `fail_open`. Secrets already used by auth: `STEAM_API_KEY`, `SESSION_SECRET`, optional `PLAYER_PAGES_PUBLISH_SECRET`. Worker also needs `STEAM_API_KEY` (`python web/cloudflare/put_worker_secrets.py` after staging via `_stage_steam_key.py`). **R2**: if create returns “enable R2”, open https://dash.cloudflare.com/?to=/:account/r2 once, then re-run `provision.py` and uncomment the `[[r2_buckets]]` block in `player-sync/wrangler.toml`, redeploy Worker. Until then, match list/stats still work via D1; full match JSON download is deferred. Ids are recorded in `.resources.json` (no secrets). ## Local `python web/serve_relations.py` continues to use `pc/player_pages/` JSON + enrich (`GET /api/players/me` runs `enrich_profile_recent`). Production `/home` uses `GET /api/players/me` (D1 + queue). ## Tests ```powershell python -m unittest pc.tests.test_player_stats -v node web/cloudflare/player-sync/test_stats.mjs ```