Skip to main content
Version: Local Β· In Progress

Deployment

ThreatWeaver currently runs two active environments: Local (developer machines) and UAT (Render). Production hosting has not been finalized and will be decided at launch time using the main branch.

Deployment Architecture​

Environments​

EnvironmentFrontendBackendDatabaseBranch
ProductionTBD at launchTBD at launchTBD at launchmain
UATdev.threatweaver.ai (Render Static)threatweaver-backend.onrender.comRender PostgreSQL (Pro 8GB)dev
Locallocalhost:3005localhost:4005Docker PostgreSQL :5432local
Production hosting not yet decided

Production infrastructure (frontend hosting, backend hosting, database) will be selected and configured at launch time. The main branch is reserved for production releases. Do not commit deployment-specific URLs until a decision is made.

Branch and Deployment Flow​

Rules:

  • All development happens on the local branch
  • Pushing to dev triggers immediate UAT deployment β€” never push without explicit confirmation
  • The main branch is protected by a pre-push hook and is reserved for production releases
  • Never force-push to dev or main

Backend Deployment (Render)​

Build Configuration​

# Build command
npm install && npm run build

# Start command
node dist/index.js

Critical constraints:

  • Never add "type": "module" to package.json -- Render requires CommonJS
  • Keep tsx in devDependencies only (not needed at runtime)
  • The compiled approach uses tsc to transpile TypeScript, then node to run the output

Pre-deploy Checklist​

  1. Verify the build succeeds locally:
    cd backend && rm -rf dist && npm run build && npm start
  2. Run migrations against the target database
  3. Confirm all environment variables are set in Render dashboard
  4. Check that no secrets are committed to the repository

Environment Variables​

Key environment variables required on Render:

VariablePurpose
DATABASE_URLPostgreSQL connection string (Supabase)
REDIS_URLUpstash Redis connection string (optional)
JWT_SECRETSecret for signing JWT tokens
TENABLE_ACCESS_KEYTenable.io API access key
TENABLE_SECRET_KEYTenable.io API secret key
ANTHROPIC_API_KEYClaude AI API key
OPENAI_API_KEYGPT API key
DEPLOYMENT_MODEsaas for multi-tenant, single for standalone

Frontend Deployment (UAT β€” Render Static)​

The React SPA is deployed to Render Static Site on push to dev. The UAT URL is https://dev.threatweaver.ai.

Build Configuration​

# Build command
npm run build

# Output directory
dist
Production Frontend TBD

Production frontend hosting (Vercel, Cloudflare Pages, or other CDN) will be decided at launch. Update this section and vercel.json / deployment config accordingly.

KB Site Deployment (Vercel)​

The KB site (kb-site/) is a Docusaurus static site intended to deploy to Vercel at https://kb.threatweaver.ai.

Docusaurus is a static site

All environment variables are build-time only β€” they get baked into the HTML/JS bundle during npm run build. There are no server-side runtime env vars.

Vercel Project Settings​

SettingValue
Root Directorykb-site
Framework PresetOther (Vercel auto-detects Docusaurus)
Build Commandnpm run build
Output Directorybuild
Node.js Version20.x (minimum)
Branchdev (auto-deploys on push)

Environment Variables (Build-time)​

Set these in Vercel Dashboard β†’ Project β†’ Settings β†’ Environment Variables.

All variables are build-time only β€” Docusaurus bakes them into the JS bundle at npm run build via customFields in docusaurus.config.ts. There are no runtime server-side vars.

Access Gate (Auth)​

VariableRequiredPurpose
KB_ACCESS_CODERecommendedPassphrase-based access gate β€” users enter this on first visit. Simpler than SSO.
MSAL_CLIENT_IDOptionalAzure AD app (client) ID for Microsoft SSO login
MSAL_TENANT_IDOptionalAzure AD tenant ID for Microsoft SSO login

Auth logic (src/theme/Root.tsx): fail-secure gate wraps every page.

  • If MSAL_CLIENT_ID + MSAL_TENANT_ID are set β†’ Microsoft SSO button shown
  • If KB_ACCESS_CODE is set β†’ passphrase fallback shown (5 wrong attempts = 60s lockout)
  • If neither is set β†’ LockedDownPage shown (nobody can enter)
  • localhost is always bypassed for local dev

API Playground Credentials​

VariableRequiredPurpose
KB_UAT_EMAILRecommendedUAT email auto-filled in the API Playground β€” testingadmin@blucypher.com
KB_UAT_PASSWORDRecommendedUAT password auto-filled in the API Playground

These are pre-filled convenience values for the team using the API Playground. They are visible in the browser bundle β€” use a shared test account, never a personal or admin account.

Where these are consumed

docusaurus.config.ts reads all five via process.env and exposes them via customFields. Components access them with useDocusaurusContext().siteConfig.customFields.kbUatEmail etc.

KB_ACCESS_CODE         = <choose a strong passphrase>
KB_UAT_EMAIL = testingadmin@blucypher.com
KB_UAT_PASSWORD = TestAdmin@Blu2026!
MSAL_CLIENT_ID = <Azure AD app client ID β€” optional>
MSAL_TENANT_ID = <Azure AD tenant ID β€” optional>

Custom Domain​

  • Target URL: https://kb.threatweaver.ai
  • Already set as the canonical url in docusaurus.config.ts
  • DNS: Add CNAME record kb β†’ cname.vercel-dns.com in your DNS provider

Backend CORS β€” Required Updates Before Going Live​

When the kb-site is live at https://kb.threatweaver.ai, every backend it calls from the API Playground must allow that origin in its CORS_ORIGIN:

BackendWhere to UpdateValue to Append
Localbackend/.env β†’ CORS_ORIGINAlready done β€” has localhost:3010
UATRender β†’ CORS_ORIGIN env var,https://kb.threatweaver.ai
ProductionTBD hosting β†’ CORS_ORIGIN,https://kb.threatweaver.ai

Content Security Policy β€” Update When Production Backend Is Known​

kb-site/vercel.json has a hardened CSP. The connect-src directive currently allows the UAT backend. When production backend URL is confirmed, add it:

"connect-src 'self' https://login.microsoftonline.com https://threatweaver-backend.onrender.com https://<PRODUCTION_BACKEND_URL>"

API Playground β€” Production URL​

src/pages/api-playground.tsx β†’ ENVIRONMENTS array has a production entry with an empty backendUrl. Fill it in when the production backend URL is confirmed:

{
id: 'production',
label: 'Production',
badge: 'PROD',
badgeColor: '#ef4444',
backendUrl: 'https://<PRODUCTION_BACKEND_URL>', // ← set this
email: '',
password: '',
note: 'Production β€” use personal credentials',
},

Pre-Launch Checklist​

Step 1 β€” Create Vercel Project​

  • Go to vercel.com β†’ New Project β†’ Import BluCypher1/ThreatWeaver
  • Set Root Directory to kb-site
  • Framework preset: Other (Docusaurus auto-detected)
  • Build command: npm run build | Output: build | Node: 20.x
  • Set deploy branch to dev

Step 2 β€” Set Environment Variables​

In Vercel Dashboard β†’ Project β†’ Settings β†’ Environment Variables, add:

VariableValueEnvironment
KB_ACCESS_CODEyour chosen passphraseProduction, Preview
KB_UAT_EMAILtestingadmin@blucypher.comProduction, Preview
KB_UAT_PASSWORDTestAdmin@Blu2026!Production, Preview
MSAL_CLIENT_IDAzure AD client IDProduction, Preview
MSAL_TENANT_IDAzure AD tenant IDProduction, Preview

Step 3 β€” Custom Domain​

  • In Vercel β†’ Project β†’ Domains β†’ add kb.threatweaver.ai
  • In your DNS provider: add CNAME kb β†’ cname.vercel-dns.com
  • Wait for SSL cert (usually < 2 min)

Step 4 β€” CORS​

  • Add https://kb.threatweaver.ai to UAT backend CORS_ORIGIN in Render dashboard
  • Add same to production backend CORS_ORIGIN when known

Step 5 β€” Final verification​

  • Trigger a fresh deploy in Vercel (or push to dev)
  • Open https://kb.threatweaver.ai β€” auth gate should appear
  • Enter KB_ACCESS_CODE β€” should unlock and land on homepage
  • Open API Playground β†’ UAT tab β†’ credentials should be pre-filled
  • Update connect-src in vercel.json with production backend URL when known

Local Development Setup​

Local development uses a hybrid approach: PostgreSQL runs in Docker, while the frontend and backend run natively on the host machine.

# Start only PostgreSQL
docker-compose up -d postgres

# Backend (in one terminal)
cd backend && npm run dev

# Frontend (in another terminal)
cd frontend && npm run dev

Important: Never run docker-compose up without specifying postgres -- this would attempt to containerize the backend and frontend, which is not supported for local development. Redis is not used locally; the cache layer degrades gracefully when unavailable.

Rollback Procedures​

Backend Rollback​

  1. In the Render dashboard, navigate to the service's deploy history
  2. Click "Redeploy" on the last known good deployment
  3. Verify the rollback by checking the health endpoint: GET /api/health

Frontend Rollback (UAT)​

  1. In the Render dashboard, navigate to the Static Site deploy history
  2. Click "Redeploy" on the last known good deployment
  3. Verify by loading https://dev.threatweaver.ai and checking the console for version info

Database Rollback​

Database migrations are forward-only. If a migration causes issues:

  1. Write a new migration that reverses the problematic changes
  2. Test the reversal migration locally
  3. Deploy the reversal migration through the normal pipeline