Environment Isolation Architecture
CRITICAL: This document describes mandatory patterns for environment handling. Violating these patterns can cause staging to use production data or vice versa.
Core Principle: FAIL-FAST, NO DEFAULTS
The PQAP application follows a strict "fail-fast" pattern for environment configuration:
- No hardcoded defaults - Components must receive explicit configuration
- Fail loudly - Missing configuration raises clear errors at startup
- Validate early - Environment validation runs before any business logic
Valid Environments
| Environment | Database | Config File | Purpose |
|---|---|---|---|
dev |
data/pqap_dev.db |
configs/dev.yaml |
Local development |
staging |
data/pqap_staging.db |
configs/staging.yaml |
Pre-production testing |
prod |
data/pqap.db |
configs/prod.yaml |
Production |
Startup Validation
At startup, validate_environment() checks:
1. config.env is set and valid
2. config.db_path is set
3. Database filename matches expected pattern for environment
Code Patterns
WRONG (Don't do this)
# Hardcoded fallback - NEVER DO THIS
def __init__(self, env: str = "dev"):
self.db_path = f"data/pqap_{env}.db"
CORRECT (Do this)
# Explicit requirement - ALWAYS DO THIS
def __init__(self, env: str):
if env is None:
raise ValueError("Environment is required")
if env not in VALID_ENVIRONMENTS:
raise ValueError(f"Invalid environment: {env}")
self.env = env
Environment-Specific Database Configuration
The DatabaseExplorer class uses environment-specific database mappings:
DATABASES_BY_ENV = {
"dev": {
"pqap": {"path": "data/pqap_dev.db", ...},
"market_history": {"path": "data/market_history.db", ...},
},
"staging": {
"pqap": {"path": "data/pqap_staging.db", ...},
"market_history": {"path": "data/market_history.db", ...},
},
"prod": {
"pqap": {"path": "data/pqap.db", ...},
"market_history": {"path": "data/market_history.db", ...},
},
}
Adding New Environment-Aware Components
- Accept
envorconfigas required parameter (no defaults) - Validate the environment is valid
- Use environment-specific paths from configuration
- Add tests in
tests/unit/test_env_isolation.py
Example Implementation
from core.env_validator import VALID_ENVIRONMENTS
class MyNewComponent:
def __init__(self, env: str):
"""
Initialize component.
Args:
env: Environment name (dev, staging, prod) - REQUIRED
Raises:
ValueError: If env is not provided or not valid
"""
if env is None:
raise ValueError(
"FATAL: env parameter is required. "
"Cannot initialize without explicit environment."
)
if env not in VALID_ENVIRONMENTS:
raise ValueError(
f"FATAL: Unknown environment '{env}'. "
f"Must be one of: {list(VALID_ENVIRONMENTS)}"
)
self.env = env
# ... rest of initialization
Testing
Run Environment Isolation Tests
python -m pytest tests/unit/test_env_isolation.py -v
What the Tests Verify
- Valid configurations pass - Dev/staging/prod with correct db paths work
- Missing configuration fails - Missing env or db_path raises ValueError
- Invalid environment fails - Typos like "production" instead of "prod" fail
- Cross-environment access fails - Dev using prod database raises error
- Components require explicit env - DatabaseExplorer and MetricsStorage fail without env
- Database mapping is correct - Each environment maps to its expected database
These tests MUST pass before any deployment.
Troubleshooting
Error: "config.env is not set"
Cause: Application started without environment configuration.
Fix: Ensure environment is specified via:
- --env command line argument
- PQAP_ENV environment variable
- Configuration file
Error: "Database path mismatch"
Cause: Environment and database path don't match (e.g., staging trying to use dev database).
Fix: Check configuration files and ensure database paths match the environment.
Error: "env parameter is required"
Cause: Component instantiated without explicit environment.
Fix: Pass environment explicitly when creating component instances:
# Wrong
explorer = DatabaseExplorer()
# Correct
explorer = DatabaseExplorer(env="dev")
Security Implications
Environment isolation prevents:
- Accidental data corruption - Dev changes won't affect prod data
- Data leakage - Production data won't be exposed in dev environments
- Configuration drift - Each environment uses validated, environment-specific config
- Silent failures - Misconfigurations fail immediately with clear error messages
Related Files
| File | Purpose |
|---|---|
src/core/env_validator.py |
Environment validation logic |
src/admin/database_explorer.py |
Environment-aware database browsing |
src/tracking/storage.py |
Environment-aware metrics storage |
tests/unit/test_env_isolation.py |
Environment isolation test suite |