#!/usr/bin/env bash set -euo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "${repo_root}" env_file="${MINEROPS_DEMO_ENV_FILE:-.env.dev}" project_name="${MINEROPS_DEMO_PROJECT:-minerops-dev}" mode="${1:-seed}" usage() { cat <<'EOF' Usage: scripts/seed-development-demo.sh [--reseed] Seeds the current Docker development database with deterministic synthetic data. --reseed reapplies the mutable demo projections without deleting immutable history. EOF } case "${mode}" in seed) [[ $# -eq 0 ]] || { usage >&2; exit 2; } ;; --reseed) [[ $# -eq 1 ]] || { usage >&2; exit 2; } ;; -h|--help) usage; exit 0 ;; *) usage >&2; exit 2 ;; esac [[ -f "${env_file}" ]] || { echo "Missing development environment file: ${env_file}" >&2; exit 1; } [[ -f compose.dev.yaml ]] || { echo "Missing compose.dev.yaml." >&2; exit 1; } [[ -f sql/development-demo.sql ]] || { echo "Missing sql/development-demo.sql." >&2; exit 1; } env_value() { awk -F= -v wanted="$1" ' $1 == wanted { sub(/^[^=]*=/, "") gsub(/\r$/, "") print exit } ' "${env_file}" } app_env="$(env_value APP_ENV)" database_name="$(env_value POSTGRES_DB)" database_host="$(env_value POSTGRES_HOST)" if [[ "${app_env}" != "development" ]]; then echo "Refusing demo seed: APP_ENV must be exactly development." >&2 exit 1 fi if [[ ! "${database_name}" =~ (^|_)(dev|development|test)(_|$) ]]; then echo "Refusing demo seed: POSTGRES_DB must be clearly named for development or testing." >&2 exit 1 fi if [[ "${database_name,,}" =~ (prod|production|live) ]]; then echo "Refusing demo seed: POSTGRES_DB resembles a production database." >&2 exit 1 fi if [[ "${database_host}" != "postgres" ]]; then echo "Refusing demo seed: POSTGRES_HOST must be the compose.dev.yaml postgres service." >&2 exit 1 fi compose=( docker compose --project-name "${project_name}" --env-file "${env_file}" -f compose.dev.yaml ) "${compose[@]}" config --quiet if ! "${compose[@]}" ps --status running --services | grep -qx postgres; then echo "Development PostgreSQL is not running for project ${project_name}." >&2 echo "Start it with: docker compose --project-name ${project_name} --env-file ${env_file} -f compose.dev.yaml up -d" >&2 exit 1 fi migration_head="$( "${compose[@]}" exec -T postgres sh -ec \ 'psql -v ON_ERROR_STOP=1 -At -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT version_num FROM alembic_version"' )" if [[ "${migration_head}" != "0014_repair_parts_tracking" ]]; then echo "Refusing demo seed: database Alembic head is ${migration_head:-missing}, expected 0014_repair_parts_tracking." >&2 exit 1 fi if [[ "${mode}" == "--reseed" ]]; then echo "Reapplying deterministic demo projections; immutable repair and MAC history will not be rewritten." else echo "Seeding deterministic MinerOps development demo data..." fi "${compose[@]}" exec -T postgres sh -ec \ 'psql -v ON_ERROR_STOP=1 -v app_env=development -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \ < sql/development-demo.sql "${compose[@]}" exec -T postgres sh -ec \ 'psql -v ON_ERROR_STOP=1 -At -F " | " -U "$POSTGRES_USER" -d "$POSTGRES_DB"' <<'SQL' SELECT 'demo summary', count(*) FILTER (WHERE asset_tag LIKE 'DEMO-MIN-%') || ' miners', (SELECT count(*) FROM location_positions WHERE source_file = 'MinerOps demo seed') || ' positions', (SELECT count(*) FROM location_positions WHERE source_file = 'MinerOps demo seed' AND miner_id IS NULL) || ' empty', (SELECT count(*) FROM repairs WHERE id::text LIKE 'd4000000-0000-4000-8000-%') || ' repairs' FROM miners; SQL echo "Demo data is ready at the configured development gateway."