# ============================================================================ # 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 # === PAYPAL (optional — alternative subscription checkout) === # Landlords can pay for their plan with PayPal alongside Stripe. Leave blank to # hide the PayPal buttons. Create a REST app at https://developer.paypal.com and # set PAYPAL_ENVIRONMENT=live for production. Create a webhook there pointing to # /api/paypal/webhook and put its id in PAYPAL_WEBHOOK_ID. Generate the # plan IDs with `node scripts/paypal-setup-plans.mjs`. PAYPAL_CLIENT_ID= PAYPAL_SECRET= PAYPAL_ENVIRONMENT=live PAYPAL_WEBHOOK_ID= PAYPAL_PRO_MONTHLY_PLAN_ID= PAYPAL_PRO_YEARLY_PLAN_ID= PAYPAL_LANDLORD_MONTHLY_PLAN_ID= PAYPAL_LANDLORD_YEARLY_PLAN_ID= # === 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 — DocuSign / Dropbox Sign) === # Leave blank to hide/disable a provider on the lease page. Configure the # provider callbacks to point at this app: # Dropbox Sign callback → /api/esign/dropbox_sign/webhook # DocuSign Connect → /api/esign/docusign/webhook # In production set DROPBOX_SIGN_TEST_MODE=false to send legally-binding docs. DROPBOX_SIGN_API_KEY= DROPBOX_SIGN_TEST_MODE=false DOCUSIGN_ACCESS_TOKEN= DOCUSIGN_ACCOUNT_ID= DOCUSIGN_BASE_URI=https://www.docusign.net # === 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 # === 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=