11 KiB
/**
- Environment Configuration
- Development | Staging | Production */
// ============================================================================ // BACKEND CONFIGURATION (PHP) // ============================================================================
// File: backend/config.php
<?php define('ENVIRONMENT', getenv('APP_ENV') ?: 'development'); // Database Configuration if (ENVIRONMENT === 'production') { define('DB_HOST', getenv('DB_HOST') ?: 'prod-db.example.com'); define('DB_USER', getenv('DB_USER') ?: 'fitness_app'); define('DB_PASS', getenv('DB_PASS')); define('DB_NAME', 'fitness_app'); define('DB_PORT', getenv('DB_PORT') ?: 3306); define('DB_CHARSET', 'utf8mb4'); // Security Headers define('FORCE_HTTPS', true); define('SECURE_COOKIES', true); define('HSTS_MAX_AGE', 31536000); // 1 year } elseif (ENVIRONMENT === 'staging') { define('DB_HOST', 'staging-db.example.com'); define('DB_USER', 'fitness_staging'); define('DB_PASS', getenv('DB_PASS')); define('DB_NAME', 'fitness_staging'); define('DB_PORT', 3306); define('FORCE_HTTPS', true); } else { // Development define('DB_HOST', 'localhost'); define('DB_USER', 'root'); define('DB_PASS', 'password'); define('DB_NAME', 'fitness_app_dev'); define('DB_PORT', 3306); define('FORCE_HTTPS', false); } // API Configuration define('API_VERSION', 'v1'); define('API_BASE_PATH', '/api/' . API_VERSION); define('REQUEST_TIMEOUT', 30); // seconds define('MAX_PAYLOAD_SIZE', 10485760); // 10MB // Rate Limiting define('RATE_LIMIT_ENABLED', true); define('RATE_LIMIT_REQUESTS', 100); // per minute define('RATE_LIMIT_WINDOW', 60); // seconds // Logging define('LOG_LEVEL', ENVIRONMENT === 'production' ? 'error' : 'debug'); define('LOG_FILE', '/var/log/fitness_api.log'); define('LOG_DATABASE', true); // Log to DB as well // CORS Configuration define('ALLOWED_ORIGINS', [ 'https://fitness-app.com', 'https://app.fitness-app.com', ENVIRONMENT === 'development' ? 'http://localhost:3000' : null ]); // Email Configuration (for notifications) define('MAIL_HOST', getenv('MAIL_HOST') ?: 'smtp.gmail.com'); define('MAIL_PORT', getenv('MAIL_PORT') ?: 587); define('MAIL_USER', getenv('MAIL_USER')); define('MAIL_PASS', getenv('MAIL_PASS')); define('MAIL_FROM', 'noreply@fitness-app.com'); // Cache Configuration define('CACHE_ENABLED', ENVIRONMENT !== 'development'); define('CACHE_DRIVER', 'redis'); // 'redis' or 'file' define('CACHE_TTL', 3600); // seconds // Security define('HMAC_ALGORITHM', 'sha256'); define('TIMESTAMP_TOLERANCE', 300); // 5 minutes define('BCRYPT_COST', 12); // API Keys (for external services) define('MAPBOX_API_KEY', getenv('MAPBOX_API_KEY')); define('WEATHER_API_KEY', getenv('WEATHER_API_KEY')); // Enable debug mode (NEVER true in production) define('DEBUG_MODE', ENVIRONMENT === 'development'); // Timezone date_default_timezone_set('UTC'); ?>// ============================================================================ // MOBILE CONFIGURATION (Dart/Flutter) // ============================================================================
// File: mobile/lib/config/environment.dart
const String kEnvironment = String.fromEnvironment('ENVIRONMENT', defaultValue: 'development');
class EnvironmentConfig { static const String apiHost = String.fromEnvironment( 'API_HOST', defaultValue: 'https://api.fitness-app.local', );
static const String mapTileServer = 'https://map-saas.intaleqapp.com/styles/basic-preview/style.json';
static const int locationUpdateInterval = 5; // seconds static const int mapRefreshInterval = 2; // seconds
// API Configuration static const Duration requestTimeout = Duration(seconds: 30); static const int maxRetries = 3;
// Location Configuration static const double minAccuracy = 10.0; // meters static const double minDistance = 10.0; // meters between coordinates static const int foregroundServicePriority = 1; // HIGH
// Database Configuration static const String databaseName = 'fitness_app.db'; static const int databaseVersion = 1;
// Feature Flags static const bool enableBackgroundTracking = true; static const bool enableOfflineSync = true; static const bool enableAnalytics = !kDebugMode;
// Get API endpoint based on environment static String get apiEndpoint { return '$apiHost/api/v1'; }
// Get workout submission endpoint static String get workoutSubmissionEndpoint { return '$apiEndpoint/workouts'; } }
class DevEnvironment { static const String apiHost = 'http://localhost:8080'; static const bool debugLogging = true; }
class StagingEnvironment { static const String apiHost = 'https://staging-api.fitness-app.com'; static const bool debugLogging = true; }
class ProductionEnvironment { static const String apiHost = 'https://api.fitness-app.com'; static const bool debugLogging = false; }
// ============================================================================ // DOCKER COMPOSE CONFIGURATION // ============================================================================
File: docker-compose.yml
version: '3.8'
services: mysql: image: mysql:8.0 container_name: fitness_app_mysql environment: MYSQL_ROOT_PASSWORD: root_password MYSQL_DATABASE: fitness_app MYSQL_USER: fitness_app MYSQL_PASSWORD: ${DB_PASSWORD} ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql - ./backend/schema.sql:/docker-entrypoint-initdb.d/schema.sql networks: - fitness_network healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] timeout: 20s retries: 10
php_api: image: php:8.2-fpm container_name: fitness_app_php environment: APP_ENV: ${APP_ENV:-development} DB_HOST: mysql DB_USER: fitness_app DB_PASS: ${DB_PASSWORD} DB_NAME: fitness_app volumes: - ./backend:/app depends_on: mysql: condition: service_healthy networks: - fitness_network
nginx: image: nginx:alpine container_name: fitness_app_nginx ports: - "80:80" - "443:443" volumes: - ./backend:/app - ./nginx.conf:/etc/nginx/nginx.conf - ./ssl:/etc/nginx/ssl depends_on: - php_api networks: - fitness_network
redis: image: redis:7-alpine container_name: fitness_app_redis ports: - "6379:6379" networks: - fitness_network healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5
volumes: mysql_data:
networks: fitness_network: driver: bridge
============================================================================
// ENVIRONMENT VARIABLES (.env file) // ============================================================================
File: .env.example (copy to .env for development)
Application
APP_ENV=development APP_DEBUG=true TIMEZONE=UTC
Database
DB_HOST=localhost DB_PORT=3306 DB_USER=fitness_app DB_PASS=your_secure_password_here DB_NAME=fitness_app
API Configuration
API_HOST=http://localhost:8080 API_VERSION=v1 API_RATE_LIMIT=100
Map Tile Server
TILE_SERVER_URL=https://map-saas.intaleqapp.com/styles/basic-preview/style.json
Email (for notifications)
MAIL_HOST=smtp.gmail.com MAIL_PORT=587 MAIL_USER=your_email@gmail.com MAIL_PASS=your_app_password
External Services
MAPBOX_API_KEY= WEATHER_API_KEY=
Security
HMAC_ALGORITHM=sha256 BCRYPT_COST=12
Logging
LOG_LEVEL=debug LOG_FILE=/var/log/fitness_api.log
Cache
CACHE_DRIVER=redis CACHE_TTL=3600
============================================================================
// NGINX CONFIGURATION // ============================================================================
File: nginx.conf
user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid;
events { worker_connections 1024; }
http { include /etc/nginx/mime.types; default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss;
# Rate limiting
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $http_x_api_key zone=api:10m rate=100r/m;
upstream php_backend {
server php_api:9000;
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
# HTTPS Server
server {
listen 443 ssl http2;
server_name api.fitness-app.com;
ssl_certificate /etc/nginx/ssl/cert.crt;
ssl_certificate_key /etc/nginx/ssl/key.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
root /app;
# Rate limiting
limit_req zone=api burst=20 nodelay;
location / {
try_files $uri $uri/ @rewrite;
}
location @rewrite {
rewrite ^/(.*)$ /api_workouts.php?url=$1 last;
}
location ~ \.php$ {
fastcgi_pass php_backend;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
}
# Deny access to sensitive files
location ~ /\. {
deny all;
}
location ~ ~$ {
deny all;
}
}
}
// ============================================================================ // BUILD CONFIGURATION (Android) // ============================================================================
File: android/app/build.gradle
android { compileSdkVersion 34 ndkVersion "25.1.8937393"
defaultConfig {
applicationId "com.fitness.tracker"
minSdkVersion 21
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
debug {
debuggable true
signingConfig signingConfigs.debug
buildConfigField "String", "API_HOST", '"http://192.168.1.100:8080"'
}
staging {
debuggable false
signingConfig signingConfigs.release
buildConfigField "String", "API_HOST", '"https://staging-api.fitness-app.com"'
}
release {
signingConfig signingConfigs.release
buildConfigField "String", "API_HOST", '"https://api.fitness-app.com"'
}
}
}
// ============================================================================ // GIT IGNORE (.gitignore) // ============================================================================
File: .gitignore
Environment
.env .env.local .env.*.local
API Credentials
api_key.txt api_secret.txt
Database
_.db _.sqlite *.sqlite3
Logs
*.log logs/
IDE
.vscode/ .idea/ _.swp _.swo
Flutter
.dart_tool/ .flutter-plugins .packages build/
Backend
vendor/ node_modules/
OS
.DS_Store Thumbs.db
Secrets
secrets.json credentials.json