Stage A: backend-only rebuild on rollback base (contract-verified against live frontend) - #8
Conversation
…rollback base Re-applies, onto the known-working d5f02f1 state, ONLY the backend-side work — verified against the production frontend's exact API contract. Zero changes to sessions.py, scoring.py, rooms.py, daily.py, or any frontend file. /sessions/start still requires track_ids exactly as the live frontend sends it (contract-tested, including the 422 shape when omitted). Large playlists & permanent previews: - Batched playlist saves: 3 statements instead of ~2 per track - Preview URLs recovered by the worker are never overwritten with empty strings on re-fetch (CASE guard), and degraded fetches can no longer truncate the playlist link table or shrink stored totals — this is the 'scraped links get trashed' bug - Single-flight playlist fetches; parallel metadata pages with Retry-After-aware 429 handling that fails fast on Spotify's multi-hour penalty boxes instead of hanging the user's request - Honest totals + fetch_complete flag (self-migrated column): truncated records re-fetch after 6h instead of being served for 7 days - On-demand preview fill: a fresh large playlist becomes fully playable in minutes; worker remains the janitor (bounded cycles, batched writes, startup banner for pm2 logs) Performance & fixes: - players-today endpoint 500s in the original code (COALESCE type error) — fixed - bcrypt + Cloudinary moved off the event loop; avatar reads capped at 5MB - Rate limiter dicts evict idle IPs; app-level gzip removed (nginx does it) - Sessions last 90 days (was 72h with no refresh = weekly forced logouts) - bcrypt 72-byte password cap (re-applied from 5d15bf3) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
backend/auth.py (1)
118-120: 🔒 Security & Privacy | 🔵 Trivial90-day token lifetime with no revocation broadens the compromise window.
Because token lifetime is the session lifetime and there's no refresh/rotation flow, a leaked token stays valid for up to ~90 days, and neither logout nor password change can invalidate it. If you keep the long expiry, consider a server-side invalidation lever — e.g. a
token_version/password_changed_atclaim checked at auth time, or a short deny-list — so compromised or post-logout tokens can be cut off before natural expiry.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/auth.py` around lines 118 - 120, Add server-side token invalidation to the authentication flow using a token_version or password_changed_at value included in issued JWTs and checked during request authentication. Ensure logout and password changes advance or invalidate that value so existing tokens are rejected, while preserving the configurable JWT_EXPIRE_HOURS lifetime.backend/database.py (1)
26-32: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueConsider surfacing genuine migration failures instead of swallowing them.
The broad
except Exception(Ruff BLE001) makes the self-migration resilient to the benign "column already exists" case, but it also silences a real ALTER failure. Sincesave_playlistwrites/reads thefetch_completecolumn unconditionally, a truly failed migration would turn into harder-to-trace runtime errors later while startup reports success.ADD COLUMN IF NOT EXISTSis already idempotent, so the try/except mainly guards against permission/transient errors — at minimum this is worth verifying doesn't hide a persistent failure.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/database.py` around lines 26 - 32, Update the self-migration around the ALTER TABLE statement to stop broadly swallowing migration failures: let genuine permission, connectivity, or SQL errors from conn.execute propagate and fail startup, while retaining the idempotent ADD COLUMN IF NOT EXISTS behavior. Remove or narrow the Exception handler and adjust logging only if needed to preserve visibility of actual failures.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@backend/auth.py`:
- Around line 118-120: Add server-side token invalidation to the authentication
flow using a token_version or password_changed_at value included in issued JWTs
and checked during request authentication. Ensure logout and password changes
advance or invalidate that value so existing tokens are rejected, while
preserving the configurable JWT_EXPIRE_HOURS lifetime.
In `@backend/database.py`:
- Around line 26-32: Update the self-migration around the ALTER TABLE statement
to stop broadly swallowing migration failures: let genuine permission,
connectivity, or SQL errors from conn.execute propagate and fail startup, while
retaining the idempotent ADD COLUMN IF NOT EXISTS behavior. Remove or narrow the
Exception handler and adjust logging only if needed to preserve visibility of
actual failures.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5f88797d-5799-48a7-a6a5-18f7602bd9fb
📒 Files selected for processing (8)
backend/auth.pybackend/database.pybackend/db_playlists.pybackend/preview_store.pybackend/preview_worker.pybackend/schema.sqlbackend/server.pybackend/stats.py
Per CodeRabbit: the broad 'except Exception' silently swallowed permission and SQL errors, which would leave the fetch_complete column missing while save_playlist references it — breaking every playlist save quietly. Now only UndefinedTableError (fresh DB, schema.sql not yet run) is tolerated; genuine failures propagate and fail startup loudly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8b788ac
into
codex/rollback-d5f02f1-working-state
Stage A: backend-only rebuild on rollback base (contract-verified against live frontend)
What this is
The careful restart. Base is the rollback (
d5f02f1+ App.js tweak) that runs in production. This PR re-applies only the backend-side performance and data-integrity work, with the original architecture and API contract untouched.Hard guarantees, tested:
sessions.py,scoring.py,rooms.py,daily.py, or any frontend file (git diffagainst base for those paths is empty)/sessions/startwithtrack_ids→/scores/submit→ session-complete →/tracks/art→/stats/activity→ audio-proxy — all pass, and omittingtrack_idsstill 422s exactly as production does todaywarningstring the frontend already displays,fetch_completeflag it ignores)fetch_completecolumn self-migrates at startupWhat it fixes
Verified
Contract suite + three integration suites (batch save/link guard, preview fill, penalty/totals) against Postgres 16; full app imports with the original 33 routes.
Deploy (backend only — frontend untouched)
Then one-time in Supabase:
UPDATE playlists SET fetched_at = NOW() - INTERVAL '8 days';Smoke test: load a playlist and start a demo game.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes