Handoff: Backend-Vitto-API Railway Production Setup
Complete instructions for deploying the new standalone backend-vitto-api to Railway production
Handoff: Backend-Vitto-API Railway Production Setup (v2 — Updated)
From: Testing Director (Cowork, Session 99) To: Coding Agent (Cursor/Claude Code) Priority: HIGH — Railway project created but configured with WRONG backend-ai-api values Estimated Scope: ~8 files modified/created, 4 phases (Phase 2 already done by Paco)
Context
Session 98 rebuilt Vitto from a 2119-line god-class embedded in backend-ai-api into a standalone backend-vitto-api on port 3003. The app structure exists (~40 files, 7 modules, ~5,100 lines), with a Dockerfile and railway.json already created.
Paco has already completed Phase 2 (Railway project creation):
- Railway project created with service "Vitto API"
- Domain
vitto-api.gograb.spaceconfigured - Deploy branch
deploy/vitto-apiconnected to GitHub - Project token created
However, the railway.toml on the deploy/vitto-api branch was copied from backend-ai-api with ALL WRONG VALUES. The current deployment is stuck failing healthchecks because it's building the wrong app entirely.
Railway Project Details (Confirmed from Dashboard)
| Field | Value |
|---|---|
| Project ID | 3990549d-4313-47e4-9682-d17b382bdba2 |
| Environment ID | 0d84c89d-6bc7-425c-8d17-14e0a5760041 |
| Service ID | 1acab221-cd3e-4c3f-9cbb-bcbc5feb7954 |
| Service Name | Vitto API |
| Domain | vitto-api.gograb.space |
| Source Repo | GoGrabSpace/editor |
| Source Branch | deploy/vitto-api |
| Token Name | vitto-api-token |
| Token Value | be1eefc9-fae9-478e-830c-472ee9b99155 |
| Dashboard | https://railway.com/project/3990549d-4313-47e4-9682-d17b382bdba2 |
Current Production Railway Status (Tested 2026-02-07)
| Service | Domain | Health | Status |
|---|---|---|---|
| Frontend | gograb.space | ✅ Working | Live |
| Backend AI API | ai-api.gograb.space | ✅ /ai-api/health returns 200 |
Live |
| Backend Docs API | docs-api.gograb.space | ✅ /docs-api/health returns 200 |
Live |
| Backend API | api.gograb.space | ⚠️ /api/health returns 404 |
Running but health endpoint missing |
| Backend Vitto API | vitto-api.gograb.space | ❌ Failing — wrong config | This handoff |
BLOCKER #1: railway.toml Has ALL Wrong Values (deploy/vitto-api branch)
The railway.toml at the repo root on the deploy/vitto-api branch was copied directly from backend-ai-api. Every service-specific value is wrong. This is why deployments are stuck on "Performing healthchecks..." indefinitely.
Current WRONG railway.toml (on deploy/vitto-api branch):
# ❌ THIS IS THE CURRENT BROKEN CONFIG — ALL VALUES FROM BACKEND-AI-API
[build]
builder = "DOCKERFILE"
dockerfilePath = "deployment/Dockerfile.railway.backend-ai" # ❌ WRONG
dockerContext = "."
watchPatterns = [
"apis/backend-ai-api/**", # ❌ WRONG
"apps/claude-agent-mcp/**", # ❌ WRONG (vitto doesn't use this)
"libs/libs-api/backend-core/**", # ✅ OK (vitto imports this)
"libs/libs-api/auth-core/**", # ❌ WRONG (vitto doesn't import this)
"libs/libs-api/llm-integration/**", # ❌ WRONG (vitto doesn't import this)
"libs/libs-foundational/core-models/**", # ⚠️ Optional (keep for safety)
"deployment/Dockerfile.railway.backend-ai", # ❌ WRONG
"package.json", # ✅ OK
"yarn.lock", # ✅ OK
"tsconfig.base.json", # ✅ OK
"nx.json" # ✅ OK
]
[deploy]
startCommand = "node dist/apis/backend-ai-api/main.js" # ❌ WRONG
healthcheckPath = "/ai-api/health" # ❌ WRONG
healthcheckTimeout = 300 # ✅ OK
restartPolicyType = "ON_FAILURE" # ✅ OK
restartPolicyMaxRetries = 10 # ✅ OK
Required CORRECT railway.toml (REPLACE on deploy/vitto-api branch):
# Railway Configuration for backend-vitto-api
# Branch: deploy/vitto-api
# Session 99: Standalone Vitto Super-Agent API
[build]
builder = "DOCKERFILE"
dockerfilePath = "deployment/Dockerfile.railway.backend-vitto"
dockerContext = "."
# Watch patterns — only files that affect backend-vitto-api builds
watchPatterns = [
# Main application
"apis/backend-vitto-api/**",
# Shared API libraries (actual imports from grep analysis)
"libs/libs-api/backend-core/**",
# Foundational libraries (transitive dependency)
"libs/libs-foundational/core-models/**",
# Build configuration
"deployment/Dockerfile.railway.backend-vitto",
"package.json",
"yarn.lock",
"tsconfig.base.json",
"nx.json"
]
[deploy]
startCommand = "node dist/apis/backend-vitto-api/main.js"
healthcheckPath = "/vitto-api/health"
healthcheckTimeout = 300
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 10
Exact Changes Summary (railway.toml):
| Setting | WRONG (current) | CORRECT (required) |
|---|---|---|
dockerfilePath |
deployment/Dockerfile.railway.backend-ai |
deployment/Dockerfile.railway.backend-vitto |
startCommand |
node dist/apis/backend-ai-api/main.js |
node dist/apis/backend-vitto-api/main.js |
healthcheckPath |
/ai-api/health |
/vitto-api/health |
watchPatterns[0] |
apis/backend-ai-api/** |
apis/backend-vitto-api/** |
watchPatterns[1] |
apps/claude-agent-mcp/** |
REMOVE |
watchPatterns[3] |
libs/libs-api/auth-core/** |
REMOVE |
watchPatterns[4] |
libs/libs-api/llm-integration/** |
REMOVE |
watchPatterns[6] |
deployment/Dockerfile.railway.backend-ai |
deployment/Dockerfile.railway.backend-vitto |
BLOCKER #2: main.ts Missing Railway PORT Detection
File: apis/backend-vitto-api/src/main.ts
Even after fixing the railway.toml, the app itself won't bind to the correct port.
Current (BROKEN for Railway):
// Line ~30
const isProduction = process.env.NODE_ENV === 'production';
// Line ~59
const port = process.env.VITTO_API_PORT || 3003;
Required (follow backend-ai-api pattern from lines 37-39, 74-76):
// Determine if Railway (check multiple indicators)
const isRailway = process.env.RAILWAY_ENVIRONMENT === 'true' ||
process.env.RAILWAY_STATIC_URL !== undefined ||
process.env.RAILWAY_SERVICE_NAME !== undefined;
// Reduce logging in production to avoid Railway rate limits
const isProduction = process.env.NODE_ENV === 'production' || isRailway;
// ... later in bootstrap() ...
// Railway sets PORT dynamically (usually 8080). Locally use VITTO_API_PORT.
const port = isRailway
? (process.env.PORT || 3003)
: (process.env.VITTO_API_PORT || 3003);
Why this matters: Railway assigns a dynamic PORT (typically 8080). Without reading process.env.PORT, the app binds to 3003 while Railway health checks hit 8080. Deployment will fail every time.
Reference: Compare apis/backend-ai-api/src/main.ts lines 37-39, 74-76.
BLOCKER #3: Environment Variables — Wrong + Missing
Dashboard Audit (Variables Tab — 10 Service Variables Currently Set):
| Variable | Currently Set | Status | Action |
|---|---|---|---|
MONGODB_CONNECTION_STRING |
✅ Set | ❌ WRONG NAME — Vitto reads VITTO_MONGODB_URI |
Rename or add VITTO_MONGODB_URI |
MONGODB_DATABASE |
✅ Set | ❌ NOT USED — Vitto embeds DB name in URI | Remove (optional) |
OPENAI_API_KEY |
✅ Set | ⚠️ Optional | Keep if multi-provider planned |
ANTHROPIC_API_KEY |
✅ Set | ✅ CORRECT | Keep — needed for Claude LLM |
GOOGLE_API_KEY |
✅ Set | ❌ NOT USED by Vitto | Remove (optional) |
JWT_SECRET |
✅ Set | ✅ CORRECT — must match other services | Keep — verify matches |
JWT_EXPIRATION |
✅ Set | ⚠️ Optional | Keep (harmless) |
NODE_ENV |
✅ Set | ✅ CORRECT — should be "production" | Keep |
ALLOWED_ORIGINS |
✅ Set | ✅ CORRECT — verify includes vitto-api.gograb.space | Verify value |
PORT |
✅ Set | ⚠️ Railway auto-sets this | Keep (no harm) |
Missing Variables (MUST ADD):
| Variable | Value | Why |
|---|---|---|
RAILWAY_ENVIRONMENT |
true |
CRITICAL — Required for isRailway detection in main.ts |
VITTO_MONGODB_URI |
mongodb+srv://<user>:<pass>@<cluster>/vitto-mind?retryWrites=true&w=majority |
CRITICAL — The env var Vitto's app.module.ts actually reads (VITTO_MONGODB_URI, NOT MONGODB_CONNECTION_STRING) |
SYSTEM_TOKEN |
<MUST MATCH OTHER SERVICES> |
Inter-service authentication |
VITTO_LLM_PROVIDER |
claude |
Default LLM provider |
VITTO_LLM_MODEL |
claude-sonnet-4-20250514 |
Default model |
VITTO_MAX_CONCURRENT |
3 |
Task concurrency limit |
VITTO_MAX_ITERATIONS |
25 |
Agent loop limit |
VITTO_MAX_TOKENS |
100000 |
Token budget per task |
VITTO_TASK_TIMEOUT_MS |
300000 |
5min task timeout |
BACKEND_API_URL |
https://api.gograb.space |
HTTP client for cross-service calls |
BACKEND_AI_API_URL |
https://ai-api.gograb.space |
HTTP client for cross-service calls |
BACKEND_DOCS_API_URL |
https://docs-api.gograb.space |
HTTP client for cross-service calls |
ALLOWED_ORIGINS — Full Value (verify in dashboard):
https://gograb.space,https://vitto-api.gograb.space,https://api.gograb.space,https://ai-api.gograb.space,https://docs-api.gograb.space,http://localhost:5200,http://localhost:5100,http://localhost:5400,http://localhost:3000,http://localhost:3001,http://localhost:3002,http://localhost:3003
Additional Issues (Non-Blocking but Important)
Issue 4: CORS additionalOrigins in main.ts
File: apis/backend-vitto-api/src/main.ts (lines 46-53)
Currently only has localhost origins in additionalOrigins. The createCorsConfig utility reads ALLOWED_ORIGINS env var which handles production, but consider adding production URLs as fallback like backend-ai-api does.
Issue 5: No .railway/projects.json Entry
File: .railway/projects.json
Add this entry to the projects object:
"backend-vitto": {
"id": "3990549d-4313-47e4-9682-d17b382bdba2",
"environmentId": "0d84c89d-6bc7-425c-8d17-14e0a5760041",
"name": "GoGrab Backend Vitto API",
"description": "Vitto super-agent API (orchestration, mind, tools)",
"type": "backend-vitto",
"apps": ["backend-vitto-api"],
"dockerfile": "deployment/Dockerfile.railway.backend-vitto",
"startCommand": "node dist/apis/backend-vitto-api/main.js",
"healthCheckPath": "/vitto-api/health",
"environment": {
"NODE_ENV": "production",
"RAILWAY_ENVIRONMENT": "true",
"PORT": "${PORT}",
"VITTO_MONGODB_URI": "${VITTO_MONGODB_URI}",
"JWT_SECRET": "${JWT_SECRET}",
"ALLOWED_ORIGINS": "${ALLOWED_ORIGINS}",
"ANTHROPIC_API_KEY": "${ANTHROPIC_API_KEY}",
"SYSTEM_TOKEN": "${SYSTEM_TOKEN}"
},
"dashboardUrl": "https://railway.com/project/3990549d-4313-47e4-9682-d17b382bdba2?environmentId=0d84c89d-6bc7-425c-8d17-14e0a5760041"
}
Issue 6: No Deploy Script
Create: deployment/deploy-vitto-api.sh
Copy from deployment/deploy-backend-ai.sh and change:
- Token var:
RAILWAY_AI_TOKEN→RAILWAY_VITTO_TOKEN - Project ID:
56e862b3...→3990549d-4313-47e4-9682-d17b382bdba2 - Environment ID:
a54fd342...→0d84c89d-6bc7-425c-8d17-14e0a5760041 - Project name:
backend-ai-api→backend-vitto-api - Health check:
/ai-api/health→/vitto-api/health - Service name in
railway up:Backend-ai-api→Vitto-api(or whatever Railway named it) - Config file:
deployment/railway.backend-ai.toml→deployment/railway.vitto.toml
Issue 7: Missing Reference Config
Create: deployment/railway.vitto.toml
# Railway Backend Vitto API Project Configuration
# Project ID: 3990549d-4313-47e4-9682-d17b382bdba2
# Environment: 0d84c89d-6bc7-425c-8d17-14e0a5760041
# Service: backend-vitto-api (Vitto Super-Agent)
[build]
builder = "DOCKERFILE"
dockerfilePath = "deployment/Dockerfile.railway.backend-vitto"
dockerContext = "."
[deploy]
startCommand = "node dist/apis/backend-vitto-api/main.js"
healthcheckPath = "/vitto-api/health"
healthcheckTimeout = 300
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 10
Issue 8: Missing Package.json Deploy Commands
File: package.json
Add these scripts:
"railway:deploy:vitto": "./deployment/deploy-vitto-api.sh",
"railway:build:vitto": "npx nx build backend-vitto-api --configuration=production",
Update railway:deploy:all to include Vitto if it exists.
Issue 9: .env.local — Add Vitto Token
Add to .env.local:
RAILWAY_VITTO_TOKEN=be1eefc9-fae9-478e-830c-472ee9b99155
Issue 10 (LOW): Dockerfile HEALTHCHECK Default Port
File: deployment/Dockerfile.railway.backend-vitto (line ~82)
Change ${PORT:-3003} to ${PORT:-8080} in HEALTHCHECK. Cosmetic since Railway always sets PORT, but aligns with expected behavior.
Implementation Plan (Updated — Phase 2 Already Done)
Phase 1: Fix railway.toml on deploy/vitto-api branch (CRITICAL — DO FIRST)
# 1. Switch to the deploy branch
git checkout deploy/vitto-api
# 2. Merge latest main
git merge main --no-edit
# 3. Replace railway.toml at repo root with the CORRECT config (see BLOCKER #1 above)
# The file must be at the repo root: ./railway.toml
# 4. Commit and push
git add railway.toml
git commit -m "fix(deploy): correct railway.toml for vitto-api (was using backend-ai-api values)"
git push
This push will automatically trigger a new Railway deployment with the correct config.
Phase 2: Fix main.ts (CRITICAL — Do Immediately After)
File: apis/backend-vitto-api/src/main.ts
- Add
isRailwaydetection at the top ofbootstrap() - Update
isProductionto includeisRailway - Change port binding to use
process.env.PORTon Railway - Commit to main, then merge into deploy/vitto-api branch
Verification: Build locally with npx nx build backend-vitto-api --configuration=production and test with:
RAILWAY_ENVIRONMENT=true PORT=8080 node dist/apis/backend-vitto-api/main.js
Should log: 🤖 VITTO Super-Agent API READY on port 8080
Phase 3: Create Deploy Infrastructure (on main branch)
- Add entry to
.railway/projects.json(see Issue 5 above) - Create
deployment/deploy-vitto-api.sh(see Issue 6 above) - Create
deployment/railway.vitto.toml(see Issue 7 above) - Update
package.jsonwith deploy/build commands (see Issue 8 above) - Add token to
.env.local(see Issue 9 above) - Merge main into deploy/vitto-api after all changes
Phase 4: Configure Railway Environment Variables (Dashboard — Paco or Agent)
Add the missing variables listed in BLOCKER #3 above. The most critical ones are:
RAILWAY_ENVIRONMENT=trueVITTO_MONGODB_URI(createvitto-minddatabase in MongoDB Atlas first)SYSTEM_TOKEN(must match other services)
Files to Create/Modify Summary
| # | File | Action | Priority | Branch |
|---|---|---|---|---|
| 1 | railway.toml (repo root) |
REPLACE — Fix all wrong backend-ai-api values | CRITICAL | deploy/vitto-api |
| 2 | apis/backend-vitto-api/src/main.ts |
Modify — Add isRailway + PORT detection | CRITICAL | main → merge to deploy/vitto-api |
| 3 | .railway/projects.json |
Modify — Add backend-vitto entry | HIGH | main |
| 4 | deployment/deploy-vitto-api.sh |
Create — Deploy script | HIGH | main |
| 5 | deployment/railway.vitto.toml |
Create — Reference config | MEDIUM | main |
| 6 | package.json |
Modify — Add deploy/build commands | HIGH | main |
| 7 | .env.local |
Modify — Add RAILWAY_VITTO_TOKEN | HIGH | local only |
| 8 | deployment/Dockerfile.railway.backend-vitto |
Modify — Fix HEALTHCHECK default port | LOW | main |
Verification Steps (Testing Director Will Verify)
After deployment, I will:
- Health check:
curl https://vitto-api.gograb.space/vitto-api/health— expect 200 OK - Cross-service auth: Get a JWT from backend-api login, send to vitto-api — should authenticate
- CORS: Make fetch from gograb.space to vitto-api — should not be blocked
- Mind DB: Check MongoDB Atlas for
vitto-minddatabase with collections - Logs: Check Railway dashboard for clean startup (no rate limit warnings)
- Startup message: Logs should show
🤖 VITTO Super-Agent API READY on port <dynamic>
Side Finding: Backend API Health Endpoint Missing
Unrelated to Vitto but discovered during audit:
https://api.gograb.space/api/health returns 404. The NestJS app IS running (it returns {"message":"Cannot GET /api/health","error":"Not Found","statusCode":404}) but the health controller isn't registered or was removed.
Action: Check apis/backend-api/src/app/ for a health controller. Low priority — separate task.
Port Reference
| Service | Local Port | Railway Port | Health Endpoint | Deploy Branch | Domain |
|---|---|---|---|---|---|
| backend-api | 3000 | Dynamic | /api/health | deploy/api | api.gograb.space |
| backend-ai-api | 3001 | Dynamic | /ai-api/health | deploy/ai-api | ai-api.gograb.space |
| backend-docs-api | 3002 | Dynamic | /docs-api/health | deploy/docs-api | docs-api.gograb.space |
| backend-vitto-api | 3003 | Dynamic | /vitto-api/health | deploy/vitto-api | vitto-api.gograb.space |