prep for self-hosting - updated readme, env example, dockerfile, compose, dockerignore

This commit is contained in:
2026-03-21 19:29:46 +02:00
parent d52088a88b
commit 010c811a48
5 changed files with 131 additions and 46 deletions

136
README.md
View File

@@ -1,56 +1,122 @@
# 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.
Self-hosted feedback board. Users submit feature requests and bug reports without creating an account - anonymous by default, with optional passkey registration for persistence across devices. No email required for anything.
## Quick start
## Self-hosting with Docker
```bash
git clone <repo-url>
git clone https://git.lashman.live/lashman/echoboard.git
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
```
Edit `.env` and fill in:
1. Set `POSTGRES_PASSWORD` to something random
2. Generate five secrets (one for each of `APP_MASTER_KEY`, `APP_BLIND_INDEX_KEY`, `TOKEN_SECRET`, `JWT_SECRET`, `ALTCHA_HMAC_KEY`):
```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```
3. Generate VAPID keys for push notifications:
```bash
npx web-push generate-vapid-keys
```
4. Set `WEBAUTHN_RP_ID` to your domain (e.g. `feedback.example.com`)
5. Set `WEBAUTHN_ORIGIN` to your full URL (e.g. `https://feedback.example.com`)
Then start it:
```bash
docker compose up -d
```
Create the initial admin account:
```bash
docker compose exec app npx tsx packages/api/src/cli/create-admin.ts
```
The app is at `http://localhost:3000` (or whatever port you set). Put a reverse proxy in front for HTTPS.
## What's included
- Boards for organizing feedback by project or topic
- Feature requests and bug reports with voting and vote budgets
- Comments with markdown, @mentions, reactions, and file attachments
- Status tracking with custom statuses per board
- Roadmap and changelog pages (with scheduled publishing)
- Full-text search with similar post detection
- Push notifications and board-level subscriptions
- RSS feeds per board
- Post view counts
- Admin dashboard with post management, merge, bulk actions, edit rollback
- Team system with invites - super admin, admin, and moderator roles
- Granular locking - lock post edits, comment edits, threads, or voting independently
- Recovery codes for cookie-based users who can't use passkeys
- Plugin system - upload zip plugins through the admin dashboard, no restart needed
- Embed widget for external sites
- Dark and light themes
- i18n ready
- ALTCHA proof-of-work spam protection (no captchas)
## Reverse proxy
Echoboard needs HTTPS for passkeys to work. Example nginx config:
```nginx
server {
listen 443 ssl;
server_name feedback.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 50m;
}
}
```
## Updating
```bash
git pull
docker compose up -d --build
```
Migrations run automatically on startup.
## Data
All persistent data lives next to the compose file:
- `./data/postgres/` - database
- `./uploads/` - avatars and attachments
- `./plugins-installed/` - uploaded plugins
## Plugins
Plugins are zip files uploaded through the admin dashboard. A plugin contains a `manifest.json` and a JS entry point. Plugins can add API routes, respond to events (post created, status changed, etc.), and store their own data. They run with full server access so only install plugins you trust.
A Gitea sync plugin is included in `plugins/gitea-sync/` as an example.
## Development
```bash
npm install
cp .env.example .env
# Fill in .env with dev values (WEBAUTHN_RP_ID=localhost, WEBAUTHN_ORIGIN=http://localhost:3000)
# set WEBAUTHN_RP_ID=localhost, WEBAUTHN_ORIGIN=http://localhost:5173
# point DATABASE_URL at a local postgres
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.
API on port 3001, Vite dev server on port 5173.
## License