Prevent BlackRoad-Operating-System monorepo from being added to Railway services

CRITICAL CHANGES:
- Add comprehensive deployment architecture documentation
- Prevent misconfiguration where monorepo is deployed instead of satellites
- Clarify monorepo-to-satellite sync model across all docs

CHANGES:
1. railway.toml
   - Add critical warning banner at top of file
   - Mark config as local development/testing only
   - Explain correct deployment model (satellites, not monorepo)

2. DEPLOYMENT_ARCHITECTURE.md (NEW)
   - Complete 500+ line deployment guide
   - Monorepo vs satellite model explained in detail
   - Critical rules: NEVER add monorepo to Railway
   - Service-to-repository mapping
   - Environment configuration guide
   - Cloudflare DNS configuration
   - Common mistakes and troubleshooting

3. README.md
   - Add prominent deployment warning box
   - Clarify monorepo is source of truth, not deployable
   - List satellite repos that should be deployed
   - Reference DEPLOYMENT_ARCHITECTURE.md

4. CLAUDE.md
   - Add critical deployment model section
   - Clarify Railway deployment is satellite-only
   - Update deployment workflow explanation
   - Add key rules for deployment

5. backend/.env.example
   - Fix ALLOWED_ORIGINS to reference satellites
   - Remove monorepo Railway URL reference
   - Add correct satellite service URLs

6. ops/domains.yaml
   - Fix os.blackroad.systems DNS target
   - Point to blackroad-os-core-production (satellite)
   - Remove incorrect monorepo Railway URL

7. scripts/validate_deployment_config.py (NEW)
   - Automated validation script
   - Checks for monorepo references in configs
   - Validates railway.toml, env files, DNS configs
   - Ensures DEPLOYMENT_ARCHITECTURE.md exists
   - Exit code 0 = pass, 1 = fail

WHY THIS MATTERS:
- Adding monorepo to Railway creates circular deploy loops
- Environment variables break (wrong service URLs)
- Cloudflare routing fails
- Service dependencies misconfigured
- Prevents production outages from misconfiguration

CORRECT MODEL:
- Monorepo = source of truth (orchestration only)
- Satellites = deployable services (Railway deployment)
- Code flows: monorepo → sync → satellite → Railway

See: DEPLOYMENT_ARCHITECTURE.md for complete details
This commit is contained in:
Claude
2025-11-19 22:31:22 +00:00
parent e7e6c4fde0
commit 9a728f655a
7 changed files with 997 additions and 25 deletions

View File

@@ -578,29 +578,55 @@ async def test_create_user(client: AsyncClient):
## Deployment
### Railway (Backend)
### ⚠️ CRITICAL: Monorepo vs Satellite Deployment Model
**Configuration** (`railway.toml`):
```toml
[build]
builder = "DOCKERFILE"
dockerfilePath = "backend/Dockerfile"
**This repository (`BlackRoad-Operating-System`) is NOT deployed to production.**
[deploy]
startCommand = "cd backend && uvicorn app.main:app --host 0.0.0.0 --port $PORT"
healthcheck.path = "/health"
```
BlackRoad OS uses a **monorepo-to-satellite sync architecture**:
**Deployment Steps**:
1. Push to main branch
2. GitHub Action triggers Railway deploy
3. Railway builds Docker image
4. Runs Alembic migrations
5. Starts FastAPI server
6. Health check validation
7. Traffic cutover
**Monorepo Role** (`BlackRoad-Operating-System`):
-**NOT deployed** to Railway or any production environment
- ✅ Source of truth for all service code
- ✅ Syncs code to satellite repos via GitHub Actions
- ✅ Orchestration, prompts, and infrastructure configs
**Manual Deploy**:
**Satellite Role** (Deployable Services):
-**ONLY satellites are deployed** to Railway
- Each satellite = one deployable service
- Satellites: `blackroad-os-core`, `blackroad-os-api`, `blackroad-os-operator`, `blackroad-os-prism-console`, `blackroad-os-docs`, `blackroad-os-web`
**Key Rules**:
1.**NEVER** add `BlackRoad-Operating-System` as a Railway service
2.**NEVER** reference monorepo in env vars or service configs
3.**NEVER** point Cloudflare to monorepo URLs
4.**ALWAYS** deploy satellite repos individually
5.**ALWAYS** edit code in monorepo (syncs to satellites automatically)
**See**: `DEPLOYMENT_ARCHITECTURE.md` for complete deployment model and troubleshooting.
---
### Railway (Satellite Deployment)
**IMPORTANT**: The `railway.toml` in this repo is for **local development/testing only**.
**Production deployment** is done via satellite repositories:
- `BlackRoad-OS/blackroad-os-core``blackroad-os-core-production` (Railway service)
- `BlackRoad-OS/blackroad-os-api``blackroad-os-api-production` (Railway service)
- `BlackRoad-OS/blackroad-os-operator``blackroad-os-operator-production` (Railway service)
- `BlackRoad-OS/blackroad-os-prism-console``blackroad-os-prism-console-production` (Railway service)
- `BlackRoad-OS/blackroad-os-docs``blackroad-os-docs-production` (Railway service)
**Deployment Flow**:
1. Edit code in monorepo (e.g., `services/core-api/`)
2. Commit and push to `main`
3. GitHub Action syncs to satellite (e.g., `BlackRoad-OS/blackroad-os-core`)
4. Satellite triggers Railway deployment
5. Railway builds Docker image
6. Runs migrations
7. Deploys to production
**Local Railway Testing** (monorepo only):
```bash
# Install Railway CLI
curl -fsSL https://railway.app/install.sh | sh
@@ -608,10 +634,13 @@ curl -fsSL https://railway.app/install.sh | sh
# Login
railway login
# Deploy
# Deploy locally (NOT for production)
railway up
```
**Production Railway Deploy** (satellites):
Done automatically via GitHub Actions when satellite repos update.
### GitHub Pages (Frontend)
**Deployment**:

523
DEPLOYMENT_ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,523 @@
# BlackRoad OS Deployment Architecture
> **Last Updated**: 2025-11-19
> **Status**: Canonical deployment model for all BlackRoad OS services
---
## Table of Contents
1. [Overview](#overview)
2. [The Monorepo vs Satellite Model](#the-monorepo-vs-satellite-model)
3. [Critical Rules](#critical-rules)
4. [Deployment Topology](#deployment-topology)
5. [Service-to-Repository Mapping](#service-to-repository-mapping)
6. [Environment Configuration](#environment-configuration)
7. [Cloudflare DNS Configuration](#cloudflare-dns-configuration)
8. [Common Mistakes to Avoid](#common-mistakes-to-avoid)
9. [Troubleshooting](#troubleshooting)
---
## Overview
BlackRoad OS uses a **monorepo-to-satellite sync architecture** where:
- **`BlackRoad-Operating-System`** (this repo) = Source of truth, orchestration, sync logic
- **Satellite repos** (`blackroad-os-core`, `blackroad-os-api`, etc.) = Deployable services
This document establishes the canonical deployment model to prevent misconfiguration.
---
## The Monorepo vs Satellite Model
### BlackRoad-Operating-System (Monorepo)
**Purpose**: Control plane and source of truth
**Role**:
- Houses all service code in `services/`, `apps/`, `docs/`
- Syncs code to satellite repos via GitHub Actions
- Stores orchestration logic, prompts, and infrastructure configs
- Serves as the "brain" - NOT the compute
**Deployment Status**: ❌ **NEVER DEPLOYED TO PRODUCTION**
**Why NOT deployable**:
- No single entry point (contains multiple services)
- Would create circular deployment dependencies
- Not designed for runtime execution
- Would break service discovery and routing
### Satellite Repositories
**Purpose**: Deployable, runtime services
**Satellites**:
| Repository | Purpose | Railway Service | Cloudflare Domain |
|------------|---------|-----------------|-------------------|
| `blackroad-os-core` | Core API & business logic | `blackroad-os-core-production` | `core.blackroad.systems` |
| `blackroad-os-api` | Public API gateway | `blackroad-os-api-production` | `api.blackroad.systems` |
| `blackroad-os-operator` | Agent runtime & orchestrator | `blackroad-os-operator-production` | `operator.blackroad.systems` |
| `blackroad-os-prism-console` | Status console frontend | `blackroad-os-prism-console-production` | `prism.blackroad.systems` |
| `blackroad-os-docs` | Documentation site | `blackroad-os-docs-production` | `docs.blackroad.systems` |
| `blackroad-os-web` | Public website | `blackroad-os-web-production` | `blackroad.systems` |
**Deployment Status**: ✅ **EACH DEPLOYED INDEPENDENTLY TO RAILWAY**
**Sync Process**:
1. Developer edits code in monorepo (e.g., `services/core-api/`)
2. GitHub Action syncs changes to satellite (`BlackRoad-OS/blackroad-os-core`)
3. Satellite triggers Railway deployment
4. Railway deploys to production
**See**: `docs/os/monorepo-sync.md` for sync details
---
## Critical Rules
### ❌ NEVER DO THIS
1. **Never add `BlackRoad-Operating-System` to Railway as a service**
- Not in production environments
- Not in staging environments
- Not in development environments (unless explicitly testing locally)
2. **Never reference the monorepo in service configurations**
- Don't add it to env vars (e.g., `MONOREPO_URL`)
- Don't add it as a dependency in other services
- Don't point Cloudflare to the monorepo
3. **Never deploy the monorepo to production**
- It's not designed to run as a service
- It will break everything
### ✅ ALWAYS DO THIS
1. **Deploy ONLY satellite repos to Railway**
- Each satellite = one Railway service
- Each service = one environment (dev, staging, production)
2. **Edit code ONLY in the monorepo**
- Satellites are read-only mirrors
- All changes flow: monorepo → sync → satellite → deploy
3. **Point Cloudflare ONLY to satellite Railway URLs**
- `core.blackroad.systems``blackroad-os-core-production.up.railway.app`
- `api.blackroad.systems``blackroad-os-api-production.up.railway.app`
- etc.
4. **Create production environments for ALL satellites**
- Each satellite needs: dev, staging, production
- Example: `blackroad-os-core-dev`, `blackroad-os-core-staging`, `blackroad-os-core-production`
---
## Deployment Topology
```
┌─────────────────────────────────────────────────────────────┐
│ BlackRoad-Operating-System (Monorepo) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ services/ │ │ apps/ │ │ docs/ │ │
│ │ core-api/ │ │ prism-console│ │ site/ │ │
│ │ public-api/ │ │ web/ │ │ │ │
│ │ operator/ │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └──────────────────┴──────────────────┘ │
│ GitHub Actions Sync │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Satellite Repositories (Deployable) │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐│
│ │ blackroad-os- │ │ blackroad-os- │ │ blackroad-os- ││
│ │ core │ │ api │ │ operator ││
│ └────────────────┘ └────────────────┘ └────────────────┘│
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐│
│ │ blackroad-os- │ │ blackroad-os- │ │ blackroad-os- ││
│ │ prism-console │ │ web │ │ docs ││
│ └────────────────┘ └────────────────┘ └────────────────┘│
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Railway (Deployment Platform) │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐│
│ │ core-production│ │ api-production │ │ operator-prod ││
│ │ .up.railway.app│ │ .up.railway.app│ │ .up.railway.app││
│ └────────────────┘ └────────────────┘ └────────────────┘│
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Cloudflare (DNS & Routing) │
│ core.blackroad.systems → blackroad-os-core-production │
│ api.blackroad.systems → blackroad-os-api-production │
│ operator.blackroad.systems → blackroad-os-operator-production│
└─────────────────────────────────────────────────────────────┘
```
---
## Service-to-Repository Mapping
### Canonical Mapping
Defined in `infra/github/sync-config.yml`:
```yaml
services:
core-api:
monorepo_path: "services/core-api"
target_repo: "BlackRoad-OS/blackroad-os-core"
target_branch: "main"
public-api:
monorepo_path: "services/public-api"
target_repo: "BlackRoad-OS/blackroad-os-api"
target_branch: "main"
operator:
monorepo_path: "services/operator"
target_repo: "BlackRoad-OS/blackroad-os-operator"
target_branch: "main"
apps:
prism-console:
monorepo_path: "apps/prism-console"
target_repo: "BlackRoad-OS/blackroad-os-prism-console"
target_branch: "main"
web:
monorepo_path: "apps/web"
target_repo: "BlackRoad-OS/blackroad-os-web"
target_branch: "main"
docs:
site:
monorepo_path: "docs/site"
target_repo: "BlackRoad-OS/blackroad-os-docs"
target_branch: "main"
```
### Development Workflow
1. **Edit in monorepo**: `services/core-api/app/main.py`
2. **Commit to monorepo**: `git commit -m "Add health endpoint"`
3. **Push to monorepo**: `git push origin main`
4. **GitHub Action syncs**: Copies `services/core-api/``BlackRoad-OS/blackroad-os-core`
5. **Railway deploys**: Deploys `blackroad-os-core` to production
---
## Environment Configuration
### Required Railway Environments
Each satellite repository needs THREE environments:
1. **Development** (`-dev`)
- Connected to: `dev` or `develop` branch
- Example: `blackroad-os-core-dev.up.railway.app`
2. **Staging** (`-staging`)
- Connected to: `staging` branch
- Example: `blackroad-os-core-staging.up.railway.app`
3. **Production** (`-production`)
- Connected to: `main` branch
- Example: `blackroad-os-core-production.up.railway.app`
### Environment Variables by Service
#### Core API (`blackroad-os-core`)
```bash
# Database
DATABASE_URL=postgresql+asyncpg://...
REDIS_URL=redis://...
# Auth
SECRET_KEY=...
ACCESS_TOKEN_EXPIRE_MINUTES=30
# Service URLs
API_URL=https://api.blackroad.systems
OPERATOR_URL=https://operator.blackroad.systems
PRISM_URL=https://prism.blackroad.systems
# Environment
ENVIRONMENT=production
DEBUG=False
```
#### Public API (`blackroad-os-api`)
```bash
# Core API reference
CORE_API_URL=https://core.blackroad.systems
# Auth
JWT_SECRET=...
# Environment
ENVIRONMENT=production
```
#### Operator (`blackroad-os-operator`)
```bash
# Core API reference
CORE_API_URL=https://core.blackroad.systems
API_URL=https://api.blackroad.systems
# GitHub
GITHUB_TOKEN=...
GITHUB_APP_ID=...
# Environment
ENVIRONMENT=production
```
#### Prism Console (`blackroad-os-prism-console`)
```bash
# Frontend env vars (Next.js)
NEXT_PUBLIC_CORE_API_URL=https://core.blackroad.systems
NEXT_PUBLIC_API_URL=https://api.blackroad.systems
NEXT_PUBLIC_OPERATOR_URL=https://operator.blackroad.systems
```
### ❌ NEVER Add These Vars
```bash
# ❌ DO NOT ADD THESE - THEY WILL BREAK EVERYTHING
MONOREPO_URL=https://github.com/blackboxprogramming/BlackRoad-Operating-System
BLACKROAD_OS_REPO=BlackRoad-Operating-System
SOURCE_REPO=BlackRoad-Operating-System
```
**Why?** These vars reference the non-deployable monorepo, creating confusion and breaking service discovery.
---
## Cloudflare DNS Configuration
### Canonical DNS Records
| Subdomain | Type | Target | Proxied |
|-----------|------|--------|---------|
| `blackroad.systems` | CNAME | `blackroad-os-web-production.up.railway.app` | ✅ Yes |
| `core.blackroad.systems` | CNAME | `blackroad-os-core-production.up.railway.app` | ✅ Yes |
| `api.blackroad.systems` | CNAME | `blackroad-os-api-production.up.railway.app` | ✅ Yes |
| `operator.blackroad.systems` | CNAME | `blackroad-os-operator-production.up.railway.app` | ✅ Yes |
| `prism.blackroad.systems` | CNAME | `blackroad-os-prism-console-production.up.railway.app` | ✅ Yes |
| `docs.blackroad.systems` | CNAME | `blackroad-os-docs-production.up.railway.app` | ✅ Yes |
| `os.blackroad.systems` | CNAME | `prism.blackroad.systems` | ✅ Yes |
### ❌ NEVER Point Cloudflare To
```
# ❌ WRONG - Monorepo is not deployed
core.blackroad.systems → blackroad-operating-system.up.railway.app
# ❌ WRONG - Monorepo doesn't exist on Railway
api.blackroad.systems → blackroad-os-monorepo-production.up.railway.app
```
**See**: `CLOUDFLARE_DNS_BLUEPRINT.md` for complete DNS configuration
---
## Common Mistakes to Avoid
### Mistake #1: Adding Monorepo to Railway
**Problem**:
```bash
# ❌ Creating Railway service for monorepo
railway link blackboxprogramming/BlackRoad-Operating-System
railway up
```
**Why it's wrong**:
- Monorepo contains multiple services (not a single deployable)
- No single entry point or health check
- Will create circular dependencies
**Solution**:
```bash
# ✅ Deploy satellite repos instead
railway link BlackRoad-OS/blackroad-os-core
railway up
```
### Mistake #2: Adding Monorepo to Service Env Vars
**Problem**:
```bash
# ❌ In blackroad-os-core environment
MONOREPO_URL=https://github.com/blackboxprogramming/BlackRoad-Operating-System
```
**Why it's wrong**:
- Services should reference other services, not the source repo
- Creates confusion between source code and runtime services
**Solution**:
```bash
# ✅ Reference other services instead
API_URL=https://api.blackroad.systems
OPERATOR_URL=https://operator.blackroad.systems
```
### Mistake #3: Pointing Cloudflare to Monorepo
**Problem**:
```
# ❌ Cloudflare DNS
core.blackroad.systems → blackroad-operating-system.up.railway.app
```
**Why it's wrong**:
- Monorepo is not deployed to Railway
- URL doesn't exist
- Will result in DNS failures
**Solution**:
```
# ✅ Point to satellite Railway URL
core.blackroad.systems → blackroad-os-core-production.up.railway.app
```
### Mistake #4: Editing Satellite Repos Directly
**Problem**:
```bash
# ❌ Editing blackroad-os-core directly
cd blackroad-os-core
git commit -m "Fix bug"
git push
```
**Why it's wrong**:
- Satellites are read-only mirrors
- Changes will be overwritten by next sync
- Creates drift between monorepo and satellite
**Solution**:
```bash
# ✅ Edit in monorepo
cd BlackRoad-Operating-System/services/core-api
# Make changes
git commit -m "Fix bug"
git push
# Sync workflow automatically updates satellite
```
---
## Troubleshooting
### Issue: "Service not deploying after code change"
**Diagnosis**:
1. Check if code was edited in monorepo (not satellite)
2. Verify sync workflow ran successfully
3. Check Railway deployment logs
**Solution**:
```bash
# 1. Verify sync workflow
gh workflow view sync-core-api
gh run list --workflow=sync-core-api
# 2. Manually trigger sync if needed
gh workflow run sync-core-api
# 3. Check Railway deployment
railway logs -s blackroad-os-core-production
```
### Issue: "Environment variables not resolving correctly"
**Diagnosis**:
1. Check if vars reference monorepo (wrong)
2. Verify service-to-service URLs are correct
3. Confirm Railway environment is set up properly
**Solution**:
```bash
# 1. List current env vars
railway variables
# 2. Remove monorepo references
railway variables delete MONOREPO_URL
# 3. Add correct service URLs
railway variables set CORE_API_URL=https://core.blackroad.systems
```
### Issue: "Cloudflare returning 522 errors"
**Diagnosis**:
1. Check if DNS points to correct Railway URL
2. Verify Railway service is running
3. Confirm health check is passing
**Solution**:
```bash
# 1. Check Railway service status
railway status
# 2. Verify health endpoint
curl https://blackroad-os-core-production.up.railway.app/health
# 3. Update Cloudflare DNS if needed
# (via Cloudflare dashboard: DNS → Edit CNAME)
```
### Issue: "Circular deployment loops"
**Diagnosis**:
- Monorepo may be configured as a dependency
- Service may be triggering its own deployment
**Solution**:
1. Remove monorepo from Railway services
2. Ensure satellites deploy independently
3. Check GitHub Actions triggers
---
## Summary
### The Golden Rules
1. **Monorepo = Source of Truth** (not deployed)
2. **Satellites = Deployable Services** (deployed to Railway)
3. **Edit in monorepo** → Sync to satellites → Deploy automatically
4. **Never add monorepo to Railway** or service configurations
5. **Cloudflare points to satellites**, not monorepo
### Quick Reference
**When you want to...**
- **Deploy a service**: Use satellite repo (`blackroad-os-core`), not monorepo
- **Edit code**: Edit in monorepo (`services/core-api`), not satellite
- **Configure DNS**: Point to satellite Railway URL, not monorepo
- **Set env vars**: Reference other services, not monorepo
- **Create new service**: Add to monorepo, create sync workflow, deploy satellite
---
**For questions or issues**, see:
- `docs/os/monorepo-sync.md` - Sync process details
- `CLOUDFLARE_DNS_BLUEPRINT.md` - DNS configuration
- `infra/railway/ENVIRONMENT_GUIDE.md` - Railway setup
- `CLAUDE.md` - Development guide
---
*Last updated: 2025-11-19*
*This document is canonical for all BlackRoad OS deployments.*

View File

@@ -31,6 +31,26 @@ BlackRoad OS is a fully functional web-based operating system interface that bri
All BlackRoad services, apps, and docs now live in this monorepo and sync out automatically to their mirror repositories under the `BlackRoad-OS` GitHub organization. Edit here; automation mirrors to the satellites.
> ### ⚠️ CRITICAL DEPLOYMENT WARNING ⚠️
>
> **This repository is NOT deployed to production.**
>
> - ❌ **DO NOT** add `BlackRoad-Operating-System` to Railway as a service
> - ❌ **DO NOT** deploy this monorepo to any production environment
> - ❌ **DO NOT** reference this repo in service configurations or env vars
>
> **Deploy ONLY the satellite repositories:**
> - `blackroad-os-core` (Core API)
> - `blackroad-os-api` (Public API)
> - `blackroad-os-operator` (Agent Runtime)
> - `blackroad-os-prism-console` (Status Console)
> - `blackroad-os-docs` (Documentation)
> - `blackroad-os-web` (Public Website)
>
> **This repo is the source of truth for code**, but **satellites are the deployable services**.
>
> **See**: `DEPLOYMENT_ARCHITECTURE.md` for complete deployment model.
### Canonical layout
- `services/core-api``BlackRoad-OS/blackroad-os-core`

View File

@@ -24,7 +24,7 @@ ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_DAYS=7
WALLET_MASTER_KEY=changeme-wallet-master-key
ALLOWED_ORIGINS=https://blackroad.systems,https://www.blackroad.systems,https://os.blackroad.systems,https://blackroad-operating-system-production.up.railway.app,http://localhost:3000,http://localhost:8000
ALLOWED_ORIGINS=https://blackroad.systems,https://www.blackroad.systems,https://os.blackroad.systems,https://core.blackroad.systems,https://api.blackroad.systems,https://blackroad-os-core-production.up.railway.app,http://localhost:3000,http://localhost:8000
JWT_SECRET=changeme-jwt-secret
SESSION_SECRET=changeme-session-secret
NEXTAUTH_SECRET=changeme-nextauth-secret

View File

@@ -32,9 +32,8 @@ domains:
mode: "dns"
record:
type: "CNAME"
value: "blackroad-operating-system-production.up.railway.app"
value: "YOUR-PROD-RAILWAY-APP.up.railway.app" # replace with your Railway host
notes: "Alternative subdomain alias for the OS application"
value: "blackroad-os-core-production.up.railway.app" # Core API satellite service
notes: "Alternative subdomain alias for the OS application - points to Core API satellite"
- name: "blackroad.ai"
type: "root"

View File

@@ -1,5 +1,33 @@
# ==============================================================================
# ⚠️ CRITICAL WARNING - DO NOT USE THIS CONFIG IN PRODUCTION RAILWAY ⚠️
# ==============================================================================
#
# This railway.toml is for LOCAL DEVELOPMENT AND TESTING ONLY.
#
# ❌ DO NOT add "BlackRoad-Operating-System" as a Railway service
# ❌ DO NOT deploy this monorepo to production Railway environments
# ❌ DO NOT add this repo to service configurations or env vars
#
# ✅ CORRECT DEPLOYMENT MODEL:
# - This repo is the SOURCE OF TRUTH (orchestration/sync only)
# - Deploy ONLY the satellite repos to Railway:
# • blackroad-os-core (from BlackRoad-OS/blackroad-os-core)
# • blackroad-os-api (from BlackRoad-OS/blackroad-os-api)
# • blackroad-os-operator (from BlackRoad-OS/blackroad-os-operator)
# • blackroad-os-prism-console (from BlackRoad-OS/blackroad-os-prism-console)
# • blackroad-os-docs (from BlackRoad-OS/blackroad-os-docs)
#
# WHY THIS MATTERS:
# - Adding the monorepo to Railway will create circular deploy loops
# - Environment variables will break (wrong service URLs)
# - Cloudflare routing will fail
# - Service dependencies will be misconfigured
#
# See: docs/os/monorepo-sync.md and DEPLOYMENT_ARCHITECTURE.md
# ==============================================================================
# BlackRoad OS Monorepo - Railway Configuration
# This configures multiple services from a single repository
# This configures multiple services from a single repository FOR LOCAL DEV ONLY
# Backend (Core API)
[[services]]

View File

@@ -0,0 +1,373 @@
#!/usr/bin/env python3
"""
Deployment Configuration Validator
This script validates that the BlackRoad-Operating-System monorepo
is NOT being incorrectly added to Railway configurations or service
environment variables.
Usage:
python scripts/validate_deployment_config.py
Exit codes:
0 - All validations passed
1 - Validation failures detected
Author: BlackRoad OS Team
Last Updated: 2025-11-19
"""
import os
import sys
import re
import json
import yaml
from pathlib import Path
from typing import List, Tuple, Dict
# ANSI color codes
GREEN = "\033[92m"
RED = "\033[91m"
YELLOW = "\033[93m"
BLUE = "\033[94m"
RESET = "\033[0m"
BOLD = "\033[1m"
# Repository root
REPO_ROOT = Path(__file__).parent.parent
# Patterns that indicate monorepo is being incorrectly referenced
FORBIDDEN_PATTERNS = [
r"BlackRoad-Operating-System",
r"blackroad-operating-system",
r"BLACKROAD_OPERATING_SYSTEM",
r"monorepo\.up\.railway\.app",
r"blackroad-os-monorepo",
]
# Allowed contexts where monorepo reference is OK
ALLOWED_FILES = [
"README.md",
"DEPLOYMENT_ARCHITECTURE.md",
"CLAUDE.md",
"docs/",
".git/",
".github/",
"infra/github/",
"scripts/",
".md", # All markdown files (usually docs)
"IMPLEMENTATION", # Implementation plan docs
"PHASE", # Phase summary docs
"ORG_STRUCTURE.md",
"CODEBASE_STATUS.md",
]
# Files to check for forbidden patterns
CHECK_PATTERNS = [
"**/.env",
"**/.env.example",
"**/.env.production",
"**/.env.staging",
"**/.env.development",
"**/railway.json",
"**/vercel.json",
"**/netlify.toml",
]
class ValidationResult:
"""Stores validation results"""
def __init__(self):
self.errors: List[Tuple[str, str]] = []
self.warnings: List[Tuple[str, str]] = []
self.passed: List[str] = []
def add_error(self, check: str, message: str):
"""Add a validation error"""
self.errors.append((check, message))
def add_warning(self, check: str, message: str):
"""Add a validation warning"""
self.warnings.append((check, message))
def add_pass(self, check: str):
"""Add a passing check"""
self.passed.append(check)
def has_failures(self) -> bool:
"""Check if there are any failures"""
return len(self.errors) > 0
def print_summary(self):
"""Print validation summary"""
print(f"\n{BOLD}{'=' * 70}{RESET}")
print(f"{BOLD}Deployment Configuration Validation Results{RESET}")
print(f"{BOLD}{'=' * 70}{RESET}\n")
# Print errors
if self.errors:
print(f"{RED}{BOLD}❌ ERRORS ({len(self.errors)}):{RESET}")
for check, message in self.errors:
print(f"{RED}{check}:{RESET} {message}")
print()
# Print warnings
if self.warnings:
print(f"{YELLOW}{BOLD}⚠️ WARNINGS ({len(self.warnings)}):{RESET}")
for check, message in self.warnings:
print(f"{YELLOW}{check}:{RESET} {message}")
print()
# Print passed checks
if self.passed:
print(f"{GREEN}{BOLD}✅ PASSED ({len(self.passed)}):{RESET}")
for check in self.passed:
print(f"{GREEN}{check}{RESET}")
print()
# Overall status
print(f"{BOLD}{'=' * 70}{RESET}")
if self.has_failures():
print(f"{RED}{BOLD}❌ VALIDATION FAILED{RESET}")
print(f"\nThe monorepo is being incorrectly referenced in deployment configs.")
print(f"See {BLUE}DEPLOYMENT_ARCHITECTURE.md{RESET} for correct deployment model.\n")
return 1
elif self.warnings:
print(f"{YELLOW}{BOLD}⚠️ VALIDATION PASSED WITH WARNINGS{RESET}\n")
return 0
else:
print(f"{GREEN}{BOLD}✅ ALL VALIDATIONS PASSED{RESET}\n")
return 0
def is_allowed_file(file_path: Path) -> bool:
"""Check if file is in allowed list for monorepo references"""
file_str = str(file_path)
for allowed in ALLOWED_FILES:
if allowed in file_str:
return True
return False
def check_railway_toml(result: ValidationResult):
"""Validate railway.toml is marked for local dev only"""
railway_toml = REPO_ROOT / "railway.toml"
if not railway_toml.exists():
result.add_warning("railway.toml", "File not found (OK if not using Railway)")
return
content = railway_toml.read_text()
# Check for warning banner
if "CRITICAL WARNING" not in content:
result.add_error(
"railway.toml",
"Missing CRITICAL WARNING banner at top of file"
)
# Check for "LOCAL DEV" or similar marker
if "LOCAL DEV" not in content and "DEVELOPMENT" not in content:
result.add_error(
"railway.toml",
"Not clearly marked as local development only"
)
if not result.errors:
result.add_pass("railway.toml has proper warnings")
def check_env_files(result: ValidationResult):
"""Check environment files for monorepo references"""
env_files = []
for pattern in CHECK_PATTERNS:
env_files.extend(REPO_ROOT.glob(pattern))
found_issues = False
checked_count = 0
for env_file in env_files:
if is_allowed_file(env_file):
continue
checked_count += 1
content = env_file.read_text()
for pattern in FORBIDDEN_PATTERNS:
matches = re.finditer(pattern, content, re.IGNORECASE)
for match in matches:
# Get line number
line_num = content[:match.start()].count('\n') + 1
result.add_error(
f"{env_file.name}:{line_num}",
f"Contains forbidden reference: '{match.group()}'"
)
found_issues = True
if checked_count == 0:
result.add_warning("env files", "No environment files found to check")
elif not found_issues:
result.add_pass(f"Environment files clean ({checked_count} checked)")
def check_satellite_configs(result: ValidationResult):
"""Check if satellites are properly configured"""
sync_config = REPO_ROOT / "infra/github/sync-config.yml"
if not sync_config.exists():
result.add_warning(
"sync-config.yml",
"Satellite sync config not found"
)
return
with open(sync_config) as f:
config = yaml.safe_load(f)
# Expected satellites
expected_services = ["core-api", "public-api", "operator"]
expected_apps = ["prism-console", "web"]
services = config.get("services", {})
apps = config.get("apps", {})
# Check all expected services are configured
missing_services = [s for s in expected_services if s not in services]
missing_apps = [a for a in expected_apps if a not in apps]
if missing_services:
result.add_warning(
"sync-config.yml",
f"Missing service configs: {', '.join(missing_services)}"
)
if missing_apps:
result.add_warning(
"sync-config.yml",
f"Missing app configs: {', '.join(missing_apps)}"
)
if not missing_services and not missing_apps:
result.add_pass("Satellite sync configuration complete")
def check_cloudflare_docs(result: ValidationResult):
"""Check Cloudflare documentation for correct DNS setup"""
cloudflare_doc = REPO_ROOT / "CLOUDFLARE_DNS_BLUEPRINT.md"
if not cloudflare_doc.exists():
result.add_warning(
"Cloudflare docs",
"CLOUDFLARE_DNS_BLUEPRINT.md not found"
)
return
content = cloudflare_doc.read_text()
# Check for incorrect monorepo references in DNS
forbidden_dns = [
"blackroad-operating-system.up.railway.app",
"monorepo.up.railway.app",
]
found_issues = False
for forbidden in forbidden_dns:
if forbidden in content.lower():
result.add_error(
"CLOUDFLARE_DNS_BLUEPRINT.md",
f"Contains forbidden DNS target: {forbidden}"
)
found_issues = True
if not found_issues:
result.add_pass("Cloudflare DNS documentation is correct")
def check_deployment_architecture_exists(result: ValidationResult):
"""Verify DEPLOYMENT_ARCHITECTURE.md exists"""
doc_path = REPO_ROOT / "DEPLOYMENT_ARCHITECTURE.md"
if not doc_path.exists():
result.add_error(
"DEPLOYMENT_ARCHITECTURE.md",
"Critical deployment documentation is missing"
)
return
content = doc_path.read_text()
# Check for key sections
required_sections = [
"Monorepo vs Satellite Model",
"Critical Rules",
"NEVER DO THIS",
"ALWAYS DO THIS",
]
missing_sections = []
for section in required_sections:
if section not in content:
missing_sections.append(section)
if missing_sections:
result.add_error(
"DEPLOYMENT_ARCHITECTURE.md",
f"Missing sections: {', '.join(missing_sections)}"
)
else:
result.add_pass("DEPLOYMENT_ARCHITECTURE.md is complete")
def check_readme_warnings(result: ValidationResult):
"""Verify README.md has deployment warnings"""
readme = REPO_ROOT / "README.md"
if not readme.exists():
result.add_error("README.md", "README.md not found")
return
content = readme.read_text()
if "DEPLOYMENT WARNING" not in content:
result.add_error(
"README.md",
"Missing deployment warning section"
)
if "DO NOT" not in content or "satellite" not in content.lower():
result.add_error(
"README.md",
"Deployment warnings are not clear or comprehensive"
)
if not result.errors:
result.add_pass("README.md has proper deployment warnings")
def main():
"""Run all validation checks"""
print(f"\n{BOLD}{BLUE}BlackRoad OS Deployment Configuration Validator{RESET}")
print(f"{BLUE}{'=' * 70}{RESET}\n")
result = ValidationResult()
# Run all checks
print("Running validation checks...\n")
check_railway_toml(result)
check_env_files(result)
check_satellite_configs(result)
check_cloudflare_docs(result)
check_deployment_architecture_exists(result)
check_readme_warnings(result)
# Print results
exit_code = result.print_summary()
sys.exit(exit_code)
if __name__ == "__main__":
main()