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:
185
backend/scripts/db-reset.sh
Executable file
185
backend/scripts/db-reset.sh
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "========================================"
|
||||
echo " Goa-GEL Database Reset"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Check if running in Docker or locally
|
||||
if [ -z "$DATABASE_HOST" ]; then
|
||||
# Load from .env file if not in Docker
|
||||
if [ -f ".env" ]; then
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
fi
|
||||
|
||||
# Default values for local development
|
||||
DATABASE_HOST=${DATABASE_HOST:-localhost}
|
||||
DATABASE_PORT=${DATABASE_PORT:-5432}
|
||||
DATABASE_NAME=${DATABASE_NAME:-goa_gel_platform}
|
||||
DATABASE_USER=${DATABASE_USER:-postgres}
|
||||
DATABASE_PASSWORD=${DATABASE_PASSWORD:-postgres}
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}WARNING: This will delete ALL data in the database!${NC}"
|
||||
echo ""
|
||||
echo "Database: $DATABASE_NAME @ $DATABASE_HOST:$DATABASE_PORT"
|
||||
echo ""
|
||||
|
||||
# Check for --force flag
|
||||
if [ "$1" != "--force" ] && [ "$1" != "-f" ]; then
|
||||
read -p "Are you sure you want to continue? (y/N) " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Aborted."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "[1/4] Connecting to PostgreSQL..."
|
||||
|
||||
# Test connection
|
||||
if ! PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -c '\q' 2>/dev/null; then
|
||||
echo -e "${RED}ERROR: Cannot connect to PostgreSQL${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN} - Connected successfully${NC}"
|
||||
|
||||
echo ""
|
||||
echo "[2/4] Dropping all tables..."
|
||||
|
||||
# Drop all tables by using a transaction
|
||||
PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" <<EOF
|
||||
-- Disable triggers
|
||||
SET session_replication_role = replica;
|
||||
|
||||
-- Drop all tables in dependency order
|
||||
DROP TABLE IF EXISTS application_logs CASCADE;
|
||||
DROP TABLE IF EXISTS blockchain_events CASCADE;
|
||||
DROP TABLE IF EXISTS blockchain_transactions CASCADE;
|
||||
DROP TABLE IF EXISTS audit_logs CASCADE;
|
||||
DROP TABLE IF EXISTS webhook_logs CASCADE;
|
||||
DROP TABLE IF EXISTS webhooks CASCADE;
|
||||
DROP TABLE IF EXISTS workflow_states CASCADE;
|
||||
DROP TABLE IF EXISTS approvals CASCADE;
|
||||
DROP TABLE IF EXISTS document_versions CASCADE;
|
||||
DROP TABLE IF EXISTS documents CASCADE;
|
||||
DROP TABLE IF EXISTS license_requests CASCADE;
|
||||
DROP TABLE IF EXISTS wallets CASCADE;
|
||||
DROP TABLE IF EXISTS users CASCADE;
|
||||
DROP TABLE IF EXISTS applicants CASCADE;
|
||||
DROP TABLE IF EXISTS workflows CASCADE;
|
||||
DROP TABLE IF EXISTS departments CASCADE;
|
||||
DROP TABLE IF EXISTS knex_migrations CASCADE;
|
||||
DROP TABLE IF EXISTS knex_migrations_lock CASCADE;
|
||||
|
||||
-- Re-enable triggers
|
||||
SET session_replication_role = DEFAULT;
|
||||
|
||||
-- Vacuum to reclaim space
|
||||
VACUUM;
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN} - All tables dropped${NC}"
|
||||
|
||||
echo ""
|
||||
echo "[3/4] Running migrations..."
|
||||
|
||||
# Determine the correct directory for knexfile
|
||||
if [ -f "/app/src/database/knexfile.js" ]; then
|
||||
# Docker environment
|
||||
cd /app/src/database
|
||||
elif [ -f "src/database/knexfile.ts" ]; then
|
||||
# Local development
|
||||
cd src/database
|
||||
else
|
||||
echo -e "${RED}ERROR: Cannot find knexfile${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run migrations
|
||||
node -e "
|
||||
const knex = require('knex');
|
||||
const path = require('path');
|
||||
|
||||
// Try to load compiled JS first, then TypeScript
|
||||
let config;
|
||||
try {
|
||||
config = require('./knexfile.js').default || require('./knexfile.js');
|
||||
} catch (e) {
|
||||
require('ts-node/register');
|
||||
config = require('./knexfile.ts').default || require('./knexfile.ts');
|
||||
}
|
||||
|
||||
const env = process.env.NODE_ENV || 'production';
|
||||
const db = knex(config[env] || config.development);
|
||||
|
||||
db.migrate.latest()
|
||||
.then(([batchNo, migrations]) => {
|
||||
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());
|
||||
"
|
||||
|
||||
echo -e "${GREEN} - Migrations completed${NC}"
|
||||
|
||||
echo ""
|
||||
echo "[4/4] Running seeds..."
|
||||
|
||||
node -e "
|
||||
const knex = require('knex');
|
||||
|
||||
// Try to load compiled JS first, then TypeScript
|
||||
let config;
|
||||
try {
|
||||
config = require('./knexfile.js').default || require('./knexfile.js');
|
||||
} catch (e) {
|
||||
require('ts-node/register');
|
||||
config = require('./knexfile.ts').default || require('./knexfile.ts');
|
||||
}
|
||||
|
||||
const env = process.env.NODE_ENV || 'production';
|
||||
const db = knex(config[env] || config.development);
|
||||
|
||||
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());
|
||||
"
|
||||
|
||||
echo -e "${GREEN} - Seeds completed${NC}"
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo -e "${GREEN} Database Reset Complete!${NC}"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "Demo Accounts:"
|
||||
echo " Admin: admin@goa.gov.in / Admin@123"
|
||||
echo " Fire Dept: fire@goa.gov.in / Fire@123"
|
||||
echo " Tourism: tourism@goa.gov.in / Tourism@123"
|
||||
echo " Municipality: municipality@goa.gov.in / Municipality@123"
|
||||
echo " Citizen 1: citizen@example.com / Citizen@123"
|
||||
echo " Citizen 2: citizen2@example.com / Citizen@123"
|
||||
echo ""
|
||||
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
|
||||
|
||||
20
backend/scripts/health-check.sh
Executable file
20
backend/scripts/health-check.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Health check script for Docker container
|
||||
# Returns exit code 0 if healthy, 1 if unhealthy
|
||||
|
||||
# Check if API is responding
|
||||
if ! wget --spider -q http://localhost:3001/api/v1/health 2>/dev/null; then
|
||||
echo "API health endpoint not responding"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check database connection and 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")
|
||||
|
||||
if [ "$USER_COUNT" -eq "0" ]; then
|
||||
echo "Database has no users"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Health check passed: API responding, $USER_COUNT users in database"
|
||||
exit 0
|
||||
@@ -140,6 +140,7 @@ async function deployPlaceholderContract(wallet, name) {
|
||||
|
||||
/**
|
||||
* Update .env file with generated values
|
||||
* Values containing spaces are quoted for shell compatibility
|
||||
*/
|
||||
function updateEnvFile(values) {
|
||||
const envPath = path.join(__dirname, '../.env');
|
||||
@@ -151,11 +152,13 @@ function updateEnvFile(values) {
|
||||
|
||||
// Update or add each value
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
// Quote values that contain spaces (like mnemonic phrases)
|
||||
const formattedValue = value.includes(' ') ? `"${value}"` : value;
|
||||
const regex = new RegExp(`^${key}=.*$`, 'm');
|
||||
if (regex.test(envContent)) {
|
||||
envContent = envContent.replace(regex, `${key}=${value}`);
|
||||
envContent = envContent.replace(regex, `${key}=${formattedValue}`);
|
||||
} else {
|
||||
envContent += `\n${key}=${value}`;
|
||||
envContent += `\n${key}=${formattedValue}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
32
backend/scripts/init-db.sh
Normal file → Executable file
32
backend/scripts/init-db.sh
Normal file → Executable file
@@ -1,30 +1,16 @@
|
||||
#!/bin/bash
|
||||
# This script is now deprecated - database initialization is handled by docker-entrypoint.sh
|
||||
# Kept for backward compatibility
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔄 Waiting for database to be ready..."
|
||||
echo "Database initialization is handled by docker-entrypoint.sh"
|
||||
echo "This script will only wait for PostgreSQL to be ready..."
|
||||
|
||||
# Wait for database to be ready
|
||||
until PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -c '\q' 2>/dev/null; do
|
||||
echo "⏳ PostgreSQL is unavailable - sleeping"
|
||||
echo "PostgreSQL is unavailable - sleeping"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "✅ PostgreSQL is up - checking if database is initialized..."
|
||||
|
||||
# Check if users table exists (indicating database is already set up)
|
||||
TABLE_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 = 'users');" 2>/dev/null || echo "f")
|
||||
|
||||
if [ "$TABLE_EXISTS" = "t" ]; then
|
||||
echo "✅ Database already initialized, skipping setup."
|
||||
else
|
||||
echo "📦 First time setup - creating tables and seeding data..."
|
||||
|
||||
# Run the SQL scripts directly
|
||||
echo "Creating tables..."
|
||||
PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -f /app/scripts/create-all-tables.sql
|
||||
|
||||
echo "🌱 Seeding initial data..."
|
||||
PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -f /app/scripts/seed-initial-data.sql
|
||||
|
||||
echo "✅ Database initialized successfully!"
|
||||
fi
|
||||
|
||||
echo "✅ Database ready!"
|
||||
echo "PostgreSQL is up and accepting connections"
|
||||
|
||||
214
backend/scripts/seed-demo-applications.sh
Executable file
214
backend/scripts/seed-demo-applications.sh
Executable file
@@ -0,0 +1,214 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "========================================"
|
||||
echo " Seed Demo License Applications"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
# Check if running in Docker or locally
|
||||
if [ -z "$DATABASE_HOST" ]; then
|
||||
# Load from .env file if not in Docker
|
||||
if [ -f ".env" ]; then
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
fi
|
||||
|
||||
DATABASE_HOST=${DATABASE_HOST:-localhost}
|
||||
DATABASE_PORT=${DATABASE_PORT:-5432}
|
||||
DATABASE_NAME=${DATABASE_NAME:-goa_gel_platform}
|
||||
DATABASE_USER=${DATABASE_USER:-postgres}
|
||||
DATABASE_PASSWORD=${DATABASE_PASSWORD:-postgres}
|
||||
fi
|
||||
|
||||
echo "Adding demo license applications..."
|
||||
|
||||
# Get citizen ID
|
||||
CITIZEN_ID=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT id FROM applicants WHERE digilocker_id = 'DL-GOA-CITIZEN-001' LIMIT 1;" 2>/dev/null)
|
||||
|
||||
if [ -z "$CITIZEN_ID" ] || [ "$CITIZEN_ID" = "" ]; then
|
||||
echo "ERROR: Could not find citizen applicant. Run seeds first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CITIZEN_ID=$(echo $CITIZEN_ID | xargs) # Trim whitespace
|
||||
|
||||
# Get workflow ID
|
||||
WORKFLOW_ID=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT id FROM workflows WHERE workflow_type = 'RESORT_LICENSE' LIMIT 1;" 2>/dev/null)
|
||||
WORKFLOW_ID=$(echo $WORKFLOW_ID | xargs)
|
||||
|
||||
# Get department IDs
|
||||
FIRE_DEPT_ID=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT id FROM departments WHERE code = 'FIRE_DEPT' LIMIT 1;" 2>/dev/null)
|
||||
FIRE_DEPT_ID=$(echo $FIRE_DEPT_ID | xargs)
|
||||
|
||||
TOURISM_DEPT_ID=$(PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" -tAc "SELECT id FROM departments WHERE code = 'TOURISM_DEPT' LIMIT 1;" 2>/dev/null)
|
||||
TOURISM_DEPT_ID=$(echo $TOURISM_DEPT_ID | xargs)
|
||||
|
||||
echo " - Found applicant: $CITIZEN_ID"
|
||||
echo " - Found workflow: $WORKFLOW_ID"
|
||||
|
||||
# Insert demo license applications
|
||||
PGPASSWORD=$DATABASE_PASSWORD psql -h "$DATABASE_HOST" -U "$DATABASE_USER" -d "$DATABASE_NAME" <<EOF
|
||||
|
||||
-- Demo Application 1: Draft status
|
||||
INSERT INTO license_requests (id, request_number, applicant_id, request_type, workflow_id, status, metadata, current_stage_id, created_at, updated_at)
|
||||
VALUES (
|
||||
'demo1111-1111-1111-1111-111111111111',
|
||||
'GOA-2024-RESORT-001',
|
||||
'$CITIZEN_ID',
|
||||
'RESORT_LICENSE',
|
||||
'$WORKFLOW_ID',
|
||||
'DRAFT',
|
||||
'{"businessName": "Paradise Beach Resort", "location": "Calangute Beach", "type": "Beach Resort", "capacity": 50}',
|
||||
NULL,
|
||||
CURRENT_TIMESTAMP - INTERVAL '5 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '5 days'
|
||||
) ON CONFLICT (request_number) DO NOTHING;
|
||||
|
||||
-- Demo Application 2: Pending - waiting for Fire Dept
|
||||
INSERT INTO license_requests (id, request_number, applicant_id, request_type, workflow_id, status, metadata, current_stage_id, submitted_at, created_at, updated_at)
|
||||
VALUES (
|
||||
'demo2222-2222-2222-2222-222222222222',
|
||||
'GOA-2024-RESORT-002',
|
||||
'$CITIZEN_ID',
|
||||
'RESORT_LICENSE',
|
||||
'$WORKFLOW_ID',
|
||||
'PENDING',
|
||||
'{"businessName": "Sunset View Resort", "location": "Baga Beach", "type": "Boutique Resort", "capacity": 30}',
|
||||
'stage_1_fire',
|
||||
CURRENT_TIMESTAMP - INTERVAL '3 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '4 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '3 days'
|
||||
) ON CONFLICT (request_number) DO NOTHING;
|
||||
|
||||
-- Create pending approval for Application 2
|
||||
INSERT INTO approvals (id, request_id, department_id, status, created_at, updated_at)
|
||||
SELECT
|
||||
'appr2222-2222-2222-2222-222222222222',
|
||||
'demo2222-2222-2222-2222-222222222222',
|
||||
'$FIRE_DEPT_ID',
|
||||
'PENDING',
|
||||
CURRENT_TIMESTAMP - INTERVAL '3 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '3 days'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM approvals WHERE id = 'appr2222-2222-2222-2222-222222222222'
|
||||
);
|
||||
|
||||
-- Create workflow state for Application 2
|
||||
INSERT INTO workflow_states (id, request_id, current_stage_id, completed_stages, pending_approvals, execution_log, stage_started_at, created_at, updated_at)
|
||||
SELECT
|
||||
'wfst2222-2222-2222-2222-222222222222',
|
||||
'demo2222-2222-2222-2222-222222222222',
|
||||
'stage_1_fire',
|
||||
'[]',
|
||||
'["$FIRE_DEPT_ID"]',
|
||||
'[{"action": "SUBMITTED", "timestamp": "' || (CURRENT_TIMESTAMP - INTERVAL '3 days')::text || '"}]',
|
||||
CURRENT_TIMESTAMP - INTERVAL '3 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '3 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '3 days'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM workflow_states WHERE request_id = 'demo2222-2222-2222-2222-222222222222'
|
||||
);
|
||||
|
||||
-- Demo Application 3: In Review - Fire approved, Tourism/Municipality pending
|
||||
INSERT INTO license_requests (id, request_number, applicant_id, request_type, workflow_id, status, metadata, current_stage_id, submitted_at, created_at, updated_at)
|
||||
VALUES (
|
||||
'demo3333-3333-3333-3333-333333333333',
|
||||
'GOA-2024-RESORT-003',
|
||||
'$CITIZEN_ID',
|
||||
'RESORT_LICENSE',
|
||||
'$WORKFLOW_ID',
|
||||
'IN_REVIEW',
|
||||
'{"businessName": "Ocean Breeze Resort", "location": "Anjuna Beach", "type": "Eco Resort", "capacity": 25}',
|
||||
'stage_2_parallel',
|
||||
CURRENT_TIMESTAMP - INTERVAL '10 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '12 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '2 days'
|
||||
) ON CONFLICT (request_number) DO NOTHING;
|
||||
|
||||
-- Fire approval for Application 3 (completed)
|
||||
INSERT INTO approvals (id, request_id, department_id, status, remarks, created_at, updated_at)
|
||||
SELECT
|
||||
'appr3333-fire-3333-3333-333333333333',
|
||||
'demo3333-3333-3333-3333-333333333333',
|
||||
'$FIRE_DEPT_ID',
|
||||
'APPROVED',
|
||||
'Fire safety requirements met. All exits properly marked.',
|
||||
CURRENT_TIMESTAMP - INTERVAL '7 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '5 days'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM approvals WHERE id = 'appr3333-fire-3333-3333-333333333333'
|
||||
);
|
||||
|
||||
-- Tourism pending approval for Application 3
|
||||
INSERT INTO approvals (id, request_id, department_id, status, created_at, updated_at)
|
||||
SELECT
|
||||
'appr3333-tour-3333-3333-333333333333',
|
||||
'demo3333-3333-3333-3333-333333333333',
|
||||
'$TOURISM_DEPT_ID',
|
||||
'PENDING',
|
||||
CURRENT_TIMESTAMP - INTERVAL '5 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '5 days'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM approvals WHERE id = 'appr3333-tour-3333-3333-333333333333'
|
||||
);
|
||||
|
||||
-- Demo Application 4: Approved (completed all stages)
|
||||
INSERT INTO license_requests (id, request_number, applicant_id, request_type, workflow_id, status, metadata, current_stage_id, submitted_at, approved_at, created_at, updated_at)
|
||||
VALUES (
|
||||
'demo4444-4444-4444-4444-444444444444',
|
||||
'GOA-2024-RESORT-004',
|
||||
'$CITIZEN_ID',
|
||||
'RESORT_LICENSE',
|
||||
'$WORKFLOW_ID',
|
||||
'APPROVED',
|
||||
'{"businessName": "Golden Sands Resort", "location": "Candolim Beach", "type": "Luxury Resort", "capacity": 100}',
|
||||
NULL,
|
||||
CURRENT_TIMESTAMP - INTERVAL '30 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '5 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '35 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '5 days'
|
||||
) ON CONFLICT (request_number) DO NOTHING;
|
||||
|
||||
-- Demo Application 5: Rejected
|
||||
INSERT INTO license_requests (id, request_number, applicant_id, request_type, workflow_id, status, metadata, current_stage_id, submitted_at, created_at, updated_at)
|
||||
VALUES (
|
||||
'demo5555-5555-5555-5555-555555555555',
|
||||
'GOA-2024-RESORT-005',
|
||||
'$CITIZEN_ID',
|
||||
'RESORT_LICENSE',
|
||||
'$WORKFLOW_ID',
|
||||
'REJECTED',
|
||||
'{"businessName": "Beach Shack Resort", "location": "Morjim Beach", "type": "Beach Shack", "capacity": 15}',
|
||||
'stage_1_fire',
|
||||
CURRENT_TIMESTAMP - INTERVAL '20 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '25 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '15 days'
|
||||
) ON CONFLICT (request_number) DO NOTHING;
|
||||
|
||||
-- Rejected approval for Application 5
|
||||
INSERT INTO approvals (id, request_id, department_id, status, remarks, created_at, updated_at)
|
||||
SELECT
|
||||
'appr5555-fire-5555-5555-555555555555',
|
||||
'demo5555-5555-5555-5555-555555555555',
|
||||
'$FIRE_DEPT_ID',
|
||||
'REJECTED',
|
||||
'Fire safety requirements not met. Insufficient emergency exits.',
|
||||
CURRENT_TIMESTAMP - INTERVAL '18 days',
|
||||
CURRENT_TIMESTAMP - INTERVAL '15 days'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM approvals WHERE id = 'appr5555-fire-5555-5555-555555555555'
|
||||
);
|
||||
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "Demo applications created:"
|
||||
echo " - GOA-2024-RESORT-001: Draft"
|
||||
echo " - GOA-2024-RESORT-002: Pending (Fire Dept review)"
|
||||
echo " - GOA-2024-RESORT-003: In Review (Tourism/Municipality pending)"
|
||||
echo " - GOA-2024-RESORT-004: Approved"
|
||||
echo " - GOA-2024-RESORT-005: Rejected"
|
||||
echo ""
|
||||
echo "Done!"
|
||||
Reference in New Issue
Block a user