Add full Docker deployment: setup.sh, update.sh, healthcheck, TURN support

- setup.sh: interactive/non-interactive one-shot installer (build, DB
  healthcheck, migrate, seed, start), idempotent secret generation, NPM
  reverse-proxy network auto-detection and optional join, optional
  AUTO_UPDATE cron install.
- update.sh: release-tag-gated updates only (never bare main), DB backup
  with retention before every update, lock file against concurrent runs,
  automatic code rollback on failed post-update healthcheck.
- Dockerfile: multi-stage build, non-root user, built-in HEALTHCHECK against
  the new /api/health route, wholesale COPY so new source dirs (e.g.
  scripts/) never silently go missing at runtime.
- docker-compose.yml: internal anouma-network (configurable), named volume
  for Postgres, app depends_on postgres healthy, no unnecessary published
  ports; docker-compose.override.yml.example documents joining an existing
  NPM network without ever touching NPM itself.
- Fix host-detection: isHost was Boolean(user), wrongly granting host
  privileges to logged-in customers; now checks user.collection === "users".
- Wire configurable STUN/TURN servers through to the WebRTC client
  (lib/meeting/iceServers.ts) so a TURN server can be added later via env
  vars only, no code changes.
- DEPLOYMENT.md, updated README.md and .env.example documenting the whole
  flow: NPM integration, env vars, WebRTC, updates, backups, rollback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 21:50:28 +02:00
co-authored by Claude Sonnet 5
parent d3d53e68a9
commit 50c39a70e0
16 changed files with 886 additions and 68 deletions
+2
View File
@@ -15,6 +15,7 @@ export type StoredMeetingSession = {
name: string;
eventTitle: string;
eventSlug: string;
iceServers: RTCIceServer[];
};
export function JoinForm({ slug }: { slug: string }) {
@@ -49,6 +50,7 @@ export function JoinForm({ slug }: { slug: string }) {
name,
eventTitle: data.eventTitle,
eventSlug: slug,
iceServers: data.iceServers,
};
sessionStorage.setItem(MEETING_SESSION_KEY, JSON.stringify(session));
router.push(`/termine/${slug}/call`);