Skip to content

refactor: merge dashboard into Worker with typed coverage schema - #13

Merged
tbjers merged 4 commits into
mainfrom
refactor/combine-dashboard-and-api-routes
Jun 25, 2026
Merged

refactor: merge dashboard into Worker with typed coverage schema#13
tbjers merged 4 commits into
mainfrom
refactor/combine-dashboard-and-api-routes

Conversation

@tbjers

@tbjers tbjers commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Single Worker now serves the SvelteKit SPA (via adapter-static) and all API routes under /api/* from one apex domain, replacing the separate Cloudflare Pages deployment
  • New D1 schema (coverage_runs + coverage_daily) replaces the old EAV metrics table with typed columns; a daily cron rollup snapshots runs older than 14 days into coverage_daily for permanent history
  • New ingest endpoint POST /api/ci/coverage accepts typed fields via zod validation (replacing /ingest with a metrics array); GitHub Action updated to match
  • Cloudflare Access JWT middleware now accepts the CF_Authorization cookie as a fallback so SPA browser fetches to /api/* are authenticated correctly

Key files

Area Change
wrangler.jsonc assets config for SPA, nodejs_compat, cron trigger
migrations/0002_coverage.sql coverage_runs + coverage_daily tables
src/routes/ci.ts New POST /api/ci/coverage with zod validation
src/db/rollup.ts Daily cron: snapshot → prune, idempotent
src/lib/db.ts getCoverageTrend (DESC LIMIT → ASC display), getLatestCoverage (daily fallback)
dashboard/ adapter-static, client-side loads, relative /api/* calls
.github/workflows/deploy-dashboard.yml wrangler deploy replaces wrangler pages deploy
.github/actions/report/src/run.ts POST typed fields to /api/ci/coverage

Test plan

  • npm test — 13 Worker integration tests (routing, rollup, CI auth, DB helpers, trend ordering, daily fallback, upsert idempotency)
  • cd .github/actions/report && npx vitest run — 52 action unit tests
  • wrangler deploy --dry-run — validates Worker config and asset resolution
  • Apply DB migration to production: wrangler d1 migrations apply coverage --remote
  • Update GitHub App webhook URL → https://coverage-tracker.zerostash.org/api/webhooks/github
  • Update shields.io badge URLs → https://coverage-tracker.zerostash.org/api/badge/:owner/:repo/:metric.json
  • Confirm Cloudflare Access app scoped to / (not /api/*)
  • wrangler secret put CF_ACCESS_AUD + wrangler secret put CF_ACCESS_TEAM_DOMAIN ✅ (done)
  • Detach custom domain from Pages; attach to Worker

🤖 Generated with Claude Code

tbjers and others added 2 commits June 25, 2026 17:12
Converges the separate Cloudflare Pages SvelteKit dashboard and the
coverage-tracker Worker into a single Worker serving static SPA assets
alongside all API routes under /api/*.

Changes:
- wrangler.jsonc: add assets config (SPA fallback), nodejs_compat flag,
  daily cron trigger (30 6 * * *); all routes now under /api/*
- migrations/0002_coverage.sql: add coverage_runs (typed columns, upsert
  on project+commit) and coverage_daily (daily rollup, PK project+day)
- src/routes/ci.ts: new ingest endpoint (POST /api/ci/coverage) with zod
  CoverageReport validation replacing old EAV /ingest route
- src/db/rollup.ts: daily rollup cron snapshots runs >14d into
  coverage_daily and prunes raw rows; idempotent via ON CONFLICT DO UPDATE
- src/lib/db.ts: add upsertCoverageRun, getLatestCoverageRun,
  getLatestCoverage (coverage_daily fallback for dormant repos),
  getCoverageTrend (DESC LIMIT subquery → ASC display order)
- src/lib/metrics.ts: single source of truth for metric-name→column mapping
- src/middleware/access.ts: add CF_Authorization cookie fallback for
  same-origin SPA fetches to /api/*
- dashboard: migrate adapter-cloudflare → adapter-static (fallback:
  index.html); convert +page.server.ts loads to client-side +page.ts;
  api.ts uses relative /api/* paths (no WORKER service binding)
- .github/workflows/deploy-dashboard.yml: replace wrangler pages deploy
  with wrangler deploy (single Worker + assets)
- .github/actions/report/src/run.ts: POST typed fields to /api/ci/coverage
  instead of metrics array to /ingest; baseline URL → /api/baseline/*
- test/: 7 integration tests (routing, rollup, ci auth) using
  @cloudflare/vitest-pool-workers with readD1Migrations/applyD1Migrations

All tests pass (7 Worker + 52 action unit tests); tsc clean; dry-run OK.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…psert idempotency

Adds 6 integration tests in test/db.test.ts:
- upsertCoverageRun: second call with same commit updates value, no duplicate
- getCoverageTrend with 25-day seed: asserts most-recent 20 days returned
  in ascending order (not oldest 20 — the DESC-LIMIT subquery fix)
- getLatestCoverage: null when empty, returns coverage_runs row when
  present, falls back to coverage_daily for dormant repos, prefers newest
  daily row when multiple exist

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dist/run.js was not rebuilt after run.ts was updated to POST to
/api/ci/coverage and fetch baselines from /api/baseline/*. The compiled
bundle still had the old /ingest and /baseline/ paths. Rebuilt via
`npm run build` in .github/actions/report/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n page)

When Cloudflare Access is configured to protect the domain, unauthenticated
requests to /api/baseline/* receive an HTML login page (200 OK after
redirect) rather than a 404. The unguarded res.json() call in runPRCheck
crashed with "Unexpected token '<'". Wrap in try/catch so the action
degrades gracefully (no baseline, threshold checks still run).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@tbjers
tbjers merged commit e6068aa into main Jun 25, 2026
4 checks passed
@tbjers
tbjers deleted the refactor/combine-dashboard-and-api-routes branch June 25, 2026 22:05
Sign up for free to 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