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:
Mahi
2026-02-08 18:44:05 -04:00
parent 2c10cd5662
commit d9de183e51
171 changed files with 10236 additions and 8386 deletions

185
backend/scripts/db-reset.sh Executable file
View 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
View 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
View 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

View File

@@ -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
View 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"

View 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!"