Skip to content

feat(dashboard): run the dashboard as a Cloudflare Worker - #80

Open
RedStar071 wants to merge 3 commits into
mainfrom
feat/dashboard-cloudflare
Open

RedStar071 wants to merge 3 commits into
mainfrom
feat/dashboard-cloudflare

Conversation

@RedStar071

@RedStar071 RedStar071 commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

Related to #5. Lets the dashboard run as a Cloudflare Worker, for the managed cloud at app.code-zero.dev. Self-hosted builds are unchanged.

  • Build: VITEHUB_HOSTING=cloudflare nuxt build emits a Worker and merges apps/web/wrangler.jsonc into .output/server/wrangler.json. Every other target builds as before.
  • Database: the connection is a Hyperdrive binding. A Worker cannot reuse a socket across requests, so database() now returns an object that resolves to a client opened for the request being served, and to the process-wide pool everywhere else. Better Auth keeps what it is given for the life of the process, so it receives that same object when no DATABASE_URL is set. New createScopedDatabase in @code-zero/database, and @code-zero/auth accepts database as an alternative to databaseUrl.
  • Task history: a Workers KV namespace bound as KV, behind the same KeyValueStorage contract. ViteHub's own KV runtime cannot be resolved by the Nitro build that emits a Worker, so on Cloudflare vite-hub/kv is aliased to a small adapter.
  • Poller: does not start inside a Worker, which is frozen between requests. Webhooks work as everywhere else.
  • Stand-ins: a Worker bundle cannot leave an import unresolved, so four packages that cannot run there are aliased to modules that say why: the React renderer resend loads, the two subscription providers that drive a local CLI, and safer-buffer (it throws while the bundle starts under nodejs_compat). reflect-metadata keeps its side effect, which the passkey verifier needs.
  • Deploy: the manual Deploy dashboard workflow builds and deploys, and can apply migrations first.

Why

The managed cloud runs on Cloudflare, and the dashboard is the part that needs a database. This does not deploy anything by itself: the workflow runs on demand.

Verification

  • aube run check:repo
  • aube run lint:ci
  • aube run typecheck
  • aube test
  • aube run build

Safety and compatibility

  • I added or updated deterministic tests for changed behavior.
  • I preserved observe mode as read-only, or explained the policy change above.
  • Runtime commands and target-repository writes remain inside the runner boundary.
  • I did not expose secrets, tokens, personal data, or untrusted output in logs.
  • I updated documentation and Agent Skills when workflows or boundaries changed.

The Hyperdrive configuration has query caching turned off, because sessions and permissions must never be read from a cache. The Worker holds its secrets on Cloudflare; the workflow never reads them. A deployment that sets neither DATABASE_URL nor a Hyperdrive binding now fails on its first query instead of at boot, with the same message.

📝 Migration

Before the first run of Deploy dashboard:

  1. Set the Worker's secrets: wrangler secret put NUXT_BETTER_AUTH_SECRET, plus the model provider's key and the mail credentials.
  2. Add the repository secret DATABASE_URL (the origin database, for migrations) and start the workflow with migrate on.
  3. Make sure app.code-zero.dev has no conflicting DNS record: a Workers custom domain creates its own.

Agent context

  • Agent/tools used: Claude Code (Claude Opus 5.5) in T3 Code.
  • What the agent did, and what you changed or verified yourself: I created the Hyperdrive configuration and chose Cloudflare, the domain and a manual deploy. The agent wrote the changes and ran the built Worker locally with wrangler dev against a disposable Postgres: sign-up and sign-in, repeated session reads, the dashboard, repository and settings procedures, task history in KV, and the passkey options endpoint all answered. It also ran the default Node build.

Reviewer notes

  • The Worker bundle inlines every dependency and needs about 6 GB of heap to build; the workflow gives it that.
  • wrangler dev rewrites the Origin header to the route's host, so locally NUXT_PUBLIC_SITE_URL has to be http://app.code-zero.dev for Better Auth to accept requests. Deployed, it is https://app.code-zero.dev from wrangler.jsonc.
  • Not here on purpose: running tasks on Cloudflare (a sandbox runner), polling as a scheduled trigger, and the control-plane worker.

🤖 AI disclosure: Wolfstar Agent Kit modified this description. My AI open-source policy.

RetriggerView in GreptileConfidence Score: 5/5

No blocking issues were identified in the reviewed changes.

Reviews (3) · Last reviewed commit: "fix(dashboard): import the request datab..." · Reviewed by Greptile

The managed cloud runs on Cloudflare, and the dashboard is the part that needs a database. A
Worker cannot reuse a socket across requests, so the database follows the request through
Hyperdrive, task history lives in Workers KV, and the poller stays off.

Adds the Cloudflare build target, the Worker configuration, stand-ins for the four packages
that cannot run in a Worker, and a manual deploy workflow.
@coldtea-pr-lens

coldtea-pr-lens Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
  • Redraw · drawn at f227c99, the branch has moved on

Architecture

Architecture diagram for wolfstar-project/code-zero at f227c99

Play the walkthrough

Inside the changed components — 2 views

Component view — Database connection handling

Internal routing between per-request Hyperdrive bindings and long-lived Drizzle consumers.

Architecture view of Component view — Database connection handling in wolfstar-project/code-zero

Component view — Worker runtime adapters

Adapters bridging Cloudflare Workers bindings into the dashboard application.

Architecture view of Component view — Worker runtime adapters in wolfstar-project/code-zero

Data flow

Data flow diagram for wolfstar-project/code-zero at f227c99

Follow each request


Tip

Run npx skills add coldteadotai/pr-lens, then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."

🪧 More tips
  • Run npx @coldtea/pr-lens-cli analyze --base origin/main on a branch, then npx @coldtea/pr-lens-cli render .pr-lens/graph.json. Same lenses, your own model key, before the pull request exists
  • Click the link under each diagram to open it on a canvas you can zoom, pan and step through
  • The diagrams are links. Click one to open it on the canvas, then press W or click play to walk through the change
  • Open a diagram on the canvas, then press W or click play to walk through the change one step at a time
  • The CLI's render reads .github/pr-lens.yml and applies your renames, exclusions and lane pins at draw time
  • Set github.comment.collapsed: true in .github/pr-lens.yml to fold the comment behind one View architecture and data flow row. Drawing still runs as before
  • Set github.draw: on-demand in .github/pr-lens.yml and PR Lens stops drawing pull requests on its own. Comment @pr-lens draw on a pull request when you want that one drawn
  • Add .github/workflows/pr-lens.yml with coldteadotai/pr-lens/packages/action@v0 and your model provider's key as its api-key to run PR Lens from your own CI. Any /chat/completions endpoint works
  • After a push, tick Redraw to draw the latest commit
  • Switch GitHub to dark mode and the diagrams follow. The moving dots are this pull request's data in motion

Thanks for using PR Lens! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out on X, Bluesky, Mastodon, Reddit or LinkedIn

Comment thread packages/database/src/client.test.ts
The selection between a client opened for the request and the process-wide pool had no test of
its own, so a change that shared one client across requests passed every existing test. It now
lives in a module of its own and is tested with overlapping requests.
greptile-apps[bot]
greptile-apps Bot previously approved these changes Oct 20, 2026
The unit tests load the database util without Nitro's auto-imports, and the helper is called when
the module loads, so it failed with a ReferenceError there.

This branch has not been deployed

No deployments
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