#!/bin/bash set -e echo "========================================" echo " Goa-GEL Backend Initialization" echo "========================================" echo "" # Function to check if this is first boot is_first_boot() { if [ ! -f "/app/data/.initialized" ]; then return 0 # true else return 1 # false fi } # Function to check if database has data db_has_data() { local count count=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT COUNT(*) FROM users;" 2>/dev/null || echo "0") if [ "$count" -gt "0" ]; then return 0 # true - has data else return 1 # false - empty fi } # Function to check if migrations table exists migrations_table_exists() { local exists exists=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'knex_migrations');" 2>/dev/null || echo "f") if [ "$exists" = "t" ]; then return 0 # true else return 1 # false fi } # Ensure data directory exists mkdir -p /app/data # Ensure .env file exists touch /app/.env # ======================================== # Step 1: Wait for PostgreSQL # ======================================== echo "[1/4] Waiting for PostgreSQL to be ready..." retries=30 until PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -c '\q' 2>/dev/null; do retries=$((retries - 1)) if [ $retries -le 0 ]; then echo "ERROR: PostgreSQL is not available after 30 retries" exit 1 fi echo " - PostgreSQL is unavailable - sleeping (${retries} retries left)" sleep 2 done echo " - PostgreSQL is up and accepting connections" # ======================================== # Step 2: Run Database Migrations # ======================================== echo "" echo "[2/4] Running database migrations..." # Change to database directory for Knex cd /app/src/database # Run migrations using the compiled knexfile if node -e " const knex = require('knex'); const config = require('./knexfile.js').default || require('./knexfile.js'); const env = process.env.NODE_ENV || 'production'; const db = knex(config[env]); db.migrate.latest() .then(([batchNo, migrations]) => { if (migrations.length === 0) { console.log(' - All migrations already applied'); } else { console.log(' - Applied ' + migrations.length + ' migration(s)'); migrations.forEach(m => console.log(' * ' + m)); } process.exit(0); }) .catch(err => { console.error(' - Migration failed:', err.message); process.exit(1); }) .finally(() => db.destroy()); "; then echo " - Migrations completed successfully" else echo "ERROR: Migration failed" exit 1 fi # ======================================== # Step 3: Run Database Seeds (if needed) # ======================================== echo "" echo "[3/4] Checking if database seeding is needed..." cd /app/src/database # Check if we should run seeds SHOULD_SEED="false" if ! db_has_data; then echo " - Database is empty, seeding required" SHOULD_SEED="true" elif [ "$FORCE_RESEED" = "true" ]; then echo " - FORCE_RESEED is set, reseeding database" SHOULD_SEED="true" else echo " - Database already has data, skipping seed" fi if [ "$SHOULD_SEED" = "true" ]; then echo " - Running database seeds..." if node -e " const knex = require('knex'); const config = require('./knexfile.js').default || require('./knexfile.js'); const env = process.env.NODE_ENV || 'production'; const db = knex(config[env]); db.seed.run() .then(() => { console.log(' - Seeds completed successfully'); process.exit(0); }) .catch(err => { console.error(' - Seed failed:', err.message); process.exit(1); }) .finally(() => db.destroy()); "; then echo " - Database seeded successfully" else echo "ERROR: Seeding failed" exit 1 fi fi # ======================================== # Step 4: Initialize Blockchain (if needed) # ======================================== echo "" echo "[4/4] Checking blockchain initialization..." cd /app if is_first_boot || [ -z "$CONTRACT_ADDRESS_LICENSE_NFT" ] || [ "$CONTRACT_ADDRESS_LICENSE_NFT" = "0x0000000000000000000000000000000000000000" ]; then echo " - Blockchain not initialized, deploying contracts..." node /app/scripts/init-blockchain.js # Mark as initialized touch /app/data/.initialized echo " - Blockchain initialization complete" # Reload environment variables if [ -f "/app/.env" ]; then set -a source /app/.env set +a fi else echo " - Blockchain already initialized, skipping" fi # ======================================== # Final Health Check # ======================================== echo "" echo "========================================" echo " Performing Health Checks" echo "========================================" # Verify database has expected data USER_COUNT=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT COUNT(*) FROM users;" 2>/dev/null || echo "0") DEPT_COUNT=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT COUNT(*) FROM departments;" 2>/dev/null || echo "0") WORKFLOW_COUNT=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT COUNT(*) FROM workflows;" 2>/dev/null || echo "0") echo " - Users: $USER_COUNT" echo " - Departments: $DEPT_COUNT" echo " - Workflows: $WORKFLOW_COUNT" if [ "$USER_COUNT" -eq "0" ] || [ "$DEPT_COUNT" -eq "0" ]; then echo "" echo "WARNING: Database appears to be empty!" echo "You may need to run: docker compose exec api npm run db:reset" fi # ======================================== # Start Application # ======================================== echo "" echo "========================================" echo " Starting NestJS Application" echo "========================================" echo "" exec npm run start:prod