# ── CluPilot .env template ───────────────────────────────────────────────
# Copy to .env, then: docker compose up -d && clupilot artisan key:generate
# Shared by Laravel AND docker-compose. No ${} interpolation (compose passes
# it literally). Values below are DEV defaults — set strong secrets for real
# deployments and NEVER commit the resulting .env.

APP_NAME=CluPilot
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

APP_LOCALE=de
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=de_DE

APP_MAINTENANCE_DRIVER=file
BCRYPT_ROUNDS=12

LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

# ── Database (MariaDB service) ───────────────────────────────────────────
# Dev defaults so `docker compose up` boots out of the box. Override for prod.
DB_CONNECTION=mariadb
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=clupilot
DB_USERNAME=clupilot
DB_PASSWORD=clupilot
DB_ROOT_PASSWORD=clupilot_root

# ── Redis (cache/session/queue) ──────────────────────────────────────────
REDIS_CLIENT=phpredis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null

CACHE_STORE=redis
QUEUE_CONNECTION=redis
FILESYSTEM_DISK=local

# ── Broadcasting / Reverb ────────────────────────────────────────────────
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=clupilot
REVERB_APP_KEY=change-me-app-key
REVERB_APP_SECRET=change-me-app-secret
# server-side: internal compose service name
REVERB_HOST=reverb
REVERB_PORT=8080
REVERB_SCHEME=http
REVERB_SERVER_HOST=0.0.0.0
REVERB_SERVER_PORT=8080

# browser-side (baked into built assets): the address a browser can reach
VITE_REVERB_APP_KEY=change-me-app-key
VITE_REVERB_HOST=localhost
VITE_REVERB_PORT=443
VITE_REVERB_SCHEME=https
VITE_APP_NAME=CluPilot

# Vite HMR host the browser connects to (dev). Set to the reachable VM address
# when developing against a remote host; localhost for local-only.
VITE_HMR_HOST=localhost

# ── Mail ─────────────────────────────────────────────────────────────────
# DEV: `log` writes mails to storage/logs (nothing is sent).
# PROD: switch to smtp and fill in the credentials below.
MAIL_MAILER=log
MAIL_FROM_ADDRESS=hello@clupilot.local
MAIL_FROM_NAME=CluPilot
# MAIL_MAILER=smtp
# MAIL_HOST=smtp.your-provider.tld
# MAIL_PORT=587
# MAIL_USERNAME=
# MAIL_PASSWORD=
# MAIL_SCHEME=smtp          # smtp | smtps (465)

# ═════════════════════════════════════════════════════════════════════════
#  CluPilot operations — fill these in to run real provisioning.
#  Everything below is OPTIONAL for local dev: left blank, the services are
#  no-ops/fakes and the app + test suite still run. Only real infrastructure
#  work (host onboarding, customer provisioning) needs them.
# ═════════════════════════════════════════════════════════════════════════

# ── Stripe (payments) ────────────────────────────────────────────────────
# WEBHOOK_SECRET is READ BY CODE today (signature check on /webhooks/stripe).
# Outside local/testing a missing secret makes the webhook fail closed.
STRIPE_WEBHOOK_SECRET=
# Not read yet — needed once the Checkout flow is built (currently the portal
# only records a purchase intent):
STRIPE_KEY=
STRIPE_SECRET=

# ── DNS (Hetzner DNS API) ────────────────────────────────────────────────
# Creates <subdomain>.<zone> A-records for each customer instance.
HETZNER_DNS_TOKEN=
CLUPILOT_DNS_ZONE=clupilot.cloud

# Host names (fsn-01.node.…) are NOT published here — that would leak the
# internal WireGuard subnet. They go into this directory instead, which the
# vpn-dns container reads (dnsmasq --hostsdir) over the dns-hosts volume; see
# docker-compose.yml. Only change if that volume is mounted somewhere else.
CLUPILOT_DNS_HOSTS_DIR=/etc/clupilot/dns-hosts

# ── Traefik (reverse proxy + TLS) ────────────────────────────────────────
# Directory ON THE PROXMOX HOST where CluPilot writes dynamic route files.
TRAEFIK_DYNAMIC_PATH=/etc/traefik/dynamic

# ── WireGuard hub (this CluPilot VM) ─────────────────────────────────────
# Hosts join this hub during onboarding; CluPilot reaches them over the tunnel.
CLUPILOT_WG_SUBNET=10.66.0.0/24
CLUPILOT_WG_HUB_IP=10.66.0.1
CLUPILOT_WG_ENDPOINT=              # public host:port peers dial, e.g. vpn.clupilot.com:51820
CLUPILOT_WG_HUB_PUBKEY=            # `wg pubkey < /etc/wireguard/privatekey`
CLUPILOT_WG_CONFIG_PATH=/etc/wireguard/wg0.conf

# ── SSH identity for host onboarding ─────────────────────────────────────
# Deployed to each fresh server after the one-time root password login.
# PREFERRED: point at files (a multi-line PEM cannot live in .env).
#   ssh-keygen -t ed25519 -N '' -C clupilot -f storage/app/ssh/clupilot
CLUPILOT_SSH_PUBLIC_KEY_PATH=
CLUPILOT_SSH_PRIVATE_KEY_PATH=
# Alternative (single-line values only):
CLUPILOT_SSH_PUBLIC_KEY=
CLUPILOT_SSH_PRIVATE_KEY=
CLUPILOT_SSH_COMMAND_TIMEOUT=2000

# ── Monitoring ───────────────────────────────────────────────────────────
# The built-in client speaks a GENERIC REST API:
#   GET/POST /monitors, GET/DELETE /monitors/{id}
# For Uptime Kuma use the bundled bridge below (Kuma's own REST API is
# read-only — monitor CRUD goes through Socket.IO):
#   MONITORING_API_URL=http://kuma-bridge:8080
# Leave blank to disable monitoring entirely: provisioning records a stable
# breadcrumb and its own health checks (occ status, TLS, admin user) still
# gate acceptance.
MONITORING_API_URL=
MONITORING_API_TOKEN=

# ── Uptime Kuma (über die mitgelieferte Bridge) ───────────────────────────
# Kuma kann Monitore nur über Socket.IO anlegen, daher die Bridge:
#   docker compose --profile monitoring up -d --build kuma-bridge
# Danach hier MONITORING_API_URL auf die Bridge zeigen lassen:
#   MONITORING_API_URL=http://kuma-bridge:8080
# MONITORING_API_TOKEN ist gleichzeitig das Bridge-Token (frei wählbar, lang).
KUMA_URL=
KUMA_USERNAME=
KUMA_PASSWORD=
KUMA_TOTP=

# Monitoring-Verhalten bei Ausfall:
#   MONITORING_REQUIRED=false -> Bereitstellung läuft weiter (Warn-Event), Standard
#   MONITORING_REQUIRED=true  -> Lauf schlägt fehl, wenn Monitoring nicht erreichbar
MONITORING_REQUIRED=false
MONITORING_ATTEMPTS=2

# ── VPN-Konfigurationen ──────────────────────────────────────────────────
# Schlüssel für hier gespeicherte WireGuard-Konfigurationen (32 Byte, base64).
# Bewusst getrennt von APP_KEY. Leer = Speichern deaktiviert.
# Erzeugen: head -c 32 /dev/urandom | base64
VPN_CONFIG_KEY=

# ── Zugangsdaten der Konsole (Stripe, DNS, Monitoring, Postfächer) ────────
# Eigener Schlüssel, ebenfalls getrennt von APP_KEY — der wird routinemäßig
# gewechselt und würde sonst jedes gespeicherte Geheimnis unlesbar machen.
# LEER = die Konsole speichert gar keine Zugangsdaten und sagt das auch.
# Erzeugen: head -c 32 /dev/urandom | base64
SECRETS_KEY=

# Netze, die als "wir" gelten, solange die Website versteckt ist
# (WireGuard-Subnetz). Alles andere sieht die Platzhalterseite.
TRUSTED_RANGES=10.66.0.0/24,127.0.0.1

# Umsatzsteuersatz des Verkäufers in Prozent. Preise in der Konfiguration
# sind NETTO; die Oberfläche weist beides aus.
CLUPILOT_TAX_PERCENT=20

# ── Wo die Konsole antwortet ─────────────────────────────────────────────
#
# ADMIN_HOSTS: Hostnamen, unter denen die Konsole erreichbar ist. Der ERSTE
# ist der kanonische — für ihn werden URLs erzeugt; die weiteren sind
# Ausweichadressen, über die jemand hereinkommt, der ausgesperrt ist.
#
# ADMIN_HOST_EXCLUSIVE: darf auf diesen Namen NUR die Konsole antworten?
#
#   true   Die Konsole liegt an der WURZEL ihres Hostnamens
#          (https://admin.…/), und Portal wie Website antworten dort mit 404.
#          Dann gehört hier ausschliesslich der Konsolen-Name hinein — eine
#          IP oder localhost mit aufzunehmen schaltet Portal und Website auf
#          genau dieser Adresse ab. Das ist die Betriebsform.
#
#   false  Die Konsole liegt unter /admin auf jedem gelisteten Namen, und
#          diese Namen bedienen weiterhin auch Portal und Website. Nur für
#          eine Maschine ohne eigene DNS-Namen sinnvoll.
#
# Ohne Eintrag gilt false — dann zeigt https://admin.…/ das PORTAL, nicht die
# Konsole, und das sieht wie ein Fehler aus, obwohl es die Vorgabe ist.
#
# APP_HOST: Hostname des Kundenportals, z. B. app.clupilot.com. Gesetzt, ist
# JEDE Portal-Route an diesen Host gebunden und existiert nirgends sonst —
# www.clupilot.com/dashboard ist dann ein 404, kein funktionierender Aufruf.
# Leer = Portal antwortet ueberall (Vorgabe, und was jede dev-Maschine ueber
# eine blanke IP braucht).
APP_HOST=

# SITE_HOST: Hostname der oeffentlichen Website. Gesetzt, antwortet die
# Startseite NUR dort — jeder andere Host (das Portal, eine blanke IP) zeigt
# unter "/" die Anmeldung bzw. das Dashboard. Leer heisst: Startseite ueberall,
# Mehrere Namen kommagetrennt, der ERSTE ist der kanonische — er liefert aus,
# alle weiteren leiten dauerhaft dorthin um (Pfad und Query bleiben erhalten):
#   SITE_HOST=www.clupilot.com,clupilot.com
# und dann liefert app.clupilot.com die Website aus. Gebunden sind Startseite,
# robots.txt und die Legal-Seiten — dadurch erzeugt route('legal.impressum')
# auch aus einer Mail heraus eine www-Adresse.
SITE_HOST=

ADMIN_HOSTS=admin.dev.clupilot.com
ADMIN_HOST_EXCLUSIVE=true

# ── Nextcloud blueprint template ─────────────────────────────────────────
# NOT an env var: set the Proxmox template VMID per plan in
# config/provisioning.php → plans.*.template_vmid (default 9000).

# ── docker-compose knobs (host-side) ─────────────────────────────────────
HOST_UID=1000
HOST_GID=1000
# Behind a reverse proxy — which is every production install — these must stay
# on loopback: Docker publishes ports ahead of UFW, so anything on 0.0.0.0 is
# reachable from the internet regardless of the firewall, and reaching a backend
# directly skips every hostname and address rule the proxy enforces.
# For local development without a proxy, set APP_PORT=80.
APP_PORT=127.0.0.1:8080
# Vite dev server (HMR). Off by default: over the HTTPS domains the
# browser cannot load assets from http://<ip>:5173. Set true only when
# working over http://10.10.90.185, then run: docker compose up -d app
VITE_AUTOSTART=false
VITE_PORT=5173
REVERB_HOST_PORT=127.0.0.1:8081
DB_HOST_PORT=3306

# ── CI (Gitea Actions) ──────────────────────────────────────────────────────
# Registrierungs-Token aus Gitea: Repo → Settings → Actions → Runners →
# "Create new runner". Danach:  docker compose --profile ci up -d runner
GITEA_INSTANCE_URL=https://git.bave.dev
GITEA_RUNNER_TOKEN=
GITEA_RUNNER_NAME=clupilot-local
# Passend zur Server-Version halten (1.20 verträgt keinen aktuellen Runner).
GITEA_RUNNER_VERSION=0.2.6

# Zone in der Zeiten ANGEZEIGT werden. Gespeichert wird immer UTC.
APP_DISPLAY_TIMEZONE=Europe/Vienna
