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β
| Environment | Frontend | Backend | Database | Branch |
|---|---|---|---|---|
| Production | TBD at launch | TBD at launch | TBD at launch | main |
| UAT | dev.threatweaver.ai (Render Static) | threatweaver-backend.onrender.com | Render PostgreSQL (Pro 8GB) | dev |
| Local | localhost:3005 | localhost:4005 | Docker PostgreSQL :5432 | local |
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
localbranch - Pushing to
devtriggers immediate UAT deployment β never push without explicit confirmation - The
mainbranch is protected by a pre-push hook and is reserved for production releases - Never force-push to
devormain
Backend Deployment (Render)β
Build Configurationβ
# Build command
npm install && npm run build
# Start command
node dist/index.js
Critical constraints:
- Never add
"type": "module"topackage.json-- Render requires CommonJS - Keep
tsxindevDependenciesonly (not needed at runtime) - The compiled approach uses
tscto transpile TypeScript, thennodeto run the output
Pre-deploy Checklistβ
- Verify the build succeeds locally:
cd backend && rm -rf dist && npm run build && npm start - Run migrations against the target database
- Confirm all environment variables are set in Render dashboard
- Check that no secrets are committed to the repository
Environment Variablesβ
Key environment variables required on Render:
| Variable | Purpose |
|---|---|
DATABASE_URL | PostgreSQL connection string (Supabase) |
REDIS_URL | Upstash Redis connection string (optional) |
JWT_SECRET | Secret for signing JWT tokens |
TENABLE_ACCESS_KEY | Tenable.io API access key |
TENABLE_SECRET_KEY | Tenable.io API secret key |
ANTHROPIC_API_KEY | Claude AI API key |
OPENAI_API_KEY | GPT API key |
DEPLOYMENT_MODE | saas 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 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.
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β
| Setting | Value |
|---|---|
| Root Directory | kb-site |
| Framework Preset | Other (Vercel auto-detects Docusaurus) |
| Build Command | npm run build |
| Output Directory | build |
| Node.js Version | 20.x (minimum) |
| Branch | dev (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)β
| Variable | Required | Purpose |
|---|---|---|
KB_ACCESS_CODE | Recommended | Passphrase-based access gate β users enter this on first visit. Simpler than SSO. |
MSAL_CLIENT_ID | Optional | Azure AD app (client) ID for Microsoft SSO login |
MSAL_TENANT_ID | Optional | Azure 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_IDare set β Microsoft SSO button shown - If
KB_ACCESS_CODEis set β passphrase fallback shown (5 wrong attempts = 60s lockout) - If neither is set β
LockedDownPageshown (nobody can enter) localhostis always bypassed for local dev
API Playground Credentialsβ
| Variable | Required | Purpose |
|---|---|---|
KB_UAT_EMAIL | Recommended | UAT email auto-filled in the API Playground β testingadmin@blucypher.com |
KB_UAT_PASSWORD | Recommended | UAT 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.
docusaurus.config.ts reads all five via process.env and exposes them via customFields. Components access them with useDocusaurusContext().siteConfig.customFields.kbUatEmail etc.
Recommended Vercel env var setup (copy-paste ready)β
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
urlindocusaurus.config.ts - DNS: Add CNAME record
kbβcname.vercel-dns.comin 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:
| Backend | Where to Update | Value to Append |
|---|---|---|
| Local | backend/.env β CORS_ORIGIN | Already done β has localhost:3010 |
| UAT | Render β CORS_ORIGIN env var | ,https://kb.threatweaver.ai |
| Production | TBD 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:
| Variable | Value | Environment |
|---|---|---|
KB_ACCESS_CODE | your chosen passphrase | Production, Preview |
KB_UAT_EMAIL | testingadmin@blucypher.com | Production, Preview |
KB_UAT_PASSWORD | TestAdmin@Blu2026! | Production, Preview |
MSAL_CLIENT_ID | Azure AD client ID | Production, Preview |
MSAL_TENANT_ID | Azure AD tenant ID | Production, 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.aito UAT backendCORS_ORIGINin Render dashboard - Add same to production backend
CORS_ORIGINwhen 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-srcinvercel.jsonwith 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β
- In the Render dashboard, navigate to the service's deploy history
- Click "Redeploy" on the last known good deployment
- Verify the rollback by checking the health endpoint:
GET /api/health
Frontend Rollback (UAT)β
- In the Render dashboard, navigate to the Static Site deploy history
- Click "Redeploy" on the last known good deployment
- Verify by loading
https://dev.threatweaver.aiand checking the console for version info
Database Rollbackβ
Database migrations are forward-only. If a migration causes issues:
- Write a new migration that reverses the problematic changes
- Test the reversal migration locally
- Deploy the reversal migration through the normal pipeline