Skip to content

chore: migrate hosting from Netlify to Cloudflare Workers (static assets) - #183

Merged
ayoub3bidi merged 5 commits into
developfrom
chore/cloudflare-workers-migration
Jun 23, 2026
Merged

chore: migrate hosting from Netlify to Cloudflare Workers (static assets)#183
ayoub3bidi merged 5 commits into
developfrom
chore/cloudflare-workers-migration

Conversation

@ayoub3bidi

@ayoub3bidi ayoub3bidi commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Contribution workflow

  • Base branch is develop: This PR targets develop, not main.
  • Guidelines and docs: Read CONTRIBUTING.md and relevant docs.
  • This template: PR template structure kept; sections below filled in.

Description

Adds Cloudflare Workers static-asset hosting for Bayan Flow, replacing Netlify in CI/CD. The Vite SPA is served from dist/ with SPA fallback (not_found_handling: single-page-application), security headers ported to public/_headers, and GitHub Actions deploy/preview workflows. Netlify config is retained for rollback during the migration observation window.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🎨 Style/UI improvement
  • ⚡ Performance improvement
  • 🧪 Test addition or improvement
  • 🔧 Chore (maintenance, dependencies, etc.)

Related Issues

Fixes #

Changes Made

  • Add wrangler.jsonc — static assets on ./dist, SPA routing, staging / production environments (bayan-flow-staging, bayan-flow)
  • Add public/_headers — CSP, HSTS, frame/options headers (ported from netlify.toml); includes Product Hunt img-src; noindex on *.workers.dev
  • Add .github/workflows/deploy-cloudflare.yml — deploy after CI passes on push to main / develop
  • Add .github/workflows/preview-cloudflare.yml — PR previews to develop via wrangler versions upload --preview-alias pr-<N>
  • Remove Netlify deploy job from ci.yml (Netlify projects kept alive for rollback; netlify.toml retained)
  • Add wrangler devDependency and deploy:cf:* / preview:cf:upload scripts
  • Treat *.workers.dev as noindex in siteSeo.js, index.html, and tests
  • Update deployContext.js comment to reference CI / wrangler (not Netlify)

Algorithm Details (if applicable)

N/A

Testing

  • Focused tests pass (pnpm vitest run src/constants/siteSeo.test.js src/utils/deployContext.test.js)
  • All existing tests pass (pnpm test:run) — CI will run full suite
  • Manual testing completed — post-merge on bayan-flow-staging.workers.dev (see migration guide in PR notes)
  • Cross-browser testing (if UI changes)

Test Results

✓ siteSeo.test.js (3 tests)
✓ deployContext.test.js (3 tests)
pnpm build — OK
wrangler deploy --dry-run --env staging — OK (53 assets)

Screenshots/GIFs

N/A (infrastructure only)

Code Quality

  • Code follows the project's coding standards
  • ESLint passes (pnpm lint) — CI
  • Prettier formatting applied (pnpm format) — CI
  • No new application console errors expected
  • N/A — no new JSDoc required

Performance Impact

  • No performance impact

Accessibility

  • N/A — no UI changes

Breaking Changes

  • CI no longer deploys to Netlify on push/PR. Production and dev custom domains are unchanged until DNS cutover (manual step after merge).
  • Requires new GitHub secrets: CF_API_TOKEN, CF_ACCOUNT_ID

Checklist

  • Contribution workflow checklist at top completed
  • Self-review completed
  • netlify.toml kept intentionally for rollback (remove in follow-up after Netlify deletion)
  • New and existing unit tests pass in CI
  • Cloudflare secrets configured before expecting deploy workflow to succeed

Additional Notes

Why keep netlify.toml?

Do not delete it in this PR. It documents the last-known Netlify config if you need to redeploy to Netlify during rollback. Remove it in a small follow-up PR after you delete the Netlify projects (~2 weeks post cutover).

Post-merge operator steps (summary)

  1. Add CF_API_TOKEN + CF_ACCOUNT_ID in GitHub → Settings → Secrets
  2. Merge to develop → smoke-test https://bayan-flow-staging.workers.dev
  3. developmain PR → smoke-test https://bayan-flow.workers.dev
  4. Uncomment custom-domain routes in wrangler.jsonc, redeploy
  5. Repoint dev.bayanflow.com and bayanflow.com in Cloudflare dashboard
  6. After ~2 weeks stable: delete Netlify projects, remove netlify.toml, clean Netlify secrets from GitHub

Reviewer Guidelines:

  • Confirm workflows reference correct secret names (CF_API_TOKEN, CF_ACCOUNT_ID)
  • Verify _headers CSP matches prior netlify.toml intent
  • Confirm SPA fallback is wrangler not_found_handling, not only _redirects

Summary by CodeRabbit

  • New Features
    • Added automated Cloudflare Workers deployments for staging and production.
    • Added Cloudflare Workers PR previews with automated preview URL commenting.
  • Bug Fixes
    • Updated robots/analytics behavior so *.workers.dev hostnames are treated as non-production (noindex).
  • Security
    • Introduced stricter security HTTP headers, including an expanded Content Security Policy.
  • Tests
    • Extended SEO noindex test coverage for Workers.dev preview hostnames.
  • Chores
    • Improved CI check gating and label triggering; added Cloudflare tooling/config and updated ignore rules.

@ayoub3bidi ayoub3bidi self-assigned this Jun 23, 2026
@netlify

netlify Bot commented Jun 23, 2026

Copy link
Copy Markdown

Deploy Preview for dev-bayanflow ready!

Name Link
🔨 Latest commit 67498c1
🔍 Latest deploy log https://app.netlify.com/projects/dev-bayanflow/deploys/6a3ae3ad80c1c60008ea3c35
😎 Deploy Preview https://deploy-preview-183--dev-bayanflow.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a88d7b7-3c0b-4781-a5ea-41233de22a6d

📥 Commits

Reviewing files that changed from the base of the PR and between c1de3ac and 67498c1.

📒 Files selected for processing (2)
  • .github/workflows/deploy-cloudflare.yml
  • .github/workflows/preview-cloudflare.yml

📝 Walkthrough

Walkthrough

Migrates the project from Netlify to Cloudflare Workers by adding wrangler.jsonc with staging/production environments, new deploy and PR-preview GitHub Actions workflows, wrangler devDependency and npm scripts, updated runtime .workers.dev hostname detection and no-index logic, a public/_headers security config, and simplifies the CI gate to remove the former Netlify deploy dependency.

Changes

Netlify → Cloudflare Workers Migration

Layer / File(s) Summary
Wrangler config, tooling, and labeler
wrangler.jsonc, package.json, .gitignore, .github/labeler.yml, src/utils/deployContext.js
Adds wrangler.jsonc with staging/production env targets and SPA asset config; adds wrangler devDependency and Cloudflare deploy/preview npm scripts; ignores .wrangler; registers wrangler.jsonc in the CI labeler; updates the deployContext comment to reference new config.
workers.dev runtime detection and security headers
src/constants/siteSeo.js, src/constants/siteSeo.test.js, index.html, public/_headers
Extends isNoIndexHostname to include .workers.dev with matching tests; updates index.html to apply noindex meta and dev Umami analytics ID on workers.dev hostnames; adds public/_headers with HSTS, CSP, and X-Robots-Tag: noindex for the *.workers.dev URL pattern.
CI gate: remove Netlify deploy dependency
.github/workflows/ci.yml
Replaces the old all-checks-pass job (which gated on a Netlify deploy) with one waiting only on quality, test, and build; removes the bash conditional that checked the deploy job result.
Cloudflare Workers deploy workflow
.github/workflows/deploy-cloudflare.yml
New workflow_run-triggered workflow that deploys to Cloudflare Workers after CI succeeds on main/develop; builds with branch-derived Vite env vars and deploys with --env production or --env staging via wrangler-action; prints branch-specific worker and custom-domain URLs.
Cloudflare Workers PR preview workflow and netlify.toml note
.github/workflows/preview-cloudflare.yml, netlify.toml
New PR workflow targeting develop that runs lint/test/build, uploads a Cloudflare Workers version with a PR-number alias, and posts or updates a PR comment with the preview URL. Updates netlify.toml with migration rollback comments and extends img-src CSP to allow api.producthunt.com.

Sequence Diagram(s)

sequenceDiagram
  participant PR as Pull Request
  participant GH as GitHub Actions
  participant CF as Cloudflare Workers
  participant Commenter as github-script

  rect rgba(100, 149, 237, 0.5)
    note over PR,Commenter: PR Preview Flow (develop branch)
    PR-->>GH: PR opened/synchronize (target: develop)
    GH->>GH: install + lint + test + build
    GH->>CF: wrangler versions upload --env staging (pr-N alias)
    CF-->>GH: Version Preview Alias URL
    GH->>Commenter: parse URL from output
    Commenter->>PR: upsert comment with preview URL table
  end

  rect rgba(144, 238, 144, 0.5)
    note over GH,CF: Deploy Flow (main / develop)
    GH-->>GH: CI workflow_run completed
    GH->>GH: install + vite build (branch env vars)
    GH->>CF: wrangler deploy --env production OR staging
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hop, hop, away from Netlify's nest,
To Cloudflare Workers — a brand new quest!
wrangler.jsonc tucked under my paw,
Staging and prod without a flaw.
Preview comments bloom on every PR,
This bunny deploys from near and far! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main objective of the PR: migrating static asset hosting from Netlify to Cloudflare Workers.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/cloudflare-workers-migration

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

@socket-security

socket-security Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedwrangler@​4.104.0991009296100

View full report

@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot 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: 5

🧹 Nitpick comments (1)
.github/workflows/deploy-cloudflare.yml (1)

61-69: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pass head_branch via an env var instead of inline expansion.

${{ github.event.workflow_run.head_branch }} is expanded directly into the run shell block. The branches/if filters constrain this to main/develop today, so it isn't currently exploitable, but inlining GitHub context into shell is the classic template-injection pattern. Bind it to env and reference "$HEAD_BRANCH" for defense-in-depth.

🛡️ Proposed fix
       - name: Output deployment URL
+        env:
+          HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
         run: |
-          if [[ "${{ github.event.workflow_run.head_branch }}" == "main" ]]; then
+          if [[ "$HEAD_BRANCH" == "main" ]]; then
             echo "Production worker: https://bayan-flow.workers.dev"
             echo "Custom domain (after DNS cutover): https://bayanflow.com"
           else
             echo "Staging worker: https://bayan-flow-staging.workers.dev"
             echo "Custom domain (after DNS cutover): https://dev.bayanflow.com"
           fi
🤖 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 @.github/workflows/deploy-cloudflare.yml around lines 61 - 69, The "Output
deployment URL" step is directly expanding the GitHub context variable `${{
github.event.workflow_run.head_branch }}` into the shell script, which creates a
potential template injection vulnerability. To fix this, add an `env` section to
the step that binds the GitHub context to an environment variable (e.g.,
`HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}`), then replace the
direct context expansion in the shell script with a reference to the environment
variable using `"$HEAD_BRANCH"`. This ensures the GitHub context is safely bound
at the workflow level rather than being directly expanded into the shell.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/deploy-cloudflare.yml:
- Around line 26-29: The checkout action in the deploy workflow is using the
default credential persistence setting, which leaves a git token in the
repository config during the build process and increases the attack surface. Add
the `persist-credentials: false` option to the actions/checkout@v6 step to
disable credential persistence, since this workflow only needs to read source
code for building and deploying without any git push operations.

In @.github/workflows/preview-cloudflare.yml:
- Around line 22-25: Add `persist-credentials: false` to the checkout action to
disable token persistence for better security. Additionally, replace all
floating action version tags with specific commit SHAs across the workflow at
lines 23, 28, 33, 60, and 72 (actions like checkout, setup-node,
actions-gh-pages, etc.) to pin exact action versions and prevent supply-chain
attacks. Finally, update the listComments call around lines 95-99 to include the
`per_page` parameter for proper pagination to ensure all comments are searched
even on PRs with many existing comments, preventing duplicate preview comments
from being created.
- Around line 95-102: The github.rest.issues.listComments call only fetches the
first page of comments (default 30 items per page), so the marker lookup in the
find() method can miss older bot comments on threads with many comments,
resulting in duplicate preview comments. Implement pagination to fetch all
comments from all pages before searching for the existing comment with the
marker. Use GitHub's paginate utility or add a loop to iterate through all pages
until no more comments are returned, accumulating all comments into a single
array before performing the find() operation.

In `@public/_headers`:
- Around line 9-10: The URL pattern on line 9 with
`https://:version.:subdomain.workers.dev/*` expects two labels before
workers.dev (e.g., label1.label2.workers.dev), but all actual deployment URLs
use only a single label (pr-{number}-bayan-flow-staging.workers.dev,
bayan-flow-staging.workers.dev, bayan-flow.workers.dev). Modify the pattern to
match the actual single-label deployment URLs by updating the pattern structure
to correctly capture these single-label subdomains before workers.dev instead of
expecting two separate labels.

In `@src/constants/siteSeo.test.js`:
- Line 34: The test line with the isNoIndexHostname function call exceeds
Prettier's line length limit and is causing formatting check failures. Break
this long line into multiple lines by extracting the hostname string into a
separate variable declared before the expect statement, or split the expect call
across multiple lines to meet the configured line length requirement.

---

Nitpick comments:
In @.github/workflows/deploy-cloudflare.yml:
- Around line 61-69: The "Output deployment URL" step is directly expanding the
GitHub context variable `${{ github.event.workflow_run.head_branch }}` into the
shell script, which creates a potential template injection vulnerability. To fix
this, add an `env` section to the step that binds the GitHub context to an
environment variable (e.g., `HEAD_BRANCH: ${{
github.event.workflow_run.head_branch }}`), then replace the direct context
expansion in the shell script with a reference to the environment variable using
`"$HEAD_BRANCH"`. This ensures the GitHub context is safely bound at the
workflow level rather than being directly expanded into the shell.
🪄 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: d40a2f3a-36d2-4d46-8a09-ddd8b703bdeb

📥 Commits

Reviewing files that changed from the base of the PR and between 6046e7c and d0a227c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • .github/labeler.yml
  • .github/workflows/ci.yml
  • .github/workflows/deploy-cloudflare.yml
  • .github/workflows/preview-cloudflare.yml
  • .gitignore
  • index.html
  • netlify.toml
  • package.json
  • public/_headers
  • src/constants/siteSeo.js
  • src/constants/siteSeo.test.js
  • src/utils/deployContext.js
  • wrangler.jsonc

Comment thread .github/workflows/deploy-cloudflare.yml
Comment thread .github/workflows/preview-cloudflare.yml
Comment thread .github/workflows/preview-cloudflare.yml Outdated
Comment thread public/_headers Outdated
Comment thread src/constants/siteSeo.test.js Outdated
@ayoub3bidi
ayoub3bidi force-pushed the chore/cloudflare-workers-migration branch from 99bbe89 to 0b20f4b Compare June 23, 2026 19:32
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown

Cloudflare Workers preview for bayan-flow-staging ready!

Name Link
🔨 Latest commit 67498c1
🔍 Latest deploy log https://github.com/ayoub3bidi/bayan-flow/actions/runs/28052735973
😎 Deploy Preview https://pr-183-bayan-flow-staging.workers.dev
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

Preview alias pr-183 on the staging worker. Updates automatically with new commits.

@ayoub3bidi
ayoub3bidi merged commit 2b0e649 into develop Jun 23, 2026
15 checks passed
@ayoub3bidi
ayoub3bidi deleted the chore/cloudflare-workers-migration branch June 23, 2026 19:57
@ayoub3bidi ayoub3bidi mentioned this pull request Jul 16, 2026
35 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant