Self-hosting.

FeedbackFlow ships as a Docker image and runs against your own MongoDB. Your feedback, uploads, and tenant data stay on infrastructure you control.

Requirements

  • Node.js 20+ (for local development) or Docker (recommended for deployment).
  • MongoDB 7+ — managed (Atlas) or self-run.
  • A domain with HTTPS for production.

Docker Compose

The fastest path. Compose brings up the app and a MongoDB instance together:

# 1 · Clone and configure
git clone <your-repo> && cd feedback
cp .env.example .env

# 2 · Generate an auth secret → paste into .env
openssl rand -base64 32

# 3 · Start everything
docker-compose up -d

# App is now on http://localhost:3000

Environment variables

Configure the app through .env. The essentials:

VariableRequiredDescription
MONGODB_URIYesMongoDB connection string.
BETTER_AUTH_SECRETYesAuth signing secret (64+ chars).
BETTER_AUTH_URLYesThe app's public URL.
STORAGE_PROVIDERNolocal · s3 · r2 (default local).
PLATFORM_ADMIN_EMAILSFor /adminComma-separated emails allowed into platform admin.
CRON_SECRETProdBearer secret for the SLA-check job.
Always set a strong BETTER_AUTH_SECRET and restrict PLATFORM_ADMIN_EMAILS to trusted accounts before going to production.

Storage providers

Attachments can live wherever you choose. The storage layer is pluggable:

  • local — files on the app's disk under public/uploads. Good for a single node.
  • s3 — Amazon S3 or any S3-compatible bucket.
  • r2 — Cloudflare R2.

Switch by setting STORAGE_PROVIDER and the provider's credentials in .env.

Database & indexes

Indexes are created automatically on first run. To initialise them explicitly:

npm run db:init

Tenant isolation is enforced through compound indexes keyed on tenantId, so queries never cross workspace boundaries.

Building the widget

The embed widget is a separate Vite build, output as a UMD bundle served from public/widget/widget.js:

npm run widget:build   # production bundle
npm run widget:dev     # watch mode

Health & jobs

A public health endpoint lets your orchestrator probe the app:

GET/api/healthPublic

SLA evaluation runs as a cron-triggered job. Schedule a periodic call (authenticated with CRON_SECRET in production):

POST/api/jobs/sla-checkCron

Production checklist

  • Set a strong BETTER_AUTH_SECRET and enable HTTPS.
  • Restrict PLATFORM_ADMIN_EMAILS to trusted accounts.
  • Enable MongoDB authentication and automatic backups.
  • Configure CORS for your domains.
  • Schedule the SLA-check job and set CRON_SECRET.