feat: Runtime configuration and Docker deployment improvements
Frontend: - Add runtime configuration service for deployment-time API URL injection - Create docker-entrypoint.sh to generate config.json from environment variables - Update ApiService, ApprovalService, and DocumentViewer to use RuntimeConfigService - Add APP_INITIALIZER to load runtime config before app starts Backend: - Fix init-blockchain.js to properly quote mnemonic phrases in .env file - Improve docker-entrypoint.sh with health checks and better error handling Docker: - Add API_BASE_URL environment variable to frontend container - Update docker-compose.yml with clear documentation for remote deployment - Reorganize .env.example with clear categories (REQUIRED FOR REMOTE, PRODUCTION, AUTO-GENERATED) Workflow fixes: - Fix DepartmentApproval interface to match backend schema - Fix stage transformation for 0-indexed stageOrder - Fix workflow list to show correct stage count from definition.stages Cleanup: - Move development artifacts to .trash directory - Remove root-level package.json (was only for utility scripts) - Add .trash/ to .gitignore
This commit is contained in:
184
backend/scripts/docker-entrypoint.sh
Normal file → Executable file
184
backend/scripts/docker-entrypoint.sh
Normal file → Executable file
@@ -1,7 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🚀 Starting Goa-GEL Backend Initialization..."
|
||||
echo "========================================"
|
||||
echo " Goa-GEL Backend Initialization"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Function to check if this is first boot
|
||||
is_first_boot() {
|
||||
@@ -12,34 +15,191 @@ is_first_boot() {
|
||||
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
|
||||
|
||||
# 1. Wait for and initialize database
|
||||
echo "📊 Step 1: Database initialization..."
|
||||
chmod +x /app/scripts/init-db.sh
|
||||
/app/scripts/init-db.sh
|
||||
# ========================================
|
||||
# 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
|
||||
|
||||
# 2. Initialize blockchain (only on first boot or if not configured)
|
||||
if is_first_boot || [ -z "$CONTRACT_ADDRESS_LICENSE_NFT" ] || [ "$CONTRACT_ADDRESS_LICENSE_NFT" = "0x0000000000000000000000000000000000000000" ]; then
|
||||
echo "🔗 Step 2: Blockchain initialization..."
|
||||
echo " - Blockchain not initialized, deploying contracts..."
|
||||
node /app/scripts/init-blockchain.js
|
||||
|
||||
# Mark as initialized
|
||||
touch /app/data/.initialized
|
||||
echo "✅ Blockchain initialization complete!"
|
||||
echo " - Blockchain initialization complete"
|
||||
|
||||
# Reload environment variables
|
||||
if [ -f "/app/.env" ]; then
|
||||
export $(grep -v '^#' /app/.env | xargs)
|
||||
set -a
|
||||
source /app/.env
|
||||
set +a
|
||||
fi
|
||||
else
|
||||
echo "⏭️ Step 2: Blockchain already initialized"
|
||||
echo " - Blockchain already initialized, skipping"
|
||||
fi
|
||||
|
||||
# 3. Start the application
|
||||
echo "🎯 Step 3: Starting NestJS application..."
|
||||
# ========================================
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user