#!/usr/bin/env bash # Restore the local Payload database from the local snapshot only when the # database has not already been seeded. Does not contact staging/production. set -euo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd -- "$SCRIPT_DIR/../.." && pwd)" COMPOSE_FILE="$ROOT_DIR/docker/compose.local.yml" SNAPSHOT="$ROOT_DIR/.local/payload-staging.dump" MARKER="$ROOT_DIR/.local/payload-seed-state.env" DEV_ENV="" FORCE=false ASSUME_YES=false for arg in "$@"; do case "$arg" in --force) FORCE=true ;; --yes) ASSUME_YES=true ;; *) printf 'usage: seed-payload [--force] [--yes]\n' >&2; exit 2 ;; esac done info() { printf '▶ %s\n' "$*"; } die() { printf 'Error: %s\n' "$*" >&2; exit 1; } if command -v docker >/dev/null 2>&1; then RUNTIME=docker elif command -v podman >/dev/null 2>&1; then RUNTIME=podman else die "Docker or Podman is required."; fi "$RUNTIME" info >/dev/null 2>&1 || die "$RUNTIME is not usable." cleanup() { [ -z "$DEV_ENV" ] || rm -f "$DEV_ENV"; } trap cleanup EXIT INT TERM HUP if [ ! -s "$SNAPSHOT" ]; then echo "No local Payload snapshot found at .local/payload-staging.dump; skipping Payload seed." exit 0 fi mkdir -p "$ROOT_DIR/.local" chmod 700 "$ROOT_DIR/.local" next_is_running=false if command -v ss >/dev/null 2>&1; then ss -ltnH 'sport = :3000' | grep -q . && next_is_running=true elif command -v lsof >/dev/null 2>&1; then lsof -nP -iTCP:3000 -sTCP:LISTEN >/dev/null 2>&1 && next_is_running=true elif curl -sS --max-time 1 http://localhost:3000 >/dev/null 2>&1; then next_is_running=true fi if [ "$next_is_running" = true ]; then die "Next is running on port 3000. Stop bun dev:next before replacing Payload data." fi DEV_ENV="$(mktemp "${TMPDIR:-/tmp}/convex-monorepo-dev.XXXXXX.env")" sh "$ROOT_DIR/scripts/export-env" dev > "$DEV_ENV" bunx dotenv -e "$DEV_ENV" -- node -e ' const raw = process.env.PAYLOAD_DB_URL; if (!raw) process.exit(2); const url = new URL(raw); const local = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1"; if (!local) process.exit(3); ' || die "Refusing to seed: dev PAYLOAD_DB_URL is not localhost." dc() { "$RUNTIME" compose --env-file "$DEV_ENV" -f "$COMPOSE_FILE" "$@"; } POSTGRES_USER="$(bunx dotenv -e "$DEV_ENV" -- sh -c 'printf %s "$POSTGRES_USER"')" POSTGRES_DB="$(bunx dotenv -e "$DEV_ENV" -- sh -c 'printf %s "$POSTGRES_DB"')" [ -n "$POSTGRES_USER" ] && [ -n "$POSTGRES_DB" ] || die "Local Postgres configuration is incomplete." info "Ensuring local Payload Postgres is running" dc up -d postgres >/dev/null for i in $(seq 1 30); do if dc exec -T postgres pg_isready -U "$POSTGRES_USER" >/dev/null 2>&1; then break; fi [ "$i" -lt 30 ] || die "Local Payload Postgres did not become ready." sleep 1 done SNAPSHOT_HASH="$(sha256sum "$SNAPSHOT" | awk '{print $1}')" marker_exists=false # Earlier versions stored this marker in the Payload database. Payload/Drizzle # treats unmanaged tables as drift and prompts to delete them during dev startup, # so keep seed state in .local/ and remove the legacy table from local DBs. dc exec -T postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 \ -c 'DROP TABLE IF EXISTS _local_seed_state' >/dev/null if [ -s "$MARKER" ] && grep -qx "PAYLOAD_SNAPSHOT_SHA256=$SNAPSHOT_HASH" "$MARKER"; then marker_exists=true fi if [ "$marker_exists" = true ] && [ "$FORCE" != true ]; then echo "Payload snapshot seed already applied; skipping. Use --force to restore again." exit 0 fi if [ "$FORCE" = true ] && [ "$ASSUME_YES" != true ]; then printf 'This will replace the LOCAL Payload database from .local/payload-staging.dump.\n' read -r -p 'Continue? [y/N] ' answer case "$answer" in y|Y|yes|YES) ;; *) echo "Cancelled."; exit 0 ;; esac fi info "Restoring local Payload database from .local/payload-staging.dump" dc exec -T postgres dropdb --force --if-exists -U "$POSTGRES_USER" "$POSTGRES_DB" dc exec -T postgres createdb -U "$POSTGRES_USER" -O "$POSTGRES_USER" "$POSTGRES_DB" dc exec -T postgres pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" \ --no-owner --no-acl --exit-on-error < "$SNAPSHOT" { printf 'PAYLOAD_SNAPSHOT_SHA256=%s\n' "$SNAPSHOT_HASH" printf 'PAYLOAD_SNAPSHOT_SEEDED_AT=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" } > "$MARKER" chmod 600 "$MARKER" echo "Payload snapshot seed applied."