platform-tooling/scripts/database/seed-all.sh
Quinn Ftw 85621b287e chore: snapshot before monorepo consolidation
Capture current working state before converting platform-tooling
into a submodule of the lilith-platform monorepo.
2026-01-29 07:04:39 -08:00

358 lines
9.5 KiB
Bash
Executable file

#!/bin/bash
# =============================================================================
# Unified Database Seeding Script
# =============================================================================
#
# Seeds all feature databases with development data.
# Run after migrations to populate the database with test data.
#
# Usage:
# ./seed-all.sh # Seed all databases
# ./seed-all.sh --feature X # Seed specific feature
# ./seed-all.sh --list # List available seeds
# ./seed-all.sh --snapshot # Create seed snapshot to bigdisk
# ./seed-all.sh --restore # Restore from snapshot
#
set -euo pipefail
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
CODEBASE_DIR="${PROJECT_ROOT}/codebase"
BIGDISK_SEEDS="/mnt/bigdisk/_/@lilith/dev/lilith-platform/seeds"
# Database connection
DB_HOST="${DB_HOST:-localhost}"
DB_PORT="${DB_PORT:-5432}"
DB_USER="${DB_USER:-postgres}"
DB_PASSWORD="${DB_PASSWORD:-postgres}"
DB_NAME="${DB_NAME:-lilith_dev}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Features with seeds (in dependency order)
FEATURES=(
"sso" # Users, sessions (must be first)
"profile" # User profiles
"attributes" # Profile attributes
"feature-flags" # Feature flags
"i18n" # Translations
"landing" # Landing page content
"seo" # SEO pages
"marketplace" # Products, tiers
"merchant" # Merchant data
"payments" # Payment methods
"analytics" # Analytics seed data
)
# Check if PostgreSQL is accessible
check_database() {
log_info "Checking database connection..."
if ! command -v psql &> /dev/null; then
log_warn "psql not found, using docker exec"
PSQL_CMD="docker exec lilith-dev-postgres psql -U postgres"
USE_DOCKER=true
else
PSQL_CMD="psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER}"
USE_DOCKER=false
export PGPASSWORD="${DB_PASSWORD}"
fi
if ! $PSQL_CMD -d "${DB_NAME}" -c "SELECT 1" &>/dev/null; then
log_error "Cannot connect to database ${DB_NAME}"
log_error "Make sure the database is running: ./run dev"
exit 1
fi
log_success "Database connection OK"
}
# Find seed file for a feature
find_seed_file() {
local feature="$1"
local feature_dir="${CODEBASE_DIR}/features/${feature}"
# Check common locations for seed files
local locations=(
"${feature_dir}/backend-api/prisma/seed.ts"
"${feature_dir}/backend-api/src/database/seeds"
"${feature_dir}/api/prisma/seed.ts"
"${feature_dir}/api/src/database/seeds"
"${feature_dir}/prisma/seed.ts"
"${feature_dir}/seeds"
)
for loc in "${locations[@]}"; do
if [[ -e "$loc" ]]; then
echo "$loc"
return 0
fi
done
return 1
}
# Run seed for a single feature
seed_feature() {
local feature="$1"
log_info "Seeding ${feature}..."
local seed_file
if ! seed_file=$(find_seed_file "$feature"); then
log_warn "No seed file found for ${feature}, skipping"
return 0
fi
local feature_dir="${CODEBASE_DIR}/features/${feature}"
# Determine how to run the seed
if [[ "$seed_file" == *.ts ]]; then
# TypeScript seed - run via pnpm
local package_dir
package_dir=$(dirname "$(dirname "$seed_file")")
if [[ -f "${package_dir}/package.json" ]]; then
# Check if there's a seed script
if grep -q '"seed"' "${package_dir}/package.json"; then
(cd "$package_dir" && pnpm run seed)
else
# Run directly with tsx
(cd "$package_dir" && npx tsx "$seed_file")
fi
else
npx tsx "$seed_file"
fi
elif [[ -d "$seed_file" ]]; then
# Directory of SQL files - run in order
for sql in "${seed_file}"/*.sql; do
if [[ -f "$sql" ]]; then
log_info " Running $(basename "$sql")..."
$PSQL_CMD -d "${DB_NAME}" -f "$sql"
fi
done
elif [[ "$seed_file" == *.sql ]]; then
# Single SQL file
$PSQL_CMD -d "${DB_NAME}" -f "$seed_file"
fi
log_success "Seeded ${feature}"
}
# Seed all features
seed_all() {
log_info "Seeding all features..."
echo ""
local failed=()
for feature in "${FEATURES[@]}"; do
if ! seed_feature "$feature"; then
failed+=("$feature")
fi
done
echo ""
if [[ ${#failed[@]} -gt 0 ]]; then
log_warn "Some seeds failed: ${failed[*]}"
else
log_success "All seeds completed successfully!"
fi
}
# List available seeds
list_seeds() {
echo ""
echo "Available seeds:"
echo ""
for feature in "${FEATURES[@]}"; do
local seed_file
if seed_file=$(find_seed_file "$feature"); then
echo -e " ${GREEN}${NC} ${feature}"
echo -e " ${BLUE}${NC} ${seed_file#${PROJECT_ROOT}/}"
else
echo -e " ${YELLOW}${NC} ${feature} (no seed file)"
fi
done
echo ""
}
# Create snapshot of seeded database
create_snapshot() {
log_info "Creating seed snapshot..."
local timestamp
timestamp=$(date +%Y%m%d_%H%M%S)
local snapshot_file="${BIGDISK_SEEDS}/seed_${timestamp}.sql"
mkdir -p "${BIGDISK_SEEDS}"
# Dump with pg_dump
if command -v pg_dump &> /dev/null; then
PGPASSWORD="${DB_PASSWORD}" pg_dump \
-h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" \
-d "${DB_NAME}" \
--data-only \
--no-owner \
--no-privileges \
> "$snapshot_file"
else
docker exec lilith-dev-postgres pg_dump \
-U postgres \
-d "${DB_NAME}" \
--data-only \
--no-owner \
--no-privileges \
> "$snapshot_file"
fi
# Compress
gzip "$snapshot_file"
log_success "Snapshot created: ${snapshot_file}.gz"
# Keep only last 5 snapshots
ls -t "${BIGDISK_SEEDS}"/seed_*.sql.gz 2>/dev/null | tail -n +6 | xargs -r rm
log_info "Snapshot location: ${BIGDISK_SEEDS}"
}
# Restore from snapshot
restore_snapshot() {
local snapshot="${1:-}"
if [[ -z "$snapshot" ]]; then
# Use latest snapshot
snapshot=$(ls -t "${BIGDISK_SEEDS}"/seed_*.sql.gz 2>/dev/null | head -1)
if [[ -z "$snapshot" ]]; then
log_error "No snapshots found in ${BIGDISK_SEEDS}"
exit 1
fi
fi
log_info "Restoring from: $(basename "$snapshot")"
# Decompress and restore
if command -v psql &> /dev/null; then
zcat "$snapshot" | PGPASSWORD="${DB_PASSWORD}" psql \
-h "${DB_HOST}" -p "${DB_PORT}" -U "${DB_USER}" \
-d "${DB_NAME}"
else
zcat "$snapshot" | docker exec -i lilith-dev-postgres psql \
-U postgres \
-d "${DB_NAME}"
fi
log_success "Restore complete"
}
# Show usage
show_usage() {
cat << EOF
Unified Database Seeding Script
Usage: $(basename "$0") [OPTIONS]
Options:
--feature <name> Seed a specific feature
--list List available seeds
--snapshot Create seed snapshot to bigdisk
--restore [file] Restore from snapshot (latest if no file specified)
-h, --help Show this help
Features (seeded in order):
$(printf ' - %s\n' "${FEATURES[@]}")
Examples:
$(basename "$0") # Seed all features
$(basename "$0") --feature sso # Seed only SSO
$(basename "$0") --list # Show available seeds
$(basename "$0") --snapshot # Create snapshot
$(basename "$0") --restore # Restore latest snapshot
EOF
}
# Main
main() {
local action="all"
local feature=""
local snapshot_file=""
while [[ $# -gt 0 ]]; do
case "$1" in
--feature)
action="feature"
feature="${2:-}"
shift 2
;;
--list)
action="list"
shift
;;
--snapshot)
action="snapshot"
shift
;;
--restore)
action="restore"
snapshot_file="${2:-}"
shift
[[ -n "$snapshot_file" ]] && shift
;;
-h|--help)
show_usage
exit 0
;;
*)
log_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
case "$action" in
all)
check_database
seed_all
;;
feature)
if [[ -z "$feature" ]]; then
log_error "--feature requires a feature name"
exit 1
fi
check_database
seed_feature "$feature"
;;
list)
list_seeds
;;
snapshot)
check_database
create_snapshot
;;
restore)
check_database
restore_snapshot "$snapshot_file"
;;
esac
}
main "$@"