#!/bin/bash # scripts/setup.sh # Intelligent Setup Script - Extract artifacts and create microservices structure set -e echo "๐Ÿš€ Setting up Bakery Forecasting Microservices Platform" echo "========================================================" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color print_step() { echo -e "${BLUE}โžค${NC} $1" } print_success() { echo -e "${GREEN}โœ“${NC} $1" } print_warning() { echo -e "${YELLOW}โš ${NC} $1" } print_error() { echo -e "${RED}โœ—${NC} $1" } # Check prerequisites print_step "Checking prerequisites..." command -v docker >/dev/null 2>&1 || { print_error "Docker is required but not installed. Please install Docker first." exit 1 } command -v docker-compose >/dev/null 2>&1 || { print_error "Docker Compose is required but not installed. Please install Docker Compose first." exit 1 } print_success "Prerequisites check passed" # Function to extract files from artifact files extract_artifact_files() { local artifact_file="$1" local description="$2" print_step "Processing $description..." if [ ! -f "$artifact_file" ]; then print_warning "Artifact file $artifact_file not found, skipping..." return fi # Read the artifact file and extract individual files local current_file="" local current_content="" local in_file=false while IFS= read -r line; do # Check if line starts with a file path (contains .py, .yml, .md, .sh, etc.) if [[ "$line" =~ ^#[[:space:]]*(.*\.(py|yml|yaml|md|sh|txt|js|json|html|css|Dockerfile|requirements\.txt))$ ]]; then # Save previous file if we were processing one if [ "$in_file" = true ] && [ -n "$current_file" ]; then # Create directory if it doesn't exist local dir=$(dirname "$current_file") mkdir -p "$dir" # Write content to file echo "$current_content" > "$current_file" print_success "Created: $current_file" fi # Start new file current_file=$(echo "$line" | sed 's/^#[[:space:]]*//') current_content="" in_file=true elif [ "$in_file" = true ]; then # Add line to current file content if [ -n "$current_content" ]; then current_content="$current_content\n$line" else current_content="$line" fi fi done < "$artifact_file" # Save the last file if [ "$in_file" = true ] && [ -n "$current_file" ]; then local dir=$(dirname "$current_file") mkdir -p "$dir" echo -e "$current_content" > "$current_file" print_success "Created: $current_file" fi } # Function to extract Python files with multiple file markers extract_python_artifact() { local artifact_file="$1" local description="$2" print_step "Processing $description..." if [ ! -f "$artifact_file" ]; then print_warning "Artifact file $artifact_file not found, skipping..." return fi # Use Python to parse the multi-file artifact python3 << EOF import re import os def extract_files(filename): with open('$artifact_file', 'r') as f: content = f.read() # Split by file markers (lines starting with # and containing file paths) files = {} current_file = None current_content = [] for line in content.split('\n'): # Check for file path markers if re.match(r'^#\s+\S+\.(py|yml|yaml|txt|sh|json|html|css|js|Dockerfile)', line): # Save previous file if current_file and current_content: files[current_file] = '\n'.join(current_content) # Start new file current_file = re.sub(r'^#\s+', '', line) current_content = [] elif current_file: current_content.append(line) # Save last file if current_file and current_content: files[current_file] = '\n'.join(current_content) # Write files for filepath, file_content in files.items(): # Clean up the content (remove leading/trailing quotes if present) file_content = file_content.strip() if file_content.startswith('"""') and file_content.endswith('"""'): file_content = file_content[3:-3] elif file_content.startswith("'''") and file_content.endswith("'''"): file_content = file_content[3:-3] # Create directory os.makedirs(os.path.dirname(filepath) if os.path.dirname(filepath) else '.', exist_ok=True) # Write file with open(filepath, 'w') as f: f.write(file_content) print(f"โœ“ Created: {filepath}") extract_files('$artifact_file') EOF } # Create base project structure first print_step "Creating base project structure..." # Create main directories mkdir -p {gateway,services/{auth,training,forecasting,data,tenant,notification},shared,frontend/{dashboard,marketing},infrastructure,deployment,tests,docs,scripts} # Create subdirectories for each service for service in auth training forecasting data tenant notification; do mkdir -p services/$service/{app/{core,models,schemas,services,api,ml},migrations/versions,tests} touch services/$service/app/__init__.py touch services/$service/app/core/__init__.py touch services/$service/app/models/__init__.py touch services/$service/app/schemas/__init__.py touch services/$service/app/services/__init__.py touch services/$service/app/api/__init__.py if [ "$service" = "training" ]; then touch services/$service/app/ml/__init__.py fi done # Create gateway structure mkdir -p gateway/{app/{core,middleware,routes},tests} touch gateway/app/__init__.py touch gateway/app/core/__init__.py touch gateway/app/middleware/__init__.py touch gateway/app/routes/__init__.py # Create shared library structure mkdir -p shared/{auth,database,messaging,monitoring,utils} for lib in auth database messaging monitoring utils; do touch shared/$lib/__init__.py done # Create infrastructure directories mkdir -p infrastructure/{docker,kubernetes,terraform,monitoring}/{base,dev,staging,production} mkdir -p infrastructure/monitoring/{prometheus,grafana,logstash} print_success "Base project structure created" # Extract files from artifacts print_step "Extracting files from artifacts..." # Process shared libraries if [ -f "shared_libraries.py" ]; then extract_python_artifact "shared_libraries.py" "Shared Libraries" fi # Process gateway service if [ -f "gateway_service.py" ]; then extract_python_artifact "gateway_service.py" "Gateway Service" fi # Process auth service if [ -f "auth_service.py" ]; then extract_python_artifact "auth_service.py" "Authentication Service" fi # Process training service if [ -f "training_service.py" ]; then extract_python_artifact "training_service.py" "Training Service" fi print_step "Creating missing service files..." # Create remaining service files that might not be in artifacts for service in forecasting data tenant notification; do service_dir="services/$service" # Create main.py if it doesn't exist if [ ! -f "$service_dir/app/main.py" ]; then cat > "$service_dir/app/main.py" << EOF """ $(echo $service | sed 's/.*/\L&/; s/[a-z]*/\u&/g') Service """ import logging from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.core.config import settings from app.core.database import database_manager from shared.monitoring.logging import setup_logging from shared.monitoring.metrics import MetricsCollector # Setup logging setup_logging("$service-service", "INFO") logger = logging.getLogger(__name__) # Create FastAPI app app = FastAPI( title="$(echo $service | sed 's/.*/\L&/; s/[a-z]*/\u&/g') Service", description="$(echo $service | sed 's/.*/\L&/; s/[a-z]*/\u&/g') service for bakery forecasting", version="1.0.0" ) # Initialize metrics collector metrics_collector = MetricsCollector("$service-service") # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.on_event("startup") async def startup_event(): """Application startup""" logger.info("Starting $(echo $service | sed 's/.*/\L&/; s/[a-z]*/\u&/g') Service") # Create database tables await database_manager.create_tables() # Start metrics server metrics_collector.start_metrics_server(8080) logger.info("$(echo $service | sed 's/.*/\L&/; s/[a-z]*/\u&/g') Service started successfully") @app.get("/health") async def health_check(): """Health check endpoint""" return { "status": "healthy", "service": "$service-service", "version": "1.0.0" } if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000) EOF print_success "Created: $service_dir/app/main.py" fi # Create config.py if it doesn't exist if [ ! -f "$service_dir/app/core/config.py" ]; then cat > "$service_dir/app/core/config.py" << EOF """ $(echo $service | sed 's/.*/\L&/; s/[a-z]*/\u&/g') service configuration """ import os from pydantic import BaseSettings class Settings(BaseSettings): """Application settings""" # Basic settings APP_NAME: str = "$(echo $service | sed 's/.*/\L&/; s/[a-z]*/\u&/g') Service" VERSION: str = "1.0.0" DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") # Database settings DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql+asyncpg://${service}_user:${service}_pass123@${service}-db:5432/${service}_db") # Redis settings REDIS_URL: str = os.getenv("REDIS_URL", "redis://redis:6379/0") # RabbitMQ settings RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/") # Service URLs AUTH_SERVICE_URL: str = os.getenv("AUTH_SERVICE_URL", "http://auth-service:8000") class Config: env_file = ".env" settings = Settings() EOF print_success "Created: $service_dir/app/core/config.py" fi # Create database.py if it doesn't exist if [ ! -f "$service_dir/app/core/database.py" ]; then cat > "$service_dir/app/core/database.py" << EOF """ Database configuration for $service service """ from shared.database.base import DatabaseManager from app.core.config import settings # Initialize database manager database_manager = DatabaseManager(settings.DATABASE_URL) # Alias for convenience get_db = database_manager.get_db EOF print_success "Created: $service_dir/app/core/database.py" fi # Create requirements.txt if it doesn't exist if [ ! -f "$service_dir/requirements.txt" ]; then cat > "$service_dir/requirements.txt" << 'EOF' fastapi==0.104.1 uvicorn[standard]==0.24.0 sqlalchemy==2.0.23 asyncpg==0.29.0 alembic==1.12.1 pydantic==2.5.0 pydantic-settings==2.1.0 httpx==0.25.2 redis==5.0.1 aio-pika==9.3.0 prometheus-client==0.17.1 python-json-logger==2.0.4 pytz==2023.3 EOF print_success "Created: $service_dir/requirements.txt" fi # Create Dockerfile if it doesn't exist if [ ! -f "$service_dir/Dockerfile" ]; then cat > "$service_dir/Dockerfile" << 'EOF' FROM python:3.11-slim WORKDIR /app # Install system dependencies RUN apt-get update && apt-get install -y \ gcc \ curl \ && rm -rf /var/lib/apt/lists/* # Copy requirements COPY requirements.txt . # Install Python dependencies RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY . . # Add shared libraries to Python path ENV PYTHONPATH="/app:/app/shared:$PYTHONPATH" # Expose port EXPOSE 8000 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1 # Run application CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] EOF print_success "Created: $service_dir/Dockerfile" fi done # Create .env file print_step "Creating environment configuration..." if [ ! -f ".env" ]; then cat > .env << 'EOF' # Environment ENVIRONMENT=development DEBUG=true LOG_LEVEL=INFO # Database URLs AUTH_DB_URL=postgresql+asyncpg://auth_user:auth_pass123@auth-db:5432/auth_db TRAINING_DB_URL=postgresql+asyncpg://training_user:training_pass123@training-db:5432/training_db FORECASTING_DB_URL=postgresql+asyncpg://forecasting_user:forecasting_pass123@forecasting-db:5432/forecasting_db DATA_DB_URL=postgresql+asyncpg://data_user:data_pass123@data-db:5432/data_db TENANT_DB_URL=postgresql+asyncpg://tenant_user:tenant_pass123@tenant-db:5432/tenant_db NOTIFICATION_DB_URL=postgresql+asyncpg://notification_user:notification_pass123@notification-db:5432/notification_db # Redis REDIS_URL=redis://redis:6379 # RabbitMQ RABBITMQ_URL=amqp://bakery:forecast123@rabbitmq:5672/ # JWT JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production-please JWT_ALGORITHM=HS256 JWT_ACCESS_TOKEN_EXPIRE_MINUTES=30 JWT_REFRESH_TOKEN_EXPIRE_DAYS=7 # External APIs AEMET_API_KEY=your-aemet-api-key-here MADRID_OPENDATA_API_KEY=your-madrid-opendata-key-here # CORS CORS_ORIGINS=http://localhost:3000,http://localhost:3001 # Email SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=your-email@gmail.com SMTP_PASSWORD=your-email-password # WhatsApp WHATSAPP_API_KEY=your-whatsapp-api-key-here # Monitoring PROMETHEUS_URL=http://prometheus:9090 GRAFANA_URL=http://grafana:3000 EOF print_success "Environment configuration created" fi # Create monitoring configuration print_step "Creating monitoring configuration..." if [ ! -f "infrastructure/monitoring/prometheus/prometheus.yml" ]; then cat > infrastructure/monitoring/prometheus/prometheus.yml << 'EOF' global: scrape_interval: 15s scrape_configs: - job_name: 'gateway' static_configs: - targets: ['gateway:8080'] - job_name: 'auth-service' static_configs: - targets: ['auth-service:8080'] - job_name: 'training-service' static_configs: - targets: ['training-service:8080'] - job_name: 'forecasting-service' static_configs: - targets: ['forecasting-service:8080'] - job_name: 'data-service' static_configs: - targets: ['data-service:8080'] - job_name: 'tenant-service' static_configs: - targets: ['tenant-service:8080'] - job_name: 'notification-service' static_configs: - targets: ['notification-service:8080'] EOF print_success "Prometheus configuration created" fi # Create utility scripts print_step "Creating utility scripts..." # Create test script cat > scripts/test.sh << 'EOF' #!/bin/bash echo "๐Ÿงช Running tests for all services..." # Run tests for each service for service in auth training forecasting data tenant notification; do echo "Testing $service service..." if docker-compose ps | grep -q "${service}-service.*Up"; then docker-compose exec -T ${service}-service python -m pytest tests/ -v || echo "Tests failed for $service" else echo "Service $service is not running, skipping tests" fi done echo "โœ… Test run completed" EOF # Create deploy script cat > scripts/deploy.sh << 'EOF' #!/bin/bash echo "๐Ÿš€ Deploying Bakery Forecasting Platform..." # Build and deploy all services docker-compose build docker-compose up -d echo "Waiting for services to be healthy..." sleep 30 # Check service health echo "Checking service health..." curl -f http://localhost:8000/health || echo "Gateway health check failed" echo "โœ… Deployment completed" echo "Gateway: http://localhost:8000" echo "API Docs: http://localhost:8000/docs" EOF # Make scripts executable chmod +x scripts/*.sh print_success "Utility scripts created" # Create .gitignore print_step "Creating .gitignore..." if [ ! -f ".gitignore" ]; then cat > .gitignore << 'EOF' # Environment .env .env.local .env.development.local .env.test.local .env.production.local # Python __pycache__/ *.py[cod] *$py.class *.so .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST .pytest_cache/ .coverage .coverage.* htmlcov/ .tox/ .nox/ .hypothesis/ .mypy_cache/ .dmyp.json dmyp.json .pyre/ # Virtual Environment venv/ ENV/ env/ .venv # Node node_modules/ npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* .npm .eslintcache .next out/ build/ dist/ # IDE .vscode/ .idea/ *.swp *.swo *~ .DS_Store # Logs logs/ *.log # Database *.db *.sqlite *.sqlite3 # ML Models *.pkl *.joblib *.h5 models/ # Data data/external/ data/processed/ *.csv *.xlsx # Docker .docker/ # Infrastructure *.tfstate *.tfstate.backup .terraform/ .terraform.lock.hcl # Kubernetes kubeconfig *.yaml.bak # Monitoring prometheus_data/ grafana_data/ elasticsearch_data/ # Artifacts (from Claude) *_service.py *_libraries.py *.md setup_scripts.sh EOF print_success ".gitignore created" fi # Create README print_step "Creating documentation..." if [ ! -f "README.md" ]; then cat > README.md << 'EOF' # Bakery Forecasting Platform - Microservices ## Overview AI-powered demand forecasting platform for bakeries in Madrid, Spain using microservices architecture. ## Architecture - **API Gateway**: Central entry point for all client requests - **Auth Service**: User authentication and authorization - **Training Service**: ML model training for demand forecasting - **Forecasting Service**: Generate predictions using trained models - **Data Service**: External data integration (weather, traffic, events) - **Tenant Service**: Multi-tenant management - **Notification Service**: Email and WhatsApp notifications ## Quick Start ### Prerequisites - Docker and Docker Compose - Python 3.11+ - Node.js 18+ ### Setup ```bash # Run setup script (this script!) ./scripts/setup.sh # Start services docker-compose up -d # Check service health curl http://localhost:8000/health ``` ### Services - **Gateway**: http://localhost:8000 - **API Docs**: http://localhost:8000/docs - **Grafana**: http://localhost:3002 - **Prometheus**: http://localhost:9090 - **RabbitMQ Management**: http://localhost:15672 ### Development #### Running Tests ```bash ./scripts/test.sh ``` #### Building Services ```bash docker-compose build ``` #### Viewing Logs ```bash # All services docker-compose logs -f # Specific service docker-compose logs -f auth-service ``` #### Service URLs (Development) - Gateway: http://localhost:8000 - Auth Service: http://localhost:8001 - Training Service: http://localhost:8002 - Forecasting Service: http://localhost:8003 - Data Service: http://localhost:8004 - Tenant Service: http://localhost:8005 - Notification Service: http://localhost:8006 ## Environment Variables Copy `.env.example` to `.env` and update the following: ```bash # External API Keys AEMET_API_KEY=your-aemet-api-key MADRID_OPENDATA_API_KEY=your-madrid-opendata-key # Email Configuration SMTP_USER=your-email@gmail.com SMTP_PASSWORD=your-email-password # WhatsApp API WHATSAPP_API_KEY=your-whatsapp-api-key # JWT Secret (change in production!) JWT_SECRET_KEY=your-super-secret-jwt-key ``` ## Troubleshooting ### Services won't start ```bash # Check if ports are available docker-compose ps netstat -tulpn | grep :8000 # Restart services docker-compose down docker-compose up -d ``` ### Database connection issues ```bash # Check database containers docker-compose logs auth-db docker-compose logs training-db # Reset databases docker-compose down -v docker-compose up -d ``` ### Service communication issues ```bash # Check service health curl http://localhost:8000/health curl http://localhost:8001/health curl http://localhost:8002/health # Check RabbitMQ open http://localhost:15672 # User: bakery, Password: forecast123 ``` ## Next Steps 1. **Configure External APIs**: Add your AEMET and Madrid Open Data API keys 2. **Test Authentication**: Register a user and test login 3. **Upload Sales Data**: Import historical sales data 4. **Train Models**: Start your first training job 5. **Generate Forecasts**: Create demand predictions ## License MIT License EOF print_success "Documentation created" fi # Final steps print_step "Final setup steps..." # Copy shared libraries to each service (for Docker builds) for service in auth training forecasting data tenant notification; do if [ -d "shared" ]; then cp -r shared services/$service/ 2>/dev/null || true fi done # Copy shared libraries to gateway if [ -d "shared" ]; then cp -r shared gateway/ 2>/dev/null || true fi # Initialize Git repository if not exists if [ ! -d ".git" ]; then git init git add . git commit -m "Initial microservices setup from artifacts" print_success "Git repository initialized" fi echo echo "๐ŸŽ‰ Setup completed successfully!" echo "===============================================" echo echo "Next steps:" echo "1. Update .env with your actual API keys" echo "2. Start services: docker-compose up -d" echo "3. Check health: curl http://localhost:8000/health" echo "4. View API docs: http://localhost:8000/docs" echo "5. Monitor services: http://localhost:3002 (Grafana)" echo echo "Services will be available at:" echo "- Gateway: http://localhost:8000" echo "- Auth Service: http://localhost:8001" echo "- Training Service: http://localhost:8002" echo "- Monitoring: http://localhost:3002" echo "- RabbitMQ: http://localhost:15672" echo echo "Artifact files processed:" [ -f "shared_libraries.py" ] && echo "โœ“ shared_libraries.py" [ -f "gateway_service.py" ] && echo "โœ“ gateway_service.py" [ -f "auth_service.py" ] && echo "โœ“ auth_service.py" [ -f "training_service.py" ] && echo "โœ“ training_service.py" [ -f "docker-compose.yml" ] && echo "โœ“ docker-compose.yml" echo echo "Happy coding! ๐Ÿš€"