pnpm monorepo with three workspaces: - @sbt/shared: zod ScoreboardState + WebSocket protocol (single source of truth) - @sbt/server: Fastify REST + raw ws WebSocket + Drizzle/Postgres, run via tsx - @sbt/web: React + Vite + Tailwind installable PWA Real-time core: the WebSocket server holds authoritative per-board state in memory, broadcasts to all clients (editors + OBS overlays) instantly, and debounces Postgres saves (~750ms). One useScoreboardSync hook powers the editor, the no-login co-edit control page, and the read-only OBS overlay. Includes email+password auth (JWT cookie), scoreboard CRUD, logo upload, customizable scorebug (characters/stocks/score/subtitles/callout/side-swap/theme), Docker Compose + Caddy/nginx deploy configs, and docs/PLAN.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.0 KiB
YAML
38 lines
1.0 KiB
YAML
services:
|
|
db:
|
|
image: postgres:16-alpine
|
|
environment:
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
|
POSTGRES_DB: ${POSTGRES_DB:-scoreboardtools}
|
|
volumes:
|
|
- db-data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ['CMD-SHELL', 'pg_isready -U postgres']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 5
|
|
restart: unless-stopped
|
|
|
|
server:
|
|
build: .
|
|
environment:
|
|
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-scoreboardtools}
|
|
JWT_SECRET: ${JWT_SECRET:?set JWT_SECRET in .env}
|
|
COOKIE_SECURE: ${COOKIE_SECURE:-true}
|
|
UPLOAD_DIR: /data/uploads
|
|
PORT: '3000'
|
|
volumes:
|
|
- uploads:/data/uploads
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
# Bind to localhost only — your reverse proxy (nginx/Caddy) terminates TLS and
|
|
# forwards to this. Drop the 127.0.0.1 prefix only if exposing directly.
|
|
ports:
|
|
- '127.0.0.1:3000:3000'
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
db-data:
|
|
uploads:
|