Echoboard

A self-hosted feedback board where users submit feature requests and bug reports without creating an account. Anonymous by default, with optional passkey registration for persistence across devices.

Quick start

git clone <repo-url>
cd echoboard
cp .env.example .env

# Generate secrets
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Paste output into APP_MASTER_KEY, APP_BLIND_INDEX_KEY, TOKEN_SECRET, JWT_SECRET, ALTCHA_HMAC_KEY

# Generate VAPID keys for push notifications
npx web-push generate-vapid-keys
# Paste into VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY

# Set WEBAUTHN_RP_ID and WEBAUTHN_ORIGIN to your domain

docker compose up -d
docker compose exec app npx echoboard create-admin --email you@example.com

Development

npm install
cp .env.example .env
# Fill in .env with dev values (WEBAUTHN_RP_ID=localhost, WEBAUTHN_ORIGIN=http://localhost:3000)

npm run dev

This starts the API on port 3000 and the Vite dev server on port 5173 (with API proxy).

Architecture

  • packages/api - Fastify + Prisma backend
  • packages/web - React + Vite frontend
  • plugins/ - Optional integrations (Gitea, GitHub, etc.)

Identity model

Two tiers of user identity:

  1. Anonymous cookie (default) - zero friction, browser-generated token, single device only
  2. Passkey (optional upgrade) - username + WebAuthn biometric, works across devices, no email needed

Plugin system

Plugins live in plugins/ and are registered in echoboard.plugins.ts. Each plugin is self-contained with its own routes, database tables, and UI components. Removing a plugin leaves zero trace in the core app.

License

CC0-1.0

Description
Self-hosted feedback board. Anonymous by default, no email required.
Readme 1.1 MiB
Languages
TypeScript 97.1%
CSS 1.5%
JavaScript 1.1%
HTML 0.2%
Dockerfile 0.1%