Files
rxminder/docs/setup/ENVIRONMENT_VARIABLES.md
2025-09-23 11:32:48 -07:00

577 lines
17 KiB
Markdown

# Environment Variables Guide
This guide explains how to use environment variables with the rxminder Kustomize deployment system.
## Overview
The rxminder application supports multiple ways to configure deployments using environment variables:
1. **Static Configuration**: Pre-generated config files
2. **Dynamic Configuration**: Runtime environment variable injection
3. **Hybrid Approach**: Combination of both methods
### Run Profiles at a Glance
| Profile | Typical Usage | Key Files |
| ----------- | --------------------------------------------------------------- | ------------------------------------------- |
| Development | Vite dev server with hot reload and optional mock CouchDB | `.env.local`, `bun run dev` |
| Testing | Jest unit/integration suites against the mock database strategy | No additional env required (`bun run test`) |
| Production | Hardened build served by Docker/Kubernetes with real services | `.env`, Docker/compose manifests |
See the [Run Profiles section](../../README.md#-run-profiles) in the project README for commands and best practices.
## Environment Variable Sources
Variables are loaded in the following priority order (last wins):
1. `~/.env` - Global user environment
2. `./.env` - Project-wide environment
3. `./.env.{environment}` - Environment-specific (e.g., `.env.dev`, `.env.prod`)
4. `./.env.local` - Local overrides (git-ignored)
5. System environment variables
## Quick Start
### Method 1: Generate Static Configuration
```bash
# Generate configuration from your environment variables
make generate-config-dev
make generate-config-prod
# Deploy using generated config
make deploy-dev
```
### Method 2: Dynamic Environment Injection
```bash
# Deploy with runtime environment variable substitution
make deploy-with-env-dev
make deploy-with-env-prod
```
## Environment Files Setup
### 1. Global User Environment (`~/.env`)
Store your personal/machine-specific settings:
```bash
# ~/.env
REGISTRY_USERNAME=your_username
REGISTRY_EMAIL=your_email@example.com
KUBECONFIG=/path/to/your/kubeconfig
```
### 2. Project Environment (`./.env`)
Store project-wide defaults:
```bash
# ./.env
APP_NAME=rxminder
REGISTRY_URL=gitea-http.taildb3494.ts.net
IMAGE_REPOSITORY=will/rxminder
COUCHDB_DATABASE_NAME=meds_app
```
### 3. Environment-Specific Files
#### Development (`./.env.dev`)
```bash
NODE_ENV=development
LOG_LEVEL=debug
DEBUG=true
IMAGE_TAG=dev
INGRESS_HOST=rxminder-dev.local
DEV_MODE=true
ENABLE_MONITORING=false
# Development database
COUCHDB_USERNAME=admin
COUCHDB_PASSWORD=devpass123
# Development resource limits
FRONTEND_MEMORY_REQUEST=16Mi
FRONTEND_MEMORY_LIMIT=32Mi
COUCHDB_MEMORY_REQUEST=64Mi
COUCHDB_MEMORY_LIMIT=128Mi
STORAGE_SIZE=1Gi
```
#### Production (`./.env.prod`)
```bash
NODE_ENV=production
LOG_LEVEL=warn
DEBUG=false
IMAGE_TAG=v1.0.0
INGRESS_HOST=rxminder.yourdomain.com
ENABLE_MONITORING=true
ENABLE_METRICS=true
ENABLE_TRACING=true
# Production performance
CACHE_TTL=3600
REQUEST_TIMEOUT=30000
MAX_CONNECTIONS=200
# Production resources
FRONTEND_REPLICAS=3
FRONTEND_MEMORY_REQUEST=256Mi
FRONTEND_MEMORY_LIMIT=512Mi
COUCHDB_MEMORY_REQUEST=512Mi
COUCHDB_MEMORY_LIMIT=1Gi
STORAGE_SIZE=10Gi
STORAGE_CLASS=ssd
# Security
ENABLE_SECURITY_HEADERS=true
ENABLE_RATE_LIMITING=true
CORS_ORIGIN=https://rxminder.yourdomain.com
# TLS/SSL
ENABLE_TLS=true
CERT_MANAGER_ISSUER=letsencrypt-prod
```
#### Staging (`./.env.staging`)
```bash
NODE_ENV=staging
LOG_LEVEL=info
DEBUG=false
IMAGE_TAG=staging
INGRESS_HOST=staging.rxminder.yourdomain.com
ENABLE_MONITORING=true
# Staging resources (between dev and prod)
FRONTEND_REPLICAS=2
FRONTEND_MEMORY_REQUEST=128Mi
FRONTEND_MEMORY_LIMIT=256Mi
STORAGE_SIZE=5Gi
```
### 4. Local Overrides (`./.env.local`)
**Note**: This file should be in `.gitignore` and used for sensitive local settings:
```bash
# ./.env.local (DO NOT COMMIT)
COUCHDB_PASSWORD=your_secure_password
REGISTRY_PASSWORD=your_registry_token
API_SECRET_KEY=your_secret_key
JWT_SECRET=your_jwt_secret
# Local development overrides
INGRESS_HOST=localhost:8080
DEV_API_URL=http://localhost:5984
```
## Available Environment Variables
### Core Application Variables
| Variable | Default | Description |
| ------------- | ------------ | ------------------------------------------------------------ |
| `APP_NAME` | `rxminder` | Application name used in labels and resources |
| `NODE_ENV` | `production` | Runtime environment (`development`, `staging`, `production`) |
| `LOG_LEVEL` | `info` | Logging level (`debug`, `info`, `warn`, `error`) |
| `DEBUG` | `false` | Enable debug mode |
| `APP_VERSION` | `1.0.0` | Application version |
### Container Registry Variables
| Variable | Default | Description |
| ------------------- | ------------------------------ | -------------------------------- |
| `REGISTRY_URL` | `gitea-http.taildb3494.ts.net` | Container registry URL |
| `IMAGE_REPOSITORY` | `will/rxminder` | Image repository path |
| `IMAGE_TAG` | `latest` | Image tag to deploy |
| `REGISTRY_USERNAME` | - | Registry authentication username |
| `REGISTRY_PASSWORD` | - | Registry authentication password |
| `REGISTRY_EMAIL` | - | Registry authentication email |
### Database Variables
| Variable | Default | Description |
| ----------------------- | -------------------------- | ---------------------------- |
| `DB_HOST` | `rxminder-couchdb-service` | Database host |
| `DB_PORT` | `5984` | Database port |
| `COUCHDB_DATABASE_NAME` | `meds_app` | CouchDB database name |
| `COUCHDB_USERNAME` | `admin` | Database username |
| `COUCHDB_PASSWORD` | - | Database password (required) |
### Email (Mailgun) Variables
| Variable | Default | Description |
| ------------------------- | ---------------------------- | ------------------------------------------------------------------------------ |
| `VITE_MAILGUN_API_KEY` | _required_ | Mailgun API key used for authenticated requests |
| `VITE_MAILGUN_DOMAIN` | _required_ | Mailgun sending domain (e.g. `mg.yourdomain.com`) |
| `VITE_MAILGUN_BASE_URL` | `https://api.mailgun.net/v3` | Mailgun REST API base URL |
| `VITE_MAILGUN_FROM_NAME` | `Medication Reminder` | Friendly name used in the `from` header |
| `VITE_MAILGUN_FROM_EMAIL` | _required_ | Email address used in the `from` header (must belong to the configured domain) |
> **Tip:** When any required Mailgun variables are missing, the application falls back to a development mode that logs email previews instead of sending real messages. Configure the variables above in `.env.local` (git ignored) before testing real email flows.
### Network & Ingress Variables
| Variable | Default | Description |
| --------------------- | -------------------- | -------------------- |
| `INGRESS_HOST` | Environment-specific | Ingress hostname |
| `INGRESS_CLASS` | `nginx` | Ingress class to use |
| `ENABLE_TLS` | `false` | Enable TLS/HTTPS |
| `CERT_MANAGER_ISSUER` | `letsencrypt-prod` | Certificate issuer |
| `CORS_ORIGIN` | `*` | CORS allowed origins |
> When running via `docker compose up --build`, CouchDB CORS settings are sourced from `couchdb-config/cors.ini`. Update the `origins` list in that file to add additional frontend domains.
### Performance Variables
| Variable | Default | Description |
| ------------------- | ------- | ------------------------------- |
| `FRONTEND_REPLICAS` | `1` | Number of frontend replicas |
| `CACHE_TTL` | `1800` | Cache time-to-live in seconds |
| `REQUEST_TIMEOUT` | `30000` | Request timeout in milliseconds |
| `MAX_CONNECTIONS` | `100` | Maximum concurrent connections |
### Resource Limits
| Variable | Default | Description |
| ------------------------- | ---------- | ----------------------- |
| `FRONTEND_MEMORY_REQUEST` | `32Mi` | Frontend memory request |
| `FRONTEND_MEMORY_LIMIT` | `64Mi` | Frontend memory limit |
| `FRONTEND_CPU_REQUEST` | `20m` | Frontend CPU request |
| `FRONTEND_CPU_LIMIT` | `40m` | Frontend CPU limit |
| `COUCHDB_MEMORY_REQUEST` | `64Mi` | CouchDB memory request |
| `COUCHDB_MEMORY_LIMIT` | `128Mi` | CouchDB memory limit |
| `STORAGE_SIZE` | `1Gi` | Storage volume size |
| `STORAGE_CLASS` | `standard` | Storage class |
### Monitoring & Observability
| Variable | Default | Description |
| ------------------- | ------- | -------------------------- |
| `ENABLE_MONITORING` | `false` | Enable monitoring features |
| `ENABLE_METRICS` | `false` | Enable metrics collection |
| `ENABLE_TRACING` | `false` | Enable distributed tracing |
| `METRICS_PORT` | `9090` | Metrics server port |
### Security Variables
| Variable | Default | Description |
| ------------------------- | ------- | ----------------------- |
| `ENABLE_SECURITY_HEADERS` | `false` | Enable security headers |
| `ENABLE_RATE_LIMITING` | `false` | Enable rate limiting |
| `API_SECRET_KEY` | - | API secret key |
| `JWT_SECRET` | - | JWT signing secret |
### Bootstrap Admin Variables
These variables control the default admin account created/updated at app startup by the frontend seeder. They are read at build-time (Vite), so changing them requires rebuilding the frontend image.
| Variable | Default | Description |
| --------------------- | ----------------- | ----------------------------------- |
| `VITE_ADMIN_EMAIL` | `admin@localhost` | Email of the default admin user |
| `VITE_ADMIN_PASSWORD` | `admin123!` | Password for the default admin user |
Notes:
- To change these in Docker, set build args in `docker-compose.yaml` or define them in `.env` and rebuild: `docker compose build frontend && docker compose up -d`.
- The seeder is idempotent: if a user with this email exists, it updates role/status and keeps the latest password you set.
## Usage Examples
### Basic Development Setup
1. Create your development environment file:
```bash
cat > .env.dev << EOF
NODE_ENV=development
LOG_LEVEL=debug
DEBUG=true
IMAGE_TAG=dev
INGRESS_HOST=rxminder-dev.local
COUCHDB_PASSWORD=devpass123
EOF
```
2. Generate configuration and deploy:
```bash
make generate-config-dev
make deploy-dev
```
### Production Deployment with Secrets
1. Set up your production environment:
```bash
# .env.prod (commit this)
NODE_ENV=production
LOG_LEVEL=warn
IMAGE_TAG=v1.0.0
INGRESS_HOST=rxminder.yourdomain.com
ENABLE_TLS=true
# .env.local (DO NOT commit)
COUCHDB_PASSWORD=your_secure_production_password
REGISTRY_PASSWORD=your_registry_token
```
2. Deploy with environment variables:
```bash
make deploy-with-env-prod
```
### Dynamic Configuration Updates
Update configuration without rebuilding:
```bash
# Update environment variable
export LOG_LEVEL=debug
# Deploy with updated configuration
./scripts/deploy-with-env.sh prod apply
```
### Testing Different Configurations
```bash
# Test with different image tag
export IMAGE_TAG=feature-branch
make diff-with-env-dev
# Test with different resources
export FRONTEND_REPLICAS=5
./scripts/deploy-with-env.sh prod dry-run
```
## Available Commands
### Configuration Generation
```bash
make generate-config-dev # Generate dev config from env vars
make generate-config-prod # Generate prod config from env vars
make generate-config-staging # Generate staging config from env vars
make generate-config-all # Generate all environment configs
make validate-config # Validate generated configuration
make generate-secrets-template # Generate secrets template files
```
### Environment-Aware Deployment
```bash
make deploy-with-env-dev # Deploy dev with env vars
make deploy-with-env-prod # Deploy prod with env vars
make deploy-with-env-staging # Deploy staging with env vars
make undeploy-with-env-dev # Remove dev deployment
make diff-with-env-dev # Show dev diff with env vars
make status-with-env-dev # Show dev status with env vars
```
### Direct Script Usage
```bash
# Generate configuration
./scripts/generate-config.sh dev
./scripts/generate-config.sh prod --secrets
# Deploy with environment variables
./scripts/deploy-with-env.sh dev apply
./scripts/deploy-with-env.sh prod diff
./scripts/deploy-with-env.sh staging delete
```
## Best Practices
### Security
1. **Never commit sensitive data**:
- Add `.env.local` to `.gitignore`
- Use external secret management for production
- Rotate passwords regularly
2. **Use environment-specific files**:
- `.env.dev` for development settings
- `.env.prod` for production configuration
- `.env.local` for sensitive overrides
### Organization
1. **Group related variables**:
- Database settings together
- Resource limits together
- Feature flags together
2. **Use descriptive names**:
- `FRONTEND_MEMORY_LIMIT` vs `MEM_LIMIT`
- `ENABLE_DEBUG_MODE` vs `DEBUG`
3. **Document your variables**:
- Add comments explaining purpose
- Include example values
- Note required vs optional
### Development Workflow
1. **Start with examples**:
```bash
cp .env.example .env.dev
# Edit .env.dev with your settings
```
2. **Test configurations**:
```bash
make generate-config-dev
make kustomize-dry-run-dev
```
3. **Validate before deploying**:
```bash
make validate-config
make diff-with-env-dev
```
## Troubleshooting
### Common Issues
1. **Variables not being loaded**:
- Check file permissions (`chmod 644 .env.*`)
- Verify file format (no spaces around `=`)
- Check file encoding (UTF-8)
2. **Configuration not updating**:
- Regenerate config: `make generate-config-dev`
- Clear cached resources: `kubectl delete configmap -l app=rxminder`
3. **Deployment failures**:
- Validate syntax: `make validate-config`
- Check logs: `kubectl logs -l app=rxminder`
- Verify resources: `kubectl describe deployment rxminder-frontend`
### Debug Commands
```bash
# Check loaded environment variables
./scripts/generate-config.sh dev --dry-run
# Validate generated configuration
make validate-config
# Show what would be deployed
./scripts/deploy-with-env.sh dev dry-run
# Check current deployment status
make status-with-env-dev
```
## Migration from Legacy System
### Step 1: Extract Current Configuration
```bash
# Export current settings to environment file
echo "APP_NAME=rxminder" > .env.dev
echo "IMAGE_TAG=dev" >> .env.dev
# ... add other variables
```
### Step 2: Test New System
```bash
# Generate and validate configuration
make generate-config-dev
make validate-config
# Test deployment
make kustomize-dry-run-dev
```
### Step 3: Deploy
```bash
# Deploy using new system
make deploy-with-env-dev
# Verify deployment
make status-with-env-dev
```
## External Secret Management
For production environments, integrate with external secret management:
### HashiCorp Vault Integration
```bash
# .env.prod
VAULT_ADDR=https://vault.yourdomain.com
VAULT_ROLE=rxminder-prod
VAULT_SECRET_PATH=secret/rxminder/prod
# Use Vault Agent or CSI driver to inject secrets
```
### Kubernetes External Secrets
```yaml
# external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: rxminder-secrets
spec:
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: couchdb-secret
data:
- secretKey: password
remoteRef:
key: rxminder/prod
property: couchdb_password
```
### AWS Secrets Manager
```bash
# .env.prod
AWS_REGION=us-west-2
AWS_SECRET_NAME=rxminder/prod/couchdb
# Use AWS Load Balancer Controller or external-secrets-operator
```
## Summary
The environment variable system provides:
- **Flexibility**: Configure deployments without changing code
- **Security**: Keep sensitive data out of version control
- **Consistency**: Standardized configuration across environments
- **Maintainability**: Clear separation of configuration and code
Choose the approach that best fits your workflow:
- **Static generation** for stable, version-controlled configurations
- **Dynamic injection** for flexible, runtime configurations
- **Hybrid approach** for the best of both worlds
For more information, see:
- [Configuration Guide](COMPLETE_TEMPLATE_CONFIGURATION.md)
- [App Name Configuration](APP_NAME_CONFIGURATION.md)
- [Project Structure](../architecture/PROJECT_STRUCTURE.md)