Skip to content

Deploy and self-host the dashboard with Void - #222

Merged
stylessh merged 3 commits into
mainfrom
stylessh/simplify-cloudflare-self-hosting
Nov 9, 2026
Merged

stylessh merged 3 commits into
mainfrom
stylessh/simplify-cloudflare-self-hosting

Conversation

@stylessh

@stylessh stylessh commented Nov 9, 2026

Copy link
Copy Markdown
Owner

Summary

Builds, runs and deploys the dashboard with Void instead of hand-made Wrangler configs, so anyone can self-host DiffKit in their own Cloudflare account with three commands (void connect, void secret sync, pnpm run deploy). See docs/self-hosting.md.

Production keeps its existing diffkit Worker, quickhub-db D1, KV namespace, diffkit-comment-media R2 bucket and diff-kit.com domain. CI pins all four resource IDs through repository variables (DIFFKIT_*, already set) and refuses to deploy without them. Without the pins, Void would bind a new, empty R2 bucket.

Changes

  • Vite 8, TanStack Start 1.169, Vitest 4. Void requires Vite 8. .inputValidator() → .validator() in 25 files; a few test mocks updated for Vitest 4.
  • void.config.ts + env.ts replace wrangler.jsonc.example, wrangler.demo.jsonc, the config generator scripts and worker-configuration.d.ts. Local secrets move from .dev.vars to .env.
  • Migrations move from drizzle/ to db/migrations/ with the same file names, so production's applied history still matches. Journal entries added for 0002–0007, which Void requires.
  • Cron moves to crons/maintenance.ts. Void only schedules crons declared there.
  • Deploy workflow runs void deploy and keeps the /login + /api/health gate with rollback on failure. All workflows read Node 24.22 from .node-version.
  • Docs: new docs/self-hosting.md and docs/runbooks/void-handoff.md; README, local dev, demo mode, e2e and rollback docs updated.

migration-destructive: approved. The only destructive statement is in 0007_drop_legacy_cache_tables.sql, which production already applied. The folder move makes the check see it as new. Nothing in this PR drops data.

Test Plan

  • Unit tests: dashboard 479, emulator 55, ui 58 pass; repo type check passes.
  • e2e: 29 of 31 pass. The two failures (repo-settings labels, create-pull-request since Calmer repo pages: no activity cards, Pierre file icons, pilled ref rows #220) also fail on main.
  • pnpm dev, pnpm dev:demo and the cron work locally.
  • Rehearsed on a throwaway copy of production deployed the current way: the handoff kept the same Worker, D1, KV, R2, secrets and data, and no migration ran again. A self-host from scratch created its resources once; a second deploy created nothing. All trial resources were deleted afterwards.
  • A build with the production pins binds exactly the IDs production serves today (checked against version 94d55cd6); partial pins are refused.
  • After merge, follow docs/runbooks/void-handoff.md step 4: bindings unchanged, diff-kit.com still attached, maintenance.status: "recent" within 5 minutes.

🤖 Generated with Claude Code

stylessh and others added 3 commits November 9, 2026 01:19
Void, which will own the Cloudflare build and deploy, requires Vite 8.
TanStack Start 1.169 is the first release on Vite 8 and renames
createServerFn's .inputValidator() to .validator(); error components now
receive the thrown value as unknown.

Vitest 4 no longer constructs arrow-function mocks with new, and reuses
an existing spy on repeated vi.spyOn, so the Octokit/App mocks are
function expressions and the token tests restore spies after each case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
void.config.ts now declares the Worker: its D1, KV and R2 bindings, the
cron trigger and compatibility settings. Void creates missing resources on
deploy and applies db/migrations (moved from drizzle/, same filenames, so
the d1_migrations history carries over) in dev and on deploy. 0007 gains
Void's allow-destructive pragma; its statements are unchanged.

env.ts lists every value the Worker reads, so a missing production secret
stops the deploy instead of failing at runtime. Local values move from
.dev.vars to .env, the example to env.example, and the demo credentials to
apps/emulator/dashboard.env, which dev:demo and the e2e suite pass through
the shell. DIFFKIT_DEMO=1 replaces CLOUDFLARE_ENV=demo, because Void reads
CLOUDFLARE_ENV to pick a named environment it does not support.

Removed: wrangler.jsonc.example, wrangler.demo.jsonc, the generated
worker-configuration.d.ts (bindings are declared in src/env.d.ts) and
resolve-wrangler-config-path.mts. Void needs Node 24.22, now pinned in
.node-version and used by every workflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The deploy workflow now runs void deploy, which applies migrations after
saving a D1 restore point and checks /__void/ready, then keeps our /login and
/api/health gate with a Wrangler rollback. generate-wrangler-dashboard-config
and run-d1-migrations are gone.

Rehearsed on a copy of production in the same account: the first Void deploy
kept the existing Worker, D1, KV, R2, secrets and data and re-ran no
migration. It also showed that a deploy without the resources named binds a
new, empty R2 bucket, so void.config.ts takes DIFFKIT_D1_DATABASE_NAME,
DIFFKIT_D1_DATABASE_ID, DIFFKIT_KV_ID and DIFFKIT_R2_BUCKET together or not at
all, and CI refuses to deploy without them. DIFFKIT_DOMAIN declares the
custom domain. A fresh account needs none of them: void deploy creates
everything (docs/self-hosting.md).

Void only deploys cron schedules declared in crons/, so the maintenance job
moves there from the entry's scheduled export, and the Drizzle journal now
lists the hand-written migrations 0002-0007, which Void requires.
docs/runbooks/void-handoff.md is the one-time production checklist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 37 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f9a550c9-c8cc-40c7-ada5-eb6727e4e233
Commits

Reviewing files that changed from the base of the PR and between e63881b and 49a6acd.

Files ignored due to path filters: 1

  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing: 95

  • .github/workflows/dashboard-deploy-production.yml
  • .github/workflows/dev-smoke.yml
  • .github/workflows/e2e.yml
  • .github/workflows/migration-check.yml
  • .github/workflows/pr-checks.yml
  • .github/workflows/production-alerts.yml
  • .node-version
  • CONTRIBUTING.md
  • README.md
  • apps/dashboard/.gitignore
  • apps/dashboard/README.md
  • apps/dashboard/biome.jsonc
  • apps/dashboard/crons/maintenance.ts
  • apps/dashboard/db/migrations/0000_pretty_the_call.sql
  • apps/dashboard/db/migrations/0001_outstanding_blizzard.sql
  • apps/dashboard/db/migrations/0002_github_revalidation_signal.sql
  • apps/dashboard/db/migrations/0003_github_cache_namespace.sql
  • apps/dashboard/db/migrations/0004_github_webhook_event.sql
  • apps/dashboard/db/migrations/0005_user_forbidden_org.sql
  • apps/dashboard/db/migrations/0006_github_change.sql
  • apps/dashboard/db/migrations/0007_drop_legacy_cache_tables.sql
  • apps/dashboard/db/migrations/meta/0000_snapshot.json
  • apps/dashboard/db/migrations/meta/0001_snapshot.json
  • apps/dashboard/db/migrations/meta/_journal.json
  • apps/dashboard/drizzle.config.ts
  • apps/dashboard/drizzle/meta/_journal.json
  • apps/dashboard/env.example
  • apps/dashboard/env.ts
  • apps/dashboard/package.json
  • apps/dashboard/src/components/layouts/dashboard-error-screen.tsx
  • apps/dashboard/src/entry-worker.test.ts
  • apps/dashboard/src/entry-worker.ts
  • apps/dashboard/src/env.d.ts
  • apps/dashboard/src/lib/github-app.server.test.ts
  • apps/dashboard/src/lib/github-emulator.server.ts
  • apps/dashboard/src/lib/github-installation-token.test.ts
  • apps/dashboard/src/lib/github.server.test.ts
  • apps/dashboard/src/lib/github/actions.ts
  • apps/dashboard/src/lib/github/code-browsing.ts
  • apps/dashboard/src/lib/github/code.ts
  • apps/dashboard/src/lib/github/comments.ts
  • apps/dashboard/src/lib/github/commits.ts
  • apps/dashboard/src/lib/github/issues.ts
  • apps/dashboard/src/lib/github/labels.ts
  • apps/dashboard/src/lib/github/milestones.ts
  • apps/dashboard/src/lib/github/notifications.ts
  • apps/dashboard/src/lib/github/pull-for-refs.ts
  • apps/dashboard/src/lib/github/pulls.ts
  • apps/dashboard/src/lib/github/references.ts
  • apps/dashboard/src/lib/github/releases.ts
  • apps/dashboard/src/lib/github/repos.ts
  • apps/dashboard/src/lib/github/reviews.ts
  • apps/dashboard/src/lib/github/search.ts
  • apps/dashboard/src/lib/github/settings-access.ts
  • apps/dashboard/src/lib/github/settings-actions.ts
  • apps/dashboard/src/lib/github/settings-org.ts
  • apps/dashboard/src/lib/github/settings-repo.ts
  • apps/dashboard/src/lib/github/settings-rules.ts
  • apps/dashboard/src/lib/github/settings-webhooks.ts
  • apps/dashboard/src/lib/github/users.ts
  • apps/dashboard/src/lib/github/validators.ts
  • apps/dashboard/src/lib/maintenance-cron.test.ts
  • apps/dashboard/src/lib/media.functions.ts
  • apps/dashboard/src/lib/testing/d1-sqlite.ts
  • apps/dashboard/src/routeTree.gen.ts
  • apps/dashboard/tsconfig.json
  • apps/dashboard/vite.config.ts
  • apps/dashboard/void.config.ts
  • apps/dashboard/worker-configuration.d.ts
  • apps/dashboard/wrangler.demo.jsonc
  • apps/dashboard/wrangler.jsonc.example
  • apps/e2e/playwright.config.ts
  • apps/e2e/support/endpoints.ts
  • apps/emulator/dashboard.env
  • apps/emulator/src/__tests__/rest-shims.test.ts
  • apps/emulator/src/seed/identity.ts
  • apps/emulator/src/shims/rest.ts
  • docs/e2e.md
  • docs/github-cache-architecture.md
  • docs/local-demo-mode.md
  • docs/local-dev.md
  • docs/runbooks/deploy-rollback.md
  • docs/runbooks/void-handoff.md
  • docs/self-hosting.md
  • package.json
  • paseo.json
  • scripts/check-d1-migrations.mjs
  • scripts/deploy-dashboard.mjs
  • scripts/dev-demo.mjs
  • scripts/dev-env.mjs
  • scripts/dev.mjs
  • scripts/generate-wrangler-dashboard-config.mjs
  • scripts/link-worktree-dev-vars.mjs
  • scripts/resolve-wrangler-config-path.mts
  • scripts/run-d1-migrations.mjs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@stylessh
stylessh merged commit f714f7b into main Nov 9, 2026
7 of 9 checks passed
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