Skip to content

Environment Management

SPOT Platform uses a simple environment system with APP_ENV as the single source of truth for determining which configuration and Docker Compose profiles to use.

Available Environments

Environment Purpose Docker Compose Profiles Default
prod Production deployment None Yes
dev Development with hot reload dev No
test Integration / E2E testing dev, test No

How It Works

Precedence Chain

The system determines the active environment using this precedence (highest to lowest):

  1. Environment variable on the command line: APP_ENV=dev make service:start
  2. .env file: APP_ENV=prod
  3. Default: prod (if not set anywhere)

Environment Variable Flow

APP_ENV (command-line export or .env)
    |
    v
Docker Compose profiles selected
    |
    v
Containers started with the matching configuration

Switching Environments

Important: Explicit Restart Required

Changing APP_ENV requires an explicit container restart. There is no automatic hot-swap.

# Start in dev mode for one command
APP_ENV=dev make service:start

# Check status against the current containers
make service:status

The override only applies to that single command and does not modify your .env.

Method 2: Persistent change in .env

# 1. Edit .env
vim .env
# Change: APP_ENV=prod
# To:     APP_ENV=dev

# 2. Restart so containers pick up the new profile set
make service:restart

Common Workflows

Development

# Start in dev mode with hot reload
APP_ENV=dev make service:start

# Make code changes (services hot-reload in dev)
# Edit services/api-gateway/src/main.py

# Tail the logs
make dev:logs

# When done
make service:stop

Testing

# Integration tests (the target sets APP_ENV=test automatically)
make test:integration

# Or run unit + integration in one go
make test

Production

Production deployments do not use this Makefile ; they run from the deploy repository with docker compose directly:

# In the deploy checkout
docker compose up -d
docker compose ps

APP_ENV=prod is the default and the deploy compose file does not load any dev/test profile.

Environment-Specific Behaviour

Production (prod)

  • Optimized for: stability, performance, security.
  • Hot reload: disabled.
  • Debug tools: disabled (no Adminer, no Mailhog).
  • Dev dependencies: not installed.
  • Compose profiles: none (base services only).

Development (dev)

  • Optimized for: developer productivity.
  • Hot reload: enabled (uvicorn --reload).
  • Debug tools: enabled (Adminer, Mailhog, devtools container).
  • Dev dependencies: installed.
  • Volume mounts: read-write for source code.
  • Debug ports: exposed (8091, 8092).
  • Compose profiles: --profile dev.

Test (test)

  • Optimized for: isolated testing.
  • Mock analyzers: included (analyzer-mock-nlp, analyzer-mock-llm).
  • Log level: WARNING (reduced verbosity).
  • Compose profiles: --profile dev --profile test.

Safety Features

pytest Safety Check

Integration tests fail if APP_ENV != test:

# tests/conftest.py
def pytest_configure(config):
    app_env = os.getenv("APP_ENV", "")
    if app_env != "test":
        raise RuntimeError("Integration tests must run in test environment")

This prevents accidental execution against development or production databases.

Troubleshooting

Services started in the wrong environment

# Stop services
make service:stop

# Verify .env has the correct APP_ENV
grep APP_ENV .env

# Start with the correct environment (inline override or edit .env)
APP_ENV=dev make service:start

Can't tell which environment is running

# APP_ENV is exported into every service container; inspect one:
docker compose exec api-gateway printenv APP_ENV

Want to force-restart with a new environment

# Complete teardown and restart
make service:stop
docker compose down -v  # WARNING: destroys data
# Edit .env to set APP_ENV if needed
make service:start

Tests failing with environment error

# Error: Integration tests must run in test environment
# Solution: use the test target (it sets APP_ENV automatically)
make test:integration

# DO NOT run pytest directly:
# pytest tests/integration/  # this will fail

Best Practices

  1. Inline override for one-offs
  2. APP_ENV=dev make service:start is clearer than editing .env when the change is temporary.

  3. Use the test targets for testing

  4. make test:integration and make test set APP_ENV=test automatically. Don't run pytest directly for integration tests.

  5. Keep .env in sync with reality

  6. If you frequently use command-line overrides, consider updating .env instead.

  7. Document environment in deployment scripts

  8. Explicitly set APP_ENV=prod (or rely on the default) in production deployment scripts.

  9. Restart after changing .env

  10. Docker Compose needs to reload with the new environment.

FAQ

Q: Can I set APP_ENV via environment variable instead of .env?

A: Yes, the command-line value takes precedence:

export APP_ENV=dev
make service:start  # Uses dev environment

Q: Do I need to restart when switching environments?

A: Yes, always. Docker Compose needs to:

  • Load different profiles (dev/test).
  • Apply different environment variables.
  • Recreate containers with the new configuration.

Q: What happens if I change .env while services are running?

A: Nothing. Changes to .env only take effect when you restart:

# Edit .env (change APP_ENV)
make service:restart  # Apply changes

Q: Can I run multiple environments simultaneously?

A: No, by design. The system uses a single set of containers. To run multiple environments:

  • Use different directories.
  • Or use different Docker Compose project names.

Q: Why is prod the default instead of dev?

A: Safety first. Production defaults force developers to explicitly opt into development mode, reducing the risk of:

  • Accidentally running dev tools in production.
  • Missing production-specific configurations.
  • Security misconfigurations.

Management Commands

The dev loop wraps docker compose through make:

  • make service:start ; start containers with the current APP_ENV.
  • make service:stop ; stop all containers.
  • make service:status ; show container status.
  • make service:restart ; restart all containers.
  • make service:logs ; view service logs.

Inline APP_ENV=... overrides any of those commands.