fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(frontend): fail build when BACKEND_URL unset; document staging footgun - #281

Merged
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard
Jun 28, 2026
Merged

fix(frontend): fail build when BACKEND_URL unset; document staging footgun#281
AndresL230 merged 2 commits into
mainfrom
fix/staging-frontend-build-url-guard

Conversation

@AndresL230

@AndresL230AndresL230 commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

What & why

Staging's dashboard was down: every proxied /api/* call returned 500. Root cause was isolated to the frontend Cloudflare worker, not the backend or DB:

  • staging.saplinglearn.com/api/users500 text/plain "Internal Server Error" (worker)
  • api.staging.saplinglearn.com/api/users401 application/json (backend healthy)

The frontend-staging worker had been built with no build-time BACKEND_URL, so the /api/:path* rewrite destination fell back to http://localhost:5000. Next's path-to-regexp then misreads the :5000 port as a route param (TypeError: Expected "5000" to be a string), 500-ing every proxied call at runtime. wrangler.toml [vars] is runtime-only and does not cover the build-time rewrite.

This PR

  • next.config.ts: throw at build time when NODE_ENV=production and BACKEND_URL is unset, so a broken worker can never ship silently again — the build fails loudly instead.
  • docs/staging/setup-checklist.md: document the build-time env vars (BACKEND_URL / NEXT_PUBLIC_API_URL / NEXT_PUBLIC_LOCAL_MODE) and the SESSION_SECRET parity requirement.

Operational note (do before/at merge)

Because this guard now fails the build without BACKEND_URL, the Build variableBACKEND_URL must be set on the Workers Builds config for both staging and prod, or the first build after merge fails:

  • staging → https://api.staging.saplinglearn.com (already set)
  • prod → https://api.saplinglearn.com (verify)

The live staging worker was already hotfixed via a one-off local deploy with BACKEND_URL set (verified: proxy 500 → 401); this PR makes the fix durable in the pipeline.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Added a build-time check to prevent production frontends from starting without a backend URL configured.
    • Improved error guidance for missing or mismatched session secrets, helping staging sign-in behave more predictably.
  • Documentation

    • Expanded the staging setup checklist with clearer environment variable requirements for frontend builds and local deployments.
    • Clarified which secrets belong to the frontend vs. backend, including exact matching requirements for session settings.

…otgun
A staging frontend build without a build-time BACKEND_URL falls back to
http://localhost:5000 in the /api rewrite destination. Next's path-to-regexp
then misreads the :5000 port as a route param ('Expected "5000" to be a
string'), so every proxied /api/* call 500s at the worker while the backend
itself is healthy. wrangler.toml [vars] is runtime-only and does not cover the
build-time rewrite.
Throw at build time when NODE_ENV=production and BACKEND_URL is unset so a
broken worker can never ship silently again, and document the build-time vars
(and the SESSION_SECRET parity requirement) in the staging checklist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitaiBot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AndresL230, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d872a64-b858-4b54-90f8-5dc3dfe7c4c5

📥 Commits

Reviewing files that changed from the base of the PR and between 4777f4c and be33f4b.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts
📝 Walkthrough

Walkthrough

Adds a production-only guard in next.config.ts that throws if BACKEND_URL is unset, preventing silent localhost fallback in production builds. Updates the staging setup checklist to document required build-time environment variables and clarifies SESSION_SECRET must exactly match the Railway value.

Changes

BACKEND_URL Guard and Staging Secrets Docs

Layer / File(s)Summary
Production BACKEND_URL guard and staging docs
frontend/next.config.ts, docs/staging/setup-checklist.md
next.config.ts throws an error when NODE_ENV === "production" and BACKEND_URL is unset. Staging checklist adds build-time env var steps, failure-mode notes, and splits ENCRYPTION_KEY/SESSION_SECRET rows with exact-match requirement for SESSION_SECRET.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐇 A rabbit checked the config with care,
"No BACKEND_URL? That's quite the scare!"
Now the build will shout if the URL's bare,
And staging secrets documented fair.
Hop hop, no silent defaults anywhere! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Title check✅ PassedThe title clearly matches the main change: a production build guard for BACKEND_URL plus staging docs updates.
Description check✅ PassedThe description covers the problem, root cause, changes, and rollout note, but it omits several template sections like issues and testing.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/staging-frontend-build-url-guard

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pagesBot commented Jun 28, 2026

Copy link
Copy Markdown

Deploying with Cloudflare Workers Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

StatusNameLatest CommitPreview URLUpdated (UTC)
✅ Deployment successful!
View logs
frontend-stagingbe33f4bCommit Preview URL

Branch Preview URL
Jun 28 2026, 04:08 AM

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.
Inline comments:
In `@docs/staging/setup-checklist.md`:
- Line 43: The setup checklist has a mismatch: it says BACKEND_URL must be
provided at build time, but the “What secret goes where” table still lists
BACKEND_URL under wrangler.toml runtime vars. Update that table to move
BACKEND_URL out of the runtime-vars grouping and clearly mark it as a build-time
variable alongside NEXT_PUBLIC_API_URL, while keeping COOKIE_DOMAIN in the
runtime worker vars section, so the guidance stays consistent with
next.config.ts behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 640b39e7-097e-4ecd-89d8-5de2b36e344f

📥 Commits

Reviewing files that changed from the base of the PR and between 1c2f6f0 and 4777f4c.

📒 Files selected for processing (2)
  • docs/staging/setup-checklist.md
  • frontend/next.config.ts

Comment threaddocs/staging/setup-checklist.md Outdated

### Step 4 — Cloudflare Workers (the frontend service)
- [ ] The `[env.staging]` block in `frontend/wrangler.toml` is already in the repo (Phase 4). Deploy: `cd frontend && npm run cf:deploy:staging` → publishes a `frontend-staging` worker.
- [ ] **Set the build-time env vars** `BACKEND_URL` and `NEXT_PUBLIC_API_URL` (both `https://api.staging.saplinglearn.com`) for the staging build. These are read by `next.config.ts`/client bundles at **build time** — `wrangler.toml [env.staging.vars]` is runtime-only and does NOT cover them. If you deploy via Cloudflare Workers Builds, add them as **Build variables** on the staging build; if you deploy locally, export them before `npm run cf:deploy:staging` (also export `NEXT_PUBLIC_LOCAL_MODE=false` so a stray local `.env.local` can't flip staging into mock mode). Miss `BACKEND_URL` and the `/api` rewrite bakes `http://localhost:5000` → every dashboard API call 500s (`next.config.ts` now fails the build loudly if it is unset).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Split BACKEND_URL out from the runtime-vars table entry.

Step 4 now correctly says BACKEND_URL must be present at build time, but the later “What secret goes where” table still groups BACKEND_URL with COOKIE_DOMAIN as a Cloudflare worker wrangler.toml var. That contradiction can send operators back to the same broken localhost rewrite path this PR is fixing.

🤖 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 `@docs/staging/setup-checklist.md` at line 43, The setup checklist has a
mismatch: it says BACKEND_URL must be provided at build time, but the “What
secret goes where” table still lists BACKEND_URL under wrangler.toml runtime
vars. Update that table to move BACKEND_URL out of the runtime-vars grouping and
clearly mark it as a build-time variable alongside NEXT_PUBLIC_API_URL, while
keeping COOKIE_DOMAIN in the runtime worker vars section, so the guidance stays
consistent with next.config.ts behavior.

A stray leading/trailing space in the Workers Builds BACKEND_URL variable
makes the /api rewrite destination start with a space, which Next rejects at
build time as 'Invalid rewrite found'. Trim the value so the build tolerates
whitespace, and validate it is an absolute http(s) origin with a clear error
that points at the variable instead of Next's cryptic message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@AndresL230
AndresL230 merged commit e6aeb5f into mainJun 28, 2026
6 checks passed
@AndresL230
AndresL230 deleted the fix/staging-frontend-build-url-guard branch August 2, 2026 18:30
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AndresL230