# ============================================================================ # PROPERTY MANAGEMENT NETWORK — Production Environment # ============================================================================ # Set these in DigitalOcean App Platform (Environment Variables). Do NOT commit real values. # # Build-time vs runtime: # NEXT_PUBLIC_* are inlined into the browser bundle at image build time, so # they must be passed as --build-arg when building the image (see DIGITALOCEAN.md). # ============================================================================ # === DATABASE (PostgreSQL) === # DO Managed Postgres (private host, direct port 25060): postgres://USER:PASSWORD@:25060/dbname DATABASE_URL=postgres://user:password@private-host:25060/dbname # TLS policy (app + migrations). Default is encrypted + certificate-verified. # disable -> no TLS (local / unix-socket development only). # no-verify -> encrypted but unverified — use for DO Managed Postgres (or supply DATABASE_CA). # require -> encrypted + verified (managed DBs with a public CA). # DATABASE_CA -> optional custom CA cert (PEM) when verifying. DATABASE_SSL=require # DATABASE_CA= # Run pending migrations automatically when the container starts. # Set to "false" for multi-replica deploys and run migrations as a one-off job. RUN_MIGRATIONS_ON_START=true # === BETTER AUTH === # Generate: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" BETTER_AUTH_SECRET=replace-with-a-64-char-hex-secret # Public base URL of the app (no trailing slash). BETTER_AUTH_URL=https://propertymanagement.network # Google OAuth (optional). Redirect URI: /api/auth/callback/google GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= # === ADMIN BOOTSTRAP & AUTH POLICY === # Grant admin access to the /admin dashboard. Comma-separated Better Auth user # IDs and/or emails. Set at least ONE on a fresh deploy or no one can administer # the platform. There is no self-service path to become an admin (by design). ADMIN_USER_IDS= ADMIN_EMAILS= # Require a verified email address before a user can sign in. Strongly # recommended in production (defaults to false / disabled if unset). REQUIRE_EMAIL_VERIFICATION=true # === STORAGE === # Local-disk fallback (used only when Spaces below is NOT configured). If you use # Spaces you no longer need the persistent volume, but keeping it is harmless. STORAGE_DIR=/app/storage # Object storage (DigitalOcean Spaces, S3-compatible) — recommended for prod. # When KEY/SECRET/BUCKET are all set, uploads + serving use the bucket. Keep the # bucket PRIVATE; files are served through the auth-gated /api/files route. SPACES_KEY= SPACES_SECRET= SPACES_REGION=nyc3 SPACES_BUCKET=property-management-network SPACES_ENDPOINT=https://nyc3.digitaloceanspaces.com # Optional: if the Space's CDN is enabled, presigned URLs serve from the edge. SPACES_CDN_ENDPOINT=https://nyc3.cdn.digitaloceanspaces.com # === STRIPE === STRIPE_SECRET_KEY=sk_live_xxx STRIPE_WEBHOOK_SECRET=whsec_xxx NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_xxx # No price IDs needed — prices are resolved by lookup key and auto-created on # first checkout, so going live is ONLY the three values above (live keys + live # webhook secret). Optionally pre-create the catalog: node scripts/stripe-setup.mjs # === AI (OpenAI) === OPENAI_API_KEY=sk-xxx # === EMAIL (SMTP — SMTP2GO) === SMTP_HOST=mail.smtp2go.com SMTP_PORT=2525 SMTP_USER= SMTP_PASS= EMAIL_FROM=postmaster@propertymanagement.network # === ACCOUNTING SYNC (optional — QuickBooks / Xero OAuth) === # Redirect URIs: /api/integrations/quickbooks/callback and .../xero/callback # QBO_ENVIRONMENT=production for live QuickBooks. Tokens are encrypted at rest # (AES-256-GCM) with a key derived from BETTER_AUTH_SECRET. QBO_CLIENT_ID= QBO_CLIENT_SECRET= QBO_ENVIRONMENT=production XERO_CLIENT_ID= XERO_CLIENT_SECRET= # === E-SIGNATURE (optional — per-landlord: each connects their OWN account) === # DocuSign: register ONE DocuSign app; landlords connect their own account via # OAuth from Settings → Integrations. Register this redirect URI in the app: # /api/esign/docusign/callback # Use account.docusign.com in production (account-d.docusign.com for demo). DOCUSIGN_CLIENT_ID= DOCUSIGN_CLIENT_SECRET= DOCUSIGN_OAUTH_BASE=account.docusign.com # Dropbox Sign: no server credentials — landlords paste their own API key and set # their account callback URL to /api/esign/dropbox_sign/webhook. DROPBOX_SIGN_TEST_MODE=false # === APP (NEXT_PUBLIC_* — also set as Build Variables) === NEXT_PUBLIC_APP_URL=https://propertymanagement.network NEXT_PUBLIC_APP_NAME=Property Management Network # Google Search Console verification token (Search Console -> Settings -> HTML tag). GOOGLE_SITE_VERIFICATION= # === ANALYTICS (Umami) === # Cookieless page analytics, loaded only in production. These NEXT_PUBLIC_* vars # are inlined at build time — set them as Build Variables in DO App Platform. # Set the website id to empty to disable. Both values are public. NEXT_PUBLIC_UMAMI_SRC=https://fickanalytics.phluit.net/script.js NEXT_PUBLIC_UMAMI_WEBSITE_ID=4066c359-596f-4d0e-9636-c035c2adfbe8 # === ERROR MONITORING (Sentry) === # DSN from your Sentry project (public — inlined in the browser bundle, so set # it as a Build Variable too). Error monitoring is disabled until this is set. NEXT_PUBLIC_SENTRY_DSN= # Build-time secret: uploads source maps so prod stack traces are un-minified. # Sentry → Settings → Auth Tokens. Set as a Build Variable; leave blank to skip. SENTRY_AUTH_TOKEN= # === MAPS / GEOCODING (OpenStreetMap — free, no key) === # Addresses are geocoded via OpenStreetMap Nominatim; the map uses Leaflet + OSM # tiles. No API key or billing. Nominatim REQUIRES an identifying User-Agent — # set a real contact URL/email so they can reach you if there's a usage issue. GEOCODER_USER_AGENT=PropertyManagementNetwork/1.0 (https://propertymanagement.network) # === CRON === # Bearer token required by the /api/cron/* and /api/follow-ups/run endpoints. CRON_SECRET=replace-with-a-random-string # === CLOUDFLARE TURNSTILE (bot protection on auth forms) === # Create a widget at https://dash.cloudflare.com/?to=/:account/turnstile # NEXT_PUBLIC_TURNSTILE_SITE_KEY is inlined at build time — also set it as a # Build Variable in Coolify. Leave both blank to disable the captcha. NEXT_PUBLIC_TURNSTILE_SITE_KEY= TURNSTILE_SECRET_KEY=