Part 3 — Deployment
For whoever runs the server. The whole app is one Docker Compose stack, so it runs the same on a home server or any cloud VM.
First install
git clone <your-repo> polltastic && cd polltastic
cp .env.example .env
Edit .env:
| Variable | What to set |
|---|---|
ADMIN_PASSWORD |
Password for the first admin account. Change this. |
ADMIN_EMAIL |
Email for that first admin (e.g. you@church.org) |
APP_SECRET |
A long random string. Signs winner QR codes — keep it stable, or old codes stop verifying |
POSTGRES_PASSWORD |
Any strong password |
DOMAIN |
:80 for a LAN test; your real domain in production |
Generate good secrets with openssl rand -base64 32.
Then:
docker compose up -d --build
Open the site and sign in at /teach with ADMIN_EMAIL / ADMIN_PASSWORD. That account is created automatically on first boot. Change the password, then add your teachers from /users.
HTTPS
Set DOMAIN=poll.yourchurch.org in .env, point that DNS name at the server, and open ports 80 and 443. Caddy fetches and renews a Let's Encrypt certificate automatically — nothing else to configure.
HTTPS isn't optional in practice: phone notifications, "Add to Home Screen", and the clipboard buttons all require it.
Push notifications (optional)
npm run vapid
Put the two keys into .env as VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY, set VAPID_SUBJECT=mailto:you@church.org, then docker compose up -d. Without these the app still works — phones just don't get notifications.
Backups
Everything lives in Postgres:
docker compose exec -T db pg_dump -U polltastic polltastic > backup-$(date +%F).sql
Keep .env somewhere safe too — losing APP_SECRET invalidates outstanding winner QR codes.
Moving to another host
pg_dumpon the old server (above).- Copy the repo and
.envto the new one, setDOMAIN. docker compose up -d --build- Restore: ``
sh docker compose exec -T db psql -U polltastic polltastic < backup.sql`` - Point DNS at the new server.
No re-architecture and no data loss — that portability is a deliberate design constraint, so you're never locked to one host.
Upgrading
git pull && docker compose up -d --build
Database migrations run automatically on boot.
Branding the icons
App icons are generated, no image editor needed. Change the colour in tools/make-icons.mjs, then:
npm run icons && docker compose up -d --build
Scale
A single instance comfortably handles a congregation. Everything is in one Node process with in-memory realtime state, which is the right choice at this size. If you ever needed multiple instances, the realtime layer (server/src/hub.ts) is deliberately isolated so it can be swapped for Redis without touching anything else.