Ship Steam login, D1 player sync, and cached「我」dashboard.

Players get a fast TTL-backed homepage (local profile / Cloudflare D1) with dense UI polish; login unlocks /home without blocking on every OpenDota refresh.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
voson
2026-08-01 01:24:30 +08:00
co-authored by Cursor
parent 4a61aeeb26
commit f5b7011c45
65 changed files with 7304 additions and 552 deletions
+55
View File
@@ -0,0 +1,55 @@
# 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
```