Files
Superminaren d81a49175b
CI / check (push) Canceled after 0s
CI / integration-e2e (push) Canceled after 0s
Deploy to production / deploy (push) Canceled after 0s
Updated
2026-10-14 23:30:02 +02:00

79 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# setup-space.sh: create the single space and its first admin on the
# docker-compose.yml stack. Wraps scripts/setup.mjs (the same code as
# `pnpm setup`) and runs it in a container on the stack's network, so the
# host needs only Docker: no Node, no pnpm, no node_modules.
#
# Usage: scripts/setup-space.sh [command] [setup.mjs flags]
# scripts/setup-space.sh interactive: space, then admin
# scripts/setup-space.sh doctor check config and DB connectivity
# scripts/setup-space.sh --yes \
# --admin-email [email protected] --admin-password '...'
#
# Reads from .env: SERVICE_ROLE_KEY, ANON_KEY, NEXT_PUBLIC_APP_URL,
# NEXT_PUBLIC_SITE_NAME and NEXT_PUBLIC_SINGLE_TENANT_SPACE_SLUG (used as the
# default space name and slug), and any SETUP_* values. Flags override these.
# The stack must already be running. If the database has no schema yet (a fresh
# volume), scripts/schema.sql is applied first.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ENV_FILE="$ROOT/.env"
NETWORK="hackerspace_net"
IMAGE="hackerspace-setup:local"
command -v docker >/dev/null || { echo "error: docker is required" >&2; exit 1; }
[[ -f "$ENV_FILE" ]] || { echo "error: $ENV_FILE not found; run scripts/generate-env.sh first" >&2; exit 1; }
docker network inspect "$NETWORK" >/dev/null 2>&1 \
|| { echo "error: network $NETWORK not found; start the stack with 'docker compose up -d'" >&2; exit 1; }
# Read single keys instead of sourcing the file, so nothing in it is executed.
env_get() { grep -E "^$1=" "$ENV_FILE" | tail -n1 | cut -d= -f2- || true; }
SERVICE_KEY="$(env_get SERVICE_ROLE_KEY)"
ANON="$(env_get ANON_KEY)"
[[ -n "$SERVICE_KEY" && -n "$ANON" ]] \
|| { echo "error: SERVICE_ROLE_KEY or ANON_KEY is empty in .env" >&2; exit 1; }
export NEXT_PUBLIC_SUPABASE_URL="http://kong:8000"
export NEXT_PUBLIC_SUPABASE_ANON_KEY="$ANON"
export SUPABASE_SERVICE_ROLE_KEY="$SERVICE_KEY"
export NEXT_PUBLIC_APP_URL="$(env_get NEXT_PUBLIC_APP_URL)"
for name in SETUP_SPACE_NAME SETUP_SPACE_SLUG SETUP_SPACE_CITY \
SETUP_ADMIN_EMAIL SETUP_ADMIN_PASSWORD SETUP_ADMIN_NAME; do
export "$name=$(env_get "$name")"
done
[[ -n "$SETUP_SPACE_NAME" ]] || export SETUP_SPACE_NAME="$(env_get NEXT_PUBLIC_SITE_NAME)"
[[ -n "$SETUP_SPACE_SLUG" ]] || export SETUP_SPACE_SLUG="$(env_get NEXT_PUBLIC_SINGLE_TENANT_SPACE_SLUG)"
dc() { docker compose -f "$ROOT/docker-compose.yml" "$@"; }
if [[ "$(dc exec -T db psql -U postgres -d postgres -Atc "select to_regclass('public.spaces') is not null" 2>/dev/null)" != "t" ]]; then
echo "No schema found; applying scripts/schema.sql"
dc exec -T db psql -v ON_ERROR_STOP=1 -q -U postgres -d postgres < "$ROOT/scripts/schema.sql" >/dev/null
# PostgREST caches the schema; restart so it sees the new tables.
dc restart rest >/dev/null
until [[ "$(dc ps rest --format '{{.State}}')" == "running" ]]; do sleep 1; done
sleep 3
fi
# The Dockerfile deps stage is Node plus installed node_modules; the scripts
# directory is mounted so edits to setup.mjs apply without a rebuild.
docker build -q --target deps -t "$IMAGE" "$ROOT" >/dev/null
tty_flags=()
[[ -t 0 && -t 1 ]] && tty_flags=(-it)
# `-e NAME` without a value forwards the variable, so secrets stay off the
# docker command line.
exec docker run --rm "${tty_flags[@]}" --network "$NETWORK" \
-v "$ROOT/scripts:/app/scripts:ro" \
-e NEXT_PUBLIC_SUPABASE_URL -e NEXT_PUBLIC_SUPABASE_ANON_KEY \
-e SUPABASE_SERVICE_ROLE_KEY -e NEXT_PUBLIC_APP_URL \
-e SETUP_SPACE_NAME -e SETUP_SPACE_SLUG -e SETUP_SPACE_CITY \
-e SETUP_ADMIN_EMAIL -e SETUP_ADMIN_PASSWORD -e SETUP_ADMIN_NAME \
"$IMAGE" node scripts/setup.mjs "$@"