2026-06-21 15:08:09 -05:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
#
|
|
|
|
|
# plum-e2e-db.sh — provision a dedicated local Postgres for E2E / dev on plum.
|
|
|
|
|
#
|
|
|
|
|
# Apricot (the old authoring host with a local 25435 Postgres) is gone; plum is
|
|
|
|
|
# now the sole authoring surface. The admin E2E smoke gate
|
|
|
|
|
# (deployments/@domains/quinn.admin/e2e/global-setup.ts) boots the @features/api
|
|
|
|
|
# server against postgresql://quinn:devpassword@localhost:25435/quinn_admin_test
|
|
|
|
|
# and needs a Postgres there. The system brew `postgresql@16` instance already
|
|
|
|
|
# runs on 5432 and hosts lilith_messaging, so we DON'T move it — we stand up a
|
|
|
|
|
# second, isolated PG16 instance on 25435 (matching the canonical quinn port in
|
|
|
|
|
# infrastructure/pg-services.yml) with its own datadir.
|
|
|
|
|
#
|
|
|
|
|
# Idempotent: safe to re-run. Survives reboot via a per-user LaunchAgent.
|
|
|
|
|
#
|
|
|
|
|
# Usage:
|
|
|
|
|
# infrastructure/scripts/plum-e2e-db.sh # provision + start
|
|
|
|
|
# infrastructure/scripts/plum-e2e-db.sh status # report state
|
|
|
|
|
# infrastructure/scripts/plum-e2e-db.sh stop # stop the instance
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
# macOS spawns helper threads for locale resolution; without a fixed locale the
|
|
|
|
|
# postmaster aborts with "became multithreaded during startup". Pin it.
|
|
|
|
|
export LC_ALL="C"
|
|
|
|
|
|
|
|
|
|
PG_PREFIX="/opt/homebrew/opt/postgresql@16"
|
|
|
|
|
PG_BIN="${PG_PREFIX}/bin"
|
|
|
|
|
DATADIR="/opt/homebrew/var/postgresql@16-quinn-e2e"
|
|
|
|
|
PORT=25435
|
|
|
|
|
LOGFILE="/opt/homebrew/var/log/postgresql@16-quinn-e2e.log"
|
|
|
|
|
PLIST="${HOME}/Library/LaunchAgents/com.lilith.quinn-e2e-pg.plist"
|
|
|
|
|
ROLE="quinn"
|
|
|
|
|
ROLE_PW="devpassword"
|
2026-06-25 02:30:04 -04:00
|
|
|
# analytics_markers migrations ALTER OWNER TO quinn_api (black prod shape).
|
|
|
|
|
API_ROLE="quinn_api"
|
2026-06-21 15:08:09 -05:00
|
|
|
DBS=("quinn_admin_test" "quinn")
|
|
|
|
|
|
|
|
|
|
if [[ ! -x "${PG_BIN}/pg_ctl" ]]; then
|
|
|
|
|
echo "ERROR: Homebrew postgresql@16 not found at ${PG_BIN}. Run: brew install postgresql@16" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
cmd="${1:-up}"
|
|
|
|
|
|
|
|
|
|
is_running() { "${PG_BIN}/pg_ctl" -D "${DATADIR}" status >/dev/null 2>&1; }
|
|
|
|
|
|
|
|
|
|
case "${cmd}" in
|
|
|
|
|
status)
|
|
|
|
|
if is_running; then
|
|
|
|
|
echo "quinn-e2e PG: RUNNING on :${PORT} (datadir ${DATADIR})"
|
|
|
|
|
"${PG_BIN}/psql" -h localhost -p "${PORT}" -d postgres -tAc \
|
|
|
|
|
"select ' db: '||datname from pg_database where datistemplate=false order by 1" 2>/dev/null || true
|
|
|
|
|
else
|
|
|
|
|
echo "quinn-e2e PG: STOPPED (datadir ${DATADIR})"
|
|
|
|
|
fi
|
|
|
|
|
exit 0
|
|
|
|
|
;;
|
|
|
|
|
stop)
|
|
|
|
|
if is_running; then
|
|
|
|
|
"${PG_BIN}/pg_ctl" -D "${DATADIR}" -m fast stop
|
|
|
|
|
echo "Stopped quinn-e2e PG."
|
|
|
|
|
else
|
|
|
|
|
echo "quinn-e2e PG already stopped."
|
|
|
|
|
fi
|
|
|
|
|
exit 0
|
|
|
|
|
;;
|
|
|
|
|
up) ;;
|
|
|
|
|
*) echo "Usage: $0 [up|status|stop]" >&2; exit 2 ;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
# --- 1. initdb (first run only) --------------------------------------------
|
|
|
|
|
if [[ ! -s "${DATADIR}/PG_VERSION" ]]; then
|
|
|
|
|
echo "==> initdb ${DATADIR} ..."
|
|
|
|
|
mkdir -p "$(dirname "${DATADIR}")"
|
|
|
|
|
"${PG_BIN}/initdb" -D "${DATADIR}" -U "${USER}" --encoding=UTF8 --locale=C >/dev/null
|
|
|
|
|
# Dedicated port; trust loopback so the E2E password is irrelevant but valid.
|
|
|
|
|
{
|
|
|
|
|
echo "port = ${PORT}"
|
|
|
|
|
echo "listen_addresses = '127.0.0.1,::1'"
|
|
|
|
|
echo "unix_socket_directories = '${DATADIR}'"
|
|
|
|
|
} >> "${DATADIR}/postgresql.conf"
|
|
|
|
|
else
|
|
|
|
|
echo "==> datadir ${DATADIR} already initialized."
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- 2. start --------------------------------------------------------------
|
|
|
|
|
mkdir -p "$(dirname "${LOGFILE}")"
|
|
|
|
|
if ! is_running; then
|
|
|
|
|
echo "==> starting quinn-e2e PG on :${PORT} ..."
|
|
|
|
|
"${PG_BIN}/pg_ctl" -D "${DATADIR}" -l "${LOGFILE}" -w start
|
|
|
|
|
else
|
|
|
|
|
echo "==> quinn-e2e PG already running."
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# --- 3. provision role + databases (idempotent) ----------------------------
|
|
|
|
|
PSQL=("${PG_BIN}/psql" -h localhost -p "${PORT}" -d postgres -v ON_ERROR_STOP=1 -X)
|
|
|
|
|
echo "==> provisioning role '${ROLE}' + databases ..."
|
|
|
|
|
"${PSQL[@]}" -tAc "select 1 from pg_roles where rolname='${ROLE}'" | grep -q 1 || \
|
|
|
|
|
"${PSQL[@]}" -c "create role ${ROLE} login superuser password '${ROLE_PW}'"
|
|
|
|
|
# Keep the password in sync even if the role pre-existed.
|
|
|
|
|
"${PSQL[@]}" -c "alter role ${ROLE} password '${ROLE_PW}'" >/dev/null
|
2026-06-25 02:30:04 -04:00
|
|
|
"${PSQL[@]}" -tAc "select 1 from pg_roles where rolname='${API_ROLE}'" | grep -q 1 || \
|
|
|
|
|
"${PSQL[@]}" -c "create role ${API_ROLE}"
|
2026-06-21 15:08:09 -05:00
|
|
|
for db in "${DBS[@]}"; do
|
|
|
|
|
"${PSQL[@]}" -tAc "select 1 from pg_database where datname='${db}'" | grep -q 1 || \
|
|
|
|
|
"${PSQL[@]}" -c "create database ${db} owner ${ROLE}"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# --- 4. LaunchAgent for reboot persistence ---------------------------------
|
|
|
|
|
if [[ ! -f "${PLIST}" ]]; then
|
|
|
|
|
echo "==> installing LaunchAgent ${PLIST} ..."
|
|
|
|
|
mkdir -p "$(dirname "${PLIST}")"
|
|
|
|
|
cat > "${PLIST}" <<PLISTEOF
|
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
|
|
|
<plist version="1.0">
|
|
|
|
|
<dict>
|
|
|
|
|
<key>Label</key><string>com.lilith.quinn-e2e-pg</string>
|
|
|
|
|
<key>ProgramArguments</key>
|
|
|
|
|
<array>
|
|
|
|
|
<string>${PG_BIN}/postgres</string>
|
|
|
|
|
<string>-D</string><string>${DATADIR}</string>
|
|
|
|
|
</array>
|
|
|
|
|
<key>EnvironmentVariables</key>
|
|
|
|
|
<dict><key>LC_ALL</key><string>C</string></dict>
|
|
|
|
|
<key>RunAtLoad</key><true/>
|
|
|
|
|
<key>KeepAlive</key><true/>
|
|
|
|
|
<key>StandardOutPath</key><string>${LOGFILE}</string>
|
|
|
|
|
<key>StandardErrorPath</key><string>${LOGFILE}</string>
|
|
|
|
|
</dict>
|
|
|
|
|
</plist>
|
|
|
|
|
PLISTEOF
|
|
|
|
|
launchctl bootstrap "gui/$(id -u)" "${PLIST}" 2>/dev/null || launchctl load "${PLIST}" 2>/dev/null || true
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
echo "quinn-e2e PG ready: postgresql://${ROLE}:${ROLE_PW}@localhost:${PORT}/quinn_admin_test"
|