Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 --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'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/)
**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

Expand Down Expand Up @@ -140,17 +141,19 @@ 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 project `cambeerfestival`, branch `release`
- Workflow: `.github/workflows/release-web.yml`
- **Staging** (Cloudflare Pages): `main.cambeerfestival.pages.dev`
- Stable preview environment
- **Staging** (Cloudflare Pages): [staging.cambeerfestival.app](https://staging.cambeerfestival.app)
- Stable staging environment
- Deployed automatically on push to `main`
- 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
- Each PR gets its own preview environment (e.g., `<branch>.cambeerfestival-staging.pages.dev`)
- Preview URL posted as comment on the PR
- Workflow: `.github/workflows/build-deploy.yml` (deploy-web-preview job)

Expand Down
1 change: 1 addition & 0 deletions cloudflare-worker/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const FESTIVALS_CACHE_CONTROL = 'no-cache, must-revalidate';
const ALLOWED_ORIGINS = [
'https://richardthe3rd.github.io',
'https://cambeerfestival.app',
'https://staging.cambeerfestival.app',
'http://localhost:8080',
'http://localhost:3000',
'http://127.0.0.1:8080',
Expand Down
127 changes: 93 additions & 34 deletions docs/CLOUDFLARE_PAGES_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,29 @@ This document explains how to set up Cloudflare Pages deployment for the Cambrid

## Overview

The app has two deployment targets:
The app uses **two separate Cloudflare Pages projects** for clean separation between production and staging:

1. **GitHub Pages** (Development/Staging): `richardthe3rd.github.io/cambridge-beer-festival-app/`
2. **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-staging`** (Staging + PR previews)
- Production branch: `main` (serves staging)
- Preview branches: PR branches (serve PR previews)
- Deploys: Git main + all PRs
- 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-staging` | `main` | `staging.cambeerfestival.app` | Staging |
| Pull Request | `cambeerfestival-staging` | `<branch>` | `<branch>.cambeerfestival-staging.pages.dev` | PR previews |
| Push to `main` | GitHub Pages | N/A | `richardthe3rd.github.io/...` | Development |

## Prerequisites

Expand All @@ -21,32 +40,36 @@ The app has two deployment targets:

## Cloudflare Configuration

### 1. Create Cloudflare Pages Project
### 1. Create Cloudflare Pages Projects

You need **two separate Cloudflare Pages projects**:
- `cambeerfestival` (production)
- `cambeerfestival-staging` (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-staging`
- 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 Staging Project:**
1. In **Workers & Pages**, click **Create application** → **Pages**
2. Set **Project name**: `cambeerfestival-staging`
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-staging`).

### 2. Get Cloudflare Account ID

Expand Down Expand Up @@ -92,24 +115,51 @@ 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 configure **one custom domain per project**:

#### 4a. Production 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. Click **Continue**
7. Cloudflare will automatically configure the DNS records
8. Optionally add `www.cambeerfestival.app` as well
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

#### 4b. Staging Project Domain

1. In Cloudflare Dashboard, go to **Workers & Pages** → **Pages**
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: `staging.cambeerfestival.app`
8. Click **Continue**
9. Cloudflare will automatically configure the DNS records

**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

If you want `www.cambeerfestival.app` to redirect to the apex domain:
1. In the `cambeerfestival` project, add `www.cambeerfestival.app` as a custom domain

**DNS Records Created** (automatic):
- `CNAME cambeerfestival.app` → `cambeerfestival.pages.dev`
- `CNAME www.cambeerfestival.app` → `cambeerfestival.pages.dev` (if www added)
- `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 `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://staging.cambeerfestival.app` (staging)

When you deploy worker changes:

Expand Down Expand Up @@ -404,16 +454,25 @@ 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-staging` created (staging/previews)
- [ ] Production project `cambeerfestival` → Production branch set to `release`
- [ ] Staging project `cambeerfestival-staging` → Production branch set to `main`
- [ ] Custom domain `cambeerfestival.app` configured on `cambeerfestival` 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
- [ ] Custom domain `cambeerfestival.app` configured in Cloudflare Pages
- [ ] 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`)
- [ ] Cloudflare Worker updated with `cambeerfestival.app` CORS origin and wildcard for Pages previews
- [ ] Push to `main` triggers successful deployment to staging

**Verification:**
- [ ] Cloudflare Worker updated with both custom domains in CORS origins
- [ ] 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
Loading