445 lines
15 KiB
Bash
Executable File
445 lines
15 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
ENV_FILE="${ROOT_DIR}/.env"
|
||
ENV_EXAMPLE="${ROOT_DIR}/.env.example"
|
||
|
||
# ── Colors ──────────────────────────────────────────────
|
||
BOLD='\033[1m'
|
||
DIM='\033[2m'
|
||
GREEN='\033[32m'
|
||
BLUE='\033[34m'
|
||
YELLOW='\033[33m'
|
||
RED='\033[31m'
|
||
NC='\033[0m'
|
||
|
||
section() { echo -e "\n${BOLD}${BLUE}${*}${NC}"; }
|
||
success() { echo -e "${GREEN}✓${NC} ${*}"; }
|
||
info() { echo -e " ${DIM}${*}${NC}"; }
|
||
warn() { echo -e "${YELLOW}⚠${NC} ${*}"; }
|
||
error() { echo -e "${RED}✗${NC} ${*}" >&2; }
|
||
|
||
# ── Helpers ──────────────────────────────────────────────
|
||
random() {
|
||
openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c "${1:-32}"
|
||
}
|
||
|
||
random_password() {
|
||
openssl rand -base64 48 | tr -dc 'A-Za-z0-9@%+=_.-' | head -c "${1:-20}"
|
||
}
|
||
|
||
ask() {
|
||
local label="$1"; local default="${2:-}"; local answer
|
||
if [[ -n "${default}" ]]; then
|
||
read -r -p " ${label} [${default}]: " answer
|
||
else
|
||
read -r -p " ${label}: " answer
|
||
fi
|
||
echo "${answer:-${default}}"
|
||
}
|
||
|
||
ask_yn() {
|
||
local label="$1"; local default_yes="${2:-true}"; local hint answer
|
||
[[ "${default_yes}" == "true" ]] && hint="J/n" || hint="j/N"
|
||
while true; do
|
||
read -r -p " ${label} [${hint}]: " answer
|
||
answer="$(echo "${answer}" | tr '[:upper:]' '[:lower:]')"
|
||
[[ -z "${answer}" && "${default_yes}" == "true" ]] && return 0
|
||
[[ -z "${answer}" && "${default_yes}" == "false" ]] && return 1
|
||
[[ "${answer}" =~ ^(j|ja|y|yes)$ ]] && return 0
|
||
[[ "${answer}" =~ ^(n|nein|no)$ ]] && return 1
|
||
echo " → Bitte mit j oder n antworten."
|
||
done
|
||
}
|
||
|
||
ask_choice() {
|
||
local label="$1"; local default="$2"; shift 2; local options=("$@"); local value
|
||
while true; do
|
||
value="$(ask "${label} (${options[*]})" "${default}")"
|
||
value="$(echo "${value}" | tr '[:upper:]' '[:lower:]')"
|
||
for opt in "${options[@]}"; do
|
||
[[ "${value}" == "${opt}" ]] && { echo "${value}"; return; }
|
||
done
|
||
echo " → Erlaubt: ${options[*]}"
|
||
done
|
||
}
|
||
|
||
get_env() {
|
||
local key="$1"
|
||
if [[ ! -f "${ENV_FILE}" ]]; then echo ""; return; fi
|
||
local line val
|
||
line="$(grep -E "^${key}=" "${ENV_FILE}" | head -n1 || true)"
|
||
[[ -z "${line}" ]] && { echo ""; return; }
|
||
val="${line#*=}"
|
||
val="${val#\"}"; val="${val%\"}"
|
||
val="${val#\'}"; val="${val%\'}"
|
||
echo "${val}"
|
||
}
|
||
|
||
set_env() {
|
||
local key="$1"; local value="$2"
|
||
if grep -qE "^${key}=" "${ENV_FILE}" 2>/dev/null; then
|
||
sed -i "s|^${key}=.*|${key}=${value}|" "${ENV_FILE}"
|
||
else
|
||
echo "${key}=${value}" >> "${ENV_FILE}"
|
||
fi
|
||
}
|
||
|
||
is_placeholder() {
|
||
local val; val="$(echo "${1:-}" | tr '[:upper:]' '[:lower:]')"
|
||
[[ -z "${val}" ]] && return 0
|
||
[[ "${val}" == change_me* ]] && return 0
|
||
[[ "${val}" == *random-secret* ]] && return 0
|
||
[[ "${val}" == *random-key* ]] && return 0
|
||
[[ "${val}" == *random-salt* ]] && return 0
|
||
[[ "${val}" == bitte-* ]] && return 0
|
||
return 1
|
||
}
|
||
|
||
mask() {
|
||
local val="${1:-}"
|
||
[[ ${#val} -le 8 ]] && { echo "********"; return; }
|
||
echo "${val:0:4}...${val: -4}"
|
||
}
|
||
|
||
urlencode() {
|
||
local s="${1:-}"; local len="${#s}"; local out="" char c
|
||
for ((i=0; i<len; i++)); do
|
||
char="${s:i:1}"
|
||
case "${char}" in
|
||
[a-zA-Z0-9.~_-]) out+="${char}" ;;
|
||
*) printf -v c '%%%02X' "'${char}"; out+="${c}" ;;
|
||
esac
|
||
done
|
||
echo "${out}"
|
||
}
|
||
|
||
check_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||
|
||
# ── Prerequisites ────────────────────────────────────────
|
||
section "[1/5] Voraussetzungen prüfen"
|
||
|
||
if ! check_cmd docker; then
|
||
error "Docker ist nicht installiert. Bitte installiere Docker zuerst."
|
||
info "→ https://docs.docker.com/engine/install/"
|
||
exit 1
|
||
fi
|
||
|
||
if ! docker info >/dev/null 2>&1; then
|
||
error "Docker-Daemon läuft nicht oder du hast keine Zugriffsrechte."
|
||
exit 1
|
||
fi
|
||
|
||
success "Docker läuft"
|
||
|
||
if ! check_cmd openssl; then
|
||
error "openssl wird benötigt (für Secret-Generierung)."
|
||
exit 1
|
||
fi
|
||
|
||
COMPOSE_CMD="docker compose"
|
||
if ! docker compose version >/dev/null 2>&1; then
|
||
if check_cmd docker-compose; then
|
||
COMPOSE_CMD="docker-compose"
|
||
else
|
||
error "Weder 'docker compose' noch 'docker-compose' gefunden."
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
success "Compose verfügbar (${COMPOSE_CMD})"
|
||
|
||
# ── Initialise .env ──────────────────────────────────────
|
||
ENV_EXISTS=false
|
||
[[ -f "${ENV_FILE}" ]] && ENV_EXISTS=true
|
||
|
||
if ${ENV_EXISTS}; then
|
||
if ask_yn ".env existiert bereits. Werte übernehmen?" "true"; then
|
||
info "Bestehende .env wird erweitert/aktualisiert."
|
||
else
|
||
cp "${ENV_EXAMPLE}" "${ENV_FILE}"
|
||
info "Neue .env aus Vorlage erstellt."
|
||
NEW_ENV=true
|
||
fi
|
||
else
|
||
cp "${ENV_EXAMPLE}" "${ENV_FILE}"
|
||
info ".env aus Vorlage erstellt."
|
||
NEW_ENV=true
|
||
fi
|
||
|
||
# ── [2/5] Base config ────────────────────────────────────
|
||
section "[2/5] Basis-Konfiguration"
|
||
|
||
if ${ENV_EXISTS} && ! is_placeholder "$(get_env PUBLIC_URL)"; then
|
||
_existing_url="$(get_env PUBLIC_URL)"
|
||
else
|
||
_existing_url="http://localhost:3000"
|
||
fi
|
||
|
||
while true; do
|
||
PUBLIC_URL="$(ask "Öffentliche URL der App" "${_existing_url}")"
|
||
if [[ "${PUBLIC_URL}" =~ ^https?:// ]]; then
|
||
break
|
||
fi
|
||
echo " → Bitte mit http:// oder https:// beginnen."
|
||
done
|
||
|
||
STACK_NAME="$(ask "Container-Präfix (für docker ps)" "$(get_env STACK_NAME)")"
|
||
[[ -z "${STACK_NAME}" ]] && STACK_NAME="calbook"
|
||
TIMEZONE="$(ask "Zeitzone" "$(get_env DEFAULT_TIMEZONE)")"
|
||
[[ -z "${TIMEZONE}" ]] && TIMEZONE="Europe/Berlin"
|
||
|
||
DEPLOYMENT_MODE="$(ask_choice "Deployment-Modus" \
|
||
"$([[ "$(get_env DEPLOYMENT_MODE)" == "proxy" ]] && echo "proxy" || echo "direct")" \
|
||
"direct" "proxy")"
|
||
|
||
if [[ "${DEPLOYMENT_MODE}" == "direct" ]]; then
|
||
COMPOSE_FILE="${ROOT_DIR}/docker-compose.direct.yml"
|
||
TRUST_PROXY="false"
|
||
else
|
||
COMPOSE_FILE="${ROOT_DIR}/docker-compose.proxy.yml"
|
||
TRUST_PROXY="true"
|
||
|
||
TRAEFIK_HOST="$(echo "${PUBLIC_URL}" | sed -E 's#^[a-zA-Z]+://##' | cut -d/ -f1 | cut -d: -f1)"
|
||
if [[ -z "${TRAEFIK_HOST}" || "${TRAEFIK_HOST}" == "localhost" || "${TRAEFIK_HOST}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||
TRAEFIK_HOST="calbook.local"
|
||
fi
|
||
TRAEFIK_HOST="$(ask "Domain für Traefik (aus URL abgeleitet)" "${TRAEFIK_HOST}")"
|
||
[[ -z "${TRAEFIK_HOST}" ]] && TRAEFIK_HOST="calbook.local"
|
||
|
||
TRAEFIK_ENTRYPOINTS="$(ask "Traefik Entrypoints" "$(get_env TRAEFIK_ENTRYPOINTS)")"
|
||
[[ -z "${TRAEFIK_ENTRYPOINTS}" ]] && TRAEFIK_ENTRYPOINTS="websecure"
|
||
|
||
if [[ "${PUBLIC_URL}" == https://* ]]; then
|
||
TRAEFIK_TLS="true"
|
||
else
|
||
TRAEFIK_TLS="false"
|
||
fi
|
||
TRAEFIK_TLS="$(ask_yn "TLS aktivieren?" "${TRAEFIK_TLS}" && echo "true" || echo "false")"
|
||
|
||
if [[ "${TRAEFIK_TLS}" == "true" ]]; then
|
||
TRAEFIK_CERTRESOLVER="$(ask "Certresolver" "$(get_env TRAEFIK_CERTRESOLVER)")"
|
||
[[ -z "${TRAEFIK_CERTRESOLVER}" ]] && TRAEFIK_CERTRESOLVER="tls_resolver"
|
||
else
|
||
TRAEFIK_CERTRESOLVER="$(get_env TRAEFIK_CERTRESOLVER)"
|
||
[[ -z "${TRAEFIK_CERTRESOLVER}" ]] && TRAEFIK_CERTRESOLVER="tls_resolver"
|
||
fi
|
||
|
||
TRAEFIK_NETWORK="$(ask "Traefik Docker-Netzwerk" "$(get_env TRAEFIK_DOCKER_NETWORK)")"
|
||
[[ -z "${TRAEFIK_NETWORK}" ]] && TRAEFIK_NETWORK="proxy"
|
||
|
||
TRAEFIK_ROUTER="$(ask "Traefik Router-Name" "$(get_env TRAEFIK_ROUTER_NAME)")"
|
||
[[ -z "${TRAEFIK_ROUTER}" ]] && TRAEFIK_ROUTER="calbook"
|
||
|
||
TRAEFIK_SERVICE="$(ask "Traefik Service-Name" "$(get_env TRAEFIK_SERVICE_NAME)")"
|
||
[[ -z "${TRAEFIK_SERVICE}" ]] && TRAEFIK_SERVICE="calbook"
|
||
fi
|
||
|
||
success "URL: ${PUBLIC_URL} | Stack: ${STACK_NAME} | Modus: ${DEPLOYMENT_MODE}"
|
||
|
||
# ── [3/5] Admin ──────────────────────────────────────────
|
||
section "[3/5] Admin-Zugang"
|
||
|
||
ADMIN_EMAIL="$(ask "Admin E-Mail" "$(get_env ADMIN_EMAIL)")"
|
||
[[ -z "${ADMIN_EMAIL}" ]] && ADMIN_EMAIL="admin@calbook.local"
|
||
|
||
ADMIN_NAME="$(ask "Admin Name" "$(get_env ADMIN_NAME)")"
|
||
[[ -z "${ADMIN_NAME}" ]] && ADMIN_NAME="CalBook Admin"
|
||
|
||
existing_pw="$(get_env ADMIN_PASSWORD)"
|
||
if ${ENV_EXISTS} && ! is_placeholder "${existing_pw}"; then
|
||
if ask_yn "Admin-Passwort beibehalten?" "true"; then
|
||
ADMIN_PASSWORD="${existing_pw}"
|
||
else
|
||
ADMIN_PASSWORD="$(ask "Neues Admin-Passwort (min. 12 Zeichen)" "")"
|
||
[[ -z "${ADMIN_PASSWORD}" ]] && ADMIN_PASSWORD="$(random_password 20)"
|
||
fi
|
||
else
|
||
ADMIN_PASSWORD="$(ask "Admin-Passwort (leer = automatisch generieren)" "")"
|
||
[[ -z "${ADMIN_PASSWORD}" ]] && ADMIN_PASSWORD="$(random_password 20)"
|
||
fi
|
||
|
||
success "Admin: ${ADMIN_EMAIL}"
|
||
|
||
# ── [4/5] SMTP & Jitsi ───────────────────────────────────
|
||
section "[4/5] E-Mail & Videokonferenz"
|
||
|
||
SMTP_MODE="$(ask_choice "SMTP-Modus" \
|
||
"$([[ "$(get_env SMTP_HOST)" == "mailhog" || -z "$(get_env SMTP_HOST)" ]] && echo "mailhog" || echo "custom")" \
|
||
"mailhog" "custom" "off")"
|
||
|
||
if [[ "${SMTP_MODE}" == "mailhog" ]]; then
|
||
SMTP_HOST="mailhog"
|
||
SMTP_PORT="1025"
|
||
SMTP_USER=""
|
||
SMTP_PASS=""
|
||
elif [[ "${SMTP_MODE}" == "custom" ]]; then
|
||
SMTP_HOST="$(ask "SMTP-Host" "$(get_env SMTP_HOST)")"
|
||
SMTP_PORT="$(ask "SMTP-Port" "$(get_env SMTP_PORT)")"
|
||
[[ -z "${SMTP_PORT}" ]] && SMTP_PORT="587"
|
||
SMTP_USER="$(ask "SMTP-Benutzer (optional)" "$(get_env SMTP_USER)")"
|
||
SMTP_PASS="$(ask "SMTP-Passwort (optional)" "$(get_env SMTP_PASS)")"
|
||
else
|
||
SMTP_HOST=""
|
||
SMTP_PORT="587"
|
||
SMTP_USER=""
|
||
SMTP_PASS=""
|
||
fi
|
||
|
||
SMTP_FROM_NAME="$(ask "Absendername" "$(get_env SMTP_FROM_NAME)")"
|
||
[[ -z "${SMTP_FROM_NAME}" ]] && SMTP_FROM_NAME="${ADMIN_NAME}"
|
||
|
||
SMTP_FROM="$(ask "Absender-E-Mail" "$(get_env SMTP_FROM)")"
|
||
[[ -z "${SMTP_FROM}" ]] && SMTP_FROM="no-reply@calbook.local"
|
||
|
||
JITSI_MODE="$(ask_choice "Jitsi-Modus" "$(get_env JITSI_MEETING_MODE)" "public" "custom")"
|
||
if [[ "${JITSI_MODE}" == "custom" ]]; then
|
||
JITSI_URL="$(ask "Jitsi-Basis-URL" "$(get_env JITSI_BASE_URL)")"
|
||
else
|
||
JITSI_URL="https://meet.jit.si"
|
||
fi
|
||
JITSI_PREFIX="$(ask "Jitsi-Raum-Präfix" "$(get_env JITSI_ROOM_PREFIX)")"
|
||
[[ -z "${JITSI_PREFIX}" ]] && JITSI_PREFIX="calbook"
|
||
|
||
success "SMTP: ${SMTP_MODE} | Jitsi: ${JITSI_MODE}"
|
||
|
||
# ── Generate secrets ─────────────────────────────────────
|
||
NEXTAUTH_SECRET="$(random 64)"
|
||
CRON_SECRET="$(random 48)"
|
||
CALDAV_KEY="$(random 64)"
|
||
JITSI_SALT="$(random 48)"
|
||
POSTGRES_PASSWORD="$(random_password 24)"
|
||
|
||
# Keep existing strong secrets if present
|
||
_secret_keys=(NEXTAUTH_SECRET CRON_SECRET CALDAV_ENCRYPTION_KEY JITSI_ROOM_SALT POSTGRES_PASSWORD)
|
||
for key in "${_secret_keys[@]}"; do
|
||
existing="$(get_env "${key}")"
|
||
if [[ -n "${existing}" ]] && ! is_placeholder "${existing}"; then
|
||
declare "${key}=${existing}"
|
||
fi
|
||
done
|
||
|
||
POSTGRES_DB="$(get_env POSTGRES_DB)"
|
||
[[ -z "${POSTGRES_DB}" ]] && POSTGRES_DB="calbook"
|
||
POSTGRES_USER="$(get_env POSTGRES_USER)"
|
||
[[ -z "${POSTGRES_USER}" ]] && POSTGRES_USER="calbook"
|
||
|
||
DATABASE_URL="postgresql://$(urlencode "${POSTGRES_USER}"):$(urlencode "${POSTGRES_PASSWORD}")@db:5432/$(urlencode "${POSTGRES_DB}")?schema=public"
|
||
|
||
# ── Write .env ───────────────────────────────────────────
|
||
set_env "STACK_NAME" "${STACK_NAME}"
|
||
set_env "DEPLOYMENT_MODE" "${DEPLOYMENT_MODE}"
|
||
set_env "PUBLIC_URL" "${PUBLIC_URL}"
|
||
set_env "NEXTAUTH_URL" "${PUBLIC_URL}"
|
||
set_env "APP_BASE_URL" "${PUBLIC_URL}"
|
||
set_env "NEXTAUTH_SECRET" "${NEXTAUTH_SECRET}"
|
||
set_env "CRON_SECRET" "${CRON_SECRET}"
|
||
set_env "TRUST_PROXY_HEADERS" "${TRUST_PROXY}"
|
||
set_env "DEFAULT_TIMEZONE" "${TIMEZONE}"
|
||
|
||
set_env "ADMIN_NAME" "${ADMIN_NAME}"
|
||
set_env "ADMIN_EMAIL" "${ADMIN_EMAIL}"
|
||
set_env "ADMIN_PASSWORD" "${ADMIN_PASSWORD}"
|
||
|
||
set_env "POSTGRES_DB" "${POSTGRES_DB}"
|
||
set_env "POSTGRES_USER" "${POSTGRES_USER}"
|
||
set_env "POSTGRES_PASSWORD" "${POSTGRES_PASSWORD}"
|
||
set_env "DATABASE_URL" "${DATABASE_URL}"
|
||
|
||
set_env "CALDAV_ENCRYPTION_KEY" "${CALDAV_KEY}"
|
||
set_env "JITSI_ROOM_SALT" "${JITSI_SALT}"
|
||
|
||
set_env "SMTP_HOST" "${SMTP_HOST}"
|
||
set_env "SMTP_PORT" "${SMTP_PORT}"
|
||
set_env "SMTP_USER" "${SMTP_USER}"
|
||
set_env "SMTP_PASS" "${SMTP_PASS}"
|
||
set_env "SMTP_FROM_NAME" "${SMTP_FROM_NAME}"
|
||
set_env "SMTP_FROM" "${SMTP_FROM}"
|
||
|
||
set_env "JITSI_MEETING_MODE" "${JITSI_MODE}"
|
||
set_env "JITSI_BASE_URL" "${JITSI_URL}"
|
||
set_env "JITSI_ROOM_PREFIX" "${JITSI_PREFIX}"
|
||
|
||
if [[ "${DEPLOYMENT_MODE}" == "proxy" ]]; then
|
||
set_env "ENABLE_TRAEFIK" "true"
|
||
set_env "TRAEFIK_HOST" "${TRAEFIK_HOST}"
|
||
set_env "TRAEFIK_ENTRYPOINTS" "${TRAEFIK_ENTRYPOINTS}"
|
||
set_env "TRAEFIK_TLS" "${TRAEFIK_TLS}"
|
||
set_env "TRAEFIK_CERTRESOLVER" "${TRAEFIK_CERTRESOLVER}"
|
||
set_env "TRAEFIK_ROUTER_NAME" "${TRAEFIK_ROUTER}"
|
||
set_env "TRAEFIK_SERVICE_NAME" "${TRAEFIK_SERVICE}"
|
||
set_env "TRAEFIK_DOCKER_NETWORK" "${TRAEFIK_NETWORK}"
|
||
else
|
||
set_env "ENABLE_TRAEFIK" "false"
|
||
fi
|
||
|
||
info ".env geschrieben."
|
||
|
||
# ── [5/5] Build & Start ──────────────────────────────────
|
||
section "[5/5] Container starten & Datenbank einrichten"
|
||
|
||
if [[ "${DEPLOYMENT_MODE}" == "proxy" ]]; then
|
||
docker network inspect "${TRAEFIK_NETWORK}" >/dev/null 2>&1 || {
|
||
info "Erstelle Traefik-Netzwerk: ${TRAEFIK_NETWORK}"
|
||
docker network create "${TRAEFIK_NETWORK}"
|
||
}
|
||
fi
|
||
|
||
if [[ "${NEW_ENV:-false}" == "true" ]]; then
|
||
VOLUME_DIR="${ROOT_DIR}/volumes/postgres-${STACK_NAME}"
|
||
if [[ -d "${VOLUME_DIR}" ]]; then
|
||
if ask_yn "Alte DB-Daten für Stack '${STACK_NAME}' gefunden. Löschen für Neuaufsetzung?" "true"; then
|
||
info "Lösche alte DB-Daten: ${VOLUME_DIR}"
|
||
rm -rf "${VOLUME_DIR}"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
SERVICES=(db calbook-app)
|
||
if [[ "${SMTP_HOST}" == "mailhog" || -z "${SMTP_HOST}" ]]; then
|
||
SERVICES+=(mailhog)
|
||
fi
|
||
|
||
info "Starte: ${SERVICES[*]}"
|
||
${COMPOSE_CMD} -f "${COMPOSE_FILE}" up -d --build "${SERVICES[@]}"
|
||
|
||
info "DB einrichten (Prisma + Seed)..."
|
||
${COMPOSE_CMD} -f "${COMPOSE_FILE}" build calbook-tools
|
||
|
||
${COMPOSE_CMD} -f "${COMPOSE_FILE}" run --rm calbook-tools npm run prisma:generate
|
||
|
||
if ! ${COMPOSE_CMD} -f "${COMPOSE_FILE}" run --rm calbook-tools npm run prisma:migrate; then
|
||
info "Migration fehlgeschlagen → prisma:push (Legacy-Fallback)..."
|
||
${COMPOSE_CMD} -f "${COMPOSE_FILE}" run --rm calbook-tools npm run prisma:push
|
||
fi
|
||
|
||
if ${COMPOSE_CMD} -f "${COMPOSE_FILE}" run --rm calbook-tools npm run db:seed; then
|
||
success "Seed abgeschlossen"
|
||
else
|
||
warn "Seed fehlgeschlagen – Admin existiert möglicherweise bereits."
|
||
fi
|
||
|
||
# ── Summary ──────────────────────────────────────────────
|
||
echo
|
||
echo -e "${BOLD}${GREEN}══════════════════════════════════════════════${NC}"
|
||
echo -e "${BOLD}${GREEN} CalBook läuft!${NC}"
|
||
echo
|
||
echo -e " URL: ${BOLD}${PUBLIC_URL}${NC}"
|
||
echo -e " Login: ${BOLD}/anmelden${NC}"
|
||
echo -e " Admin: ${BOLD}${ADMIN_EMAIL}${NC}"
|
||
echo -e " Passwort: ${BOLD}${ADMIN_PASSWORD}${NC}"
|
||
echo -e " Compose: ${DIM}${COMPOSE_FILE}${NC}"
|
||
echo -e " Modus: ${DEPLOYMENT_MODE}"
|
||
if [[ "${SMTP_HOST}" == "mailhog" ]]; then
|
||
if [[ "${DEPLOYMENT_MODE}" == "direct" ]]; then
|
||
echo -e " Mailhog: ${BOLD}http://localhost:8025${NC}"
|
||
else
|
||
echo -e " Mailhog: ${DIM}intern (kein Host-Port)${NC}"
|
||
fi
|
||
fi
|
||
echo -e "${BOLD}${GREEN}══════════════════════════════════════════════${NC}"
|
||
echo
|
||
echo "Logs: ${COMPOSE_CMD} -f ${COMPOSE_FILE} logs -f calbook-app db"
|
||
echo
|