feat: add unified install.sh and enhance self-healing in run.sh
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
APP_NAME="Biiproject Kit"
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_TIMEZONE=UTC
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
|
||||||
|
APP_PORT=8000
|
||||||
|
VITE_PORT=5173
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=pgsql
|
||||||
|
DB_HOST=pgsql
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_DATABASE=biiskit
|
||||||
|
DB_USERNAME=sail
|
||||||
|
DB_PASSWORD=password
|
||||||
|
FORWARD_DB_PORT=5432
|
||||||
|
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=log
|
||||||
|
FILESYSTEM_DISK=public
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
CACHE_STORE=redis
|
||||||
|
CACHE_PREFIX=bii_kit_
|
||||||
|
|
||||||
|
REDIS_CLIENT=phpredis
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
FORWARD_REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_HOST=127.0.0.1
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@biiproject.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
# OAuth (Passport)
|
||||||
|
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=
|
||||||
|
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=
|
||||||
Executable
+163
@@ -0,0 +1,163 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# --- Color Definitions for Premium Look ---
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
WHITE='\033[1;37m'
|
||||||
|
BOLD='\033[1m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${CYAN}======================================================${NC}"
|
||||||
|
echo -e "${GREEN}${BOLD} ⚡ Biiproject Kit v2 — Professional Installer ⚡ ${NC}"
|
||||||
|
echo -e "${CYAN}======================================================${NC}"
|
||||||
|
|
||||||
|
# 1. Pre-flight Checks (Docker & Daemon status)
|
||||||
|
echo -e "${CYAN}[1/7] Verifying Docker environment...${NC}"
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
echo -e " ${RED}❌ Error: Docker is not installed on this system.${NC}"
|
||||||
|
echo -e " ${YELLOW}👉 Please install Docker before running the installer.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! docker info &> /dev/null; then
|
||||||
|
echo -e " ${RED}❌ Error: Docker daemon is not running.${NC}"
|
||||||
|
echo -e " ${YELLOW}👉 Please start Docker Desktop or the Docker service and try again.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo -e " ${GREEN}✔ Docker is installed and running perfectly.${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 2. Check and Create Environment File (.env)
|
||||||
|
echo -e "${CYAN}[2/7] Preparing configuration environment (.env)...${NC}"
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
if [ -f .env.example ]; then
|
||||||
|
cp .env.example .env
|
||||||
|
echo -e " ${GREEN}✔ Created .env from .env.example template.${NC}"
|
||||||
|
else
|
||||||
|
echo -e " ${RED}❌ Error: .env.example template is missing!${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e " ${GREEN}✔ Configuration file .env is already present.${NC}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 3. Clean up conflicting containers
|
||||||
|
echo -e "${CYAN}[3/7] Cleaning up existing container conflicts...${NC}"
|
||||||
|
# Safely stop and remove containers by name to prevent conflict issues on port mapping
|
||||||
|
CONFLICT_CONTAINERS=("bii-kit-web" "bii-kit-pgsql" "bii-kit-redis")
|
||||||
|
for container in "${CONFLICT_CONTAINERS[@]}"; do
|
||||||
|
if [ ! -z "$(docker ps -a -q -f name=^/${container}$ 2>/dev/null)" ]; then
|
||||||
|
echo -ne " ${YELLOW}Removing old container $container...${NC}"
|
||||||
|
docker rm -f "$container" &>/dev/null
|
||||||
|
echo -e "\r ${GREEN}✔ Container $container successfully cleared. ${NC}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo -e " ${GREEN}✔ Conflict scanning complete.${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 4. Zero-Dependency Host Bootstrapping: Composer Install
|
||||||
|
echo -e "${CYAN}[4/7] Installing PHP dependencies via Composer...${NC}"
|
||||||
|
echo -e " ${YELLOW}⚙ Bootstrapping Composer packages inside lightweight PHP container...${NC}"
|
||||||
|
docker run --rm \
|
||||||
|
-u "$(id -u):$(id -g)" \
|
||||||
|
-v "$(pwd):/var/www/html" \
|
||||||
|
-w /var/www/html \
|
||||||
|
laravelsail/php83-composer:latest \
|
||||||
|
composer install --ignore-platform-reqs
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e " ${RED}❌ Error: Composer dependency installation failed.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo -e " ${GREEN}✔ Composer dependencies successfully installed.${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 5. Booting Docker Services for DB Migration
|
||||||
|
echo -e "${CYAN}[5/7] Spin up database & Redis services...${NC}"
|
||||||
|
docker compose up pgsql redis -d
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e " ${RED}❌ Error: Failed to boot Postgres & Redis services.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DB_CONTAINER="bii-kit-pgsql"
|
||||||
|
echo -ne " ${YELLOW}Waiting for PostgreSQL ($DB_CONTAINER) to become healthy...${NC}"
|
||||||
|
RETRIES=0
|
||||||
|
MAX_RETRIES=40
|
||||||
|
while [ $RETRIES -lt $MAX_RETRIES ]; do
|
||||||
|
STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$DB_CONTAINER" 2>/dev/null)
|
||||||
|
if [ "$STATUS" = "healthy" ]; then
|
||||||
|
echo -e "\r ${GREEN}✔ PostgreSQL is healthy and ready to accept connections! ${NC}"
|
||||||
|
break
|
||||||
|
elif [ "$STATUS" = "unhealthy" ]; then
|
||||||
|
echo -e "\r ${RED}⚠ PostgreSQL health check failed. Proceeding anyway...${NC}"
|
||||||
|
break
|
||||||
|
elif [ -z "$STATUS" ]; then
|
||||||
|
RUNNING=$(docker inspect --format='{{.State.Running}}' "$DB_CONTAINER" 2>/dev/null)
|
||||||
|
if [ "$RUNNING" = "true" ]; then
|
||||||
|
echo -e "\r ${GREEN}✔ PostgreSQL container is running. ${NC}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo -n "."
|
||||||
|
sleep 1.5
|
||||||
|
RETRIES=$((RETRIES + 1))
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 6. Initialize Database & Application Keys
|
||||||
|
echo -e "${CYAN}[6/7] Initializing keys and database seeds...${NC}"
|
||||||
|
|
||||||
|
# Start sails application container in background temporarily to execute artisan commands
|
||||||
|
docker compose up laravel.test -d
|
||||||
|
|
||||||
|
# Secure directories owner & permissions
|
||||||
|
echo -e " ${YELLOW}Securing workspace file permissions...${NC}"
|
||||||
|
docker compose exec -u root laravel.test chown -R sail:sail /var/www/html/storage /var/www/html/bootstrap/cache 2>/dev/null
|
||||||
|
docker compose exec -u root laravel.test chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache 2>/dev/null
|
||||||
|
|
||||||
|
# Generate APP_KEY
|
||||||
|
APP_KEY_VAL=$(grep "^APP_KEY=" .env | cut -d'=' -f2- | tr -d '"'\''')
|
||||||
|
if [ -z "$APP_KEY_VAL" ] || [ "$APP_KEY_VAL" = "base64:" ] || [ "$APP_KEY_VAL" = "SomeRandomString" ]; then
|
||||||
|
echo -e " ${YELLOW}⚙ Generating application encryption key...${NC}"
|
||||||
|
docker compose exec -u sail laravel.test php artisan key:generate
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run migrations and seeders
|
||||||
|
echo -e " ${YELLOW}⚙ Initializing database schemas & Spatie RBAC tables...${NC}"
|
||||||
|
docker compose exec -u sail laravel.test php artisan migrate:fresh --seed
|
||||||
|
|
||||||
|
# Generate Passport OAuth2 Keys
|
||||||
|
echo -e " ${YELLOW}⚙ Creating Passport OAuth2 server authentication client keys...${NC}"
|
||||||
|
docker compose exec -u sail laravel.test php artisan passport:keys --force
|
||||||
|
docker compose exec -u sail laravel.test php artisan passport:client --personal --no-interaction
|
||||||
|
echo -e " ${GREEN}✔ Database and keys successfully initialized.${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 7. Compiling Frontend assets
|
||||||
|
echo -e "${CYAN}[7/7] Installing and compiling React Frontend...${NC}"
|
||||||
|
echo -e " ${YELLOW}⚙ Installing Node modules (NPM)...${NC}"
|
||||||
|
docker compose exec -u sail laravel.test npm install
|
||||||
|
|
||||||
|
echo -e " ${YELLOW}⚙ Compiling production web bundles (Vite)...${NC}"
|
||||||
|
docker compose exec -u sail laravel.test npm run build
|
||||||
|
|
||||||
|
# Storage Symlink
|
||||||
|
docker compose exec -u sail laravel.test php artisan storage:link &>/dev/null
|
||||||
|
|
||||||
|
# Final permission secure
|
||||||
|
docker compose exec -u root laravel.test chown -R sail:sail /var/www/html/node_modules /var/www/html/package-lock.json 2>/dev/null
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}=================================================================${NC}"
|
||||||
|
echo -e " 🎉 ${GREEN}${BOLD}Installation Complete! biiproject-kit v2 is ready!${NC} 🎉"
|
||||||
|
echo -e "${CYAN}=================================================================${NC}"
|
||||||
|
echo -e " ${WHITE}You can now run the application stack anytime by executing:${NC}"
|
||||||
|
echo -e " 👉 ${GREEN}${BOLD}./run.sh${NC}"
|
||||||
|
echo -e "${CYAN}=================================================================${NC}"
|
||||||
|
echo ""
|
||||||
@@ -6,40 +6,32 @@ BLUE='\033[0;34m'
|
|||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
CYAN='\033[0;36m'
|
CYAN='\033[0;36m'
|
||||||
MAGENTA='\033[0;35m'
|
|
||||||
WHITE='\033[1;37m'
|
WHITE='\033[1;37m'
|
||||||
BOLD='\033[1m'
|
BOLD='\033[1m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
echo -e "${CYAN}======================================================${NC}"
|
echo -e "${CYAN}======================================================${NC}"
|
||||||
echo -e "${GREEN}${BOLD} 🐳 Biiproject Kit — Fully Containerized Setup 🐳 ${NC}"
|
echo -e "${GREEN}${BOLD} 🐳 Biiproject Kit v2 — Docker Runtime Engine 🐳 ${NC}"
|
||||||
echo -e "${CYAN}======================================================${NC}"
|
echo -e "${CYAN}======================================================${NC}"
|
||||||
|
|
||||||
# 1. Pre-flight Checks (Docker & Daemon status)
|
# 1. Pre-flight Checks
|
||||||
echo -e "${CYAN}[1/8] Checking Docker & system environment...${NC}"
|
echo -e "${CYAN}[1/6] Checking system environment...${NC}"
|
||||||
if ! command -v docker &> /dev/null; then
|
if ! command -v docker &> /dev/null; then
|
||||||
echo -e " ${RED}❌ Error: Docker is not installed on this system.${NC}"
|
echo -e " ${RED}❌ Error: Docker is not installed on this system.${NC}"
|
||||||
echo -e " ${YELLOW}👉 Please install Docker and Docker Compose before running this script.${NC}"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! docker info &> /dev/null; then
|
if ! docker info &> /dev/null; then
|
||||||
echo -e " ${RED}❌ Error: Docker daemon is not running.${NC}"
|
echo -e " ${RED}❌ Error: Docker daemon is not running.${NC}"
|
||||||
echo -e " ${YELLOW}👉 Please start your Docker service/desktop and try again.${NC}"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo -e " ${GREEN}✔ Docker is installed and running perfectly.${NC}"
|
echo -e " ${GREEN}✔ Docker is installed and running perfectly.${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 2. Prevent Port & Container conflicts
|
# 2. Port & Container Conflicts Resolution (Self-Healing)
|
||||||
echo -e "${CYAN}[2/8] Checking for port conflicts...${NC}"
|
echo -e "${CYAN}[2/6] Preventing port and container name conflicts...${NC}"
|
||||||
|
|
||||||
# Ensure .env is present to parse ports
|
# Resolve ports dynamically
|
||||||
if [ ! -f .env ] && [ -f .env.example ]; then
|
|
||||||
cp .env.example .env
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Resolve ports dynamically from .env or defaults
|
|
||||||
PORT_8000=$(grep "^APP_PORT=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"'\''')
|
PORT_8000=$(grep "^APP_PORT=" .env 2>/dev/null | cut -d'=' -f2- | tr -d '"'\''')
|
||||||
PORT_8000=${PORT_8000:-8000}
|
PORT_8000=${PORT_8000:-8000}
|
||||||
|
|
||||||
@@ -49,111 +41,49 @@ PORT_5432=${PORT_5432:-5432}
|
|||||||
PORT_6379=$(grep -E "^(FORWARD_REDIS_PORT|REDIS_PORT)=" .env 2>/dev/null | head -n1 | cut -d'=' -f2- | tr -d '"'\''')
|
PORT_6379=$(grep -E "^(FORWARD_REDIS_PORT|REDIS_PORT)=" .env 2>/dev/null | head -n1 | cut -d'=' -f2- | tr -d '"'\''')
|
||||||
PORT_6379=${PORT_6379:-6379}
|
PORT_6379=${PORT_6379:-6379}
|
||||||
|
|
||||||
# Stop local processes using these ports
|
# Kill local system processes occupying these ports
|
||||||
if command -v lsof &>/dev/null && command -v fuser &>/dev/null; then
|
if command -v lsof &>/dev/null && command -v fuser &>/dev/null; then
|
||||||
for port in "$PORT_8000" "$PORT_5432" "$PORT_6379"; do
|
for port in "$PORT_8000" "$PORT_5432" "$PORT_6379"; do
|
||||||
if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null ; then
|
if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null ; then
|
||||||
echo -e "${YELLOW}⚠ Port $port is occupied by a local process. Releasing it...${NC}"
|
echo -e " ${YELLOW}⚠ Port $port is occupied locally. Freeing up port $port...${NC}"
|
||||||
fuser -k $port/tcp 2>/dev/null
|
fuser -k $port/tcp 2>/dev/null
|
||||||
sleep 1
|
sleep 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Find the container names from our own docker-compose.yml to avoid stopping ourselves
|
# Scan and remove conflicting stopped containers with same names
|
||||||
MY_CONTAINERS=$(grep "container_name:" docker-compose.yml 2>/dev/null | awk '{print $2}' | tr -d '"'\''')
|
CONFLICT_CONTAINERS=("bii-kit-web" "bii-kit-pgsql" "bii-kit-redis")
|
||||||
|
for container in "${CONFLICT_CONTAINERS[@]}"; do
|
||||||
stop_conflict_on_port() {
|
if [ ! -z "$(docker ps -a -q -f name=^/${container}$ 2>/dev/null)" ]; then
|
||||||
local port=$1
|
# Check if container is running
|
||||||
local port_type=$2
|
if [ ! -z "$(docker ps -q -f name=^/${container}$ 2>/dev/null)" ]; then
|
||||||
|
echo -ne " ${YELLOW}Stopping conflicting running container: $container...${NC}"
|
||||||
local conflicting_container=$(docker ps --filter "publish=$port" --format "{{.Names}}" 2>/dev/null)
|
docker stop "$container" &>/dev/null
|
||||||
if [ ! -z "$conflicting_container" ]; then
|
fi
|
||||||
local is_ours=false
|
echo -ne " ${YELLOW}Removing conflicting container $container to avoid duplication...${NC}"
|
||||||
for ours in $MY_CONTAINERS; do
|
docker rm -f "$container" &>/dev/null
|
||||||
if [ "$conflicting_container" = "$ours" ]; then
|
echo -e "\r ${GREEN}✔ Cleared conflicting container: $container. ${NC}"
|
||||||
is_ours=true
|
|
||||||
break
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
echo -e " ${GREEN}✔ Environment conflicts resolved successfully.${NC}"
|
||||||
if [ "$is_ours" = "false" ]; then
|
|
||||||
echo -e "${YELLOW}⚠ Port $port ($port_type) is occupied by container '$conflicting_container'. Stopping conflict...${NC}"
|
|
||||||
docker stop "$conflicting_container" &>/dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_conflict_on_port "$PORT_8000" "Web Server"
|
|
||||||
stop_conflict_on_port "$PORT_5432" "PostgreSQL Database"
|
|
||||||
stop_conflict_on_port "$PORT_6379" "Redis Cache"
|
|
||||||
echo -e " ${GREEN}✔ Ports $PORT_8000 (Web), $PORT_5432 (Postgres), and $PORT_6379 (Redis) are clear and ready.${NC}"
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 3. Environment File (.env) check
|
# 3. Booting Docker Compose Stack
|
||||||
echo -e "${CYAN}[3/8] Verifying configuration environment (.env)...${NC}"
|
echo -e "${CYAN}[3/6] Starting application containers...${NC}"
|
||||||
if [ ! -f .env ]; then
|
|
||||||
echo -e " ${YELLOW}⚠ .env file not found. Creating from template (.env.example)...${NC}"
|
|
||||||
cp .env.example .env
|
|
||||||
ENV_CREATED=true
|
|
||||||
else
|
|
||||||
echo -e " ${GREEN}✔ Environment configuration file (.env) is present.${NC}"
|
|
||||||
ENV_CREATED=false
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 4. Install Composer dependencies (Zero-Dependency Host)
|
|
||||||
echo -e "${CYAN}[4/8] Checking backend dependencies (Composer)...${NC}"
|
|
||||||
if [ ! -d vendor ]; then
|
|
||||||
echo -e " ${YELLOW}⚠ Vendor directory not found. Installing via lightweight PHP container...${NC}"
|
|
||||||
docker run --rm \
|
|
||||||
-u "$(id -u):$(id -g)" \
|
|
||||||
-v "$(pwd):/var/www/html" \
|
|
||||||
-w /var/www/html \
|
|
||||||
laravelsail/php83-composer:latest \
|
|
||||||
composer install --ignore-platform-reqs
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo -e " ${RED}❌ Error: Failed to install composer dependencies via Docker.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo -e " ${GREEN}✔ Composer dependencies successfully installed.${NC}"
|
|
||||||
else
|
|
||||||
echo -e " ${GREEN}✔ Composer dependencies are up to date.${NC}"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 5. Start Docker Compose stack
|
|
||||||
echo -e "${CYAN}[5/8] Booting up Docker Compose containers...${NC}"
|
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo -e " ${RED}❌ Error: Failed to start Docker containers. Please check docker-compose.yml.${NC}"
|
echo -e " ${RED}❌ Error: Failed to start containers. Try running: docker compose down && docker compose up -d${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo -e " ${GREEN}✔ Docker Compose services booted successfully.${NC}"
|
echo -e " ${GREEN}✔ Containers booted successfully.${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Resolve DB container dynamically
|
# 4. Service Health Check & Permissions Correction
|
||||||
DB_CONTAINER=$(docker compose ps --format "{{.Name}}" pgsql 2>/dev/null)
|
echo -e "${CYAN}[4/6] Waiting for database health & setting permissions...${NC}"
|
||||||
if [ -z "$DB_CONTAINER" ]; then
|
|
||||||
DB_CONTAINER=$(grep -A 10 -E "^ pgsql:" docker-compose.yml 2>/dev/null | grep "container_name:" | head -n1 | awk '{print $2}' | tr -d '"'\''')
|
|
||||||
fi
|
|
||||||
if [ -z "$DB_CONTAINER" ]; then
|
|
||||||
DB_CONTAINER="bii-kit-pgsql"
|
DB_CONTAINER="bii-kit-pgsql"
|
||||||
fi
|
|
||||||
|
|
||||||
# Resolve Redis container dynamically
|
|
||||||
REDIS_CONTAINER=$(docker compose ps --format "{{.Name}}" redis 2>/dev/null)
|
|
||||||
if [ -z "$REDIS_CONTAINER" ]; then
|
|
||||||
REDIS_CONTAINER=$(grep -A 10 -E "^ redis:" docker-compose.yml 2>/dev/null | grep "container_name:" | head -n1 | awk '{print $2}' | tr -d '"'\''')
|
|
||||||
fi
|
|
||||||
if [ -z "$REDIS_CONTAINER" ]; then
|
|
||||||
REDIS_CONTAINER="bii-kit-redis"
|
REDIS_CONTAINER="bii-kit-redis"
|
||||||
fi
|
|
||||||
|
|
||||||
# 6. Wait for Databases to be ready (Self-Healing)
|
|
||||||
echo -e "${CYAN}[6/8] Waiting for services to be ready & configuring permissions...${NC}"
|
|
||||||
|
|
||||||
echo -ne " ${YELLOW}Checking PostgreSQL database ($DB_CONTAINER)...${NC}"
|
echo -ne " ${YELLOW}Checking PostgreSQL database ($DB_CONTAINER)...${NC}"
|
||||||
RETRIES=0
|
RETRIES=0
|
||||||
@@ -164,13 +94,12 @@ while [ $RETRIES -lt $MAX_RETRIES ]; do
|
|||||||
echo -e "\r ${GREEN}✔ PostgreSQL is healthy and ready to accept connections! ${NC}"
|
echo -e "\r ${GREEN}✔ PostgreSQL is healthy and ready to accept connections! ${NC}"
|
||||||
break
|
break
|
||||||
elif [ "$STATUS" = "unhealthy" ]; then
|
elif [ "$STATUS" = "unhealthy" ]; then
|
||||||
echo -e "\r ${RED}⚠ PostgreSQL health check reported unhealthy. Proceeding anyway...${NC}"
|
echo -e "\r ${RED}⚠ PostgreSQL health check failed. Proceeding... ${NC}"
|
||||||
break
|
break
|
||||||
elif [ -z "$STATUS" ]; then
|
elif [ -z "$STATUS" ]; then
|
||||||
# Check if container is at least running
|
|
||||||
RUNNING=$(docker inspect --format='{{.State.Running}}' "$DB_CONTAINER" 2>/dev/null)
|
RUNNING=$(docker inspect --format='{{.State.Running}}' "$DB_CONTAINER" 2>/dev/null)
|
||||||
if [ "$RUNNING" = "true" ]; then
|
if [ "$RUNNING" = "true" ]; then
|
||||||
echo -e "\r ${GREEN}✔ PostgreSQL container is running (no healthcheck status). ${NC}"
|
echo -e "\r ${GREEN}✔ PostgreSQL is running (no healthcheck defined). ${NC}"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -184,16 +113,12 @@ RETRIES=0
|
|||||||
while [ $RETRIES -lt $MAX_RETRIES ]; do
|
while [ $RETRIES -lt $MAX_RETRIES ]; do
|
||||||
STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$REDIS_CONTAINER" 2>/dev/null)
|
STATUS=$(docker inspect --format='{{.State.Health.Status}}' "$REDIS_CONTAINER" 2>/dev/null)
|
||||||
if [ "$STATUS" = "healthy" ]; then
|
if [ "$STATUS" = "healthy" ]; then
|
||||||
echo -e "\r ${GREEN}✔ Redis is healthy and ready to accept connections! ${NC}"
|
echo -e "\r ${GREEN}✔ Redis is healthy and ready! ${NC}"
|
||||||
break
|
|
||||||
elif [ "$STATUS" = "unhealthy" ]; then
|
|
||||||
echo -e "\r ${RED}⚠ Redis health check reported unhealthy. Proceeding anyway...${NC}"
|
|
||||||
break
|
break
|
||||||
elif [ -z "$STATUS" ]; then
|
elif [ -z "$STATUS" ]; then
|
||||||
# Check if container is at least running
|
|
||||||
RUNNING=$(docker inspect --format='{{.State.Running}}' "$REDIS_CONTAINER" 2>/dev/null)
|
RUNNING=$(docker inspect --format='{{.State.Running}}' "$REDIS_CONTAINER" 2>/dev/null)
|
||||||
if [ "$RUNNING" = "true" ]; then
|
if [ "$RUNNING" = "true" ]; then
|
||||||
echo -e "\r ${GREEN}✔ Redis container is running (no healthcheck status). ${NC}"
|
echo -e "\r ${GREEN}✔ Redis is running. ${NC}"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -202,87 +127,43 @@ while [ $RETRIES -lt $MAX_RETRIES ]; do
|
|||||||
RETRIES=$((RETRIES + 1))
|
RETRIES=$((RETRIES + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
# Extra sleep to ensure Docker internal DNS has fully propagated the container names
|
# Extra sleep for container initialization
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# Correct any permission issues on build and storage folders before continuing
|
# Writable directories permission fix
|
||||||
echo -ne " ${YELLOW}Securing workspace file permissions...${NC}"
|
|
||||||
docker compose exec -u root laravel.test chown -R sail:sail /var/www/html/storage /var/www/html/bootstrap/cache 2>/dev/null
|
docker compose exec -u root laravel.test chown -R sail:sail /var/www/html/storage /var/www/html/bootstrap/cache 2>/dev/null
|
||||||
docker compose exec -u root laravel.test chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache 2>/dev/null
|
docker compose exec -u root laravel.test chmod -R 775 /var/www/html/storage /var/www/html/bootstrap/cache 2>/dev/null
|
||||||
if [ -d public/build ]; then
|
echo -e " ${GREEN}✔ Folder write permissions secured.${NC}"
|
||||||
docker compose exec -u root laravel.test chown -R sail:sail /var/www/html/public/build 2>/dev/null
|
|
||||||
docker compose exec -u root laravel.test chmod -R 775 /var/www/html/public/build 2>/dev/null
|
|
||||||
fi
|
|
||||||
echo -e "\r ${GREEN}✔ Workspace file permissions secured. ${NC}"
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 7. Securing Application & Database Initialization
|
# 5. Database Migration Sync
|
||||||
echo -e "${CYAN}[7/8] Securely initializing application database & keys...${NC}"
|
echo -e "${CYAN}[5/6] Checking for pending database migrations...${NC}"
|
||||||
|
|
||||||
# Check for empty key
|
|
||||||
APP_KEY_VAL=$(grep "^APP_KEY=" .env | cut -d'=' -f2- | tr -d '"'\''')
|
|
||||||
if [ -z "$APP_KEY_VAL" ] || [ "$APP_KEY_VAL" = "base64:" ] || [ "$APP_KEY_VAL" = "SomeRandomString" ]; then
|
|
||||||
echo -e " ${YELLOW}⚙ Generating unique application encryption key...${NC}"
|
|
||||||
docker compose exec -u sail laravel.test php artisan key:generate
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if tables exist to decide fresh migrate & seed or regular migrate
|
|
||||||
TABLE_EXISTS=$(docker compose exec -u sail laravel.test php artisan tinker --execute="echo Schema::hasTable('users') ? 'yes' : 'no';" 2>/dev/null | tr -d '\r\n')
|
|
||||||
|
|
||||||
if [ "$TABLE_EXISTS" != "yes" ]; then
|
|
||||||
echo -e " ${YELLOW}⚙ Database is uninitialized. Running migrations & seeding default accounts...${NC}"
|
|
||||||
docker compose exec -u sail laravel.test php artisan migrate:fresh --seed
|
|
||||||
else
|
|
||||||
USER_COUNT=$(docker compose exec -u sail laravel.test php artisan tinker --execute="echo App\Models\User::count();" 2>/dev/null | tr -d '\r\n')
|
|
||||||
if [[ -z "$USER_COUNT" || "$USER_COUNT" == "0" ]]; then
|
|
||||||
echo -e " ${YELLOW}⚙ Database has tables but no records. Seeding default accounts...${NC}"
|
|
||||||
docker compose exec -u sail laravel.test php artisan db:seed
|
|
||||||
else
|
|
||||||
echo -e " ${GREEN}✔ Database already initialized with $USER_COUNT users. Running pending migrations...${NC}"
|
|
||||||
docker compose exec -u sail laravel.test php artisan migrate
|
docker compose exec -u sail laravel.test php artisan migrate
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 8. Frontend Assets (NPM dependencies and dev server)
|
# 6. Booting Live-reload Dev Server
|
||||||
echo -e "${CYAN}[8/8] Preparing frontend assets & live-reload server...${NC}"
|
echo -e "${CYAN}[6/6] Launching React Vite dev server...${NC}"
|
||||||
if [ ! -d node_modules ]; then
|
# Stop any duplicate background dev servers inside container
|
||||||
echo -e " ${YELLOW}⚙ Node modules not found. Installing NPM packages inside container...${NC}"
|
docker compose exec -u sail laravel.test pkill -f "vite" &>/dev/null
|
||||||
docker compose exec -u sail laravel.test npm install
|
|
||||||
else
|
|
||||||
echo -e " ${GREEN}✔ Node dependencies are already present.${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure storage symlink exists
|
# Start Vite server in detached mode
|
||||||
docker compose exec -u sail laravel.test php artisan storage:link &>/dev/null
|
|
||||||
|
|
||||||
# Clean up permissions again in case npm install created any root-owned folders
|
|
||||||
docker compose exec -u root laravel.test chown -R sail:sail /var/www/html/node_modules /var/www/html/package-lock.json 2>/dev/null
|
|
||||||
|
|
||||||
# Build production assets first to ensure page loads immediately
|
|
||||||
echo -e " ${YELLOW}⚙ Compiling frontend production assets (Vite)...${NC}"
|
|
||||||
docker compose exec -u sail laravel.test npm run build
|
|
||||||
|
|
||||||
# Start Vite live-reload server in background
|
|
||||||
echo -e " ${GREEN}✔ Production assets compiled. Launching Vite live-reload server in background...${NC}"
|
|
||||||
docker compose exec -d -u sail laravel.test npm run dev
|
docker compose exec -d -u sail laravel.test npm run dev
|
||||||
|
echo -e " ${GREEN}✔ Vite live-reload dev server launched in background.${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Retrieve ports for display
|
# Final Premium Screen Info
|
||||||
PORT_8000=$(grep "^APP_PORT=" .env | cut -d'=' -f2- | tr -d '"'\''')
|
|
||||||
PORT_8000=${PORT_8000:-8000}
|
|
||||||
|
|
||||||
echo -e "${CYAN}=========================================================${NC}"
|
echo -e "${CYAN}=========================================================${NC}"
|
||||||
echo -e " 🎉 ${GREEN}${BOLD}Biiproject Kit is running fully in Docker!${NC} 🎉"
|
echo -e " 🎉 ${GREEN}${BOLD}Biiproject Kit v2 is running successfully!${NC} 🎉"
|
||||||
echo -e "${CYAN}=========================================================${NC}"
|
echo -e "${CYAN}=========================================================${NC}"
|
||||||
echo -e " 🚀 ${WHITE}${BOLD}Web Application:${NC} ${GREEN}http://localhost:${PORT_8000}${NC}"
|
echo -e " 🚀 ${WHITE}${BOLD}Web Application:${NC} ${GREEN}http://localhost:${PORT_8000}${NC}"
|
||||||
echo -e " 📋 ${WHITE}${BOLD}Activity Telemetry:${NC} ${GREEN}http://localhost:${PORT_8000}/activity-logs${NC}"
|
echo -e " 📋 ${WHITE}${BOLD}Activity Telemetry:${NC} ${GREEN}http://localhost:${PORT_8000}/activity-logs${NC}"
|
||||||
echo -e " 📖 ${WHITE}${BOLD}Documentation Hub:${NC} ${GREEN}http://localhost:${PORT_8000}/documentation${NC}"
|
echo -e " 📖 ${WHITE}${BOLD}Documentation Hub:${NC} ${GREEN}http://localhost:${PORT_8000}/documentation${NC}"
|
||||||
echo -e " 🐘 ${WHITE}${BOLD}Database Port (Postgres):${NC} ${YELLOW}5432${NC}"
|
echo -e " 🐘 ${WHITE}${BOLD}Postgres Port:${NC} ${YELLOW}${PORT_5432}${NC}"
|
||||||
echo -e " 🍒 ${WHITE}${BOLD}Redis Port (Cache):${NC} ${YELLOW}6379${NC}"
|
echo -e " 🍒 ${WHITE}${BOLD}Redis Port:${NC} ${YELLOW}${PORT_6379}${NC}"
|
||||||
echo -e "${CYAN}=========================================================${NC}"
|
echo -e "${CYAN}=========================================================${NC}"
|
||||||
echo -e " ${YELLOW}${BOLD}Useful Commands:${NC}"
|
echo -e " ${YELLOW}${BOLD}Useful Commands:${NC}"
|
||||||
echo -e " 👉 View live logs: ${CYAN}docker compose logs -f${NC}"
|
echo -e " 👉 View live logs: ${CYAN}docker compose logs -f${NC}"
|
||||||
echo -e " 👉 Stop the stack: ${CYAN}docker compose down${NC}"
|
echo -e " 👉 Stop the stack: ${CYAN}docker compose down${NC}"
|
||||||
echo -e " 👉 Restart containers: ${CYAN}./run.sh${NC}"
|
echo -e " 👉 Restart containers: ${CYAN}./run.sh${NC}"
|
||||||
echo -e "${CYAN}=========================================================${NC}"
|
echo -e "${CYAN}=========================================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user