Skip to content

Commit 33d8f93

Browse files
tbjersclaude
andauthored
Add Phase 5 Svelte dashboard on Cloudflare Pages (#4)
* Add Phase 5 Svelte dashboard on Cloudflare Pages SvelteKit 5 app in dashboard/ with SSR load functions that forward the Cf-Access-Jwt-Assertion header server-side so the token never reaches browser JS. uPlot sparklines on the overview cards, full trend charts on the drill-in page with metric selector and branch input. Cloudflare Pages build settings: root=dashboard, output=.svelte-kit/cloudflare. Configure WORKER_URL env var in Pages dashboard before deploying. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix dashboard API redirect handling and scope wrangler config - api.ts: add redirect:'manual' to all Worker fetch calls so that Cloudflare Access login redirects (302) surface as HTTP errors instead of silently returning HTML that breaks JSON.parse - Add dashboard/wrangler.toml so the adapter-cloudflare dev server stops walking up to the root wrangler.jsonc (which was injecting the Worker's WORKER_URL env var into the dashboard process) - Update .gitignore to cover .dev.vars; update .env.example to document both Vite (.env) and wrangler (.dev.vars) dev patterns Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add local dev bypass for Cloudflare Access + Service Token plan Worker: - src/types.ts: add optional DEV_BYPASS_SECRET to Bindings - src/middleware/access.ts: if DEV_BYPASS_SECRET is set and the request carries a matching X-Dev-Bypass header, skip JWT verification; the guard is dead code in production where the env var is never set - .dev.vars.example: document DEV_BYPASS_SECRET with a warning Dashboard: - api.ts: add optional extraHeaders param to fetchProjects/fetchTrend - +page.server.ts (both routes): read DEV_BYPASS_SECRET from env and pass X-Dev-Bypass when set; no-op in production - .env.example: document both WORKER_URL and DEV_BYPASS_SECRET Docs: - docs/plans/service-auth-token.md: future refactor to replace bypass + JWT forwarding with Cloudflare Access Service Tokens Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add local D1 seed script and mark Phase 5 as implemented - test/seed-local.sql: inserts a test owner, project, and 15+4 metric data points for local development against wrangler d1 --local - package.json: add db:seed:local script (npx wrangler d1 execute) - docs/PROGRESS.md: update Phase 5 from "Not started" to "Implemented – pending Pages deployment", listing what's done vs. still outstanding Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add dashboard CI deploy workflow via Cloudflare Pages Direct Upload - .github/workflows/deploy-dashboard.yml: builds and deploys the dashboard on push to main (production) and on PRs (preview branch), path-filtered to dashboard/** so unrelated changes don't trigger it - dashboard/package.json: add wrangler ^4.104.0 as devDependency so the workflow resolves it from node_modules after npm ci Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Document dashboard deployment in INSTALLATION.md (step 14) Covers: Pages project creation, WORKER_URL secret, GitHub Actions secrets, Access application, and the "run from dashboard/ dir" note to avoid the wrangler pages_build_output_dir warning. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix INSTALLATION.md: wrangler pages warning is unavoidable, not a cd issue Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Convert dashboard/wrangler.toml to wrangler.jsonc, unignore it The root .gitignore blanket-ignores wrangler.jsonc to protect the Worker's secrets. Add !dashboard/wrangler.jsonc to allow the Pages config to be committed. This suppresses the spurious "missing pages_build_output_dir" warning on wrangler pages commands (wrangler finds the .jsonc before walking up to the root wrangler.jsonc). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Remove stale wrangler pages warning note from INSTALLATION.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add nodejs_compat flag to dashboard Pages config SvelteKit uses node:async_hooks internally; without nodejs_compat the Pages worker throws at runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix deploy: remove wrangler from dashboard deps, install v4 in CI @sveltejs/adapter-cloudflare@4.x declares a peer dep on wrangler@^3; having wrangler@^4 in devDependencies caused an ERESOLVE conflict on npm ci. Remove it from package.json and install wrangler@^4 globally as a dedicated CI step before the deploy, keeping peer deps clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 43843c8 commit 33d8f93

30 files changed

Lines changed: 4817 additions & 7 deletions

.dev.vars.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@ GITHUB_WEBHOOK_SECRET=
1717
CF_ACCESS_AUD=
1818
# Your Cloudflare Access team domain, e.g. myteam.cloudflareaccess.com
1919
CF_ACCESS_TEAM_DOMAIN=
20+
21+
# Local dev only — lets the dashboard bypass Access JWT verification when running locally.
22+
# Set the same random string in dashboard/.dev.vars (or dashboard/.env).
23+
# NEVER add this to wrangler.jsonc vars or set it as a wrangler secret.
24+
DEV_BYPASS_SECRET=
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Deploy dashboard
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'dashboard/**'
8+
- '.github/workflows/deploy-dashboard.yml'
9+
pull_request:
10+
paths:
11+
- 'dashboard/**'
12+
- '.github/workflows/deploy-dashboard.yml'
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
deploy:
19+
runs-on: ubuntu-latest
20+
environment:
21+
name: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
22+
url: ${{ steps.deploy.outputs.deployment-url }}
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- uses: actions/setup-node@v4
27+
with:
28+
node-version: '20'
29+
cache: npm
30+
cache-dependency-path: dashboard/package-lock.json
31+
32+
- name: Install dependencies
33+
working-directory: dashboard
34+
run: npm ci
35+
36+
- name: Install wrangler
37+
run: npm install -g wrangler@^4
38+
39+
- name: Build
40+
working-directory: dashboard
41+
run: npm run build
42+
43+
- name: Deploy to Cloudflare Pages
44+
id: deploy
45+
working-directory: dashboard
46+
run: |
47+
OUTPUT=$(wrangler pages deploy \
48+
${{ github.ref != 'refs/heads/main' && format('--branch {0}', github.head_ref || github.ref_name) || '' }})
49+
echo "$OUTPUT"
50+
URL=$(echo "$OUTPUT" | grep -oP 'https://[^\s]+\.pages\.dev[^\s]*' | tail -1)
51+
echo "deployment-url=${URL}" >> "$GITHUB_OUTPUT"
52+
env:
53+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
54+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ node_modules/
44
.*.vars
55
!.*.vars.example
66
wrangler.jsonc
7+
!dashboard/wrangler.jsonc
78
*.local
89
*.pem

dashboard/.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# For local development with `npm run dev` (Vite):
2+
# Copy to .env
3+
#
4+
# For local development with `wrangler pages dev` (simulates Cloudflare runtime):
5+
# Copy to .dev.vars
6+
7+
# URL of your deployed Worker (no trailing slash)
8+
WORKER_URL=https://coverage-tracker.yourdomain.com
9+
10+
# Local dev only — must match DEV_BYPASS_SECRET in the Worker's .dev.vars.
11+
# With this set, the dashboard passes X-Dev-Bypass to the local Worker so it
12+
# skips Cloudflare Access JWT verification during local development.
13+
# NEVER set this in production (Cloudflare Pages environment variables).
14+
DEV_BYPASS_SECRET=

dashboard/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules/
2+
.svelte-kit/
3+
build/
4+
.env
5+
.env.*
6+
!.env.example
7+
.dev.vars

0 commit comments

Comments
 (0)