Skip to content

Deploy Complete RAG Modulo Application #463

Deploy Complete RAG Modulo Application

Deploy Complete RAG Modulo Application #463

# =============================================================================
# Workflow: Deploy Complete RAG Modulo Application
# =============================================================================
# Description: Comprehensive deployment workflow for RAG Modulo application
# including infrastructure, backend, and frontend components
# to IBM Cloud Code Engine with security scanning and testing.
#
# Author: RAG Modulo Team
# Last Updated: 2025-01-13
# Version: 2.0
#
# Triggers:
# - Manual dispatch (workflow_dispatch)
# - Daily builds (schedule: 2 AM UTC)
# - Push to main/develop branches
#
# Prerequisites:
# - IBM Cloud API Key configured as secret
# - IBM Cloud Container Registry namespace created
# - All application secrets configured in repository settings
#
# Jobs:
# 1. deploy-infrastructure: Deploy PostgreSQL, MinIO, etcd, Milvus
# 2. build-and-push-backend: Build and push backend Docker image
# 3. build-and-push-frontend: Build and push frontend Docker image
# 4. security-scan-*: Scan images for vulnerabilities with Trivy
# 5. deploy-*: Deploy applications to IBM Cloud Code Engine
# 6. smoke-test: Verify deployment health and functionality
#
# Security Features:
# - Trivy vulnerability scanning with SARIF output
# - Non-root container execution
# - Command injection prevention
# - Secret management via GitHub Secrets
#
# Resources Deployed:
# - Backend: 1 CPU, 4GB RAM, scales 1-5 instances
# - Frontend: 0.5 CPU, 1GB RAM, scales 1-3 instances
# - PostgreSQL: 0.5 CPU, 2GB RAM
# - MinIO: 0.25 CPU, 1GB RAM
# - etcd: 0.25 CPU, 1GB RAM
# - Milvus: 0.5 CPU, 2GB RAM
# =============================================================================
name: Deploy Complete RAG Modulo Application
# Define workflow triggers
on:
# Manual deployment with environment selection
workflow_dispatch:
inputs:
environment:
description: "Deployment environment"
required: true
default: "dev"
type: choice
options:
- dev
- staging
- production
skip_security_scan:
description: "Skip security scanning (not recommended)"
required: false
default: false
type: boolean
deploy_after_build:
description: "Deploy after building (for daily builds)"
required: false
default: false
type: boolean
# Daily automated builds at 2 AM UTC
schedule:
- cron: "0 2 * * *"
# Automatic deployment on code changes
push:
branches:
- main
- develop
# Define environment variables for the entire workflow
env:
PROJECT_NAME: rag-modulo-${{ inputs.environment || 'dev' }}
BACKEND_APP_NAME: ${{ vars.BACKEND_APP_NAME || 'rag-modulo-backend' }}
FRONTEND_APP_NAME: ${{ vars.FRONTEND_APP_NAME || 'rag-modulo-frontend' }}
IBM_CLOUD_REGION: ${{ vars.IBM_CLOUD_REGION || 'us-south' }}
CR_NAMESPACE: ${{ vars.IBM_CR_NAMESPACE || 'rag_modulo' }}
# ICR uses shortened region names: us-south -> us, eu-gb -> uk, ca-tor -> ca, etc.
ICR_REGION: ${{ vars.IBM_CLOUD_REGION == 'eu-gb' && 'uk' || (vars.IBM_CLOUD_REGION == 'us-south' && 'us' ||
(vars.IBM_CLOUD_REGION == 'us-east' && 'us' || (vars.IBM_CLOUD_REGION == 'ca-tor' && 'ca' ||
vars.IBM_CLOUD_REGION))) }}
# Prevent concurrent deployments to avoid conflicts
concurrency:
group: deploy-complete-app-${{ github.ref }}
cancel-in-progress: false
# =============================================================================
# WORKFLOW JOBS
# =============================================================================
jobs:
# ---------------------------------------------------------------------------
# Job 1: Deploy Infrastructure Components
# ---------------------------------------------------------------------------
# Purpose: Deploy core infrastructure services (PostgreSQL, MinIO, etcd, Milvus)
# Dependencies: None (runs first)
# Outputs: Infrastructure services ready for application deployment
# ---------------------------------------------------------------------------
deploy-infrastructure:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Ansible and dependencies
run: |
pip install ansible
ansible-galaxy collection install -r deployment/ansible/requirements.yml
- name: Set up IBM Cloud CLI
uses: IBM/actions-ibmcloud-cli@v1
with:
api_key: ${{ secrets.IBM_CLOUD_API_KEY }}
region: ${{ env.IBM_CLOUD_REGION }}
group: ${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}
plugins: code-engine
- name: Deploy Infrastructure using Ansible
env:
IBM_CLOUD_API_KEY: ${{ secrets.IBM_CLOUD_API_KEY }}
IBM_CLOUD_REGION: ${{ env.IBM_CLOUD_REGION }}
IBM_CLOUD_RESOURCE_GROUP: ${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}
COLLECTIONDB_USER: ${{ secrets.COLLECTIONDB_USER }}
COLLECTIONDB_PASS: ${{ secrets.COLLECTIONDB_PASS }}
COLLECTIONDB_NAME: ${{ secrets.COLLECTIONDB_NAME }}
MINIO_ROOT_USER: ${{ secrets.MINIO_ROOT_USER || 'minioadmin' }}
MINIO_ROOT_PASSWORD: ${{ secrets.MINIO_ROOT_PASSWORD || 'minioadmin' }}
run: |
# Create temporary inventory for infrastructure deployment
cat > /tmp/inventory.yml << EOF
all:
hosts:
localhost:
ansible_connection: local
ansible_python_interpreter: "{{ ansible_playbook_python }}"
vars:
project_name: "rag-modulo"
environment: "dev"
region: "${{ env.IBM_CLOUD_REGION }}"
resource_group_id: "${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}"
ibmcloud_api_key: "${{ secrets.IBM_CLOUD_API_KEY }}"
EOF
# Note: Full Ansible deployment will be implemented in next iteration
# For now, we'll use IBM Cloud CLI directly for infrastructure
echo "Deploying infrastructure components..."
ibmcloud login --apikey "$IBM_CLOUD_API_KEY" --no-region
ibmcloud target -r "$IBM_CLOUD_REGION" -g "$IBM_CLOUD_RESOURCE_GROUP"
# Create Code Engine project if it doesn't exist (idempotent)
# Check if project exists and handle soft-deleted state
if ibmcloud ce project get --name "$PROJECT_NAME" 2>&1 | grep -q "soft deleted"; then
echo "⚠️ Project '$PROJECT_NAME' is soft-deleted, creating new one with timestamp..."
NEW_PROJECT_NAME="${PROJECT_NAME}-$(date +%s)"
echo "🆕 Creating project '$NEW_PROJECT_NAME'..."
ibmcloud ce project create --name "$NEW_PROJECT_NAME"
ibmcloud ce project select --name "$NEW_PROJECT_NAME"
echo "PROJECT_NAME=$NEW_PROJECT_NAME" >> $GITHUB_ENV
elif ibmcloud ce project get --name "$PROJECT_NAME" &>/dev/null; then
echo "✅ Project '$PROJECT_NAME' exists - selecting..."
ibmcloud ce project select --name "$PROJECT_NAME"
else
echo "🆕 Creating project '$PROJECT_NAME'..."
ibmcloud ce project create --name "$PROJECT_NAME"
ibmcloud ce project select --name "$PROJECT_NAME"
fi
echo "Infrastructure deployment placeholder - will be enhanced with full Ansible playbook"
# ---------------------------------------------------------------------------
# Job 2: Build and Push Backend Application
# ---------------------------------------------------------------------------
# Purpose: Build Docker image for backend FastAPI application and push to registry
# Dependencies: deploy-infrastructure (must complete first)
# Outputs: Backend Docker image in IBM Cloud Container Registry
# Security: Multi-stage build, non-root user, CPU-only PyTorch
# ---------------------------------------------------------------------------
build-and-push-backend:
needs: deploy-infrastructure
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
security-events: write
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to IBM Cloud Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.ICR_REGION }}.icr.io
username: iamapikey
password: ${{ secrets.IBM_CLOUD_API_KEY }}
- name: Build and push backend Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.codeengine
platforms: linux/amd64
push: true
tags: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.BACKEND_APP_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-and-push-frontend:
needs: deploy-infrastructure
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
security-events: write
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to IBM Cloud Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.ICR_REGION }}.icr.io
username: iamapikey
password: ${{ secrets.IBM_CLOUD_API_KEY }}
- name: Build and push frontend Docker image
uses: docker/build-push-action@v6
with:
context: ./frontend
file: ./frontend/Dockerfile.frontend
platforms: linux/amd64
push: true
tags: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.FRONTEND_APP_NAME }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
security-scan-backend:
needs: build-and-push-backend
if: ${{ !inputs.skip_security_scan }}
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Run Trivy vulnerability scanner (Backend)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 pinned to SHA
with:
image-ref: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.BACKEND_APP_NAME }}:${{ github.sha }}
format: "sarif"
output: "trivy-backend-results.sarif"
- name: Upload Trivy scan results to GitHub Security tab (Backend)
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-backend-results.sarif"
- name: Run Trivy vulnerability scanner (Backend - Table)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 pinned to SHA
with:
image-ref: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.BACKEND_APP_NAME }}:${{ github.sha }}
format: "table"
exit-code: "1"
severity: "CRITICAL,HIGH"
security-scan-frontend:
needs: build-and-push-frontend
if: ${{ !inputs.skip_security_scan }}
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Run Trivy vulnerability scanner (Frontend)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 pinned to SHA
with:
image-ref: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.FRONTEND_APP_NAME }}:${{ github.sha }}
format: "sarif"
output: "trivy-frontend-results.sarif"
- name: Upload Trivy scan results to GitHub Security tab (Frontend)
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: "trivy-frontend-results.sarif"
- name: Run Trivy vulnerability scanner (Frontend - Table)
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 pinned to SHA
with:
image-ref: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.FRONTEND_APP_NAME }}:${{ github.sha }}
format: "table"
exit-code: "1"
severity: "CRITICAL,HIGH"
deploy-backend:
needs: [build-and-push-backend, security-scan-backend]
if: always() && (needs.security-scan-backend.result == 'success' || needs.security-scan-backend.result == 'skipped')
&& (github.event_name == 'workflow_dispatch' || github.event_name == 'push' || (github.event_name == 'schedule' &&
inputs.deploy_after_build == true))
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Set up IBM Cloud CLI
uses: IBM/actions-ibmcloud-cli@v1
with:
api_key: ${{ secrets.IBM_CLOUD_API_KEY }}
region: ${{ env.IBM_CLOUD_REGION }}
group: ${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}
plugins: code-engine
- name: Deploy Backend to Code Engine
env:
IBM_CLOUD_API_KEY: ${{ secrets.IBM_CLOUD_API_KEY }}
ICR_REGION: ${{ env.ICR_REGION }}
IMAGE_URL: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.BACKEND_APP_NAME }}:${{ github.sha }}
APP_NAME: ${{ env.BACKEND_APP_NAME }}
IBM_CLOUD_REGION: ${{ env.IBM_CLOUD_REGION }}
IBM_CLOUD_RESOURCE_GROUP: ${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}
SKIP_AUTH: ${{ secrets.SKIP_AUTH }}
OIDC_DISCOVERY_ENDPOINT: ${{ secrets.OIDC_DISCOVERY_ENDPOINT }}
IBM_CLIENT_ID: ${{ secrets.IBM_CLIENT_ID }}
IBM_CLIENT_SECRET: ${{ secrets.IBM_CLIENT_SECRET }}
FRONTEND_URL: ${{ secrets.FRONTEND_URL }}
WATSONX_APIKEY: ${{ secrets.WATSONX_APIKEY }}
WATSONX_INSTANCE_ID: ${{ secrets.WATSONX_INSTANCE_ID }}
COLLECTIONDB_USER: ${{ secrets.COLLECTIONDB_USER }}
COLLECTIONDB_PASS: ${{ secrets.COLLECTIONDB_PASS }}
COLLECTIONDB_HOST: rag-modulo-postgres
COLLECTIONDB_PORT: "5432"
COLLECTIONDB_NAME: ${{ secrets.COLLECTIONDB_NAME }}
VECTOR_DB: "milvus"
MILVUS_HOST: rag-modulo-milvus
MILVUS_PORT: "19530"
MILVUS_USER: ""
MILVUS_PASSWORD: ""
MINIO_ENDPOINT: rag-modulo-minio:9000
MINIO_ACCESS_KEY: ${{ secrets.MINIO_ROOT_USER || 'minioadmin' }}
MINIO_SECRET_KEY: ${{ secrets.MINIO_ROOT_PASSWORD || 'minioadmin' }}
MINIO_USE_SSL: "false"
JWT_SECRET_KEY: ${{ secrets.JWT_SECRET_KEY }}
LOG_LEVEL: "INFO"
run: |
echo "Deploying backend application..."
ibmcloud login --apikey "$IBM_CLOUD_API_KEY" --no-region
ibmcloud target -r "$IBM_CLOUD_REGION" -g "$IBM_CLOUD_RESOURCE_GROUP"
ibmcloud ce project select --name "$PROJECT_NAME"
# Create or update registry access secret
echo "Setting up registry access..."
if ibmcloud ce secret get --name icr-secret > /dev/null 2>&1; then
echo "Registry secret already exists"
else
echo "Creating registry access secret..."
ibmcloud ce secret create --name icr-secret \
--format registry \
--server ${ICR_REGION}.icr.io \
--username iamapikey \
--password "$IBM_CLOUD_API_KEY"
fi
# Deploy or update backend application
if ibmcloud ce app get "$APP_NAME" > /dev/null 2>&1; then
echo "Updating existing backend application..."
ibmcloud ce app update "$APP_NAME" \
--image "$IMAGE_URL" \
--registry-secret icr-secret \
--min-scale 1 \
--max-scale 5 \
--cpu 1 \
--memory 4G \
--env DATABASE_URL="postgresql://$COLLECTIONDB_USER:$COLLECTIONDB_PASS@$COLLECTIONDB_HOST:$COLLECTIONDB_PORT/$COLLECTIONDB_NAME?sslmode=require" \
--env MILVUS_HOST="$MILVUS_HOST" \
--env MILVUS_PORT="$MILVUS_PORT" \
--env MINIO_ENDPOINT="$MINIO_ENDPOINT" \
--env MINIO_ACCESS_KEY="$MINIO_ACCESS_KEY" \
--env MINIO_SECRET_KEY="$MINIO_SECRET_KEY" \
--env WATSONX_APIKEY="$WATSONX_APIKEY" \
--env WATSONX_INSTANCE_ID="$WATSONX_INSTANCE_ID" \
--env JWT_SECRET_KEY="$JWT_SECRET_KEY" \
--env LOG_LEVEL="$LOG_LEVEL" \
--env SKIP_AUTH="$SKIP_AUTH"
else
echo "Creating new backend application..."
ibmcloud ce app create --name "$APP_NAME" \
--image "$IMAGE_URL" \
--registry-secret icr-secret \
--min-scale 1 \
--max-scale 5 \
--cpu 1 \
--memory 4G \
--port 8000 \
--env DATABASE_URL="postgresql://$COLLECTIONDB_USER:$COLLECTIONDB_PASS@$COLLECTIONDB_HOST:$COLLECTIONDB_PORT/$COLLECTIONDB_NAME?sslmode=require" \
--env MILVUS_HOST="$MILVUS_HOST" \
--env MILVUS_PORT="$MILVUS_PORT" \
--env MINIO_ENDPOINT="$MINIO_ENDPOINT" \
--env MINIO_ACCESS_KEY="$MINIO_ACCESS_KEY" \
--env MINIO_SECRET_KEY="$MINIO_SECRET_KEY" \
--env WATSONX_APIKEY="$WATSONX_APIKEY" \
--env WATSONX_INSTANCE_ID="$WATSONX_INSTANCE_ID" \
--env JWT_SECRET_KEY="$JWT_SECRET_KEY" \
--env LOG_LEVEL="$LOG_LEVEL" \
--env SKIP_AUTH="$SKIP_AUTH"
fi
echo "Backend deployment complete!"
deploy-frontend:
needs: [build-and-push-frontend, security-scan-frontend]
if: always() && (needs.security-scan-frontend.result == 'success' || needs.security-scan-frontend.result ==
'skipped') && (github.event_name == 'workflow_dispatch' || github.event_name == 'push' || (github.event_name ==
'schedule' && inputs.deploy_after_build == true))
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Set up IBM Cloud CLI
uses: IBM/actions-ibmcloud-cli@v1
with:
api_key: ${{ secrets.IBM_CLOUD_API_KEY }}
region: ${{ env.IBM_CLOUD_REGION }}
group: ${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}
plugins: code-engine
- name: Deploy Frontend to Code Engine
env:
IBM_CLOUD_API_KEY: ${{ secrets.IBM_CLOUD_API_KEY }}
ICR_REGION: ${{ env.ICR_REGION }}
IMAGE_URL: ${{ env.ICR_REGION }}.icr.io/${{ env.CR_NAMESPACE }}/${{ env.FRONTEND_APP_NAME }}:${{ github.sha }}
APP_NAME: ${{ env.FRONTEND_APP_NAME }}
IBM_CLOUD_REGION: ${{ env.IBM_CLOUD_REGION }}
IBM_CLOUD_RESOURCE_GROUP: ${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}
REACT_APP_API_URL: ${{ secrets.REACT_APP_API_URL }}
REACT_APP_WS_URL: ${{ secrets.REACT_APP_WS_URL }}
run: |
echo "Deploying frontend application..."
ibmcloud login --apikey "$IBM_CLOUD_API_KEY" --no-region
ibmcloud target -r "$IBM_CLOUD_REGION" -g "$IBM_CLOUD_RESOURCE_GROUP"
ibmcloud ce project select --name "$PROJECT_NAME"
# Create or update registry access secret (if not already created by backend)
echo "Setting up registry access..."
if ibmcloud ce secret get --name icr-secret > /dev/null 2>&1; then
echo "Registry secret already exists"
else
echo "Creating registry access secret..."
ibmcloud ce secret create --name icr-secret \
--format registry \
--server ${ICR_REGION}.icr.io \
--username iamapikey \
--password "$IBM_CLOUD_API_KEY"
fi
# Deploy or update frontend application
if ibmcloud ce app get "$APP_NAME" > /dev/null 2>&1; then
echo "Updating existing frontend application..."
ibmcloud ce app update "$APP_NAME" \
--image "$IMAGE_URL" \
--registry-secret icr-secret \
--min-scale 1 \
--max-scale 3 \
--cpu 0.5 \
--memory 1G \
--env REACT_APP_API_URL="$REACT_APP_API_URL" \
--env REACT_APP_WS_URL="$REACT_APP_WS_URL"
else
echo "Creating new frontend application..."
ibmcloud ce app create --name "$APP_NAME" \
--image "$IMAGE_URL" \
--registry-secret icr-secret \
--min-scale 1 \
--max-scale 3 \
--cpu 0.5 \
--memory 1G \
--port 3000 \
--env REACT_APP_API_URL="$REACT_APP_API_URL" \
--env REACT_APP_WS_URL="$REACT_APP_WS_URL"
fi
echo "Frontend deployment complete!"
smoke-test:
needs: [deploy-backend, deploy-frontend]
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v5
- name: Set up IBM Cloud CLI
uses: IBM/actions-ibmcloud-cli@v1
with:
api_key: ${{ secrets.IBM_CLOUD_API_KEY }}
region: ${{ env.IBM_CLOUD_REGION }}
group: ${{ vars.IBM_CLOUD_RESOURCE_GROUP || 'rag-modulo-deployment' }}
plugins: code-engine
- name: Test Backend Health
run: |
BACKEND_URL=$(ibmcloud ce app get --name "${{ env.BACKEND_APP_NAME }}" --output json | jq -r '.status.url' | head -1)
if [ -n "$BACKEND_URL" ]; then
echo "Testing backend at: $BACKEND_URL/health"
if curl -f -s "$BACKEND_URL/health" > /dev/null; then
echo "✅ Backend health check passed"
else
echo "❌ Backend health check failed"
exit 1
fi
else
echo "❌ Could not determine backend URL"
exit 1
fi
- name: Test Frontend Health
run: |
FRONTEND_URL=$(ibmcloud ce app get --name "${{ env.FRONTEND_APP_NAME }}" --output json | jq -r '.status.url' | head -1)
if [ -n "$FRONTEND_URL" ]; then
echo "Testing frontend at: $FRONTEND_URL"
if curl -f -s "$FRONTEND_URL" > /dev/null; then
echo "✅ Frontend health check passed"
else
echo "❌ Frontend health check failed"
exit 1
fi
else
echo "❌ Could not determine frontend URL"
exit 1
fi
- name: Test Application Integration
run: |
BACKEND_URL=$(ibmcloud ce app get --name "${{ env.BACKEND_APP_NAME }}" --output json | jq -r '.status.url' | head -1)
FRONTEND_URL=$(ibmcloud ce app get --name "${{ env.FRONTEND_APP_NAME }}" --output json | jq -r '.status.url' | head -1)
echo "✅ Complete application deployed successfully!"
echo "Backend URL: $BACKEND_URL"
echo "Frontend URL: $FRONTEND_URL"
echo "Application is ready for use!"