officer-setup section 5: Postgres, and only Postgres
The original offered five containers. Of those:
Postgres the only database Officer has — account, passkeys, settings,
dashboards, email accounts, the queue. Required.
Redis not referenced anywhere in the platform. No import of the client,
no environment variable, no mention; the only "redis" string in
src/ is the word "rediscover" in a comment. Dropped. (It is still
in package.json and comes out in the dependency pass.)
SearXNG zero references anywhere. Dropped. If it ever arrives it brings
its own compose file and its own Redis with it.
Mailhog a development convenience, offered separately rather than here.
Nginx PM a deployment choice — Caddy, Traefik, nginx or the tailnet — and
not something a setup script should pick.
Provisioned into $OFFICER_ROOT/dockers/postgres/, the same convention the app
store uses: one directory per service, the compose file in it, relative bind
mounts so the data sits beside the compose file.
Bound to 127.0.0.1, deliberately and with the reason in the compose file itself.
Docker publishes ports by writing iptables rules underneath ufw, so "5432:5432"
is reachable from the internet whatever the firewall reports — the same mechanism
the machine-setup firewall section exists to close. The platform runs on this
machine, so loopback is all it needs.
The password lives in a 0600 .env beside the compose file rather than inside it,
so the compose file can be read or copied without carrying a credential. A second
run reuses it rather than minting a new one, which would leave the container and
the URL disagreeing.
Readiness is waited for rather than assumed: Postgres initialises its data
directory on first start, and db:push against a database that is still starting
fails in a way that reads as a schema problem.
Choosing an existing database checks the URL but does not insist on it — the URL
may be right and the database not yet started, and refusing to continue over that
would be worse than saying so.
Also carries the whitespace fix for the comment removed in the previous commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,8 @@ source "$SCRIPT_DIR/officer-setup/lib/preflight.sh"
|
||||
source "$SCRIPT_DIR/officer-setup/lib/repo.sh"
|
||||
# shellcheck source=officer-setup/lib/layout.sh
|
||||
source "$SCRIPT_DIR/officer-setup/lib/layout.sh"
|
||||
# shellcheck source=officer-setup/lib/postgres.sh
|
||||
source "$SCRIPT_DIR/officer-setup/lib/postgres.sh"
|
||||
|
||||
trap 'echo ""; echo -e "${RED}╔══════════════════════════════════════════════════╗${NC}"; echo -e "${RED}║ OFFICER SETUP FAILED${NC}"; echo -e "${RED}║ Step: ${CURRENT_STEP:-unknown}${NC}"; echo -e "${RED}║ Line: $LINENO${NC}"; echo -e "${RED}║ Command: $BASH_COMMAND${NC}"; echo -e "${RED}╚══════════════════════════════════════════════════╝${NC}"' ERR
|
||||
|
||||
@@ -326,10 +328,119 @@ if ! skip; then
|
||||
step_ok
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# 5. Database
|
||||
# =============================================================================
|
||||
#
|
||||
# POSTGRES_URL is set here and written by the environment section below.
|
||||
|
||||
step "Database"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
info "Database — Postgres, the only one Officer has"
|
||||
echo " It holds the account, passkeys, settings, dashboards, email"
|
||||
echo " accounts and the job queue. Nothing else in the platform is a"
|
||||
echo " database."
|
||||
echo ""
|
||||
echo " compose file: $(pg_compose_exists && echo "$(pg_compose_file)" || echo 'not written yet')"
|
||||
echo " container: $(pg_container_running && echo "${PG_CONTAINER} running" || echo 'not running')"
|
||||
echo " port ${PG_PORT}: $(pg_port_in_use && echo 'something is listening' || echo 'free')"
|
||||
|
||||
POSTGRES_URL=""
|
||||
|
||||
# An existing compose file means this ran before. Reuse its password rather
|
||||
# than minting a new one, which would leave the container and the URL
|
||||
# disagreeing about the credential.
|
||||
if pg_compose_exists && PG_EXISTING_PASSWORD="$(pg_password_from_env_file)"; then
|
||||
POSTGRES_URL="$(pg_url "$PG_EXISTING_PASSWORD")"
|
||||
echo ""
|
||||
echo " already provisioned here — reusing the password from $(pg_env_file)"
|
||||
pg_container_running || {
|
||||
info " starting it"
|
||||
pg_compose_up >/dev/null 2>&1 || true
|
||||
}
|
||||
if pg_wait_ready; then
|
||||
ok "postgres answering on 127.0.0.1:${PG_PORT}"
|
||||
SUMMARY+=("Database: existing Postgres at ${PG_CONTAINER}")
|
||||
else
|
||||
warn "the container is not answering — check: docker logs ${PG_CONTAINER}"
|
||||
ERRORS+=("Database: provisioned but not answering")
|
||||
fi
|
||||
|
||||
else
|
||||
echo ""
|
||||
info "Which Postgres should Officer use?"
|
||||
echo ""
|
||||
echo " [1] provision one here"
|
||||
echo " ${PG_IMAGE} in $(pg_service_dir), bound to 127.0.0.1 only."
|
||||
echo " Docker publishes ports by writing iptables rules beneath ufw,"
|
||||
echo " so a database published to every interface is reachable from"
|
||||
echo " the internet whatever the firewall says. Loopback is all the"
|
||||
echo " platform needs — it runs on this machine."
|
||||
echo ""
|
||||
echo " [2] use one you already run"
|
||||
echo " Give the connection URL. Nothing is provisioned."
|
||||
echo ""
|
||||
|
||||
DB_PICK=""
|
||||
while [[ -z "$DB_PICK" ]]; do
|
||||
if ! read -rp " Which one? (1/2) [1]: " DB_CHOICE; then
|
||||
echo ""
|
||||
fail "No answer."
|
||||
fi
|
||||
case "${DB_CHOICE:-1}" in
|
||||
1)
|
||||
if ! command -v docker &>/dev/null; then
|
||||
warn "Docker is not installed, so there is nothing to provision into."
|
||||
continue
|
||||
fi
|
||||
if pg_port_in_use; then
|
||||
warn "something is already listening on ${PG_PORT} — provisioning here would fail to bind"
|
||||
echo " If that is a Postgres you already run, pick 2 and give its URL."
|
||||
continue
|
||||
fi
|
||||
DB_PICK=provision
|
||||
;;
|
||||
2) DB_PICK=existing ;;
|
||||
*) warn "Pick 1 or 2." ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$DB_PICK" == provision ]]; then
|
||||
PG_PASSWORD="$(openssl rand -base64 32 | tr -d '/+=' | head -c 32)"
|
||||
write_pg_compose "$PG_PASSWORD"
|
||||
ok "compose written to $(pg_compose_file)"
|
||||
if pg_compose_up && pg_wait_ready; then
|
||||
POSTGRES_URL="$(pg_url "$PG_PASSWORD")"
|
||||
ok "postgres answering on 127.0.0.1:${PG_PORT}, database '${PG_DATABASE}'"
|
||||
SUMMARY+=("Database: provisioned at $(pg_service_dir)")
|
||||
else
|
||||
warn "the container did not come up — check: docker logs ${PG_CONTAINER}"
|
||||
ERRORS+=("Database: container did not start")
|
||||
SUMMARY+=("Database: provisioning FAILED")
|
||||
fi
|
||||
else
|
||||
echo ""
|
||||
ask_required POSTGRES_URL "Connection URL" "postgresql://user:password@host:5432/officer"
|
||||
if pg_url_works "$POSTGRES_URL"; then
|
||||
ok "reachable"
|
||||
SUMMARY+=("Database: existing, ${POSTGRES_URL%%:*}://…")
|
||||
else
|
||||
# Not fatal. The URL may be right and the database not started yet, and
|
||||
# refusing to continue over that would be worse than saying so.
|
||||
warn "could not connect with that URL"
|
||||
echo " Kept anyway — check it before running the schema step."
|
||||
ERRORS+=("Database: the given URL did not answer")
|
||||
SUMMARY+=("Database: existing URL kept, did not answer")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
step_ok
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# NOT BUILT YET
|
||||
# =============================================================================
|
||||
# 4 Database Postgres in docker, or one you already run
|
||||
# 5 Environment .env
|
||||
# 6 Schema db:push
|
||||
# 7 Build gen:index
|
||||
|
||||
Reference in New Issue
Block a user