Skip to main content

Environment Separation Guide

Overview

This backend implements strict environment separation to ensure development, testing, and production environments are fully isolated, secure, and reproducible.

Why Strict Environment Separation Matters

Safety

  • Prevents production data contamination during testing
  • Ensures test databases never touch production data
  • Makes configuration bugs visible immediately

Reproducibility

  • Each environment has explicit, validated configuration
  • No silent fallbacks or hidden defaults
  • Configuration is version-controlled via example files

Security

  • Production enforces DEBUG=false (fail-fast if violated)
  • Secrets are environment-specific
  • Test environments use mock API keys

Speed

  • Development uses optimized settings for fast feedback
  • Testing uses isolated resources for parallel execution
  • Production uses optimized settings for performance

Architecture

Three Environments

EnvironmentPurposeDatabaseDebugLoggingTypical Use
developmentLocal developmentDev DBtrueDEBUGHot reload, API docs, verbose errors
testingAutomated testsTest DBtrueINFOpytest, CI/CD, isolated tests
productionLive deploymentProd DBfalseWARNINGProduction API, strict security

Configuration Files

.env.development.example  → Copy to .env.development
.env.testing.example → Copy to .env.testing
.env.production.example → Copy to .env.production
.env → Fallback (not recommended for production)

Environment Loading

  1. Application reads ENV variable
  2. Validates ENV against allowed values (development, testing, production)
  3. Loads .env.{ENV} file (e.g., .env.testing)
  4. Falls back to .env if environment-specific file doesn't exist
  5. Validates all constraints (DATABASE_URL required, production DEBUG=false, etc.)
  6. Fails fast if any constraint is violated

Setup Instructions

1. Development Environment

# Copy example file
cp .env.development.example .env.development

# Edit with your settings
nano .env.development

# Key settings to change:
# - DATABASE_URL: Use a DEVELOPMENT database
# - DEBUG: Keep as true
# - LOG_LEVEL: DEBUG for maximum visibility
# - DB_ECHO: true to see SQL queries

Run development server:

cd backend
export ENV=development # Linux/Mac
# OR
set ENV=development # Windows CMD
# OR
$env:ENV="development" # Windows PowerShell

uvicorn src.main:app --reload --host 0.0.0.0 --port 8000

2. Testing Environment

# Copy example file
cp .env.testing.example .env.testing

# Edit with your settings
nano .env.testing

# Key settings to change:
# - DATABASE_URL: Use a separate TEST database
# - DEBUG: Keep as true
# - LOG_LEVEL: INFO (less noise than DEBUG)
# - DB_ECHO: false (unless debugging tests)

Create test database:

# PostgreSQL
createdb physical_ai_handbook_test
psql -c "GRANT ALL PRIVILEGES ON DATABASE physical_ai_handbook_test TO test;"

# Or use in-memory SQLite (faster, but limited features)
# DATABASE_URL=sqlite+aiosqlite:///:memory:

Run tests:

cd backend
export ENV=testing

pytest # All tests
pytest -m unit # Only unit tests
pytest -m integration # Only integration tests
pytest -v # Verbose output
pytest --cov # With coverage

3. Production Environment

# Copy example file
cp .env.production.example .env.production

# Edit with your PRODUCTION settings
nano .env.production

# CRITICAL settings:
# - ENV: Must be "production"
# - DEBUG: MUST be false (enforced)
# - DATABASE_URL: Production database with strong password
# - LOG_LEVEL: WARNING or ERROR (reduce log volume)
# - All API keys: Use production keys

Run production server:

cd backend
export ENV=production

# Do NOT use --reload in production
# Use production WSGI server
gunicorn src.main:app \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
--access-logfile - \
--error-logfile -

Configuration Reference

Core Settings

VariableRequiredDevelopmentTestingProduction
ENVYesdevelopmenttestingproduction
DEBUGYestruetruefalse (enforced)
LOG_LEVELNoDEBUGINFOWARNING
DATABASE_URLYesDev DBTest DBProd DB
DB_ECHONotruefalsefalse

Validation Rules

  1. ENV must be valid

    • Only: development, testing, production
    • Invalid values cause immediate failure
  2. DATABASE_URL is required

    • Cannot be empty
    • Application fails to start without it
  3. Production MUST have DEBUG=false

    • Running production with DEBUG=true is a security risk
    • Application fails to start if violated
  4. Per-environment isolation

    • Test database must not be production database
    • Development database must not be production database
    • Each environment loads its own configuration

Best Practices

Development

  • ✅ Use separate database from production
  • ✅ Enable DB_ECHO to see SQL queries
  • ✅ Use LOG_LEVEL=DEBUG for troubleshooting
  • ✅ Keep API keys separate from production
  • ❌ Never commit .env.development with real secrets

Testing

  • ✅ Use completely isolated test database
  • ✅ Use mock API keys (not real ones)
  • ✅ Set ENV=testing before running tests
  • ✅ Clean up test data after tests
  • ❌ Never point tests at production database

Production

  • ✅ DEBUG must be false (enforced)
  • ✅ Use strong, randomly generated passwords (32+ chars)
  • ✅ Store secrets in secret manager (AWS Secrets Manager, etc.)
  • ✅ Enable SSL/TLS for database connections
  • ✅ Use LOG_LEVEL=WARNING or ERROR
  • ✅ Rotate secrets regularly (every 90 days)
  • ❌ Never commit .env.production to version control
  • ❌ Never run production with --reload flag

Security Checklist

Before Deploying to Production

  • DEBUG=false (verified)
  • Strong database password set
  • Production API keys configured
  • Database backups enabled
  • Monitoring and alerts configured
  • SSL/TLS certificates installed
  • Security headers configured
  • Rate limiting enabled
  • CORS properly configured
  • Secrets stored in secret manager
  • Log aggregation configured
  • Error tracking enabled (Sentry, etc.)
  • Firewall rules configured
  • Regular security audits scheduled