From c6521982bb4089c0760f83ad71f9fdf10c0652e5 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 2 Dec 2025 21:47:45 +0000 Subject: [PATCH 1/6] Configure separate preview and production domains MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change establishes clear separation between staging and production deployments using different Cloudflare Pages branches and custom domains: Changes: - Update release-web.yml to deploy to 'release' branch (not 'main') - Add preview.cambeerfestival.app to worker CORS origins - Update documentation to reflect new architecture Architecture: - Production: cambeerfestival.app (CF Pages 'release' branch, deployed on git tags) - Preview: preview.cambeerfestival.app (CF Pages 'main' branch, deployed on git main) - PR Previews: .cambeerfestival.pages.dev (CF Pages '' branch) Next step: Configure custom domains in Cloudflare Dashboard to point: - cambeerfestival.app → release branch - preview.cambeerfestival.app → main branch --- .github/workflows/release-web.yml | 2 +- README.md | 13 ++++--- cloudflare-worker/worker.js | 1 + docs/CLOUDFLARE_PAGES_SETUP.md | 58 ++++++++++++++++++++++++------- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release-web.yml b/.github/workflows/release-web.yml index 1ea4aa13..921a2f2a 100644 --- a/.github/workflows/release-web.yml +++ b/.github/workflows/release-web.yml @@ -82,4 +82,4 @@ jobs: with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: pages deploy build/web --project-name=cambeerfestival --branch=main + command: pages deploy build/web --project-name=cambeerfestival --branch=release diff --git a/README.md b/README.md index 7a8db57d..bc08a77b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ A Flutter app for browsing beers, ciders, meads, and more at the Cambridge Beer Festival. **Production**: [https://cambeerfestival.app](https://cambeerfestival.app) -**Staging**: [https://richardthe3rd.github.io/cambridge-beer-festival-app/](https://richardthe3rd.github.io/cambridge-beer-festival-app/) +**Preview**: [https://preview.cambeerfestival.app](https://preview.cambeerfestival.app) +**Development**: [https://richardthe3rd.github.io/cambridge-beer-festival-app/](https://richardthe3rd.github.io/cambridge-beer-festival-app/) ## Features @@ -140,23 +141,25 @@ The app is deployed to multiple environments: - **Production** (Cloudflare Pages): [cambeerfestival.app](https://cambeerfestival.app) - Deployed on version tags (e.g., `v2025.12.0`) + - Uses Cloudflare Pages `release` branch - Workflow: `.github/workflows/release-web.yml` -- **Staging** (Cloudflare Pages): `main.cambeerfestival.pages.dev` - - Stable preview environment +- **Preview/Staging** (Cloudflare Pages): [preview.cambeerfestival.app](https://preview.cambeerfestival.app) + - Stable staging environment - Deployed automatically on push to `main` + - Uses Cloudflare Pages `main` branch - Workflow: `.github/workflows/build-deploy.yml` (deploy-web-preview job) - **Development** (GitHub Pages): [richardthe3rd.github.io/cambridge-beer-festival-app](https://richardthe3rd.github.io/cambridge-beer-festival-app/) - Alternative development environment - Deployed automatically on push to `main` - Workflow: `.github/workflows/build-deploy.yml` (deploy-web job) - **PR Previews** (Cloudflare Pages): Unique URL per pull request - - Each PR gets its own preview environment + - Each PR gets its own preview environment (e.g., `.cambeerfestival.pages.dev`) - Preview URL posted as comment on the PR - Workflow: `.github/workflows/build-deploy.yml` (deploy-web-preview job) ### Deployment Strategy -1. **Development changes**: Push to `main` → Staging (Cloudflare) + GitHub Pages updated +1. **Development changes**: Push to `main` → Preview (Cloudflare) + GitHub Pages updated 2. **PR reviews**: Open PR → Unique Cloudflare Pages preview created 3. **Production releases**: Create tag (e.g., `v2025.12.0`) → Production deployment to cambeerfestival.app diff --git a/cloudflare-worker/worker.js b/cloudflare-worker/worker.js index 67dd5206..56b6b6dd 100644 --- a/cloudflare-worker/worker.js +++ b/cloudflare-worker/worker.js @@ -22,6 +22,7 @@ const FESTIVALS_CACHE_CONTROL = 'no-cache, must-revalidate'; const ALLOWED_ORIGINS = [ 'https://richardthe3rd.github.io', 'https://cambeerfestival.app', + 'https://preview.cambeerfestival.app', 'http://localhost:8080', 'http://localhost:3000', 'http://127.0.0.1:8080', diff --git a/docs/CLOUDFLARE_PAGES_SETUP.md b/docs/CLOUDFLARE_PAGES_SETUP.md index d5e6b89f..87d696aa 100644 --- a/docs/CLOUDFLARE_PAGES_SETUP.md +++ b/docs/CLOUDFLARE_PAGES_SETUP.md @@ -8,10 +8,19 @@ This document explains how to set up Cloudflare Pages deployment for the Cambrid ## Overview -The app has two deployment targets: +The app has three deployment targets: -1. **GitHub Pages** (Development/Staging): `richardthe3rd.github.io/cambridge-beer-festival-app/` -2. **Cloudflare Pages** (Production): `cambeerfestival.app` +1. **GitHub Pages** (Development): `richardthe3rd.github.io/cambridge-beer-festival-app/` +2. **Cloudflare Pages Staging** (Preview): `preview.cambeerfestival.app` +3. **Cloudflare Pages Production**: `cambeerfestival.app` + +### Deployment Architecture + +| Git Event | Cloudflare Pages Branch | Custom Domain | Purpose | +|-----------|------------------------|---------------|---------| +| Pull Request | `` | `.cambeerfestival.pages.dev` | PR previews | +| Push to `main` | `main` | `preview.cambeerfestival.app` | Staging | +| Version tag (e.g., `v2025.12.0`) | `release` | `cambeerfestival.app` | Production | ## Prerequisites @@ -92,24 +101,46 @@ You can reuse the same token by adding Pages permissions to it: **Note**: Using a single token with both Workers and Pages permissions is simpler and follows the principle of consolidating CI/CD credentials for the same application. -### 4. Configure Custom Domain +### 4. Configure Custom Domains + +You need to set up **two custom domains** pointing to different Cloudflare Pages branches: + +#### 4a. Production Domain (cambeerfestival.app) 1. In Cloudflare Dashboard, go to **Workers & Pages** → **Pages** 2. Select your `cambeerfestival` project 3. Go to **Custom domains** tab 4. Click **Set up a custom domain** 5. Enter: `cambeerfestival.app` -6. Click **Continue** -7. Cloudflare will automatically configure the DNS records -8. Optionally add `www.cambeerfestival.app` as well +6. **Important**: Select **Branch**: `release` (not `main`) +7. Click **Continue** +8. Cloudflare will automatically configure the DNS records + +#### 4b. Preview/Staging Domain (preview.cambeerfestival.app) + +1. In the same **Custom domains** tab +2. Click **Set up a custom domain** again +3. Enter: `preview.cambeerfestival.app` +4. **Important**: Select **Branch**: `main` +5. Click **Continue** +6. Cloudflare will automatically configure the DNS records + +#### 4c. Optional: WWW Redirect + +If you want `www.cambeerfestival.app` to redirect to the apex domain: +1. Add `www.cambeerfestival.app` as a custom domain +2. Select **Branch**: `release` **DNS Records Created** (automatic): -- `CNAME cambeerfestival.app` → `cambeerfestival.pages.dev` -- `CNAME www.cambeerfestival.app` → `cambeerfestival.pages.dev` (if www added) +- `CNAME cambeerfestival.app` → `cambeerfestival.pages.dev` (points to `release` branch) +- `CNAME preview.cambeerfestival.app` → `cambeerfestival.pages.dev` (points to `main` branch) +- `CNAME www.cambeerfestival.app` → `cambeerfestival.pages.dev` (optional, points to `release` branch) ### 5. Update Cloudflare Worker -The Cloudflare Worker for API proxy has already been updated to allow `https://cambeerfestival.app` in CORS origins. +The Cloudflare Worker for API proxy has already been updated to allow both custom domains in CORS origins: +- `https://cambeerfestival.app` (production) +- `https://preview.cambeerfestival.app` (staging) When you deploy worker changes: @@ -407,13 +438,14 @@ Both should remain in free tier unless app sees very high traffic. - [ ] Cloudflare Pages project `cambeerfestival` created - [ ] Cloudflare Account ID obtained - [ ] Cloudflare API Token updated with **both** Workers Scripts + Pages permissions -- [ ] Custom domain `cambeerfestival.app` configured in Cloudflare Pages +- [ ] Custom domain `cambeerfestival.app` configured → points to `release` branch +- [ ] Custom domain `preview.cambeerfestival.app` configured → points to `main` branch - [ ] DNS records configured (automatic via Cloudflare) - [ ] GitHub Secret `CLOUDFLARE_API_TOKEN` verified (should work for both Workers and Pages) - [ ] GitHub Secret `CLOUDFLARE_ACCOUNT_ID` added - [ ] GitHub Secret `GOOGLE_SERVICES_JSON` verified - [ ] Workflow files committed (`.github/workflows/release-web.yml` and `build-deploy.yml`) -- [ ] Cloudflare Worker updated with `cambeerfestival.app` CORS origin and wildcard for Pages previews -- [ ] Push to `main` triggers successful deployment to staging +- [ ] Cloudflare Worker updated with both custom domains in CORS origins +- [ ] Push to `main` triggers successful deployment to `https://preview.cambeerfestival.app` - [ ] Create tag triggers production deployment to `https://cambeerfestival.app` - [ ] API calls work without CORS errors on all environments From 34e7d1f0909b7e49f1764ad7c290ee88e522ea87 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Dec 2025 08:10:24 +0000 Subject: [PATCH 2/6] Use separate Cloudflare Pages projects for staging and production MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes build-deploy.yml to deploy previews to a separate 'cambeerfestival-preview' project instead of sharing the same project. Architecture: - Project 'cambeerfestival': Production only (git tags → release branch) - Project 'cambeerfestival-preview': Staging + PRs (git main → main branch, PRs → PR branches) Each project has its own custom domain: - cambeerfestival.app → cambeerfestival project - preview.cambeerfestival.app → cambeerfestival-preview project This provides clean separation between production and staging environments while working within Cloudflare Pages' production/preview branch model. --- .github/workflows/build-deploy.yml | 2 +- docs/CLOUDFLARE_PAGES_SETUP.md | 131 +++++++++++++++++------------ 2 files changed, 80 insertions(+), 53 deletions(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index 598a75ab..6a24ba23 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -263,7 +263,7 @@ jobs: with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: pages deploy build/web --project-name=cambeerfestival --branch=${{ github.head_ref || github.ref_name }} + command: pages deploy build/web --project-name=cambeerfestival-preview --branch=${{ github.head_ref || github.ref_name }} - name: Comment PR with Preview URL if: github.event_name == 'pull_request' diff --git a/docs/CLOUDFLARE_PAGES_SETUP.md b/docs/CLOUDFLARE_PAGES_SETUP.md index 87d696aa..677e4262 100644 --- a/docs/CLOUDFLARE_PAGES_SETUP.md +++ b/docs/CLOUDFLARE_PAGES_SETUP.md @@ -8,19 +8,29 @@ This document explains how to set up Cloudflare Pages deployment for the Cambrid ## Overview -The app has three deployment targets: +The app uses **two separate Cloudflare Pages projects** for clean separation between production and staging: -1. **GitHub Pages** (Development): `richardthe3rd.github.io/cambridge-beer-festival-app/` -2. **Cloudflare Pages Staging** (Preview): `preview.cambeerfestival.app` -3. **Cloudflare Pages Production**: `cambeerfestival.app` +### Cloudflare Pages Projects + +**Project 1: `cambeerfestival`** (Production only) +- Production branch: `release` +- Deploys: Git tags (e.g., `v2025.12.0`) +- Custom domain: `cambeerfestival.app` + +**Project 2: `cambeerfestival-preview`** (Staging + PR previews) +- Production branch: `main` (serves staging) +- Preview branches: PR branches (serve PR previews) +- Deploys: Git main + all PRs +- Custom domain: `preview.cambeerfestival.app` ### Deployment Architecture -| Git Event | Cloudflare Pages Branch | Custom Domain | Purpose | -|-----------|------------------------|---------------|---------| -| Pull Request | `` | `.cambeerfestival.pages.dev` | PR previews | -| Push to `main` | `main` | `preview.cambeerfestival.app` | Staging | -| Version tag (e.g., `v2025.12.0`) | `release` | `cambeerfestival.app` | Production | +| Git Event | CF Project | CF Branch | URL | Purpose | +|-----------|------------|-----------|-----|---------| +| Version tag | `cambeerfestival` | `release` | `cambeerfestival.app` | Production | +| Push to `main` | `cambeerfestival-preview` | `main` | `preview.cambeerfestival.app` | Staging | +| Pull Request | `cambeerfestival-preview` | `` | `.cambeerfestival-preview.pages.dev` | PR previews | +| Push to `main` | GitHub Pages | N/A | `richardthe3rd.github.io/...` | Development | ## Prerequisites @@ -30,32 +40,36 @@ The app has three deployment targets: ## Cloudflare Configuration -### 1. Create Cloudflare Pages Project +### 1. Create Cloudflare Pages Projects + +You need **two separate Cloudflare Pages projects**: +- `cambeerfestival` (production) +- `cambeerfestival-preview` (staging/previews) -**Option A: Let GitHub Actions Create the Project (Easiest)** +**Option A: Let GitHub Actions Create the Projects (Easiest)** -The GitHub Actions workflow will automatically create the Cloudflare Pages project on the first deployment. You can skip this step and jump to step 2 (Get Account ID) and step 3 (Create API Token). +Both projects will be automatically created on their first deployment. You can skip this step and jump to step 2 (Get Account ID) and step 3 (Create API Token). -When the workflow runs, it will create a project named `cambeerfestival` automatically. +- First push to `main` will create `cambeerfestival-preview` +- First git tag will create `cambeerfestival` -**Option B: Create Project Manually** +**Option B: Create Projects Manually** -If you prefer to create the project manually first: +If you prefer to create the projects manually first: +**For Production Project:** 1. Log in to [Cloudflare Dashboard](https://dash.cloudflare.com/) 2. Navigate to **Workers & Pages** -3. Click **Create application** or **Create** -4. Choose **Pages** tab -5. Click **Connect to Git** (you can set this up or skip automatic deployments) - - OR use **Upload assets** if available -6. If using Connect to Git: - - You can connect to your repository but disable automatic deployments - - GitHub Actions will handle deployments instead -7. Set **Project name**: `cambeerfestival` +3. Click **Create application** → **Pages** +4. Set **Project name**: `cambeerfestival` +5. Disable automatic deployments (GitHub Actions will handle deployments) -**Important**: The project name must be `cambeerfestival` to match the workflow configuration. +**For Preview Project:** +1. In **Workers & Pages**, click **Create application** → **Pages** +2. Set **Project name**: `cambeerfestival-preview` +3. Disable automatic deployments -**Note**: With GitHub Actions using `cloudflare/pages-action@v1`, the project will be created automatically on first deployment if it doesn't exist. Manual creation is optional. +**Important**: Project names must match the workflow configuration (`cambeerfestival` and `cambeerfestival-preview`). ### 2. Get Cloudflare Account ID @@ -103,38 +117,43 @@ You can reuse the same token by adding Pages permissions to it: ### 4. Configure Custom Domains -You need to set up **two custom domains** pointing to different Cloudflare Pages branches: +You need to configure **one custom domain per project**: + +#### 4a. Production Project Domain + +1. In Cloudflare Dashboard, go to **Workers & Pages** → **Pages** +2. Select the **`cambeerfestival`** project +3. Go to **Settings** → **Builds & deployments** +4. Set **Production branch** to: `release` +5. Go to **Custom domains** tab +6. Click **Set up a custom domain** +7. Enter: `cambeerfestival.app` +8. Click **Continue** +9. Cloudflare will automatically configure the DNS records -#### 4a. Production Domain (cambeerfestival.app) +#### 4b. Preview/Staging Project Domain 1. In Cloudflare Dashboard, go to **Workers & Pages** → **Pages** -2. Select your `cambeerfestival` project -3. Go to **Custom domains** tab -4. Click **Set up a custom domain** -5. Enter: `cambeerfestival.app` -6. **Important**: Select **Branch**: `release` (not `main`) -7. Click **Continue** -8. Cloudflare will automatically configure the DNS records - -#### 4b. Preview/Staging Domain (preview.cambeerfestival.app) - -1. In the same **Custom domains** tab -2. Click **Set up a custom domain** again -3. Enter: `preview.cambeerfestival.app` -4. **Important**: Select **Branch**: `main` -5. Click **Continue** -6. Cloudflare will automatically configure the DNS records +2. Create or select the **`cambeerfestival-preview`** project +3. Go to **Settings** → **Builds & deployments** +4. Set **Production branch** to: `main` +5. Go to **Custom domains** tab +6. Click **Set up a custom domain** +7. Enter: `preview.cambeerfestival.app` +8. Click **Continue** +9. Cloudflare will automatically configure the DNS records + +**Note**: The `cambeerfestival-preview` project will be automatically created by GitHub Actions on the first deployment if it doesn't exist. #### 4c. Optional: WWW Redirect If you want `www.cambeerfestival.app` to redirect to the apex domain: -1. Add `www.cambeerfestival.app` as a custom domain -2. Select **Branch**: `release` +1. In the `cambeerfestival` project, add `www.cambeerfestival.app` as a custom domain **DNS Records Created** (automatic): -- `CNAME cambeerfestival.app` → `cambeerfestival.pages.dev` (points to `release` branch) -- `CNAME preview.cambeerfestival.app` → `cambeerfestival.pages.dev` (points to `main` branch) -- `CNAME www.cambeerfestival.app` → `cambeerfestival.pages.dev` (optional, points to `release` branch) +- `CNAME cambeerfestival.app` → `cambeerfestival.pages.dev` +- `CNAME preview.cambeerfestival.app` → `cambeerfestival-preview.pages.dev` +- `CNAME www.cambeerfestival.app` → `cambeerfestival.pages.dev` (optional) ### 5. Update Cloudflare Worker @@ -435,16 +454,24 @@ Both should remain in free tier unless app sees very high traffic. ## Summary Checklist -- [ ] Cloudflare Pages project `cambeerfestival` created +**Cloudflare Setup:** +- [ ] Cloudflare Pages project `cambeerfestival` created (production) +- [ ] Cloudflare Pages project `cambeerfestival-preview` created (staging/previews) +- [ ] Production project `cambeerfestival` → Production branch set to `release` +- [ ] Preview project `cambeerfestival-preview` → Production branch set to `main` +- [ ] Custom domain `cambeerfestival.app` configured on `cambeerfestival` project +- [ ] Custom domain `preview.cambeerfestival.app` configured on `cambeerfestival-preview` project +- [ ] DNS records configured (automatic via Cloudflare) - [ ] Cloudflare Account ID obtained - [ ] Cloudflare API Token updated with **both** Workers Scripts + Pages permissions -- [ ] Custom domain `cambeerfestival.app` configured → points to `release` branch -- [ ] Custom domain `preview.cambeerfestival.app` configured → points to `main` branch -- [ ] DNS records configured (automatic via Cloudflare) + +**GitHub Setup:** - [ ] GitHub Secret `CLOUDFLARE_API_TOKEN` verified (should work for both Workers and Pages) - [ ] GitHub Secret `CLOUDFLARE_ACCOUNT_ID` added - [ ] GitHub Secret `GOOGLE_SERVICES_JSON` verified - [ ] Workflow files committed (`.github/workflows/release-web.yml` and `build-deploy.yml`) + +**Verification:** - [ ] Cloudflare Worker updated with both custom domains in CORS origins - [ ] Push to `main` triggers successful deployment to `https://preview.cambeerfestival.app` - [ ] Create tag triggers production deployment to `https://cambeerfestival.app` From c4f122015966a0edac78e0b605c037f132846042 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 3 Dec 2025 08:16:43 +0000 Subject: [PATCH 3/6] Rename preview to staging to avoid CF terminology confusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cloudflare Pages uses "preview" to refer to non-production branches, which made our "preview" staging environment confusing. Renamed to "staging" for clarity: - Project: cambeerfestival-preview → cambeerfestival-staging - Domain: preview.cambeerfestival.app → staging.cambeerfestival.app - Updated CORS origins in worker - Updated all documentation This provides clearer separation between: - Production: cambeerfestival.app - Staging: staging.cambeerfestival.app - PR Previews: .cambeerfestival-staging.pages.dev --- .github/workflows/build-deploy.yml | 4 ++-- README.md | 12 +++++----- cloudflare-worker/worker.js | 2 +- docs/CLOUDFLARE_PAGES_SETUP.md | 38 +++++++++++++++--------------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index 6a24ba23..72294711 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -257,13 +257,13 @@ jobs: name: web-build path: build/web - - name: Deploy Preview to Cloudflare Pages + - name: Deploy to Cloudflare Pages (Staging/PR Previews) id: deploy uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: pages deploy build/web --project-name=cambeerfestival-preview --branch=${{ github.head_ref || github.ref_name }} + command: pages deploy build/web --project-name=cambeerfestival-staging --branch=${{ github.head_ref || github.ref_name }} - name: Comment PR with Preview URL if: github.event_name == 'pull_request' diff --git a/README.md b/README.md index bc08a77b..6b0dbde8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A Flutter app for browsing beers, ciders, meads, and more at the Cambridge Beer Festival. **Production**: [https://cambeerfestival.app](https://cambeerfestival.app) -**Preview**: [https://preview.cambeerfestival.app](https://preview.cambeerfestival.app) +**Staging**: [https://staging.cambeerfestival.app](https://staging.cambeerfestival.app) **Development**: [https://richardthe3rd.github.io/cambridge-beer-festival-app/](https://richardthe3rd.github.io/cambridge-beer-festival-app/) ## Features @@ -141,25 +141,25 @@ The app is deployed to multiple environments: - **Production** (Cloudflare Pages): [cambeerfestival.app](https://cambeerfestival.app) - Deployed on version tags (e.g., `v2025.12.0`) - - Uses Cloudflare Pages `release` branch + - Uses Cloudflare Pages project `cambeerfestival`, branch `release` - Workflow: `.github/workflows/release-web.yml` -- **Preview/Staging** (Cloudflare Pages): [preview.cambeerfestival.app](https://preview.cambeerfestival.app) +- **Staging** (Cloudflare Pages): [staging.cambeerfestival.app](https://staging.cambeerfestival.app) - Stable staging environment - Deployed automatically on push to `main` - - Uses Cloudflare Pages `main` branch + - Uses Cloudflare Pages project `cambeerfestival-staging`, branch `main` - Workflow: `.github/workflows/build-deploy.yml` (deploy-web-preview job) - **Development** (GitHub Pages): [richardthe3rd.github.io/cambridge-beer-festival-app](https://richardthe3rd.github.io/cambridge-beer-festival-app/) - Alternative development environment - Deployed automatically on push to `main` - Workflow: `.github/workflows/build-deploy.yml` (deploy-web job) - **PR Previews** (Cloudflare Pages): Unique URL per pull request - - Each PR gets its own preview environment (e.g., `.cambeerfestival.pages.dev`) + - Each PR gets its own preview environment (e.g., `.cambeerfestival-staging.pages.dev`) - Preview URL posted as comment on the PR - Workflow: `.github/workflows/build-deploy.yml` (deploy-web-preview job) ### Deployment Strategy -1. **Development changes**: Push to `main` → Preview (Cloudflare) + GitHub Pages updated +1. **Development changes**: Push to `main` → Staging (Cloudflare) + GitHub Pages updated 2. **PR reviews**: Open PR → Unique Cloudflare Pages preview created 3. **Production releases**: Create tag (e.g., `v2025.12.0`) → Production deployment to cambeerfestival.app diff --git a/cloudflare-worker/worker.js b/cloudflare-worker/worker.js index 56b6b6dd..940c96aa 100644 --- a/cloudflare-worker/worker.js +++ b/cloudflare-worker/worker.js @@ -22,7 +22,7 @@ const FESTIVALS_CACHE_CONTROL = 'no-cache, must-revalidate'; const ALLOWED_ORIGINS = [ 'https://richardthe3rd.github.io', 'https://cambeerfestival.app', - 'https://preview.cambeerfestival.app', + 'https://staging.cambeerfestival.app', 'http://localhost:8080', 'http://localhost:3000', 'http://127.0.0.1:8080', diff --git a/docs/CLOUDFLARE_PAGES_SETUP.md b/docs/CLOUDFLARE_PAGES_SETUP.md index 677e4262..1cc970d2 100644 --- a/docs/CLOUDFLARE_PAGES_SETUP.md +++ b/docs/CLOUDFLARE_PAGES_SETUP.md @@ -17,19 +17,19 @@ The app uses **two separate Cloudflare Pages projects** for clean separation bet - Deploys: Git tags (e.g., `v2025.12.0`) - Custom domain: `cambeerfestival.app` -**Project 2: `cambeerfestival-preview`** (Staging + PR previews) +**Project 2: `cambeerfestival-staging`** (Staging + PR previews) - Production branch: `main` (serves staging) - Preview branches: PR branches (serve PR previews) - Deploys: Git main + all PRs -- Custom domain: `preview.cambeerfestival.app` +- Custom domain: `staging.cambeerfestival.app` ### Deployment Architecture | Git Event | CF Project | CF Branch | URL | Purpose | |-----------|------------|-----------|-----|---------| | Version tag | `cambeerfestival` | `release` | `cambeerfestival.app` | Production | -| Push to `main` | `cambeerfestival-preview` | `main` | `preview.cambeerfestival.app` | Staging | -| Pull Request | `cambeerfestival-preview` | `` | `.cambeerfestival-preview.pages.dev` | PR previews | +| Push to `main` | `cambeerfestival-staging` | `main` | `staging.cambeerfestival.app` | Staging | +| Pull Request | `cambeerfestival-staging` | `` | `.cambeerfestival-staging.pages.dev` | PR previews | | Push to `main` | GitHub Pages | N/A | `richardthe3rd.github.io/...` | Development | ## Prerequisites @@ -44,13 +44,13 @@ The app uses **two separate Cloudflare Pages projects** for clean separation bet You need **two separate Cloudflare Pages projects**: - `cambeerfestival` (production) -- `cambeerfestival-preview` (staging/previews) +- `cambeerfestival-staging` (staging/previews) **Option A: Let GitHub Actions Create the Projects (Easiest)** Both projects will be automatically created on their first deployment. You can skip this step and jump to step 2 (Get Account ID) and step 3 (Create API Token). -- First push to `main` will create `cambeerfestival-preview` +- First push to `main` will create `cambeerfestival-staging` - First git tag will create `cambeerfestival` **Option B: Create Projects Manually** @@ -64,12 +64,12 @@ If you prefer to create the projects manually first: 4. Set **Project name**: `cambeerfestival` 5. Disable automatic deployments (GitHub Actions will handle deployments) -**For Preview Project:** +**For Staging Project:** 1. In **Workers & Pages**, click **Create application** → **Pages** -2. Set **Project name**: `cambeerfestival-preview` +2. Set **Project name**: `cambeerfestival-staging` 3. Disable automatic deployments -**Important**: Project names must match the workflow configuration (`cambeerfestival` and `cambeerfestival-preview`). +**Important**: Project names must match the workflow configuration (`cambeerfestival` and `cambeerfestival-staging`). ### 2. Get Cloudflare Account ID @@ -131,19 +131,19 @@ You need to configure **one custom domain per project**: 8. Click **Continue** 9. Cloudflare will automatically configure the DNS records -#### 4b. Preview/Staging Project Domain +#### 4b. Staging Project Domain 1. In Cloudflare Dashboard, go to **Workers & Pages** → **Pages** -2. Create or select the **`cambeerfestival-preview`** project +2. Create or select the **`cambeerfestival-staging`** project 3. Go to **Settings** → **Builds & deployments** 4. Set **Production branch** to: `main` 5. Go to **Custom domains** tab 6. Click **Set up a custom domain** -7. Enter: `preview.cambeerfestival.app` +7. Enter: `staging.cambeerfestival.app` 8. Click **Continue** 9. Cloudflare will automatically configure the DNS records -**Note**: The `cambeerfestival-preview` project will be automatically created by GitHub Actions on the first deployment if it doesn't exist. +**Note**: The `cambeerfestival-staging` project will be automatically created by GitHub Actions on the first deployment if it doesn't exist. #### 4c. Optional: WWW Redirect @@ -152,14 +152,14 @@ If you want `www.cambeerfestival.app` to redirect to the apex domain: **DNS Records Created** (automatic): - `CNAME cambeerfestival.app` → `cambeerfestival.pages.dev` -- `CNAME preview.cambeerfestival.app` → `cambeerfestival-preview.pages.dev` +- `CNAME staging.cambeerfestival.app` → `cambeerfestival-staging.pages.dev` - `CNAME www.cambeerfestival.app` → `cambeerfestival.pages.dev` (optional) ### 5. Update Cloudflare Worker The Cloudflare Worker for API proxy has already been updated to allow both custom domains in CORS origins: - `https://cambeerfestival.app` (production) -- `https://preview.cambeerfestival.app` (staging) +- `https://staging.cambeerfestival.app` (staging) When you deploy worker changes: @@ -456,11 +456,11 @@ Both should remain in free tier unless app sees very high traffic. **Cloudflare Setup:** - [ ] Cloudflare Pages project `cambeerfestival` created (production) -- [ ] Cloudflare Pages project `cambeerfestival-preview` created (staging/previews) +- [ ] Cloudflare Pages project `cambeerfestival-staging` created (staging/previews) - [ ] Production project `cambeerfestival` → Production branch set to `release` -- [ ] Preview project `cambeerfestival-preview` → Production branch set to `main` +- [ ] Staging project `cambeerfestival-staging` → Production branch set to `main` - [ ] Custom domain `cambeerfestival.app` configured on `cambeerfestival` project -- [ ] Custom domain `preview.cambeerfestival.app` configured on `cambeerfestival-preview` project +- [ ] Custom domain `staging.cambeerfestival.app` configured on `cambeerfestival-staging` project - [ ] DNS records configured (automatic via Cloudflare) - [ ] Cloudflare Account ID obtained - [ ] Cloudflare API Token updated with **both** Workers Scripts + Pages permissions @@ -473,6 +473,6 @@ Both should remain in free tier unless app sees very high traffic. **Verification:** - [ ] Cloudflare Worker updated with both custom domains in CORS origins -- [ ] Push to `main` triggers successful deployment to `https://preview.cambeerfestival.app` +- [ ] Push to `main` triggers successful deployment to `https://staging.cambeerfestival.app` - [ ] Create tag triggers production deployment to `https://cambeerfestival.app` - [ ] API calls work without CORS errors on all environments From 1b3047edeecdb73e9149503f28a8cb24ae0d72d1 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 4 Dec 2025 16:44:22 +0000 Subject: [PATCH 4/6] Fix staging project name to match existing Cloudflare project User created project as 'staging-cambeerfestival' but workflow was referencing 'cambeerfestival-staging'. Updated workflow to match the existing project name. --- .github/workflows/build-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index 72294711..dcba4f0d 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -263,7 +263,7 @@ jobs: with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: pages deploy build/web --project-name=cambeerfestival-staging --branch=${{ github.head_ref || github.ref_name }} + command: pages deploy build/web --project-name=staging-cambeerfestival --branch=${{ github.head_ref || github.ref_name }} - name: Comment PR with Preview URL if: github.event_name == 'pull_request' From cdc96aec889643f6888f07dcf701ea48dca41cf5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 4 Dec 2025 16:54:14 +0000 Subject: [PATCH 5/6] Use branch-based URL in PR preview comments Changes PR comments to show the nicer branch-based URL: - Before: https://ef29be34.staging-cambeerfestival.pages.dev - After: https://claude-preview-domain-cicd-0.staging-cambeerfestival.pages.dev The branch-based alias is more readable and matches the branch name. --- .github/workflows/build-deploy.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index dcba4f0d..3b41a652 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -270,7 +270,8 @@ jobs: uses: actions/github-script@v7 with: script: | - const previewUrl = '${{ steps.deploy.outputs.deployment-url }}'; + const branch = '${{ github.head_ref }}'; + const previewUrl = `https://${branch}.staging-cambeerfestival.pages.dev`; const comment = `## 🚀 Cloudflare Pages Preview Your preview deployment is ready! From 9fa42f066e3422314e5502ff282dce84656cdea5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 4 Dec 2025 16:56:14 +0000 Subject: [PATCH 6/6] Use pages-deployment-alias-url output for PR comments Uses the official wrangler-action output for alias URLs instead of manually constructing them. Falls back to deployment-url if alias is not available. This is more reliable and handles branch name encoding automatically. --- .github/workflows/build-deploy.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml index 3b41a652..041c7adc 100644 --- a/.github/workflows/build-deploy.yml +++ b/.github/workflows/build-deploy.yml @@ -270,8 +270,9 @@ jobs: uses: actions/github-script@v7 with: script: | - const branch = '${{ github.head_ref }}'; - const previewUrl = `https://${branch}.staging-cambeerfestival.pages.dev`; + const aliasUrl = '${{ steps.deploy.outputs.pages-deployment-alias-url }}'; + const deployUrl = '${{ steps.deploy.outputs.deployment-url }}'; + const previewUrl = aliasUrl || deployUrl; const comment = `## 🚀 Cloudflare Pages Preview Your preview deployment is ready!