# ============================================================================= # beenvoice-web — environment template # ============================================================================= # # Quick start (local dev): # cp .env.example .env.local # docker compose -f docker-compose.dev.yml up -d # Postgres + MinIO # bun run db:push # or: bun run db:migrate # bun run dev # MinIO console: http://localhost:9001 (minioadmin / minioadmin) # # Quick start (Docker app + Postgres): # cp .env.example .env # # edit AUTH_SECRET + public URLs below # ./scripts/docker-deploy.sh # # ----------------------------------------------------------------------------- # Build-time vs runtime (Docker) # ----------------------------------------------------------------------------- # # Baked into the image at `docker compose build` (rebuild after changes): # NEXT_PUBLIC_APP_URL # NEXT_PUBLIC_* branding / theme defaults # NEXT_PUBLIC_AUTHENTIK_ENABLED # NEXT_PUBLIC_UMAMI_* # # Read from .env when the container starts (restart app after changes): # AUTH_SECRET, BETTER_AUTH_URL, DATABASE_URL (compose overrides host), # RESEND_*, DISABLE_SIGNUPS, AUTHENTIK_* secrets, CRON_SECRET # # `NEXT_PUBLIC_APP_URL` should still match your public browser URL for SSR, # emails, and MCP links. In the browser, sign-in uses the current page origin # automatically so dev works when Next picks another port (e.g. 3002). # # Updating production: git pull && ./scripts/docker-deploy.sh # (or: docker compose up -d --build). Plain `docker compose up -d` does NOT rebuild. # Migrations run on every app start (idempotent — only pending SQL is applied). # ============================================================================= # Core — required # ============================================================================= # PostgreSQL connection string. # Local dev (docker-compose.dev.yml): host is localhost DATABASE_URL=postgres://postgres:postgres@localhost:5432/postgres # Session signing secret. Required in production. # Generate: openssl rand -base64 32 AUTH_SECRET=change-me-generate-a-real-secret # Public URL users open in the browser (scheme + host + port if non-standard). # Must match how you access the app for cookies, OAuth callbacks, and email links. BETTER_AUTH_URL=http://localhost:3000 # Same as BETTER_AUTH_URL in most setups. Embedded in the client bundle at build. NEXT_PUBLIC_APP_URL=http://localhost:3000 # ============================================================================= # Local development # ============================================================================= NODE_ENV=development # Set true when connecting to local Postgres without SSL (default for compose). DB_DISABLE_SSL=true # Dev-only: host ports for `docker compose -f docker-compose.dev.yml`. POSTGRES_PORT=5432 MINIO_API_PORT=9000 MINIO_CONSOLE_PORT=9001 # Optional: if Next dev picks another port, you do not need to change URLs for # sign-in — the auth client uses window.location.origin in the browser. # ============================================================================= # Docker Compose (app + database) # ============================================================================= # Host port mapped to container :3000 (WEB_PORT, then PORT, then 3000). WEB_PORT=3000 # App image tag for docker-compose.yml (optional). docker-deploy.sh sets # beenvoice: automatically; default without it is beenvoice:local. # BEENVOICE_IMAGE=beenvoice:local # Postgres credentials for docker-compose.yml `db` service. # DATABASE_URL inside the app container is set by compose (host `db`, not localhost). POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres POSTGRES_DB=postgres # ============================================================================= # White-label defaults (optional) # ============================================================================= # Baked in at Docker build. After first deploy, admins can override many of # Optional white-label defaults (build-time). Users choose light/dark in Settings. NEXT_PUBLIC_BRAND_NAME=beenvoice NEXT_PUBLIC_BRAND_TAGLINE=Simple and efficient invoicing for freelancers and small businesses NEXT_PUBLIC_BRAND_LOGO_TEXT=beenvoice NEXT_PUBLIC_BRAND_ICON=$ # ============================================================================= # Email — Resend (optional) # ============================================================================= # Leave blank to disable invoice and password-reset email delivery. RESEND_API_KEY= RESEND_DOMAIN= # ============================================================================= # Analytics — Umami (optional) # ============================================================================= # Leave website ID blank to disable. NEXT_PUBLIC_UMAMI_WEBSITE_ID= NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.umami.is/script.js # ============================================================================= # Access control (optional) # ============================================================================= # Block new email/password registrations (default: true / signups off). # Set DISABLE_SIGNUPS=false to allow new email/password signups. # DISABLE_SIGNUPS=false # Bearer token for POST /api/cron/generate-recurring (recurring invoice cron). # CRON_SECRET= # ============================================================================= # Receipt storage — S3-compatible (optional) # ============================================================================= # When S3_BUCKET + S3_ACCESS_KEY + S3_SECRET_KEY are unset, receipts land in # .data/receipts/ (dev-friendly). Works with AWS S3, MinIO, Cloudflare R2, etc. # # S3_ENDPOINT — who can reach MinIO? # • Host dev (bun dev + docker-compose.dev.yml MinIO on the host): localhost:9000 # • App in Docker (docker-compose.yml): http://minio:9000 (Compose service name) # • Coolify — see docs/COOLIFY.md for full steps. Summary: # - Best: one Compose resource with docker-compose.yml (app+db+minio); do not override S3_ENDPOINT. # - App + separate MinIO stack: ENOTFOUND minio means the app is not on MinIO's Docker network. # Fix: Beevoice Application → enable "Connect to Predefined Network" (same destination as MinIO), # set S3_ENDPOINT=http://:9000 (often NOT bare "minio"). # - NEVER use localhost in production — inside the app container that is the app, not MinIO. # Troubleshooting getaddrinfo ENOTFOUND minio: # 1) Confirm Beevoice and MinIO are same Coolify project/destination # 2) Enable Connect to Predefined Network on Beevoice; redeploy # 3) Copy hostname from MinIO resource internal URL → S3_ENDPOINT (http://HOST:9000) # 4) Or deploy docker-compose.yml as a single stack instead # # Local dev with docker-compose.dev.yml MinIO (host `bun dev`): S3_ENDPOINT=http://localhost:9000 S3_BUCKET=beenvoice-receipts S3_ACCESS_KEY=minioadmin S3_SECRET_KEY=minioadmin S3_REGION=us-east-1 # # docker-compose.yml sets S3_ENDPOINT=http://minio:9000 inside the app container # automatically. MINIO_ROOT_* below must match S3_ACCESS_KEY / S3_SECRET_KEY. MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=minioadmin # ============================================================================= # SSO — Authentik OIDC (optional) # ============================================================================= # Set NEXT_PUBLIC_AUTHENTIK_ENABLED=true and rebuild the image to show SSO on # sign-in. Server secrets are runtime-only (no rebuild needed for secrets). NEXT_PUBLIC_AUTHENTIK_ENABLED=false AUTHENTIK_ISSUER= AUTHENTIK_CLIENT_ID= AUTHENTIK_CLIENT_SECRET= # Optional extra trusted origin for better-auth (defaults derived from issuer). AUTHENTIK_ORIGIN= # ============================================================================= # Advanced / CI (usually unset) # ============================================================================= # Skip Zod env validation during `next build` (set automatically in Dockerfile). # SKIP_ENV_VALIDATION=1