- Go 32.9%
- HTML 24.1%
- TypeScript 21.5%
- JavaScript 11.8%
- CSS 8.2%
- Other 1.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The previous fix scoped "Als Nächstes" strictly to the selected day tab, but that meant switching to a day whose bands had already passed (by wall-clock time) just showed an empty box, even though the person's actual next band might be on a following day -- there was no way to know that without a real date, since "Tag 1".."Tag 5" were just labels. Each day in festival.ini now requires a `date = YYYY-MM-DD` key (validated at startup like the other fields). The backend exposes it via /api/config, and computeUpcoming() now builds a real Date per band (day's date + band's time, with times before 06:00 correctly rolling onto the next real calendar date) and returns the next N signed-up bands across the whole festival by actual chronological order -- completely independent of which day tab happens to be selected. Verified with realistic past/today/tomorrow scenarios: past bands are excluded, today's remaining bands and tomorrow's bands are both picked up in the right order, and the midnight-rollover math resolves to the correct following calendar date. No dedicated security review for this one: it's a config schema addition plus client-side date arithmetic, no new user input, no new WS message type, no new trust boundary. |
||
| .claude | ||
| backend | ||
| config | ||
| frontend | ||
| migration | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| README.md | ||
| sboa26-signup-firebase.html | ||
Festival Track - Live Signup Board
Festival Track is a live festival signup board that replaces the legacy Firebase-based HTML file. It allows festival participants to sign up for performances in real time, with live synchronization across all connected browsers—no page reload necessary.
Prerequisites
- Docker (version 20.10+)
- Docker Compose (version 2.0+)
- A text editor to configure
config/festival.ini
Quick Start
-
Prepare environment variables:
cp .env.example .envEdit
.envand set a strong password forPOSTGRES_PASSWORD. Never commit this file to version control. -
Configure the festival lineup:
cp config/festival.ini.example config/festival.iniconfig/festival.iniis gitignored (just like.env) so your real lineup and participant names never end up in version control -- only the generic.exampletemplate is tracked. Editconfig/festival.inito set:- Event metadata (
[event]section): title, tagline, description, footer - Participant names (
[participants]section): comma-separated list of names - Days and stages:
[days]section lists the day order; one[<DayName>]section per day withstages=...line; one[<DayName>.<StageName>]section per stage withBand Name = HH:MMentries
- Event metadata (
-
Start the services:
docker compose up -d --buildThis builds the Docker image and starts both the PostgreSQL database and the web app.
-
Access the app: Open your browser to
http://localhost:8080(or the port you set in.envviaAPP_PORT).
Configuration
Environment Variables (.env)
POSTGRES_USER: Database user (default:festival)POSTGRES_PASSWORD: Required. Choose a strong, unique password.POSTGRES_DB: Database name (default:festival)APP_PORT: Host port for the web app (default:8080)DEBUG: Set totrueto dump the fully parsed config (all days, stages, bands, and participants, each with the generated id) todocker compose logs appat startup. Default: off. Useful for verifyingfestival.iniwas parsed as expected.
Config validation
At startup the app validates festival.ini and refuses to start (with a list of every problem found) if it detects: no participants, duplicate participant names, no days, a day with no stages, a stage with no bands, a band with an empty name/time, a band time that isn't HH:MM, a day with a missing/malformed date, or two bands whose generated ids collide. A sparse lineup (e.g. a day with only one stage) is valid and will not be rejected.
INI Configuration (config/festival.ini)
Example structure:
[event]
title = Festival Name
eyebrow = Location / Year
subtitle = Description for participants
footer = Footer text
[participants]
names = Alice, Bob, Charlie, Diana
[days]
order = Day 1, Day 2, Day 3
[Day 1]
date = 2026-08-13
stages = Main Stage, Side Stage
[Day 1.Main Stage]
Band A = 14:00
Band B = 15:30
Band C = 17:00
[Day 1.Side Stage]
Band X = 14:30
Band Y = 16:00
Every day section needs a date = YYYY-MM-DD -- the real calendar date that day starts on. This is what lets the "Als Nächstes" section on the page work out what's genuinely coming up next (across the whole event, not just the currently selected day tab), instead of guessing from the system clock and whichever day happens to be selected. A band timed before 06:00 (e.g. 01:00) is treated as the tail end of that day's program, past midnight into the following real date -- you don't need to adjust anything for that, just set each day's date to the date its program actually starts.
Important: Configuration changes require restarting the app service:
docker compose restart app
Architecture
- Frontend: TypeScript single-page application (SPA) built with esbuild. Assets are statically embedded in the Go binary.
- Backend: Go 1.25 REST + WebSocket server that handles:
- Config queries (
/api/config) - Health checks (
/healthz) - Live WebSocket broadcasts for signup changes (
/ws) - Static file serving (frontend assets)
- Config queries (
- Database: PostgreSQL 16 running in a separate container with persistent data volume.
- Networking: Compose-internal network; database is not exposed to the host. Only the web app port (
APP_PORT) is published.
Deployment Notes
TLS/HTTPS
This deployment runs plain HTTP. For production or public-facing use, deploy behind a reverse proxy (Caddy, nginx, Traefik) to provide HTTPS termination. Example with Caddy:
caddy reverse-proxy --from :443 --to localhost:8080
Stopping and Cleanup
Stop services without removing data:
docker compose down
Remove everything including the database volume:
docker compose down -v
Logs
View app logs:
docker compose logs -f app
View database logs:
docker compose logs -f db
Development
To rebuild the image after code changes:
docker compose up -d --build
To run without daemon mode (see logs in real time):
docker compose up --build
Press Ctrl+C to stop.