# Copy to stacks/manager/.env (kept out of git — see the repo root's # .gitignore) and fill in real values. # ── Platform-operator login ───────────────────────────────────────────── MANAGER_EMAIL="you@example.com" # bcrypt hash (cost 12) of your chosen password — generate one with: # node -e "console.log(require('bcryptjs').hashSync('your-password', 12))" # (run from the manager/ directory so it resolves the bcryptjs dependency) MANAGER_PASSWORD_HASH="replace-me" # Signs the session cookie — generate with: openssl rand -hex 32 MANAGER_SESSION_SECRET="replace-me" # Encrypts secrets (e.g. the SMTP password) stored in Settings > Email — # see src/lib/global-settings.ts. Must be a 32-byte value, hex-encoded. # Generate with: openssl rand -hex 32 # Losing/rotating this makes any previously-saved secret undecryptable — # you'd need to re-enter it in Settings afterward. MANAGER_SETTINGS_ENCRYPTION_KEY="replace-me" # The URL this app is actually served at (used to decide whether the # session cookie needs its Secure attribute) — e.g. "https://manager.example.com". MANAGER_PUBLIC_URL="https://manager.example.com" # ── Shared MySQL (see stacks/infra/compose.yaml) ──────────────────────── MYSQL_HOST="next-chair-mysql" MYSQL_PORT="3306" # Same value as stacks/infra/.env's MYSQL_ROOT_PASSWORD — needed here too # to create each new business's database/user. Two copies of the same # value, deliberately not derived from one another — see stacks/infra/ # compose.yaml's own note on why MYSQL_*/DATABASE_* aren't cross-wired. MYSQL_ROOT_PASSWORD="replace-me" # ── Docker / stacks ────────────────────────────────────────────────────── # This repo's absolute path on the VPS, e.g. "/opt/nextchair/stacks" — NOT # a relative path. This container shells `docker compose` out to the # HOST's dockerd via the mounted Docker socket (see src/lib/docker.ts), so # a compose-file path only resolves to the same file on both sides if the # bind-mount doesn't change it — meaning this must be mounted at the # identical path inside the container too (see stacks/manager/compose.yaml). STACKS_DIR="/opt/nextchair/stacks" # Every business's compose.yaml (see src/lib/compose-template.ts) uses # this image tag — rebuild with `docker build -t nextchair-app:latest .` # from the repo root after a code update, then use each business's # "Update" button (or `docker compose up -d --force-recreate`) to pick it # up. NEXTCHAIR_IMAGE="nextchair-app:latest" # ── Scheduler, backups, alerts (all optional) ─────────────────────────── # The built-in scheduler (notification cron, daily Google reviews sync, # health checks, scheduled backups) starts with the Manager. Set to 1 to # turn it off, e.g. to keep using the host-crontab fallback # (stacks/infra/scripts/process-cron.sh) instead — never run both. # MANAGER_SCHEDULER_DISABLED="1" # Scheduled-backup times and the dashboard's dates use the container's # timezone (UTC by default). Set e.g. TZ="Europe/London" to change it. # TZ="Europe/London" # Largest .7z accepted by the Restore page's upload (bytes; default 4 GiB). # BACKUP_UPLOAD_MAX_BYTES="4294967296" # An external dead-man's-switch (healthchecks.io, Better Stack…): the # scheduler GETs this URL every 5 minutes, so you're told if the whole # VPS or the Manager is down — something a self-hosted check can't report. # MANAGER_HEARTBEAT_URL="https://hc-ping.com/your-uuid"