Deployment Map
Backend and pipeline auto-deploy from main on Railway; the dashboard auto-deploys on Vercel; the web app and this docs site ship by manual Vercel CLI deploy. No staging environment — rollouts rely on feature flags and manual migration gates.
Hosting Platforms
npx vercel --prod --yes (auto-aliases the production domains). A merge does not publish.npm run deploy (regenerate + CLI deploy). Only rendered .html ships.iOS App (SwiftUI)
GitHub Repositories
| Repository | Visibility | CI/CD | Config Files |
|---|---|---|---|
| vibebullish-backend | Private | Railway auto-deploy on push to main (Wait-for-CI); Go test workflow | railway.toml, nixpacks.toml, Procfile |
| vibebullish-data-pipeline | Private | Railway auto-deploy on push to main (Wait-for-CI); Python test workflow; Dockerfile build | railway.toml, Dockerfile, requirements.lock, Procfile |
| vibebullish-web | Private | Manual Vercel CLI deploy; no Git-triggered deploy | vercel.json, next.config.ts |
| vibebullish-data-pipeline-dashboard | Public | Vercel Git auto-deploy on merge to main | vercel.json |
| vibebullish-docs | Private | Manual npm run deploy (regenerate + Vercel CLI) |
vercel.json, .vercelignore, package.json |
| vibebullish-ios | Private | Manual Xcode build + release | project.yml (XcodeGen) |
Visibility verified 2026-09-29.
Environment Variables
Variable names only. Values live in the Railway / Vercel dashboards and in gitignored local env files. Required = production depends on it; Optional = an operational switch or a feature that stays off when unset; Retired = no longer read by code.
Go Backend
Railway| Variable | Group | Purpose |
|---|---|---|
| DATABASE_URL | Required | PostgreSQL connection |
| POLYGON_API_KEY | Required | Market data; startup fails without it |
| DEEPSEEK_API_KEY | Required | LLM labeler / narrator / risk flagger |
| FIREBASE_CREDENTIALS_JSON | Required | Firebase Admin credentials |
| PIPELINE_BASE_URL | Required | Pipeline ML inference endpoint |
| FINNHUB_API_KEY | Required | News and insider data |
| SNAPTRADE_CLIENT_ID SNAPTRADE_CONSUMER_KEY | Required | Brokerage linking (SnapTrade) |
| INTERNAL_API_TOKEN | Required | Auth for internal endpoints |
| RUN_MIGRATION | Optional | Runs gated migrations when true |
| AUTOPILOT_MODE | Optional | Auto-Pilot mode switch; defaults to off |
| DQ_READINESS_EPISODES DQ_READINESS_EPOCH | Optional | Data-quality readiness episodes; off unless both set |
| ML_INFERENCE_MAX_CONCURRENCY ML_INFERENCE_BREAKER_THRESHOLD ML_INFERENCE_BREAKER_COOLDOWN_SEC | Optional | Inference gate concurrency and circuit breaker |
| BROKERAGE_ACCESS | Optional | Brokerage connect: open or allowlist |
| SLACK_*_WEBHOOK_URL | Optional | Alert and digest channel webhooks |
| OPENAI_API_KEY | Optional | Legacy provider client; warns if unset |
| ANTHROPIC_API_KEY | Optional | Legacy provider client; unavailable if unset |
| BRAVE_SEARCH_API_KEY | Retired | Unused since 2026-06; no code reference |
Python Pipeline
Railway| Variable | Group | Purpose |
|---|---|---|
| DATABASE_URL | Required | PostgreSQL connection (shared database) |
| POLYGON_API_KEY | Required | Market data, news, reference data |
| INTERNAL_API_TOKEN | Required | Internal endpoints fail closed without it |
| BACKEND_BASE_URL | Required | Backend base URL for callbacks |
| FINNHUB_API_KEY | Optional | Finnhub news gap-fill |
| DEEPSEEK_API_KEY | Optional | LLM labeling of news and filings |
| REDIS_URL | Optional | Cache; runs uncached when unset |
| SLACK_PIPELINE_WEBHOOK_URL | Optional | Training and daily-summary posts |
| NEWSAPI_KEY | Retired | No code reference |
Next.js Web App
Vercel# Required
NEXT_PUBLIC_API_URL
# Required for sign-in (auth is disabled when unset)
NEXT_PUBLIC_FIREBASE_API_KEY
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET
NEXT_PUBLIC_FIREBASE_APP_ID
iOS App
Local configVibeBullish/GoogleService-Info.plist
VibeBullish/Environment.env
// Environment.env is local-only (gitignored)
// and bundled by a build script
Deploy Process
Backend / Pipeline (Railway)
# Local gate before merge — backend
gofmt -l .
go vet ./...
go test ./...
# Local gate before merge — pipeline
pytest
# Push / merge to main triggers the Railway deploy
# (backend: not during market hours)
git push origin main
# CI status
gh run list --limit 5
# For database migrations
# Set RUN_MIGRATION=true in Railway dashboard, deploy, then unset
As of 2026-09-29 GitHub Actions CI is not running; full local test suites are the gate. Check gh run list for a green run before assuming CI is back.
Web App (Vercel)
# From the repo on latest main. Builds and auto-aliases
# www.vibebullish.com and vibebullish.com
npx vercel --prod --yes
Docs Site (Vercel)
# Regenerates the allowlisted pages, checks the upload set against
# the committed inventory, runs the Vercel CLI production deploy,
# then probes the live site
npm run deploy
iOS App
# Regenerate Xcode project after file changes
./generate-project.sh
# Open in Xcode
open VibeBullish.xcodeproj
# Archive and upload via Xcode Organizer
# Then submit for App Store review
Docs Site Publishing
What ships
Public, no auth- Pages — the hand-written
.htmlpages plus pages generated from an allowlist of markdown files (scripts/build-docs.mjs). One allowlist entry = one public page. - Excluded by
.vercelignore— all markdown sources,research/,reads/,mockups/,ops/,docs/,scripts/and the build tooling. A markdown file that is not on the allowlist is never uploaded. - Inventory gate — before publish, the set of files the deploy would upload is compared with a committed inventory (
docs/site-inventory.txt); any difference in either direction stops the deploy. - Publish step —
npm run deployruns regenerate, inventory check, Vercel CLI deploy, then a post-deploy probe of the live site. Pushing or merging to main does not publish.
Important Notes
- No staging environment — Railway auto-deploys main to production. Use feature flags and
RUN_MIGRATION=truegates for risky changes. - CI is not currently the gate — As of 2026-09-29 GitHub Actions CI is not running; full local test suites are the gate. Check
gh run listfor a green run before assuming CI is back. - No backend deploy during market hours — a mid-session restart resets the WebSocket bar cache.
- Merging to main does not publish the web app or this docs site — both ship by manual Vercel CLI deploy (
npx vercel --prod --yes,npm run deploy). - Polygon WebSocket constraint — Real-time plan; the backend holds the single stocks WebSocket connection — do not open a second one from another service.
- XcodeGen required — Always run
xcodegen generateafter adding or moving Swift files in the iOS project.
Verified against vibebullish-docs@0a4edb1, vibebullish-backend@07c641de,
vibebullish-data-pipeline@ee230ea, vibebullish-web@ce8ec92 on 2026-09-29.
Runtime observations are dated inline; a source sha does not vouch for deployed configuration or database contents.