Staging Environment
Context
Section titled “Context”Nucleus currently runs in two environments:
- Dev/local —
pnpm dev, mock auth, local D1 (.wrangler/) - Production —
*.nucleus.fastcustom domains, real CF Access, prod D1 / KV / R2
There is no persistent staging environment where changes can be verified end-to-end (app + agents + pulse + mcp, all wired together) before hitting prod. This doc plans one.
What already exists (and why it’s not enough)
Section titled “What already exists (and why it’s not enough)”1. Per-PR preview deployments
Section titled “1. Per-PR preview deployments”See Preview Deployments. CI spins up a nucleus-preview-pr-{number} D1 database and a Worker version alias on pr-{number}.nucleus-app.workers.dev for every PR. Great for isolated smoke-tests, but:
- Only the app worker — no admin, portal, pulse, mcp, agents, or orchestrator
- R2 (
UPLOADS) and Analytics Engine still point at production bindings - Ephemeral — destroyed on PR close, so nothing to demo from
*.workers.devonly — no custom domain, no CF Access
2. [env.preview] in Wrangler config
Section titled “2. [env.preview] in Wrangler config”apps/app/wrangler.toml and apps/portal/wrangler.toml have [env.preview] sections pointing at nucleus-db-preview (1b38e91d-…). Twelve other workers — admin, pulse, mcp, orchestrator, and the 11 agents — have no preview env at all. No preview KVs, no preview R2, no preview DO namespace, no preview custom domain, no CF Access on *.workers.dev.
Net: preview is a scratch-DB hatch, not staging.
Recommended approach: *.staging.nucleus.fast
Section titled “Recommended approach: *.staging.nucleus.fast”Add a Wrangler environment called staging to every worker, with its own subdomain, databases, bindings, and secrets.
Subdomains
Section titled “Subdomains”app.staging.nucleus.fastadmin.staging.nucleus.fastportal.staging.nucleus.fastpulse.staging.nucleus.fastmcp.staging.nucleus.fastorchestrator.staging.nucleus.fast*.agent.staging.nucleus.fast(11 agents)docs.staging.nucleus.fast(Pages branch deploy)staging.nucleus.fast(site — Pages branch deploy)
Cloudflare resources to create
Section titled “Cloudflare resources to create”| Resource | Count | Notes |
|---|---|---|
| D1 databases | 2 | nucleus-db-staging, pulse-db-staging — apply migrations on first deploy |
| R2 buckets | 1 | nucleus-uploads-staging |
| KV namespaces | 7 | COOLDOWNS, TA_KV, RELEASE_STATE, PA_KV, CONTENT_STORE, DEV_AGENT_KV, MCP_SESSIONS (staging versions) |
| Durable Objects | 1 | DocumentCollabDO — new migration tag in staging env |
| CF Access app | 1 | Policy covering *.staging.nucleus.fast, same @dotcollective.com.au rule |
| DNS records | ~15 | One per subdomain pointing at the staging worker |
Wrangler config changes
Section titled “Wrangler config changes”Every worker gets an [env.staging] block:
apps/app/wrangler.toml— staging D1 ID, staging R2 bucket, DO migration tag, env vars (APP_URL=https://app.staging.nucleus.fast,CF_ACCESS_TEAM_DOMAIN=nucleusfast). Consider reducing or disabling crons in staging.apps/admin/wrangler.toml— staging agent URLs (point at staging agents, not prod)apps/portal/wrangler.toml— staging D1 +APP_URLapps/pulse/worker/wrangler.toml— staging D1; swap hardcodedENV = "production"for an env-specific varapps/mcp/wrangler.jsonc— staging KV, stagingNUCLEUS_APPservice binding, stagingNUCLEUS_API_URLapps/orchestrator/wrangler.toml— staging KV, staging DO + Container class nameapps/agents/*/wrangler.toml— staging KVs, service bindings targeting staging app worker, staging agent URLs
Code changes
Section titled “Code changes”- Replace hardcoded
https://app.nucleus.fast,https://mcp.nucleus.fast,https://pulse.nucleus.fastfallbacks withc.env.APP_URL/c.env.MCP_URL/ etc. Grep for.nucleus.faststring literals inapps/*/worker/. - Anywhere
ENVis compared (e.g. pulse’s hardcoded"production"), make it avars.ENVvalue.
Secrets
Section titled “Secrets”Every secret gets re-set with wrangler secret put --env staging <NAME>:
- App (~15):
NUCLEUS_SERVICE_TOKEN,CONNECTIONS_ENCRYPTION_KEY,XERO_CLIENT_SECRET,GOOGLE_CLIENT_SECRET,ANTHROPIC_API_KEY,CF_AI_API_TOKEN,CF_API_TOKEN, Slack / Twilio / Unsplash / TikTok / ReverseContact / Scrapin keys,MCP_BRIDGE_SECRET - Pulse (~8): Slack + Productive OAuth,
TOKEN_ENCRYPTION_KEY,RESEND_API_KEY,DEV_BEARER_TOKEN - Admin:
ADMIN_SECRET - Agents (per agent):
ANTHROPIC_API_KEY,GITHUB_TOKEN,SLACK_BOT_TOKEN,NUCLEUS_SERVICE_TOKEN, plus agent-specific keys
OAuth choice point: staging can either (a) reuse prod OAuth apps with staging redirect URIs added, or (b) register separate staging OAuth apps per integration. (b) is cleaner isolation; (a) is ~80% less work. Recommend (a) for internal integrations (Slack, GitHub, Xero) and (b) only where the vendor requires it.
Deployment
Section titled “Deployment”Add to root package.json:
deploy:staging → runs deploy:*:staging in paralleldeploy:app:staging → wrangler deploy --env staging (per workspace)Add .github/workflows/deploy-staging.yml triggered on push to a staging branch (or on PR label). Mirror the existing deploy-app.yml patterns with --env staging.
Migrations / seeding
Section titled “Migrations / seeding”cd apps/appwrangler d1 migrations apply nucleus-db-staging --remotewrangler d1 execute nucleus-db-staging --remote --file db/seed.sqlOptional: pipe a sanitised prod snapshot to staging for realistic testing.
Verification
Section titled “Verification”curl https://app.staging.nucleus.fast/api/healthreturns 200- Log in through CF Access → frontend loads,
/api/users/mereturns the seeded admin user - Pulse: pair a dev device against
pulse.staging.nucleus.fast, confirm Slack status updates - MCP: point Claude Desktop at
mcp.staging.nucleus.fast, confirmlist_companiesreturns - Run at least one cron manually (
wrangler trigger <worker> --env staging) and confirm it hits staging DB, not prod
Effort estimate
Section titled “Effort estimate”| Slice | Effort | What it unlocks |
|---|---|---|
| MVP — app + mcp + pulse only, staging D1, CF Access, DNS | ~1 day | End-to-end UI/API testing on a staging domain |
| Full parity — all 15 workers, KVs, R2, DO, OAuth redirects, staging agents, CI workflow | ~3–4 days | True pre-prod environment; agents schedule against staging DB |
| Hardened — sanitised prod data seeding, separate OAuth apps, alerts, staging-specific rate limits | ~1 week total | Safe for demoing / training / QA without touching prod data |
Recommendation: do the MVP slice first. Agents are homogeneous — once one has an [env.staging] block, the rest are copy-paste.
Critical files
Section titled “Critical files”apps/app/wrangler.toml— template for the[env.staging]block every worker needsapps/app/worker/middleware/auth.ts— verify it doesn’t assume a prod-only CF Access audienceapps/pulse/worker/wrangler.toml— hardcodedENV = "production"needs to become env-specificapps/mcp/wrangler.jsonc— service bindingNUCLEUS_APPmust point atnucleus-appin the matching env.github/workflows/deploy-app.yml(and siblings) — template for newdeploy-staging.yml- Root
package.json— adddeploy:*:stagingscripts